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 int 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 188 buf = dma_buf_export(&exp_info); 189 if (IS_ERR(buf)) { 190 ret = PTR_ERR(buf); 191 goto err; 192 } 193 194 flags = 0; 195 if (head->flags & UDMABUF_FLAGS_CLOEXEC) 196 flags |= O_CLOEXEC; 197 return dma_buf_fd(buf, flags); 198 199 err: 200 while (pgbuf > 0) 201 put_page(ubuf->pages[--pgbuf]); 202 if (memfd) 203 fput(memfd); 204 kfree(ubuf->pages); 205 kfree(ubuf); 206 return ret; 207 } 208 209 static long udmabuf_ioctl_create(struct file *filp, unsigned long arg) 210 { 211 struct udmabuf_create create; 212 struct udmabuf_create_list head; 213 struct udmabuf_create_item list; 214 215 if (copy_from_user(&create, (void __user *)arg, 216 sizeof(create))) 217 return -EFAULT; 218 219 head.flags = create.flags; 220 head.count = 1; 221 list.memfd = create.memfd; 222 list.offset = create.offset; 223 list.size = create.size; 224 225 return udmabuf_create(&head, &list); 226 } 227 228 static long udmabuf_ioctl_create_list(struct file *filp, unsigned long arg) 229 { 230 struct udmabuf_create_list head; 231 struct udmabuf_create_item *list; 232 int ret = -EINVAL; 233 u32 lsize; 234 235 if (copy_from_user(&head, (void __user *)arg, sizeof(head))) 236 return -EFAULT; 237 if (head.count > list_limit) 238 return -EINVAL; 239 lsize = sizeof(struct udmabuf_create_item) * head.count; 240 list = memdup_user((void __user *)(arg + sizeof(head)), lsize); 241 if (IS_ERR(list)) 242 return PTR_ERR(list); 243 244 ret = udmabuf_create(&head, list); 245 kfree(list); 246 return ret; 247 } 248 249 static long udmabuf_ioctl(struct file *filp, unsigned int ioctl, 250 unsigned long arg) 251 { 252 long ret; 253 254 switch (ioctl) { 255 case UDMABUF_CREATE: 256 ret = udmabuf_ioctl_create(filp, arg); 257 break; 258 case UDMABUF_CREATE_LIST: 259 ret = udmabuf_ioctl_create_list(filp, arg); 260 break; 261 default: 262 ret = -ENOTTY; 263 break; 264 } 265 return ret; 266 } 267 268 static const struct file_operations udmabuf_fops = { 269 .owner = THIS_MODULE, 270 .unlocked_ioctl = udmabuf_ioctl, 271 }; 272 273 static struct miscdevice udmabuf_misc = { 274 .minor = MISC_DYNAMIC_MINOR, 275 .name = "udmabuf", 276 .fops = &udmabuf_fops, 277 }; 278 279 static int __init udmabuf_dev_init(void) 280 { 281 return misc_register(&udmabuf_misc); 282 } 283 284 static void __exit udmabuf_dev_exit(void) 285 { 286 misc_deregister(&udmabuf_misc); 287 } 288 289 module_init(udmabuf_dev_init) 290 module_exit(udmabuf_dev_exit) 291 292 MODULE_AUTHOR("Gerd Hoffmann <kraxel@redhat.com>"); 293 MODULE_LICENSE("GPL v2"); 294