diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2014-08-10 04:10:24 +1000 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2014-08-10 05:13:25 +1000 |
commit | 96af8222cef78ab4d92186d5e10880dc78395415 (patch) | |
tree | b90b8fe780d6e0530dfd98a798a08133ced8823c | |
parent | 4acfd707e28c820ba8ed8c12b497413a133d8c8f (diff) |
drm/nouveau/pm: audit and version NVIF_PERFMON class and methods
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>
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/perfmon/base.c | 127 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/include/core/class.h | 31 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvif/class.h | 34 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvif/ioctl.h | 2 |
4 files changed, 116 insertions, 78 deletions
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/base.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/base.c index 748100307bb6..63013812f7c9 100644 --- a/drivers/gpu/drm/nouveau/core/engine/perfmon/base.c +++ b/drivers/gpu/drm/nouveau/core/engine/perfmon/base.c @@ -22,8 +22,11 @@ * 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, }, {}, }; diff --git a/drivers/gpu/drm/nouveau/core/include/core/class.h b/drivers/gpu/drm/nouveau/core/include/core/class.h index 53004b7a3f46..3df23606eb02 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/class.h +++ b/drivers/gpu/drm/nouveau/core/include/core/class.h @@ -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 diff --git a/drivers/gpu/drm/nouveau/nvif/class.h b/drivers/gpu/drm/nouveau/nvif/class.h index 5279d0dd4d6f..decca22ea528 100644 --- a/drivers/gpu/drm/nouveau/nvif/class.h +++ b/drivers/gpu/drm/nouveau/nvif/class.h @@ -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 diff --git a/drivers/gpu/drm/nouveau/nvif/ioctl.h b/drivers/gpu/drm/nouveau/nvif/ioctl.h index 38f24d1e9f60..67a56711b18c 100644 --- a/drivers/gpu/drm/nouveau/nvif/ioctl.h +++ b/drivers/gpu/drm/nouveau/nvif/ioctl.h @@ -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) */ }; |