From 586491e6fc27f1783081955fd26d70789ddb3a07 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sun, 10 Aug 2014 04:10:24 +1000 Subject: [PATCH] drm/nouveau/device: audit and version NV_DEVICE class 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 --- .../gpu/drm/nouveau/core/engine/device/base.c | 155 +++++++++++------- .../gpu/drm/nouveau/core/engine/disp/nv50.c | 2 +- .../gpu/drm/nouveau/core/engine/dmaobj/base.c | 2 +- .../gpu/drm/nouveau/core/include/core/class.h | 30 ---- drivers/gpu/drm/nouveau/nouveau_abi16.c | 8 +- drivers/gpu/drm/nouveau/nouveau_drm.c | 18 +- drivers/gpu/drm/nouveau/nvif/class.h | 25 +++ 7 files changed, 135 insertions(+), 105 deletions(-) diff --git a/drivers/gpu/drm/nouveau/core/engine/device/base.c b/drivers/gpu/drm/nouveau/core/engine/device/base.c index 8d74a31635bf..c7e9794a3abc 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/base.c @@ -195,66 +195,117 @@ nouveau_devobj_wr32(struct nouveau_object *object, u64 addr, u32 data) nv_wr32(object->engine, addr, data); } +static int +nouveau_devobj_map(struct nouveau_object *object, u64 *addr, u32 *size) +{ + struct nouveau_device *device = nv_device(object); + *addr = nv_device_resource_start(device, 0); + *size = nv_device_resource_len(device, 0); + return 0; +} + static const u64 disable_map[] = { - [NVDEV_SUBDEV_VBIOS] = NV_DEVICE_DISABLE_VBIOS, - [NVDEV_SUBDEV_DEVINIT] = NV_DEVICE_DISABLE_CORE, - [NVDEV_SUBDEV_GPIO] = NV_DEVICE_DISABLE_CORE, - [NVDEV_SUBDEV_I2C] = NV_DEVICE_DISABLE_CORE, - [NVDEV_SUBDEV_CLOCK] = NV_DEVICE_DISABLE_CORE, - [NVDEV_SUBDEV_MXM] = NV_DEVICE_DISABLE_CORE, - [NVDEV_SUBDEV_MC] = NV_DEVICE_DISABLE_CORE, - [NVDEV_SUBDEV_BUS] = NV_DEVICE_DISABLE_CORE, - [NVDEV_SUBDEV_TIMER] = NV_DEVICE_DISABLE_CORE, - [NVDEV_SUBDEV_FB] = NV_DEVICE_DISABLE_CORE, - [NVDEV_SUBDEV_LTCG] = NV_DEVICE_DISABLE_CORE, - [NVDEV_SUBDEV_IBUS] = NV_DEVICE_DISABLE_CORE, - [NVDEV_SUBDEV_INSTMEM] = NV_DEVICE_DISABLE_CORE, - [NVDEV_SUBDEV_VM] = NV_DEVICE_DISABLE_CORE, - [NVDEV_SUBDEV_BAR] = NV_DEVICE_DISABLE_CORE, - [NVDEV_SUBDEV_VOLT] = NV_DEVICE_DISABLE_CORE, - [NVDEV_SUBDEV_THERM] = NV_DEVICE_DISABLE_CORE, - [NVDEV_SUBDEV_PWR] = NV_DEVICE_DISABLE_CORE, - [NVDEV_ENGINE_DMAOBJ] = NV_DEVICE_DISABLE_CORE, - [NVDEV_ENGINE_PERFMON] = NV_DEVICE_DISABLE_CORE, - [NVDEV_ENGINE_FIFO] = NV_DEVICE_DISABLE_FIFO, - [NVDEV_ENGINE_SW] = NV_DEVICE_DISABLE_FIFO, - [NVDEV_ENGINE_GR] = NV_DEVICE_DISABLE_GRAPH, - [NVDEV_ENGINE_MPEG] = NV_DEVICE_DISABLE_MPEG, - [NVDEV_ENGINE_ME] = NV_DEVICE_DISABLE_ME, - [NVDEV_ENGINE_VP] = NV_DEVICE_DISABLE_VP, - [NVDEV_ENGINE_CRYPT] = NV_DEVICE_DISABLE_CRYPT, - [NVDEV_ENGINE_BSP] = NV_DEVICE_DISABLE_BSP, - [NVDEV_ENGINE_PPP] = NV_DEVICE_DISABLE_PPP, - [NVDEV_ENGINE_COPY0] = NV_DEVICE_DISABLE_COPY0, - [NVDEV_ENGINE_COPY1] = NV_DEVICE_DISABLE_COPY1, - [NVDEV_ENGINE_VIC] = NV_DEVICE_DISABLE_VIC, - [NVDEV_ENGINE_VENC] = NV_DEVICE_DISABLE_VENC, - [NVDEV_ENGINE_DISP] = NV_DEVICE_DISABLE_DISP, + [NVDEV_SUBDEV_VBIOS] = NV_DEVICE_V0_DISABLE_VBIOS, + [NVDEV_SUBDEV_DEVINIT] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_SUBDEV_GPIO] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_SUBDEV_I2C] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_SUBDEV_CLOCK] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_SUBDEV_MXM] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_SUBDEV_MC] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_SUBDEV_BUS] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_SUBDEV_TIMER] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_SUBDEV_FB] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_SUBDEV_LTCG] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_SUBDEV_IBUS] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_SUBDEV_INSTMEM] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_SUBDEV_VM] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_SUBDEV_BAR] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_SUBDEV_VOLT] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_SUBDEV_THERM] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_SUBDEV_PWR] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_ENGINE_DMAOBJ] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_ENGINE_PERFMON] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_ENGINE_FIFO] = NV_DEVICE_V0_DISABLE_FIFO, + [NVDEV_ENGINE_SW] = NV_DEVICE_V0_DISABLE_FIFO, + [NVDEV_ENGINE_GR] = NV_DEVICE_V0_DISABLE_GRAPH, + [NVDEV_ENGINE_MPEG] = NV_DEVICE_V0_DISABLE_MPEG, + [NVDEV_ENGINE_ME] = NV_DEVICE_V0_DISABLE_ME, + [NVDEV_ENGINE_VP] = NV_DEVICE_V0_DISABLE_VP, + [NVDEV_ENGINE_CRYPT] = NV_DEVICE_V0_DISABLE_CRYPT, + [NVDEV_ENGINE_BSP] = NV_DEVICE_V0_DISABLE_BSP, + [NVDEV_ENGINE_PPP] = NV_DEVICE_V0_DISABLE_PPP, + [NVDEV_ENGINE_COPY0] = NV_DEVICE_V0_DISABLE_COPY0, + [NVDEV_ENGINE_COPY1] = NV_DEVICE_V0_DISABLE_COPY1, + [NVDEV_ENGINE_VIC] = NV_DEVICE_V0_DISABLE_VIC, + [NVDEV_ENGINE_VENC] = NV_DEVICE_V0_DISABLE_VENC, + [NVDEV_ENGINE_DISP] = NV_DEVICE_V0_DISABLE_DISP, [NVDEV_SUBDEV_NR] = 0, }; +static void +nouveau_devobj_dtor(struct nouveau_object *object) +{ + struct nouveau_devobj *devobj = (void *)object; + int i; + + for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--) + nouveau_object_ref(NULL, &devobj->subdev[i]); + + nouveau_parent_destroy(&devobj->base); +} + +static struct nouveau_oclass +nouveau_devobj_oclass_super = { + .handle = NV_DEVICE, + .ofuncs = &(struct nouveau_ofuncs) { + .dtor = nouveau_devobj_dtor, + .init = _nouveau_parent_init, + .fini = _nouveau_parent_fini, + .mthd = nouveau_devobj_mthd, + .map = nouveau_devobj_map, + .rd08 = nouveau_devobj_rd08, + .rd16 = nouveau_devobj_rd16, + .rd32 = nouveau_devobj_rd32, + .wr08 = nouveau_devobj_wr08, + .wr16 = nouveau_devobj_wr16, + .wr32 = nouveau_devobj_wr32, + } +}; + static int nouveau_devobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { + union { + struct nv_device_v0 v0; + } *args = data; struct nouveau_client *client = nv_client(parent); struct nouveau_device *device; struct nouveau_devobj *devobj; - struct nv_device_class *args = data; u32 boot0, strap; u64 disable, mmio_base, mmio_size; void __iomem *map; int ret, i, c; - if (size < sizeof(struct nv_device_class)) - return -EINVAL; + nv_ioctl(parent, "create device size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(parent, "create device v%d device %016llx " + "disable %016llx debug0 %016llx\n", + args->v0.version, args->v0.device, + args->v0.disable, args->v0.debug0); + } else + return ret; + + /* give priviledged clients register access */ + if (client->super) + oclass = &nouveau_devobj_oclass_super; /* find the device subdev that matches what the client requested */ device = nv_device(client->device); - if (args->device != ~0) { - device = nouveau_device_find(args->device); + if (args->v0.device != ~0) { + device = nouveau_device_find(args->v0.device); if (!device) return -ENODEV; } @@ -273,14 +324,14 @@ nouveau_devobj_ctor(struct nouveau_object *parent, mmio_size = nv_device_resource_len(device, 0); /* translate api disable mask into internal mapping */ - disable = args->debug0; + disable = args->v0.debug0; for (i = 0; i < NVDEV_SUBDEV_NR; i++) { - if (args->disable & disable_map[i]) + if (args->v0.disable & disable_map[i]) disable |= (1ULL << i); } /* identify the chipset, and determine classes of subdev/engines */ - if (!(args->disable & NV_DEVICE_DISABLE_IDENTIFY) && + if (!(args->v0.disable & NV_DEVICE_V0_DISABLE_IDENTIFY) && !device->card_type) { map = ioremap(mmio_base, 0x102000); if (map == NULL) @@ -379,7 +430,7 @@ nouveau_devobj_ctor(struct nouveau_object *parent, nv_debug(device, "crystal freq: %dKHz\n", device->crystal); } - if (!(args->disable & NV_DEVICE_DISABLE_MMIO) && + if (!(args->v0.disable & NV_DEVICE_V0_DISABLE_MMIO) && !nv_subdev(device)->mmio) { nv_subdev(device)->mmio = ioremap(mmio_base, mmio_size); if (!nv_subdev(device)->mmio) { @@ -435,18 +486,6 @@ nouveau_devobj_ctor(struct nouveau_object *parent, return 0; } -static void -nouveau_devobj_dtor(struct nouveau_object *object) -{ - struct nouveau_devobj *devobj = (void *)object; - int i; - - for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--) - nouveau_object_ref(NULL, &devobj->subdev[i]); - - nouveau_parent_destroy(&devobj->base); -} - static struct nouveau_ofuncs nouveau_devobj_ofuncs = { .ctor = nouveau_devobj_ctor, @@ -454,12 +493,6 @@ nouveau_devobj_ofuncs = { .init = _nouveau_parent_init, .fini = _nouveau_parent_fini, .mthd = nouveau_devobj_mthd, - .rd08 = nouveau_devobj_rd08, - .rd16 = nouveau_devobj_rd16, - .rd32 = nouveau_devobj_rd32, - .wr08 = nouveau_devobj_wr08, - .wr16 = nouveau_devobj_wr16, - .wr32 = nouveau_devobj_wr32, }; /****************************************************************************** diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c index 5311f0fcd291..ca8ce9cace7f 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c @@ -990,7 +990,7 @@ nv50_disp_data_ctor(struct nouveau_object *parent, int ret = -EBUSY; /* no context needed for channel objects... */ - if (nv_mclass(parent) != NV_DEVICE_CLASS) { + if (nv_mclass(parent) != NV_DEVICE) { atomic_inc(&parent->refcount); *pobject = parent; return 1; diff --git a/drivers/gpu/drm/nouveau/core/engine/dmaobj/base.c b/drivers/gpu/drm/nouveau/core/engine/dmaobj/base.c index 5103e88d1877..a11b83d50f9c 100644 --- a/drivers/gpu/drm/nouveau/core/engine/dmaobj/base.c +++ b/drivers/gpu/drm/nouveau/core/engine/dmaobj/base.c @@ -88,7 +88,7 @@ nouveau_dmaobj_ctor(struct nouveau_object *parent, dmaobj->conf0 = args->conf0; switch (nv_mclass(parent)) { - case NV_DEVICE_CLASS: + case NV_DEVICE: /* delayed, or no, binding */ break; default: diff --git a/drivers/gpu/drm/nouveau/core/include/core/class.h b/drivers/gpu/drm/nouveau/core/include/core/class.h index 37d47cb44a7b..fa35f0041562 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/class.h +++ b/drivers/gpu/drm/nouveau/core/include/core/class.h @@ -3,36 +3,6 @@ #include -/* Device class - * - * 0080: NV_DEVICE - */ -#define NV_DEVICE_CLASS 0x00000080 - -#define NV_DEVICE_DISABLE_IDENTIFY 0x0000000000000001ULL -#define NV_DEVICE_DISABLE_MMIO 0x0000000000000002ULL -#define NV_DEVICE_DISABLE_VBIOS 0x0000000000000004ULL -#define NV_DEVICE_DISABLE_CORE 0x0000000000000008ULL -#define NV_DEVICE_DISABLE_DISP 0x0000000000010000ULL -#define NV_DEVICE_DISABLE_FIFO 0x0000000000020000ULL -#define NV_DEVICE_DISABLE_GRAPH 0x0000000100000000ULL -#define NV_DEVICE_DISABLE_MPEG 0x0000000200000000ULL -#define NV_DEVICE_DISABLE_ME 0x0000000400000000ULL -#define NV_DEVICE_DISABLE_VP 0x0000000800000000ULL -#define NV_DEVICE_DISABLE_CRYPT 0x0000001000000000ULL -#define NV_DEVICE_DISABLE_BSP 0x0000002000000000ULL -#define NV_DEVICE_DISABLE_PPP 0x0000004000000000ULL -#define NV_DEVICE_DISABLE_COPY0 0x0000008000000000ULL -#define NV_DEVICE_DISABLE_COPY1 0x0000010000000000ULL -#define NV_DEVICE_DISABLE_VIC 0x0000020000000000ULL -#define NV_DEVICE_DISABLE_VENC 0x0000040000000000ULL - -struct nv_device_class { - u64 device; /* device identifier, ~0 for client default */ - u64 disable; /* disable particular subsystems */ - u64 debug0; /* as above, but *internal* ids, and *NOT* ABI */ -}; - /* DMA object classes * * 0002: NV_DMA_FROM_MEMORY diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index 3192bbaf3df5..1e312feb12e4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -41,6 +41,10 @@ nouveau_abi16_get(struct drm_file *file_priv, struct drm_device *dev) struct nouveau_abi16 *abi16; cli->abi16 = abi16 = kzalloc(sizeof(*abi16), GFP_KERNEL); if (cli->abi16) { + struct nv_device_v0 args = { + .device = ~0ULL, + }; + INIT_LIST_HEAD(&abi16->channels); /* allocate device object targeting client's default @@ -49,9 +53,7 @@ nouveau_abi16_get(struct drm_file *file_priv, struct drm_device *dev) */ if (nvif_device_init(&cli->base.base, NULL, NOUVEAU_ABI16_DEVICE, NV_DEVICE, - &(struct nv_device_class) { - .device = ~0ULL, - }, sizeof(struct nv_device_class), + &args, sizeof(args), &abi16->device) == 0) return cli->abi16; diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 9d0ad53b99d6..f9f2e0efd07c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -383,18 +383,18 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) * (possibly) execute vbios init tables (see nouveau_agp.h) */ if (pdev && drm_pci_device_is_agp(dev) && dev->agp) { + const u64 enables = NV_DEVICE_V0_DISABLE_IDENTIFY | + NV_DEVICE_V0_DISABLE_MMIO; /* dummy device object, doesn't init anything, but allows * agp code access to registers */ ret = nvif_device_init(&drm->client.base.base, NULL, - NVDRM_DEVICE, NV_DEVICE_CLASS, - &(struct nv_device_class) { + NVDRM_DEVICE, NV_DEVICE, + &(struct nv_device_v0) { .device = ~0, - .disable = - ~(NV_DEVICE_DISABLE_MMIO | - NV_DEVICE_DISABLE_IDENTIFY), + .disable = ~enables, .debug0 = ~0, - }, sizeof(struct nv_device_class), + }, sizeof(struct nv_device_v0), &drm->device); if (ret) goto fail_device; @@ -404,12 +404,12 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) } ret = nvif_device_init(&drm->client.base.base, NULL, NVDRM_DEVICE, - NV_DEVICE_CLASS, - &(struct nv_device_class) { + NV_DEVICE, + &(struct nv_device_v0) { .device = ~0, .disable = 0, .debug0 = 0, - }, sizeof(struct nv_device_class), + }, sizeof(struct nv_device_v0), &drm->device); if (ret) goto fail_device; diff --git a/drivers/gpu/drm/nouveau/nvif/class.h b/drivers/gpu/drm/nouveau/nvif/class.h index 3013656bdfa6..0aa6272b972c 100644 --- a/drivers/gpu/drm/nouveau/nvif/class.h +++ b/drivers/gpu/drm/nouveau/nvif/class.h @@ -27,6 +27,31 @@ struct nv_client_devlist_v0 { * device ******************************************************************************/ +struct nv_device_v0 { + __u8 version; + __u8 pad01[7]; + __u64 device; /* device identifier, ~0 for client default */ +#define NV_DEVICE_V0_DISABLE_IDENTIFY 0x0000000000000001ULL +#define NV_DEVICE_V0_DISABLE_MMIO 0x0000000000000002ULL +#define NV_DEVICE_V0_DISABLE_VBIOS 0x0000000000000004ULL +#define NV_DEVICE_V0_DISABLE_CORE 0x0000000000000008ULL +#define NV_DEVICE_V0_DISABLE_DISP 0x0000000000010000ULL +#define NV_DEVICE_V0_DISABLE_FIFO 0x0000000000020000ULL +#define NV_DEVICE_V0_DISABLE_GRAPH 0x0000000100000000ULL +#define NV_DEVICE_V0_DISABLE_MPEG 0x0000000200000000ULL +#define NV_DEVICE_V0_DISABLE_ME 0x0000000400000000ULL +#define NV_DEVICE_V0_DISABLE_VP 0x0000000800000000ULL +#define NV_DEVICE_V0_DISABLE_CRYPT 0x0000001000000000ULL +#define NV_DEVICE_V0_DISABLE_BSP 0x0000002000000000ULL +#define NV_DEVICE_V0_DISABLE_PPP 0x0000004000000000ULL +#define NV_DEVICE_V0_DISABLE_COPY0 0x0000008000000000ULL +#define NV_DEVICE_V0_DISABLE_COPY1 0x0000010000000000ULL +#define NV_DEVICE_V0_DISABLE_VIC 0x0000020000000000ULL +#define NV_DEVICE_V0_DISABLE_VENC 0x0000040000000000ULL + __u64 disable; /* disable particular subsystems */ + __u64 debug0; /* as above, but *internal* ids, and *NOT* ABI */ +}; + #define NV_DEVICE_V0_INFO 0x00 struct nv_device_info_v0 {