drm/nouveau/pm: audit and version NVIF_PERFMON class and methods
authorBen Skeggs <bskeggs@redhat.com>
Sat, 9 Aug 2014 18:10:24 +0000 (04:10 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Sat, 9 Aug 2014 19:13:25 +0000 (05:13 +1000)
The full object interfaces are about to be exposed to userspace, so we
need to check for any security-related issues and version the structs
to make it easier to handle any changes we may need in the future.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/core/engine/perfmon/base.c
drivers/gpu/drm/nouveau/core/include/core/class.h
drivers/gpu/drm/nouveau/nvif/class.h
drivers/gpu/drm/nouveau/nvif/ioctl.h

index 748100307bb6fcfa09dc2c50c5b9b83a709c4a27..63013812f7c952d7e6648a9ccebea08dc71b5605 100644 (file)
  * Authors: Ben Skeggs
  */
 
+#include <core/client.h>
 #include <core/option.h>
-#include <core/class.h>
+#include <nvif/unpack.h>
+#include <nvif/class.h>
+#include <nvif/ioctl.h>
 
 #include <subdev/clock.h>
 
@@ -101,24 +104,28 @@ nouveau_perfsig_wrap(struct nouveau_perfmon *ppm, const char *name,
  * Perfmon object classes
  ******************************************************************************/
 static int
-nouveau_perfctr_query(struct nouveau_object *object, u32 mthd,
-                     void *data, u32 size)
+nouveau_perfctr_query(struct nouveau_object *object, void *data, u32 size)
 {
+       union {
+               struct nvif_perfctr_query_v0 v0;
+       } *args = data;
        struct nouveau_device *device = nv_device(object);
        struct nouveau_perfmon *ppm = (void *)object->engine;
        struct nouveau_perfdom *dom = NULL, *chk;
-       struct nv_perfctr_query *args = data;
        const bool all = nouveau_boolopt(device->cfgopt, "NvPmShowAll", false);
        const bool raw = nouveau_boolopt(device->cfgopt, "NvPmUnnamed", all);
        const char *name;
        int tmp = 0, di, si;
-       char path[64];
-
-       if (size < sizeof(*args))
-               return -EINVAL;
+       int ret;
 
-       di = (args->iter & 0xff000000) >> 24;
-       si = (args->iter & 0x00ffffff) - 1;
+       nv_ioctl(object, "perfctr query size %d\n", size);
+       if (nvif_unpack(args->v0, 0, 0, false)) {
+               nv_ioctl(object, "perfctr query vers %d iter %08x\n",
+                        args->v0.version, args->v0.iter);
+               di = (args->v0.iter & 0xff000000) >> 24;
+               si = (args->v0.iter & 0x00ffffff) - 1;
+       } else
+               return ret;
 
        list_for_each_entry(chk, &ppm->domains, head) {
                if (tmp++ == di) {
@@ -132,19 +139,17 @@ nouveau_perfctr_query(struct nouveau_object *object, u32 mthd,
 
        if (si >= 0) {
                if (raw || !(name = dom->signal[si].name)) {
-                       snprintf(path, sizeof(path), "/%s/%02x", dom->name, si);
-                       name = path;
+                       snprintf(args->v0.name, sizeof(args->v0.name),
+                                "/%s/%02x", dom->name, si);
+               } else {
+                       strncpy(args->v0.name, name, sizeof(args->v0.name));
                }
-
-               if (args->name)
-                       strncpy(args->name, name, args->size);
-               args->size = strlen(name) + 1;
        }
 
        do {
                while (++si < dom->signal_nr) {
                        if (all || dom->signal[si].name) {
-                               args->iter = (di << 24) | ++si;
+                               args->v0.iter = (di << 24) | ++si;
                                return 0;
                        }
                }
@@ -153,21 +158,26 @@ nouveau_perfctr_query(struct nouveau_object *object, u32 mthd,
                dom = list_entry(dom->head.next, typeof(*dom), head);
        } while (&dom->head != &ppm->domains);
 
-       args->iter = 0xffffffff;
+       args->v0.iter = 0xffffffff;
        return 0;
 }
 
 static int
-nouveau_perfctr_sample(struct nouveau_object *object, u32 mthd,
-                      void *data, u32 size)
+nouveau_perfctr_sample(struct nouveau_object *object, void *data, u32 size)
 {
+       union {
+               struct nvif_perfctr_sample none;
+       } *args = data;
        struct nouveau_perfmon *ppm = (void *)object->engine;
        struct nouveau_perfctr *ctr, *tmp;
        struct nouveau_perfdom *dom;
-       struct nv_perfctr_sample *args = data;
+       int ret;
 
-       if (size < sizeof(*args))
-               return -EINVAL;
+       nv_ioctl(object, "perfctr sample size %d\n", size);
+       if (nvif_unvers(args->none)) {
+               nv_ioctl(object, "perfctr sample\n");
+       } else
+               return ret;
        ppm->sequence++;
 
        list_for_each_entry(dom, &ppm->domains, head) {
@@ -206,22 +216,45 @@ nouveau_perfctr_sample(struct nouveau_object *object, u32 mthd,
 }
 
 static int
-nouveau_perfctr_read(struct nouveau_object *object, u32 mthd,
-                    void *data, u32 size)
+nouveau_perfctr_read(struct nouveau_object *object, void *data, u32 size)
 {
+       union {
+               struct nvif_perfctr_read_v0 v0;
+       } *args = data;
        struct nouveau_perfctr *ctr = (void *)object;
-       struct nv_perfctr_read *args = data;
+       int ret;
+
+       nv_ioctl(object, "perfctr read size %d\n", size);
+       if (nvif_unpack(args->v0, 0, 0, false)) {
+               nv_ioctl(object, "perfctr read vers %d\n", args->v0.version);
+       } else
+               return ret;
 
-       if (size < sizeof(*args))
-               return -EINVAL;
        if (!ctr->clk)
                return -EAGAIN;
 
-       args->clk = ctr->clk;
-       args->ctr = ctr->ctr;
+       args->v0.clk = ctr->clk;
+       args->v0.ctr = ctr->ctr;
        return 0;
 }
 
+static int
+nouveau_perfctr_mthd(struct nouveau_object *object, u32 mthd,
+                    void *data, u32 size)
+{
+       switch (mthd) {
+       case NVIF_PERFCTR_V0_QUERY:
+               return nouveau_perfctr_query(object, data, size);
+       case NVIF_PERFCTR_V0_SAMPLE:
+               return nouveau_perfctr_sample(object, data, size);
+       case NVIF_PERFCTR_V0_READ:
+               return nouveau_perfctr_read(object, data, size);
+       default:
+               break;
+       }
+       return -EINVAL;
+}
+
 static void
 nouveau_perfctr_dtor(struct nouveau_object *object)
 {
@@ -237,19 +270,27 @@ nouveau_perfctr_ctor(struct nouveau_object *parent,
                     struct nouveau_oclass *oclass, void *data, u32 size,
                     struct nouveau_object **pobject)
 {
+       union {
+               struct nvif_perfctr_v0 v0;
+       } *args = data;
        struct nouveau_perfmon *ppm = (void *)engine;
        struct nouveau_perfdom *dom = NULL;
        struct nouveau_perfsig *sig[4] = {};
        struct nouveau_perfctr *ctr;
-       struct nv_perfctr_class *args = data;
        int ret, i;
 
-       if (size < sizeof(*args))
-               return -EINVAL;
+       nv_ioctl(parent, "create perfctr size %d\n", size);
+       if (nvif_unpack(args->v0, 0, 0, false)) {
+               nv_ioctl(parent, "create perfctr vers %d logic_op %04x\n",
+                        args->v0.version, args->v0.logic_op);
+       } else
+               return ret;
 
-       for (i = 0; i < ARRAY_SIZE(args->signal) && args->signal[i].name; i++) {
-               sig[i] = nouveau_perfsig_find(ppm, args->signal[i].name,
-                                             args->signal[i].size, &dom);
+       for (i = 0; i < ARRAY_SIZE(args->v0.name) && args->v0.name[i][0]; i++) {
+               sig[i] = nouveau_perfsig_find(ppm, args->v0.name[i],
+                                             strnlen(args->v0.name[i],
+                                             sizeof(args->v0.name[i])),
+                                             &dom);
                if (!sig[i])
                        return -EINVAL;
        }
@@ -260,7 +301,7 @@ nouveau_perfctr_ctor(struct nouveau_object *parent,
                return ret;
 
        ctr->slot = -1;
-       ctr->logic_op = args->logic_op;
+       ctr->logic_op = args->v0.logic_op;
        ctr->signal[0] = sig[0];
        ctr->signal[1] = sig[1];
        ctr->signal[2] = sig[2];
@@ -276,21 +317,13 @@ nouveau_perfctr_ofuncs = {
        .dtor = nouveau_perfctr_dtor,
        .init = nouveau_object_init,
        .fini = nouveau_object_fini,
-};
-
-static struct nouveau_omthds
-nouveau_perfctr_omthds[] = {
-       { NV_PERFCTR_QUERY, NV_PERFCTR_QUERY, nouveau_perfctr_query },
-       { NV_PERFCTR_SAMPLE, NV_PERFCTR_SAMPLE, nouveau_perfctr_sample },
-       { NV_PERFCTR_READ, NV_PERFCTR_READ, nouveau_perfctr_read },
-       {}
+       .mthd = nouveau_perfctr_mthd,
 };
 
 struct nouveau_oclass
 nouveau_perfmon_sclass[] = {
-       { .handle = NV_PERFCTR_CLASS,
+       { .handle = NVIF_IOCTL_NEW_V0_PERFCTR,
          .ofuncs = &nouveau_perfctr_ofuncs,
-         .omthds =  nouveau_perfctr_omthds,
        },
        {},
 };
index 53004b7a3f465b0aac568395dd42a414912b9c32..3df23606eb0268026f17cd45ba7d3f80c2091a94 100644 (file)
@@ -3,37 +3,6 @@
 
 #include <nvif/class.h>
 
-/* Perfmon counter class
- *
- * XXXX: NV_PERFCTR
- */
-#define NV_PERFCTR_CLASS                                             0x0000ffff
-#define NV_PERFCTR_QUERY                                             0x00000000
-#define NV_PERFCTR_SAMPLE                                            0x00000001
-#define NV_PERFCTR_READ                                              0x00000002
-
-struct nv_perfctr_class {
-       u16 logic_op;
-       struct {
-               char __user *name; /*XXX: use cfu when exposed to userspace */
-               u32 size;
-       } signal[4];
-};
-
-struct nv_perfctr_query {
-       u32 iter;
-       u32 size;
-       char __user *name; /*XXX: use ctu when exposed to userspace */
-};
-
-struct nv_perfctr_sample {
-};
-
-struct nv_perfctr_read {
-       u32 ctr;
-       u32 clk;
-};
-
 /* Device control class
  *
  * XXXX: NV_CONTROL
index 5279d0dd4d6f67c4272a705e2f638de9f1ba87b0..decca22ea5280ac5c2e1d3bd69ac1ab5524532d0 100644 (file)
@@ -151,4 +151,38 @@ struct gf110_dma_v0 {
        __u8  pad03[5];
 };
 
+
+/*******************************************************************************
+ * perfmon
+ ******************************************************************************/
+
+struct nvif_perfctr_v0 {
+       __u8  version;
+       __u8  pad01[1];
+       __u16 logic_op;
+       __u8  pad04[4];
+       char  name[4][64];
+};
+
+#define NVIF_PERFCTR_V0_QUERY                                              0x00
+#define NVIF_PERFCTR_V0_SAMPLE                                             0x01
+#define NVIF_PERFCTR_V0_READ                                               0x02
+
+struct nvif_perfctr_query_v0 {
+       __u8  version;
+       __u8  pad01[3];
+       __u32 iter;
+       char  name[64];
+};
+
+struct nvif_perfctr_sample {
+};
+
+struct nvif_perfctr_read_v0 {
+       __u8  version;
+       __u8  pad01[7];
+       __u32 ctr;
+       __u32 clk;
+};
+
 #endif
index 38f24d1e9f60d745b38eef5cfd787206b23509af..67a56711b18c91b7840f68b4310e189b93297c90 100644 (file)
@@ -48,6 +48,8 @@ struct nvif_ioctl_new_v0 {
        __u8  route;
        __u64 token;
        __u32 handle;
+/* these class numbers are made up by us, and not nvidia-assigned */
+#define NVIF_IOCTL_NEW_V0_PERFCTR                                    0x0000ffff
        __u32 oclass;
        __u8  data[];           /* class data (class.h) */
 };