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 <bskeggs@redhat.com>
This commit is contained in:
Ben Skeggs 2014-08-10 04:10:24 +10:00
parent aedf43d5fc
commit 586491e6fc
7 changed files with 135 additions and 105 deletions

View File

@ -195,66 +195,117 @@ nouveau_devobj_wr32(struct nouveau_object *object, u64 addr, u32 data)
nv_wr32(object->engine, addr, 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[] = { static const u64 disable_map[] = {
[NVDEV_SUBDEV_VBIOS] = NV_DEVICE_DISABLE_VBIOS, [NVDEV_SUBDEV_VBIOS] = NV_DEVICE_V0_DISABLE_VBIOS,
[NVDEV_SUBDEV_DEVINIT] = NV_DEVICE_DISABLE_CORE, [NVDEV_SUBDEV_DEVINIT] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_GPIO] = NV_DEVICE_DISABLE_CORE, [NVDEV_SUBDEV_GPIO] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_I2C] = NV_DEVICE_DISABLE_CORE, [NVDEV_SUBDEV_I2C] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_CLOCK] = NV_DEVICE_DISABLE_CORE, [NVDEV_SUBDEV_CLOCK] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_MXM] = NV_DEVICE_DISABLE_CORE, [NVDEV_SUBDEV_MXM] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_MC] = NV_DEVICE_DISABLE_CORE, [NVDEV_SUBDEV_MC] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_BUS] = NV_DEVICE_DISABLE_CORE, [NVDEV_SUBDEV_BUS] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_TIMER] = NV_DEVICE_DISABLE_CORE, [NVDEV_SUBDEV_TIMER] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_FB] = NV_DEVICE_DISABLE_CORE, [NVDEV_SUBDEV_FB] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_LTCG] = NV_DEVICE_DISABLE_CORE, [NVDEV_SUBDEV_LTCG] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_IBUS] = NV_DEVICE_DISABLE_CORE, [NVDEV_SUBDEV_IBUS] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_INSTMEM] = NV_DEVICE_DISABLE_CORE, [NVDEV_SUBDEV_INSTMEM] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_VM] = NV_DEVICE_DISABLE_CORE, [NVDEV_SUBDEV_VM] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_BAR] = NV_DEVICE_DISABLE_CORE, [NVDEV_SUBDEV_BAR] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_VOLT] = NV_DEVICE_DISABLE_CORE, [NVDEV_SUBDEV_VOLT] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_THERM] = NV_DEVICE_DISABLE_CORE, [NVDEV_SUBDEV_THERM] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_PWR] = NV_DEVICE_DISABLE_CORE, [NVDEV_SUBDEV_PWR] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_ENGINE_DMAOBJ] = NV_DEVICE_DISABLE_CORE, [NVDEV_ENGINE_DMAOBJ] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_ENGINE_PERFMON] = NV_DEVICE_DISABLE_CORE, [NVDEV_ENGINE_PERFMON] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_ENGINE_FIFO] = NV_DEVICE_DISABLE_FIFO, [NVDEV_ENGINE_FIFO] = NV_DEVICE_V0_DISABLE_FIFO,
[NVDEV_ENGINE_SW] = NV_DEVICE_DISABLE_FIFO, [NVDEV_ENGINE_SW] = NV_DEVICE_V0_DISABLE_FIFO,
[NVDEV_ENGINE_GR] = NV_DEVICE_DISABLE_GRAPH, [NVDEV_ENGINE_GR] = NV_DEVICE_V0_DISABLE_GRAPH,
[NVDEV_ENGINE_MPEG] = NV_DEVICE_DISABLE_MPEG, [NVDEV_ENGINE_MPEG] = NV_DEVICE_V0_DISABLE_MPEG,
[NVDEV_ENGINE_ME] = NV_DEVICE_DISABLE_ME, [NVDEV_ENGINE_ME] = NV_DEVICE_V0_DISABLE_ME,
[NVDEV_ENGINE_VP] = NV_DEVICE_DISABLE_VP, [NVDEV_ENGINE_VP] = NV_DEVICE_V0_DISABLE_VP,
[NVDEV_ENGINE_CRYPT] = NV_DEVICE_DISABLE_CRYPT, [NVDEV_ENGINE_CRYPT] = NV_DEVICE_V0_DISABLE_CRYPT,
[NVDEV_ENGINE_BSP] = NV_DEVICE_DISABLE_BSP, [NVDEV_ENGINE_BSP] = NV_DEVICE_V0_DISABLE_BSP,
[NVDEV_ENGINE_PPP] = NV_DEVICE_DISABLE_PPP, [NVDEV_ENGINE_PPP] = NV_DEVICE_V0_DISABLE_PPP,
[NVDEV_ENGINE_COPY0] = NV_DEVICE_DISABLE_COPY0, [NVDEV_ENGINE_COPY0] = NV_DEVICE_V0_DISABLE_COPY0,
[NVDEV_ENGINE_COPY1] = NV_DEVICE_DISABLE_COPY1, [NVDEV_ENGINE_COPY1] = NV_DEVICE_V0_DISABLE_COPY1,
[NVDEV_ENGINE_VIC] = NV_DEVICE_DISABLE_VIC, [NVDEV_ENGINE_VIC] = NV_DEVICE_V0_DISABLE_VIC,
[NVDEV_ENGINE_VENC] = NV_DEVICE_DISABLE_VENC, [NVDEV_ENGINE_VENC] = NV_DEVICE_V0_DISABLE_VENC,
[NVDEV_ENGINE_DISP] = NV_DEVICE_DISABLE_DISP, [NVDEV_ENGINE_DISP] = NV_DEVICE_V0_DISABLE_DISP,
[NVDEV_SUBDEV_NR] = 0, [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 static int
nouveau_devobj_ctor(struct nouveau_object *parent, nouveau_devobj_ctor(struct nouveau_object *parent,
struct nouveau_object *engine, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject) struct nouveau_object **pobject)
{ {
union {
struct nv_device_v0 v0;
} *args = data;
struct nouveau_client *client = nv_client(parent); struct nouveau_client *client = nv_client(parent);
struct nouveau_device *device; struct nouveau_device *device;
struct nouveau_devobj *devobj; struct nouveau_devobj *devobj;
struct nv_device_class *args = data;
u32 boot0, strap; u32 boot0, strap;
u64 disable, mmio_base, mmio_size; u64 disable, mmio_base, mmio_size;
void __iomem *map; void __iomem *map;
int ret, i, c; int ret, i, c;
if (size < sizeof(struct nv_device_class)) nv_ioctl(parent, "create device size %d\n", size);
return -EINVAL; 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 */ /* find the device subdev that matches what the client requested */
device = nv_device(client->device); device = nv_device(client->device);
if (args->device != ~0) { if (args->v0.device != ~0) {
device = nouveau_device_find(args->device); device = nouveau_device_find(args->v0.device);
if (!device) if (!device)
return -ENODEV; return -ENODEV;
} }
@ -273,14 +324,14 @@ nouveau_devobj_ctor(struct nouveau_object *parent,
mmio_size = nv_device_resource_len(device, 0); mmio_size = nv_device_resource_len(device, 0);
/* translate api disable mask into internal mapping */ /* translate api disable mask into internal mapping */
disable = args->debug0; disable = args->v0.debug0;
for (i = 0; i < NVDEV_SUBDEV_NR; i++) { for (i = 0; i < NVDEV_SUBDEV_NR; i++) {
if (args->disable & disable_map[i]) if (args->v0.disable & disable_map[i])
disable |= (1ULL << i); disable |= (1ULL << i);
} }
/* identify the chipset, and determine classes of subdev/engines */ /* 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) { !device->card_type) {
map = ioremap(mmio_base, 0x102000); map = ioremap(mmio_base, 0x102000);
if (map == NULL) if (map == NULL)
@ -379,7 +430,7 @@ nouveau_devobj_ctor(struct nouveau_object *parent,
nv_debug(device, "crystal freq: %dKHz\n", device->crystal); 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) {
nv_subdev(device)->mmio = ioremap(mmio_base, mmio_size); nv_subdev(device)->mmio = ioremap(mmio_base, mmio_size);
if (!nv_subdev(device)->mmio) { if (!nv_subdev(device)->mmio) {
@ -435,18 +486,6 @@ nouveau_devobj_ctor(struct nouveau_object *parent,
return 0; 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 static struct nouveau_ofuncs
nouveau_devobj_ofuncs = { nouveau_devobj_ofuncs = {
.ctor = nouveau_devobj_ctor, .ctor = nouveau_devobj_ctor,
@ -454,12 +493,6 @@ nouveau_devobj_ofuncs = {
.init = _nouveau_parent_init, .init = _nouveau_parent_init,
.fini = _nouveau_parent_fini, .fini = _nouveau_parent_fini,
.mthd = nouveau_devobj_mthd, .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,
}; };
/****************************************************************************** /******************************************************************************

View File

@ -990,7 +990,7 @@ nv50_disp_data_ctor(struct nouveau_object *parent,
int ret = -EBUSY; int ret = -EBUSY;
/* no context needed for channel objects... */ /* no context needed for channel objects... */
if (nv_mclass(parent) != NV_DEVICE_CLASS) { if (nv_mclass(parent) != NV_DEVICE) {
atomic_inc(&parent->refcount); atomic_inc(&parent->refcount);
*pobject = parent; *pobject = parent;
return 1; return 1;

View File

@ -88,7 +88,7 @@ nouveau_dmaobj_ctor(struct nouveau_object *parent,
dmaobj->conf0 = args->conf0; dmaobj->conf0 = args->conf0;
switch (nv_mclass(parent)) { switch (nv_mclass(parent)) {
case NV_DEVICE_CLASS: case NV_DEVICE:
/* delayed, or no, binding */ /* delayed, or no, binding */
break; break;
default: default:

View File

@ -3,36 +3,6 @@
#include <nvif/class.h> #include <nvif/class.h>
/* 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 /* DMA object classes
* *
* 0002: NV_DMA_FROM_MEMORY * 0002: NV_DMA_FROM_MEMORY

View File

@ -41,6 +41,10 @@ nouveau_abi16_get(struct drm_file *file_priv, struct drm_device *dev)
struct nouveau_abi16 *abi16; struct nouveau_abi16 *abi16;
cli->abi16 = abi16 = kzalloc(sizeof(*abi16), GFP_KERNEL); cli->abi16 = abi16 = kzalloc(sizeof(*abi16), GFP_KERNEL);
if (cli->abi16) { if (cli->abi16) {
struct nv_device_v0 args = {
.device = ~0ULL,
};
INIT_LIST_HEAD(&abi16->channels); INIT_LIST_HEAD(&abi16->channels);
/* allocate device object targeting client's default /* 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, if (nvif_device_init(&cli->base.base, NULL,
NOUVEAU_ABI16_DEVICE, NV_DEVICE, NOUVEAU_ABI16_DEVICE, NV_DEVICE,
&(struct nv_device_class) { &args, sizeof(args),
.device = ~0ULL,
}, sizeof(struct nv_device_class),
&abi16->device) == 0) &abi16->device) == 0)
return cli->abi16; return cli->abi16;

View File

@ -383,18 +383,18 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
* (possibly) execute vbios init tables (see nouveau_agp.h) * (possibly) execute vbios init tables (see nouveau_agp.h)
*/ */
if (pdev && drm_pci_device_is_agp(dev) && dev->agp) { 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 /* dummy device object, doesn't init anything, but allows
* agp code access to registers * agp code access to registers
*/ */
ret = nvif_device_init(&drm->client.base.base, NULL, ret = nvif_device_init(&drm->client.base.base, NULL,
NVDRM_DEVICE, NV_DEVICE_CLASS, NVDRM_DEVICE, NV_DEVICE,
&(struct nv_device_class) { &(struct nv_device_v0) {
.device = ~0, .device = ~0,
.disable = .disable = ~enables,
~(NV_DEVICE_DISABLE_MMIO |
NV_DEVICE_DISABLE_IDENTIFY),
.debug0 = ~0, .debug0 = ~0,
}, sizeof(struct nv_device_class), }, sizeof(struct nv_device_v0),
&drm->device); &drm->device);
if (ret) if (ret)
goto fail_device; 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, ret = nvif_device_init(&drm->client.base.base, NULL, NVDRM_DEVICE,
NV_DEVICE_CLASS, NV_DEVICE,
&(struct nv_device_class) { &(struct nv_device_v0) {
.device = ~0, .device = ~0,
.disable = 0, .disable = 0,
.debug0 = 0, .debug0 = 0,
}, sizeof(struct nv_device_class), }, sizeof(struct nv_device_v0),
&drm->device); &drm->device);
if (ret) if (ret)
goto fail_device; goto fail_device;

View File

@ -27,6 +27,31 @@ struct nv_client_devlist_v0 {
* device * 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 #define NV_DEVICE_V0_INFO 0x00
struct nv_device_info_v0 { struct nv_device_info_v0 {