1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Framework for userspace DMA-BUF allocations 4 * 5 * Copyright (C) 2011 Google, Inc. 6 * Copyright (C) 2019 Linaro Ltd. 7 */ 8 9 #include <linux/cdev.h> 10 #include <linux/device.h> 11 #include <linux/dma-buf.h> 12 #include <linux/dma-heap.h> 13 #include <linux/err.h> 14 #include <linux/list.h> 15 #include <linux/nospec.h> 16 #include <linux/syscalls.h> 17 #include <linux/uaccess.h> 18 #include <linux/xarray.h> 19 #include <uapi/linux/dma-heap.h> 20 21 #define DEVNAME "dma_heap" 22 23 #define NUM_HEAP_MINORS 128 24 25 /** 26 * struct dma_heap - represents a dmabuf heap in the system 27 * @name: used for debugging/device-node name 28 * @ops: ops struct for this heap 29 * @priv: private data for this heap 30 * @heap_devt: heap device node 31 * @list: list head connecting to list of heaps 32 * @heap_cdev: heap char device 33 * 34 * Represents a heap of memory from which buffers can be made. 35 */ 36 struct dma_heap { 37 const char *name; 38 const struct dma_heap_ops *ops; 39 void *priv; 40 dev_t heap_devt; 41 struct list_head list; 42 struct cdev heap_cdev; 43 }; 44 45 static LIST_HEAD(heap_list); 46 static DEFINE_MUTEX(heap_list_lock); 47 static dev_t dma_heap_devt; 48 static struct class *dma_heap_class; 49 static DEFINE_XARRAY_ALLOC(dma_heap_minors); 50 51 static int dma_heap_buffer_alloc(struct dma_heap *heap, size_t len, 52 u32 fd_flags, 53 u64 heap_flags) 54 { 55 struct dma_buf *dmabuf; 56 int fd; 57 58 /* 59 * Allocations from all heaps have to begin 60 * and end on page boundaries. 61 */ 62 len = PAGE_ALIGN(len); 63 if (!len) 64 return -EINVAL; 65 66 dmabuf = heap->ops->allocate(heap, len, fd_flags, heap_flags); 67 if (IS_ERR(dmabuf)) 68 return PTR_ERR(dmabuf); 69 70 fd = dma_buf_fd(dmabuf, fd_flags); 71 if (fd < 0) { 72 dma_buf_put(dmabuf); 73 /* just return, as put will call release and that will free */ 74 } 75 return fd; 76 } 77 78 static int dma_heap_open(struct inode *inode, struct file *file) 79 { 80 struct dma_heap *heap; 81 82 heap = xa_load(&dma_heap_minors, iminor(inode)); 83 if (!heap) { 84 pr_err("dma_heap: minor %d unknown.\n", iminor(inode)); 85 return -ENODEV; 86 } 87 88 /* instance data as context */ 89 file->private_data = heap; 90 nonseekable_open(inode, file); 91 92 return 0; 93 } 94 95 static long dma_heap_ioctl_allocate(struct file *file, void *data) 96 { 97 struct dma_heap_allocation_data *heap_allocation = data; 98 struct dma_heap *heap = file->private_data; 99 int fd; 100 101 if (heap_allocation->fd) 102 return -EINVAL; 103 104 if (heap_allocation->fd_flags & ~DMA_HEAP_VALID_FD_FLAGS) 105 return -EINVAL; 106 107 if (heap_allocation->heap_flags & ~DMA_HEAP_VALID_HEAP_FLAGS) 108 return -EINVAL; 109 110 fd = dma_heap_buffer_alloc(heap, heap_allocation->len, 111 heap_allocation->fd_flags, 112 heap_allocation->heap_flags); 113 if (fd < 0) 114 return fd; 115 116 heap_allocation->fd = fd; 117 118 return 0; 119 } 120 121 static unsigned int dma_heap_ioctl_cmds[] = { 122 DMA_HEAP_IOCTL_ALLOC, 123 }; 124 125 static long dma_heap_ioctl(struct file *file, unsigned int ucmd, 126 unsigned long arg) 127 { 128 char stack_kdata[128]; 129 char *kdata = stack_kdata; 130 unsigned int kcmd; 131 unsigned int in_size, out_size, drv_size, ksize; 132 int nr = _IOC_NR(ucmd); 133 int ret = 0; 134 135 if (nr >= ARRAY_SIZE(dma_heap_ioctl_cmds)) 136 return -EINVAL; 137 138 nr = array_index_nospec(nr, ARRAY_SIZE(dma_heap_ioctl_cmds)); 139 /* Get the kernel ioctl cmd that matches */ 140 kcmd = dma_heap_ioctl_cmds[nr]; 141 142 /* Figure out the delta between user cmd size and kernel cmd size */ 143 drv_size = _IOC_SIZE(kcmd); 144 out_size = _IOC_SIZE(ucmd); 145 in_size = out_size; 146 if ((ucmd & kcmd & IOC_IN) == 0) 147 in_size = 0; 148 if ((ucmd & kcmd & IOC_OUT) == 0) 149 out_size = 0; 150 ksize = max(max(in_size, out_size), drv_size); 151 152 /* If necessary, allocate buffer for ioctl argument */ 153 if (ksize > sizeof(stack_kdata)) { 154 kdata = kmalloc(ksize, GFP_KERNEL); 155 if (!kdata) 156 return -ENOMEM; 157 } 158 159 if (copy_from_user(kdata, (void __user *)arg, in_size) != 0) { 160 ret = -EFAULT; 161 goto err; 162 } 163 164 /* zero out any difference between the kernel/user structure size */ 165 if (ksize > in_size) 166 memset(kdata + in_size, 0, ksize - in_size); 167 168 switch (kcmd) { 169 case DMA_HEAP_IOCTL_ALLOC: 170 ret = dma_heap_ioctl_allocate(file, kdata); 171 break; 172 default: 173 ret = -ENOTTY; 174 goto err; 175 } 176 177 if (copy_to_user((void __user *)arg, kdata, out_size) != 0) 178 ret = -EFAULT; 179 err: 180 if (kdata != stack_kdata) 181 kfree(kdata); 182 return ret; 183 } 184 185 static const struct file_operations dma_heap_fops = { 186 .owner = THIS_MODULE, 187 .open = dma_heap_open, 188 .unlocked_ioctl = dma_heap_ioctl, 189 #ifdef CONFIG_COMPAT 190 .compat_ioctl = dma_heap_ioctl, 191 #endif 192 }; 193 194 /** 195 * dma_heap_get_drvdata - get per-heap driver data 196 * @heap: DMA-Heap to retrieve private data for 197 * 198 * Returns: 199 * The per-heap data for the heap. 200 */ 201 void *dma_heap_get_drvdata(struct dma_heap *heap) 202 { 203 return heap->priv; 204 } 205 206 /** 207 * dma_heap_get_name - get heap name 208 * @heap: DMA-Heap to retrieve the name of 209 * 210 * Returns: 211 * The char* for the heap name. 212 */ 213 const char *dma_heap_get_name(struct dma_heap *heap) 214 { 215 return heap->name; 216 } 217 218 /** 219 * dma_heap_add - adds a heap to dmabuf heaps 220 * @exp_info: information needed to register this heap 221 */ 222 struct dma_heap *dma_heap_add(const struct dma_heap_export_info *exp_info) 223 { 224 struct dma_heap *heap, *h, *err_ret; 225 struct device *dev_ret; 226 unsigned int minor; 227 int ret; 228 229 if (!exp_info->name || !strcmp(exp_info->name, "")) { 230 pr_err("dma_heap: Cannot add heap without a name\n"); 231 return ERR_PTR(-EINVAL); 232 } 233 234 if (!exp_info->ops || !exp_info->ops->allocate) { 235 pr_err("dma_heap: Cannot add heap with invalid ops struct\n"); 236 return ERR_PTR(-EINVAL); 237 } 238 239 heap = kzalloc(sizeof(*heap), GFP_KERNEL); 240 if (!heap) 241 return ERR_PTR(-ENOMEM); 242 243 heap->name = exp_info->name; 244 heap->ops = exp_info->ops; 245 heap->priv = exp_info->priv; 246 247 /* Find unused minor number */ 248 ret = xa_alloc(&dma_heap_minors, &minor, heap, 249 XA_LIMIT(0, NUM_HEAP_MINORS - 1), GFP_KERNEL); 250 if (ret < 0) { 251 pr_err("dma_heap: Unable to get minor number for heap\n"); 252 err_ret = ERR_PTR(ret); 253 goto err0; 254 } 255 256 /* Create device */ 257 heap->heap_devt = MKDEV(MAJOR(dma_heap_devt), minor); 258 259 cdev_init(&heap->heap_cdev, &dma_heap_fops); 260 ret = cdev_add(&heap->heap_cdev, heap->heap_devt, 1); 261 if (ret < 0) { 262 pr_err("dma_heap: Unable to add char device\n"); 263 err_ret = ERR_PTR(ret); 264 goto err1; 265 } 266 267 dev_ret = device_create(dma_heap_class, 268 NULL, 269 heap->heap_devt, 270 NULL, 271 heap->name); 272 if (IS_ERR(dev_ret)) { 273 pr_err("dma_heap: Unable to create device\n"); 274 err_ret = ERR_CAST(dev_ret); 275 goto err2; 276 } 277 278 mutex_lock(&heap_list_lock); 279 /* check the name is unique */ 280 list_for_each_entry(h, &heap_list, list) { 281 if (!strcmp(h->name, exp_info->name)) { 282 mutex_unlock(&heap_list_lock); 283 pr_err("dma_heap: Already registered heap named %s\n", 284 exp_info->name); 285 err_ret = ERR_PTR(-EINVAL); 286 goto err3; 287 } 288 } 289 290 /* Add heap to the list */ 291 list_add(&heap->list, &heap_list); 292 mutex_unlock(&heap_list_lock); 293 294 return heap; 295 296 err3: 297 device_destroy(dma_heap_class, heap->heap_devt); 298 err2: 299 cdev_del(&heap->heap_cdev); 300 err1: 301 xa_erase(&dma_heap_minors, minor); 302 err0: 303 kfree(heap); 304 return err_ret; 305 } 306 307 static char *dma_heap_devnode(const struct device *dev, umode_t *mode) 308 { 309 return kasprintf(GFP_KERNEL, "dma_heap/%s", dev_name(dev)); 310 } 311 312 static int dma_heap_init(void) 313 { 314 int ret; 315 316 ret = alloc_chrdev_region(&dma_heap_devt, 0, NUM_HEAP_MINORS, DEVNAME); 317 if (ret) 318 return ret; 319 320 dma_heap_class = class_create(DEVNAME); 321 if (IS_ERR(dma_heap_class)) { 322 unregister_chrdev_region(dma_heap_devt, NUM_HEAP_MINORS); 323 return PTR_ERR(dma_heap_class); 324 } 325 dma_heap_class->devnode = dma_heap_devnode; 326 327 return 0; 328 } 329 subsys_initcall(dma_heap_init); 330