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  
dma_heap_buffer_alloc(struct dma_heap * heap,size_t len,u32 fd_flags,u64 heap_flags)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  
dma_heap_open(struct inode * inode,struct file * file)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  
dma_heap_ioctl_allocate(struct file * file,void * data)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  
dma_heap_ioctl(struct file * file,unsigned int ucmd,unsigned long arg)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   */
dma_heap_get_drvdata(struct dma_heap * heap)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   */
dma_heap_get_name(struct dma_heap * heap)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   */
dma_heap_add(const struct dma_heap_export_info * exp_info)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  
dma_heap_devnode(const struct device * dev,umode_t * mode)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  
dma_heap_init(void)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