1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/cred.h> 3 #include <linux/device.h> 4 #include <linux/dma-buf.h> 5 #include <linux/highmem.h> 6 #include <linux/init.h> 7 #include <linux/kernel.h> 8 #include <linux/memfd.h> 9 #include <linux/miscdevice.h> 10 #include <linux/module.h> 11 #include <linux/shmem_fs.h> 12 #include <linux/slab.h> 13 #include <linux/udmabuf.h> 14 15 static const u32 list_limit = 1024; /* udmabuf_create_list->count limit */ 16 static const size_t size_limit_mb = 64; /* total dmabuf size, in megabytes */ 17 18 struct udmabuf { 19 pgoff_t pagecount; 20 struct page **pages; 21 }; 22 23 static vm_fault_t udmabuf_vm_fault(struct vm_fault *vmf) 24 { 25 struct vm_area_struct *vma = vmf->vma; 26 struct udmabuf *ubuf = vma->vm_private_data; 27 28 vmf->page = ubuf->pages[vmf->pgoff]; 29 get_page(vmf->page); 30 return 0; 31 } 32 33 static const struct vm_operations_struct udmabuf_vm_ops = { 34 .fault = udmabuf_vm_fault, 35 }; 36 37 static int mmap_udmabuf(struct dma_buf *buf, struct vm_area_struct *vma) 38 { 39 struct udmabuf *ubuf = buf->priv; 40 41 if ((vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) == 0) 42 return -EINVAL; 43 44 vma->vm_ops = &udmabuf_vm_ops; 45 vma->vm_private_data = ubuf; 46 return 0; 47 } 48 49 static struct sg_table *map_udmabuf(struct dma_buf_attachment *at, 50 enum dma_data_direction direction) 51 { 52 struct udmabuf *ubuf = at->dmabuf->priv; 53 struct sg_table *sg; 54 int ret; 55 56 sg = kzalloc(sizeof(*sg), GFP_KERNEL); 57 if (!sg) 58 return ERR_PTR(-ENOMEM); 59 ret = sg_alloc_table_from_pages(sg, ubuf->pages, ubuf->pagecount, 60 0, ubuf->pagecount << PAGE_SHIFT, 61 GFP_KERNEL); 62 if (ret < 0) 63 goto err; 64 if (!dma_map_sg(at->dev, sg->sgl, sg->nents, direction)) { 65 ret = -EINVAL; 66 goto err; 67 } 68 return sg; 69 70 err: 71 sg_free_table(sg); 72 kfree(sg); 73 return ERR_PTR(ret); 74 } 75 76 static void unmap_udmabuf(struct dma_buf_attachment *at, 77 struct sg_table *sg, 78 enum dma_data_direction direction) 79 { 80 sg_free_table(sg); 81 kfree(sg); 82 } 83 84 static void release_udmabuf(struct dma_buf *buf) 85 { 86 struct udmabuf *ubuf = buf->priv; 87 pgoff_t pg; 88 89 for (pg = 0; pg < ubuf->pagecount; pg++) 90 put_page(ubuf->pages[pg]); 91 kfree(ubuf->pages); 92 kfree(ubuf); 93 } 94 95 static void *kmap_udmabuf(struct dma_buf *buf, unsigned long page_num) 96 { 97 struct udmabuf *ubuf = buf->priv; 98 struct page *page = ubuf->pages[page_num]; 99 100 return kmap(page); 101 } 102 103 static void kunmap_udmabuf(struct dma_buf *buf, unsigned long page_num, 104 void *vaddr) 105 { 106 kunmap(vaddr); 107 } 108 109 static const struct dma_buf_ops udmabuf_ops = { 110 .map_dma_buf = map_udmabuf, 111 .unmap_dma_buf = unmap_udmabuf, 112 .release = release_udmabuf, 113 .map = kmap_udmabuf, 114 .unmap = kunmap_udmabuf, 115 .mmap = mmap_udmabuf, 116 }; 117 118 #define SEALS_WANTED (F_SEAL_SHRINK) 119 #define SEALS_DENIED (F_SEAL_WRITE) 120 121 static long udmabuf_create(const struct udmabuf_create_list *head, 122 const struct udmabuf_create_item *list) 123 { 124 DEFINE_DMA_BUF_EXPORT_INFO(exp_info); 125 struct file *memfd = NULL; 126 struct udmabuf *ubuf; 127 struct dma_buf *buf; 128 pgoff_t pgoff, pgcnt, pgidx, pgbuf = 0, pglimit; 129 struct page *page; 130 int seals, ret = -EINVAL; 131 u32 i, flags; 132 133 ubuf = kzalloc(sizeof(*ubuf), GFP_KERNEL); 134 if (!ubuf) 135 return -ENOMEM; 136 137 pglimit = (size_limit_mb * 1024 * 1024) >> PAGE_SHIFT; 138 for (i = 0; i < head->count; i++) { 139 if (!IS_ALIGNED(list[i].offset, PAGE_SIZE)) 140 goto err; 141 if (!IS_ALIGNED(list[i].size, PAGE_SIZE)) 142 goto err; 143 ubuf->pagecount += list[i].size >> PAGE_SHIFT; 144 if (ubuf->pagecount > pglimit) 145 goto err; 146 } 147 ubuf->pages = kmalloc_array(ubuf->pagecount, sizeof(*ubuf->pages), 148 GFP_KERNEL); 149 if (!ubuf->pages) { 150 ret = -ENOMEM; 151 goto err; 152 } 153 154 pgbuf = 0; 155 for (i = 0; i < head->count; i++) { 156 ret = -EBADFD; 157 memfd = fget(list[i].memfd); 158 if (!memfd) 159 goto err; 160 if (!shmem_mapping(file_inode(memfd)->i_mapping)) 161 goto err; 162 seals = memfd_fcntl(memfd, F_GET_SEALS, 0); 163 if (seals == -EINVAL) 164 goto err; 165 ret = -EINVAL; 166 if ((seals & SEALS_WANTED) != SEALS_WANTED || 167 (seals & SEALS_DENIED) != 0) 168 goto err; 169 pgoff = list[i].offset >> PAGE_SHIFT; 170 pgcnt = list[i].size >> PAGE_SHIFT; 171 for (pgidx = 0; pgidx < pgcnt; pgidx++) { 172 page = shmem_read_mapping_page( 173 file_inode(memfd)->i_mapping, pgoff + pgidx); 174 if (IS_ERR(page)) { 175 ret = PTR_ERR(page); 176 goto err; 177 } 178 ubuf->pages[pgbuf++] = page; 179 } 180 fput(memfd); 181 memfd = NULL; 182 } 183 184 exp_info.ops = &udmabuf_ops; 185 exp_info.size = ubuf->pagecount << PAGE_SHIFT; 186 exp_info.priv = ubuf; 187 exp_info.flags = O_RDWR; 188 189 buf = dma_buf_export(&exp_info); 190 if (IS_ERR(buf)) { 191 ret = PTR_ERR(buf); 192 goto err; 193 } 194 195 flags = 0; 196 if (head->flags & UDMABUF_FLAGS_CLOEXEC) 197 flags |= O_CLOEXEC; 198 return dma_buf_fd(buf, flags); 199 200 err: 201 while (pgbuf > 0) 202 put_page(ubuf->pages[--pgbuf]); 203 if (memfd) 204 fput(memfd); 205 kfree(ubuf->pages); 206 kfree(ubuf); 207 return ret; 208 } 209 210 static long udmabuf_ioctl_create(struct file *filp, unsigned long arg) 211 { 212 struct udmabuf_create create; 213 struct udmabuf_create_list head; 214 struct udmabuf_create_item list; 215 216 if (copy_from_user(&create, (void __user *)arg, 217 sizeof(create))) 218 return -EFAULT; 219 220 head.flags = create.flags; 221 head.count = 1; 222 list.memfd = create.memfd; 223 list.offset = create.offset; 224 list.size = create.size; 225 226 return udmabuf_create(&head, &list); 227 } 228 229 static long udmabuf_ioctl_create_list(struct file *filp, unsigned long arg) 230 { 231 struct udmabuf_create_list head; 232 struct udmabuf_create_item *list; 233 int ret = -EINVAL; 234 u32 lsize; 235 236 if (copy_from_user(&head, (void __user *)arg, sizeof(head))) 237 return -EFAULT; 238 if (head.count > list_limit) 239 return -EINVAL; 240 lsize = sizeof(struct udmabuf_create_item) * head.count; 241 list = memdup_user((void __user *)(arg + sizeof(head)), lsize); 242 if (IS_ERR(list)) 243 return PTR_ERR(list); 244 245 ret = udmabuf_create(&head, list); 246 kfree(list); 247 return ret; 248 } 249 250 static long udmabuf_ioctl(struct file *filp, unsigned int ioctl, 251 unsigned long arg) 252 { 253 long ret; 254 255 switch (ioctl) { 256 case UDMABUF_CREATE: 257 ret = udmabuf_ioctl_create(filp, arg); 258 break; 259 case UDMABUF_CREATE_LIST: 260 ret = udmabuf_ioctl_create_list(filp, arg); 261 break; 262 default: 263 ret = -ENOTTY; 264 break; 265 } 266 return ret; 267 } 268 269 static const struct file_operations udmabuf_fops = { 270 .owner = THIS_MODULE, 271 .unlocked_ioctl = udmabuf_ioctl, 272 }; 273 274 static struct miscdevice udmabuf_misc = { 275 .minor = MISC_DYNAMIC_MINOR, 276 .name = "udmabuf", 277 .fops = &udmabuf_fops, 278 }; 279 280 static int __init udmabuf_dev_init(void) 281 { 282 return misc_register(&udmabuf_misc); 283 } 284 285 static void __exit udmabuf_dev_exit(void) 286 { 287 misc_deregister(&udmabuf_misc); 288 } 289 290 module_init(udmabuf_dev_init) 291 module_exit(udmabuf_dev_exit) 292 293 MODULE_AUTHOR("Gerd Hoffmann <kraxel@redhat.com>"); 294 MODULE_LICENSE("GPL v2"); 295