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 dma_unmap_sg(at->dev, sg->sgl, sg->nents, direction); 81 sg_free_table(sg); 82 kfree(sg); 83 } 84 85 static void release_udmabuf(struct dma_buf *buf) 86 { 87 struct udmabuf *ubuf = buf->priv; 88 pgoff_t pg; 89 90 for (pg = 0; pg < ubuf->pagecount; pg++) 91 put_page(ubuf->pages[pg]); 92 kfree(ubuf->pages); 93 kfree(ubuf); 94 } 95 96 static void *kmap_udmabuf(struct dma_buf *buf, unsigned long page_num) 97 { 98 struct udmabuf *ubuf = buf->priv; 99 struct page *page = ubuf->pages[page_num]; 100 101 return kmap(page); 102 } 103 104 static void kunmap_udmabuf(struct dma_buf *buf, unsigned long page_num, 105 void *vaddr) 106 { 107 kunmap(vaddr); 108 } 109 110 static const struct dma_buf_ops udmabuf_ops = { 111 .map_dma_buf = map_udmabuf, 112 .unmap_dma_buf = unmap_udmabuf, 113 .release = release_udmabuf, 114 .map = kmap_udmabuf, 115 .unmap = kunmap_udmabuf, 116 .mmap = mmap_udmabuf, 117 }; 118 119 #define SEALS_WANTED (F_SEAL_SHRINK) 120 #define SEALS_DENIED (F_SEAL_WRITE) 121 122 static long udmabuf_create(const struct udmabuf_create_list *head, 123 const struct udmabuf_create_item *list) 124 { 125 DEFINE_DMA_BUF_EXPORT_INFO(exp_info); 126 struct file *memfd = NULL; 127 struct udmabuf *ubuf; 128 struct dma_buf *buf; 129 pgoff_t pgoff, pgcnt, pgidx, pgbuf = 0, pglimit; 130 struct page *page; 131 int seals, ret = -EINVAL; 132 u32 i, flags; 133 134 ubuf = kzalloc(sizeof(*ubuf), GFP_KERNEL); 135 if (!ubuf) 136 return -ENOMEM; 137 138 pglimit = (size_limit_mb * 1024 * 1024) >> PAGE_SHIFT; 139 for (i = 0; i < head->count; i++) { 140 if (!IS_ALIGNED(list[i].offset, PAGE_SIZE)) 141 goto err; 142 if (!IS_ALIGNED(list[i].size, PAGE_SIZE)) 143 goto err; 144 ubuf->pagecount += list[i].size >> PAGE_SHIFT; 145 if (ubuf->pagecount > pglimit) 146 goto err; 147 } 148 ubuf->pages = kmalloc_array(ubuf->pagecount, sizeof(*ubuf->pages), 149 GFP_KERNEL); 150 if (!ubuf->pages) { 151 ret = -ENOMEM; 152 goto err; 153 } 154 155 pgbuf = 0; 156 for (i = 0; i < head->count; i++) { 157 ret = -EBADFD; 158 memfd = fget(list[i].memfd); 159 if (!memfd) 160 goto err; 161 if (!shmem_mapping(file_inode(memfd)->i_mapping)) 162 goto err; 163 seals = memfd_fcntl(memfd, F_GET_SEALS, 0); 164 if (seals == -EINVAL) 165 goto err; 166 ret = -EINVAL; 167 if ((seals & SEALS_WANTED) != SEALS_WANTED || 168 (seals & SEALS_DENIED) != 0) 169 goto err; 170 pgoff = list[i].offset >> PAGE_SHIFT; 171 pgcnt = list[i].size >> PAGE_SHIFT; 172 for (pgidx = 0; pgidx < pgcnt; pgidx++) { 173 page = shmem_read_mapping_page( 174 file_inode(memfd)->i_mapping, pgoff + pgidx); 175 if (IS_ERR(page)) { 176 ret = PTR_ERR(page); 177 goto err; 178 } 179 ubuf->pages[pgbuf++] = page; 180 } 181 fput(memfd); 182 memfd = NULL; 183 } 184 185 exp_info.ops = &udmabuf_ops; 186 exp_info.size = ubuf->pagecount << PAGE_SHIFT; 187 exp_info.priv = ubuf; 188 exp_info.flags = O_RDWR; 189 190 buf = dma_buf_export(&exp_info); 191 if (IS_ERR(buf)) { 192 ret = PTR_ERR(buf); 193 goto err; 194 } 195 196 flags = 0; 197 if (head->flags & UDMABUF_FLAGS_CLOEXEC) 198 flags |= O_CLOEXEC; 199 return dma_buf_fd(buf, flags); 200 201 err: 202 while (pgbuf > 0) 203 put_page(ubuf->pages[--pgbuf]); 204 if (memfd) 205 fput(memfd); 206 kfree(ubuf->pages); 207 kfree(ubuf); 208 return ret; 209 } 210 211 static long udmabuf_ioctl_create(struct file *filp, unsigned long arg) 212 { 213 struct udmabuf_create create; 214 struct udmabuf_create_list head; 215 struct udmabuf_create_item list; 216 217 if (copy_from_user(&create, (void __user *)arg, 218 sizeof(create))) 219 return -EFAULT; 220 221 head.flags = create.flags; 222 head.count = 1; 223 list.memfd = create.memfd; 224 list.offset = create.offset; 225 list.size = create.size; 226 227 return udmabuf_create(&head, &list); 228 } 229 230 static long udmabuf_ioctl_create_list(struct file *filp, unsigned long arg) 231 { 232 struct udmabuf_create_list head; 233 struct udmabuf_create_item *list; 234 int ret = -EINVAL; 235 u32 lsize; 236 237 if (copy_from_user(&head, (void __user *)arg, sizeof(head))) 238 return -EFAULT; 239 if (head.count > list_limit) 240 return -EINVAL; 241 lsize = sizeof(struct udmabuf_create_item) * head.count; 242 list = memdup_user((void __user *)(arg + sizeof(head)), lsize); 243 if (IS_ERR(list)) 244 return PTR_ERR(list); 245 246 ret = udmabuf_create(&head, list); 247 kfree(list); 248 return ret; 249 } 250 251 static long udmabuf_ioctl(struct file *filp, unsigned int ioctl, 252 unsigned long arg) 253 { 254 long ret; 255 256 switch (ioctl) { 257 case UDMABUF_CREATE: 258 ret = udmabuf_ioctl_create(filp, arg); 259 break; 260 case UDMABUF_CREATE_LIST: 261 ret = udmabuf_ioctl_create_list(filp, arg); 262 break; 263 default: 264 ret = -ENOTTY; 265 break; 266 } 267 return ret; 268 } 269 270 static const struct file_operations udmabuf_fops = { 271 .owner = THIS_MODULE, 272 .unlocked_ioctl = udmabuf_ioctl, 273 }; 274 275 static struct miscdevice udmabuf_misc = { 276 .minor = MISC_DYNAMIC_MINOR, 277 .name = "udmabuf", 278 .fops = &udmabuf_fops, 279 }; 280 281 static int __init udmabuf_dev_init(void) 282 { 283 return misc_register(&udmabuf_misc); 284 } 285 286 static void __exit udmabuf_dev_exit(void) 287 { 288 misc_deregister(&udmabuf_misc); 289 } 290 291 module_init(udmabuf_dev_init) 292 module_exit(udmabuf_dev_exit) 293 294 MODULE_AUTHOR("Gerd Hoffmann <kraxel@redhat.com>"); 295 MODULE_LICENSE("GPL v2"); 296