From 180c9188f4cb7163f1e3e7d5098eaabf29a98540 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 20 Feb 2008 13:27:10 +1000 Subject: drm/ttm: add ioctl to get back memory managed area sized taken from modesetting branch but could be useful outside it. --- libdrm/xf86drm.c | 15 +++++++++++++++ libdrm/xf86mm.h | 1 + linux-core/drm_bo.c | 37 +++++++++++++++++++++++++++++++++++++ linux-core/drm_drv.c | 2 ++ linux-core/drm_objects.h | 2 ++ shared-core/drm.h | 6 ++++++ 6 files changed, 63 insertions(+) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index fb8f1c66..3317ba5c 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2871,6 +2871,21 @@ int drmMMUnlock(int fd, unsigned memType, int unlockBM) return drmIoctlTimeout(fd, DRM_IOCTL_MM_UNLOCK, &arg); } +int drmMMInfo(int fd, unsigned memType, uint64_t *size) +{ + struct drm_mm_info_arg arg; + + memset(&arg, 0, sizeof(arg)); + + arg.mem_type = memType; + + if (ioctl(fd, DRM_IOCTL_MM_INFO, &arg)) + return -errno; + + *size = arg.p_size; + return 0; +} + int drmBOVersion(int fd, unsigned int *major, unsigned int *minor, unsigned int *patchlevel) diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index c80288a7..bb573407 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -172,6 +172,7 @@ extern int drmMMInit(int fd, unsigned long pOffset, unsigned long pSize, extern int drmMMTakedown(int fd, unsigned memType); extern int drmMMLock(int fd, unsigned memType, int lockBM, int ignoreNoEvict); extern int drmMMUnlock(int fd, unsigned memType, int unlockBM); +extern int drmMMInfo(int fd, unsigned memType, uint64_t *size); extern int drmBOSetStatus(int fd, drmBO *buf, uint64_t flags, uint64_t mask, unsigned int hint, diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 95802fe2..b67946eb 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -2283,6 +2283,7 @@ int drm_bo_init_mm(struct drm_device *dev, } man->has_type = 1; man->use_type = 1; + man->size = p_size; INIT_LIST_HEAD(&man->lru); INIT_LIST_HEAD(&man->pinned); @@ -2553,6 +2554,42 @@ int drm_mm_unlock_ioctl(struct drm_device *dev, return 0; } +int drm_mm_info_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) +{ + struct drm_mm_info_arg *arg = data; + struct drm_buffer_manager *bm = &dev->bm; + struct drm_bo_driver *driver = dev->driver->bo_driver; + struct drm_mem_type_manager *man; + int ret = 0; + int mem_type = arg->mem_type; + + if (!driver) { + DRM_ERROR("Buffer objects are not supported by this driver\n"); + return -EINVAL; + } + + if (mem_type >= DRM_BO_MEM_TYPES) { + DRM_ERROR("Illegal memory type %d\n", arg->mem_type); + return -EINVAL; + } + + mutex_lock(&dev->struct_mutex); + if (!bm->initialized) { + DRM_ERROR("DRM memory manager was not initialized\n"); + ret = -EINVAL; + goto out; + } + + + man = &bm->man[arg->mem_type]; + + arg->p_size = man->size; + +out: + mutex_unlock(&dev->struct_mutex); + + return ret; +} /* * buffer object vm functions. */ diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 1daa8653..b8b8333e 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -148,6 +148,8 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_BO_INFO, drm_bo_info_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_BO_WAIT_IDLE, drm_bo_wait_idle_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_BO_VERSION, drm_bo_version_ioctl, 0), + + DRM_IOCTL_DEF(DRM_IOCTL_MM_INFO, drm_mm_info_ioctl, 0), }; #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index fd32f0f4..ae0725c1 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -525,6 +525,7 @@ struct drm_mem_type_manager { unsigned long io_offset; unsigned long io_size; void *io_addr; + uint64_t size; /* size of managed area for reporting to userspace */ }; struct drm_bo_lock { @@ -651,6 +652,7 @@ extern int drm_mm_init_ioctl(struct drm_device *dev, void *data, struct drm_file extern int drm_mm_takedown_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mm_lock_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mm_unlock_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int drm_mm_info_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_bo_version_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_bo_driver_finish(struct drm_device *dev); extern int drm_bo_driver_init(struct drm_device *dev); diff --git a/shared-core/drm.h b/shared-core/drm.h index 663696c1..5981dcb8 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -955,6 +955,11 @@ struct drm_mm_init_arg { uint64_t p_size; }; +struct drm_mm_info_arg { + unsigned int mem_type; + uint64_t p_size; +}; + /** * \name Ioctls Definitions */ @@ -1046,6 +1051,7 @@ struct drm_mm_init_arg { #define DRM_IOCTL_BO_INFO DRM_IOWR(0xd4, struct drm_bo_reference_info_arg) #define DRM_IOCTL_BO_WAIT_IDLE DRM_IOWR(0xd5, struct drm_bo_map_wait_idle_arg) #define DRM_IOCTL_BO_VERSION DRM_IOR(0xd6, struct drm_bo_version_arg) +#define DRM_IOCTL_MM_INFO DRM_IOWR(0xd7, struct drm_mm_info_arg) /*@}*/ -- cgit v1.2.3 From d5c0101252e9f48ef1b59f48c05fea7007df97f0 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 18 Feb 2008 10:39:21 +1000 Subject: ttm: make sure userspace can't destroy kernel create memory managers this adds something to say the kernel initialised the memory region not the userspace. and blocks userspace from deallocating kernel areas --- linux-core/drm_bo.c | 30 ++++++++++++++++++++---------- linux-core/drm_objects.h | 6 ++++-- shared-core/nouveau_mem.c | 6 +++--- 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index b67946eb..3e8ffa0f 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -2180,7 +2180,7 @@ restart: return 0; } -int drm_bo_clean_mm(struct drm_device *dev, unsigned mem_type) +int drm_bo_clean_mm(struct drm_device *dev, unsigned mem_type, int kern_clean) { struct drm_buffer_manager *bm = &dev->bm; struct drm_mem_type_manager *man = &bm->man[mem_type]; @@ -2196,6 +2196,13 @@ int drm_bo_clean_mm(struct drm_device *dev, unsigned mem_type) "memory manager type %u\n", mem_type); return ret; } + + if ((man->kern_init_type) && (kern_clean == 0)) { + DRM_ERROR("Trying to take down kernel initialized " + "memory manager type %u\n", mem_type); + return -EPERM; + } + man->use_type = 0; man->has_type = 0; @@ -2247,9 +2254,9 @@ static int drm_bo_lock_mm(struct drm_device *dev, unsigned mem_type) return ret; } -int drm_bo_init_mm(struct drm_device *dev, - unsigned type, - unsigned long p_offset, unsigned long p_size) +int drm_bo_init_mm(struct drm_device *dev, unsigned type, + unsigned long p_offset, unsigned long p_size, + int kern_init) { struct drm_buffer_manager *bm = &dev->bm; int ret = -EINVAL; @@ -2283,6 +2290,7 @@ int drm_bo_init_mm(struct drm_device *dev, } man->has_type = 1; man->use_type = 1; + man->kern_init_type = kern_init; man->size = p_size; INIT_LIST_HEAD(&man->lru); @@ -2316,7 +2324,7 @@ int drm_bo_driver_finish(struct drm_device *dev) man = &bm->man[i]; if (man->has_type) { man->use_type = 0; - if ((i != DRM_BO_MEM_LOCAL) && drm_bo_clean_mm(dev, i)) { + if ((i != DRM_BO_MEM_LOCAL) && drm_bo_clean_mm(dev, i, 1)) { ret = -EBUSY; DRM_ERROR("DRM memory manager type %d " "is not clean.\n", i); @@ -2386,7 +2394,7 @@ int drm_bo_driver_init(struct drm_device *dev) * Initialize the system memory buffer type. * Other types need to be driver / IOCTL initialized. */ - ret = drm_bo_init_mm(dev, DRM_BO_MEM_LOCAL, 0, 0); + ret = drm_bo_init_mm(dev, DRM_BO_MEM_LOCAL, 0, 0, 1); if (ret) goto out_unlock; @@ -2446,7 +2454,7 @@ int drm_mm_init_ioctl(struct drm_device *dev, void *data, struct drm_file *file_ goto out; } ret = drm_bo_init_mm(dev, arg->mem_type, - arg->p_offset, arg->p_size); + arg->p_offset, arg->p_size, 0); out: mutex_unlock(&dev->struct_mutex); @@ -2485,9 +2493,11 @@ int drm_mm_takedown_ioctl(struct drm_device *dev, void *data, struct drm_file *f goto out; } ret = 0; - if (drm_bo_clean_mm(dev, arg->mem_type)) { - DRM_ERROR("Memory manager type %d not clean. " - "Delaying takedown\n", arg->mem_type); + if ((ret = drm_bo_clean_mm(dev, arg->mem_type, 0))) { + if (ret == -EINVAL) + DRM_ERROR("Memory manager type %d not clean. " + "Delaying takedown\n", arg->mem_type); + ret = 0; } out: mutex_unlock(&dev->struct_mutex); diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index ae0725c1..69e3f67f 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -516,6 +516,7 @@ struct drm_buffer_object { struct drm_mem_type_manager { int has_type; int use_type; + int kern_init_type; struct drm_mm manager; struct list_head lru; struct list_head pinned; @@ -684,9 +685,10 @@ extern int drm_bo_mem_space(struct drm_buffer_object *bo, extern int drm_bo_move_buffer(struct drm_buffer_object *bo, uint64_t new_mem_flags, int no_wait, int move_unfenced); -extern int drm_bo_clean_mm(struct drm_device *dev, unsigned mem_type); +extern int drm_bo_clean_mm(struct drm_device *dev, unsigned mem_type, int kern_clean); extern int drm_bo_init_mm(struct drm_device *dev, unsigned type, - unsigned long p_offset, unsigned long p_size); + unsigned long p_offset, unsigned long p_size, + int kern_init); extern int drm_bo_handle_validate(struct drm_file *file_priv, uint32_t handle, uint64_t flags, uint64_t mask, uint32_t hint, uint32_t fence_class, int use_old_fence_class, diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index 3d376aed..80b2990d 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -376,7 +376,7 @@ nouveau_mem_init_ttm(struct drm_device *dev) bar1_size = drm_get_resource_len(dev, 1) >> PAGE_SHIFT; if (bar1_size < vram_size) { if ((ret = drm_bo_init_mm(dev, DRM_BO_MEM_PRIV0, - bar1_size, vram_size - bar1_size))) { + bar1_size, vram_size - bar1_size, 1))) { DRM_ERROR("Failed PRIV0 mm init: %d\n", ret); return ret; } @@ -387,7 +387,7 @@ nouveau_mem_init_ttm(struct drm_device *dev) #ifdef HACK_OLD_MM vram_size /= 4; #endif - if ((ret = drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, vram_size))) { + if ((ret = drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, vram_size, 1))) { DRM_ERROR("Failed VRAM mm init: %d\n", ret); return ret; } @@ -407,7 +407,7 @@ nouveau_mem_init_ttm(struct drm_device *dev) if ((ret = drm_bo_init_mm(dev, DRM_BO_MEM_TT, 0, dev_priv->gart_info.aper_size >> - PAGE_SHIFT))) { + PAGE_SHIFT, 1))) { DRM_ERROR("Failed TT mm init: %d\n", ret); return ret; } -- cgit v1.2.3