OSDN Git Service

drm/tee_shm: Drop dma_buf_k(unmap) support
[tomoyo/tomoyo-test1.git] / drivers / tee / tee_shm.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2015-2016, Linaro Limited
4  */
5 #include <linux/device.h>
6 #include <linux/dma-buf.h>
7 #include <linux/fdtable.h>
8 #include <linux/idr.h>
9 #include <linux/sched.h>
10 #include <linux/slab.h>
11 #include <linux/tee_drv.h>
12 #include "tee_private.h"
13
14 static void tee_shm_release(struct tee_shm *shm)
15 {
16         struct tee_device *teedev = shm->teedev;
17
18         mutex_lock(&teedev->mutex);
19         idr_remove(&teedev->idr, shm->id);
20         if (shm->ctx)
21                 list_del(&shm->link);
22         mutex_unlock(&teedev->mutex);
23
24         if (shm->flags & TEE_SHM_POOL) {
25                 struct tee_shm_pool_mgr *poolm;
26
27                 if (shm->flags & TEE_SHM_DMA_BUF)
28                         poolm = teedev->pool->dma_buf_mgr;
29                 else
30                         poolm = teedev->pool->private_mgr;
31
32                 poolm->ops->free(poolm, shm);
33         } else if (shm->flags & TEE_SHM_REGISTER) {
34                 size_t n;
35                 int rc = teedev->desc->ops->shm_unregister(shm->ctx, shm);
36
37                 if (rc)
38                         dev_err(teedev->dev.parent,
39                                 "unregister shm %p failed: %d", shm, rc);
40
41                 for (n = 0; n < shm->num_pages; n++)
42                         put_page(shm->pages[n]);
43
44                 kfree(shm->pages);
45         }
46
47         if (shm->ctx)
48                 teedev_ctx_put(shm->ctx);
49
50         kfree(shm);
51
52         tee_device_put(teedev);
53 }
54
55 static struct sg_table *tee_shm_op_map_dma_buf(struct dma_buf_attachment
56                         *attach, enum dma_data_direction dir)
57 {
58         return NULL;
59 }
60
61 static void tee_shm_op_unmap_dma_buf(struct dma_buf_attachment *attach,
62                                      struct sg_table *table,
63                                      enum dma_data_direction dir)
64 {
65 }
66
67 static void tee_shm_op_release(struct dma_buf *dmabuf)
68 {
69         struct tee_shm *shm = dmabuf->priv;
70
71         tee_shm_release(shm);
72 }
73
74 static int tee_shm_op_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
75 {
76         struct tee_shm *shm = dmabuf->priv;
77         size_t size = vma->vm_end - vma->vm_start;
78
79         /* Refuse sharing shared memory provided by application */
80         if (shm->flags & TEE_SHM_REGISTER)
81                 return -EINVAL;
82
83         return remap_pfn_range(vma, vma->vm_start, shm->paddr >> PAGE_SHIFT,
84                                size, vma->vm_page_prot);
85 }
86
87 static const struct dma_buf_ops tee_shm_dma_buf_ops = {
88         .map_dma_buf = tee_shm_op_map_dma_buf,
89         .unmap_dma_buf = tee_shm_op_unmap_dma_buf,
90         .release = tee_shm_op_release,
91         .mmap = tee_shm_op_mmap,
92 };
93
94 static struct tee_shm *__tee_shm_alloc(struct tee_context *ctx,
95                                        struct tee_device *teedev,
96                                        size_t size, u32 flags)
97 {
98         struct tee_shm_pool_mgr *poolm = NULL;
99         struct tee_shm *shm;
100         void *ret;
101         int rc;
102
103         if (ctx && ctx->teedev != teedev) {
104                 dev_err(teedev->dev.parent, "ctx and teedev mismatch\n");
105                 return ERR_PTR(-EINVAL);
106         }
107
108         if (!(flags & TEE_SHM_MAPPED)) {
109                 dev_err(teedev->dev.parent,
110                         "only mapped allocations supported\n");
111                 return ERR_PTR(-EINVAL);
112         }
113
114         if ((flags & ~(TEE_SHM_MAPPED | TEE_SHM_DMA_BUF))) {
115                 dev_err(teedev->dev.parent, "invalid shm flags 0x%x", flags);
116                 return ERR_PTR(-EINVAL);
117         }
118
119         if (!tee_device_get(teedev))
120                 return ERR_PTR(-EINVAL);
121
122         if (!teedev->pool) {
123                 /* teedev has been detached from driver */
124                 ret = ERR_PTR(-EINVAL);
125                 goto err_dev_put;
126         }
127
128         shm = kzalloc(sizeof(*shm), GFP_KERNEL);
129         if (!shm) {
130                 ret = ERR_PTR(-ENOMEM);
131                 goto err_dev_put;
132         }
133
134         shm->flags = flags | TEE_SHM_POOL;
135         shm->teedev = teedev;
136         shm->ctx = ctx;
137         if (flags & TEE_SHM_DMA_BUF)
138                 poolm = teedev->pool->dma_buf_mgr;
139         else
140                 poolm = teedev->pool->private_mgr;
141
142         rc = poolm->ops->alloc(poolm, shm, size);
143         if (rc) {
144                 ret = ERR_PTR(rc);
145                 goto err_kfree;
146         }
147
148         mutex_lock(&teedev->mutex);
149         shm->id = idr_alloc(&teedev->idr, shm, 1, 0, GFP_KERNEL);
150         mutex_unlock(&teedev->mutex);
151         if (shm->id < 0) {
152                 ret = ERR_PTR(shm->id);
153                 goto err_pool_free;
154         }
155
156         if (flags & TEE_SHM_DMA_BUF) {
157                 DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
158
159                 exp_info.ops = &tee_shm_dma_buf_ops;
160                 exp_info.size = shm->size;
161                 exp_info.flags = O_RDWR;
162                 exp_info.priv = shm;
163
164                 shm->dmabuf = dma_buf_export(&exp_info);
165                 if (IS_ERR(shm->dmabuf)) {
166                         ret = ERR_CAST(shm->dmabuf);
167                         goto err_rem;
168                 }
169         }
170
171         if (ctx) {
172                 teedev_ctx_get(ctx);
173                 mutex_lock(&teedev->mutex);
174                 list_add_tail(&shm->link, &ctx->list_shm);
175                 mutex_unlock(&teedev->mutex);
176         }
177
178         return shm;
179 err_rem:
180         mutex_lock(&teedev->mutex);
181         idr_remove(&teedev->idr, shm->id);
182         mutex_unlock(&teedev->mutex);
183 err_pool_free:
184         poolm->ops->free(poolm, shm);
185 err_kfree:
186         kfree(shm);
187 err_dev_put:
188         tee_device_put(teedev);
189         return ret;
190 }
191
192 /**
193  * tee_shm_alloc() - Allocate shared memory
194  * @ctx:        Context that allocates the shared memory
195  * @size:       Requested size of shared memory
196  * @flags:      Flags setting properties for the requested shared memory.
197  *
198  * Memory allocated as global shared memory is automatically freed when the
199  * TEE file pointer is closed. The @flags field uses the bits defined by
200  * TEE_SHM_* in <linux/tee_drv.h>. TEE_SHM_MAPPED must currently always be
201  * set. If TEE_SHM_DMA_BUF global shared memory will be allocated and
202  * associated with a dma-buf handle, else driver private memory.
203  */
204 struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags)
205 {
206         return __tee_shm_alloc(ctx, ctx->teedev, size, flags);
207 }
208 EXPORT_SYMBOL_GPL(tee_shm_alloc);
209
210 struct tee_shm *tee_shm_priv_alloc(struct tee_device *teedev, size_t size)
211 {
212         return __tee_shm_alloc(NULL, teedev, size, TEE_SHM_MAPPED);
213 }
214 EXPORT_SYMBOL_GPL(tee_shm_priv_alloc);
215
216 struct tee_shm *tee_shm_register(struct tee_context *ctx, unsigned long addr,
217                                  size_t length, u32 flags)
218 {
219         struct tee_device *teedev = ctx->teedev;
220         const u32 req_flags = TEE_SHM_DMA_BUF | TEE_SHM_USER_MAPPED;
221         struct tee_shm *shm;
222         void *ret;
223         int rc;
224         int num_pages;
225         unsigned long start;
226
227         if (flags != req_flags)
228                 return ERR_PTR(-ENOTSUPP);
229
230         if (!tee_device_get(teedev))
231                 return ERR_PTR(-EINVAL);
232
233         if (!teedev->desc->ops->shm_register ||
234             !teedev->desc->ops->shm_unregister) {
235                 tee_device_put(teedev);
236                 return ERR_PTR(-ENOTSUPP);
237         }
238
239         teedev_ctx_get(ctx);
240
241         shm = kzalloc(sizeof(*shm), GFP_KERNEL);
242         if (!shm) {
243                 ret = ERR_PTR(-ENOMEM);
244                 goto err;
245         }
246
247         shm->flags = flags | TEE_SHM_REGISTER;
248         shm->teedev = teedev;
249         shm->ctx = ctx;
250         shm->id = -1;
251         addr = untagged_addr(addr);
252         start = rounddown(addr, PAGE_SIZE);
253         shm->offset = addr - start;
254         shm->size = length;
255         num_pages = (roundup(addr + length, PAGE_SIZE) - start) / PAGE_SIZE;
256         shm->pages = kcalloc(num_pages, sizeof(*shm->pages), GFP_KERNEL);
257         if (!shm->pages) {
258                 ret = ERR_PTR(-ENOMEM);
259                 goto err;
260         }
261
262         rc = get_user_pages_fast(start, num_pages, FOLL_WRITE, shm->pages);
263         if (rc > 0)
264                 shm->num_pages = rc;
265         if (rc != num_pages) {
266                 if (rc >= 0)
267                         rc = -ENOMEM;
268                 ret = ERR_PTR(rc);
269                 goto err;
270         }
271
272         mutex_lock(&teedev->mutex);
273         shm->id = idr_alloc(&teedev->idr, shm, 1, 0, GFP_KERNEL);
274         mutex_unlock(&teedev->mutex);
275
276         if (shm->id < 0) {
277                 ret = ERR_PTR(shm->id);
278                 goto err;
279         }
280
281         rc = teedev->desc->ops->shm_register(ctx, shm, shm->pages,
282                                              shm->num_pages, start);
283         if (rc) {
284                 ret = ERR_PTR(rc);
285                 goto err;
286         }
287
288         if (flags & TEE_SHM_DMA_BUF) {
289                 DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
290
291                 exp_info.ops = &tee_shm_dma_buf_ops;
292                 exp_info.size = shm->size;
293                 exp_info.flags = O_RDWR;
294                 exp_info.priv = shm;
295
296                 shm->dmabuf = dma_buf_export(&exp_info);
297                 if (IS_ERR(shm->dmabuf)) {
298                         ret = ERR_CAST(shm->dmabuf);
299                         teedev->desc->ops->shm_unregister(ctx, shm);
300                         goto err;
301                 }
302         }
303
304         mutex_lock(&teedev->mutex);
305         list_add_tail(&shm->link, &ctx->list_shm);
306         mutex_unlock(&teedev->mutex);
307
308         return shm;
309 err:
310         if (shm) {
311                 size_t n;
312
313                 if (shm->id >= 0) {
314                         mutex_lock(&teedev->mutex);
315                         idr_remove(&teedev->idr, shm->id);
316                         mutex_unlock(&teedev->mutex);
317                 }
318                 if (shm->pages) {
319                         for (n = 0; n < shm->num_pages; n++)
320                                 put_page(shm->pages[n]);
321                         kfree(shm->pages);
322                 }
323         }
324         kfree(shm);
325         teedev_ctx_put(ctx);
326         tee_device_put(teedev);
327         return ret;
328 }
329 EXPORT_SYMBOL_GPL(tee_shm_register);
330
331 /**
332  * tee_shm_get_fd() - Increase reference count and return file descriptor
333  * @shm:        Shared memory handle
334  * @returns user space file descriptor to shared memory
335  */
336 int tee_shm_get_fd(struct tee_shm *shm)
337 {
338         int fd;
339
340         if (!(shm->flags & TEE_SHM_DMA_BUF))
341                 return -EINVAL;
342
343         get_dma_buf(shm->dmabuf);
344         fd = dma_buf_fd(shm->dmabuf, O_CLOEXEC);
345         if (fd < 0)
346                 dma_buf_put(shm->dmabuf);
347         return fd;
348 }
349
350 /**
351  * tee_shm_free() - Free shared memory
352  * @shm:        Handle to shared memory to free
353  */
354 void tee_shm_free(struct tee_shm *shm)
355 {
356         /*
357          * dma_buf_put() decreases the dmabuf reference counter and will
358          * call tee_shm_release() when the last reference is gone.
359          *
360          * In the case of driver private memory we call tee_shm_release
361          * directly instead as it doesn't have a reference counter.
362          */
363         if (shm->flags & TEE_SHM_DMA_BUF)
364                 dma_buf_put(shm->dmabuf);
365         else
366                 tee_shm_release(shm);
367 }
368 EXPORT_SYMBOL_GPL(tee_shm_free);
369
370 /**
371  * tee_shm_va2pa() - Get physical address of a virtual address
372  * @shm:        Shared memory handle
373  * @va:         Virtual address to tranlsate
374  * @pa:         Returned physical address
375  * @returns 0 on success and < 0 on failure
376  */
377 int tee_shm_va2pa(struct tee_shm *shm, void *va, phys_addr_t *pa)
378 {
379         if (!(shm->flags & TEE_SHM_MAPPED))
380                 return -EINVAL;
381         /* Check that we're in the range of the shm */
382         if ((char *)va < (char *)shm->kaddr)
383                 return -EINVAL;
384         if ((char *)va >= ((char *)shm->kaddr + shm->size))
385                 return -EINVAL;
386
387         return tee_shm_get_pa(
388                         shm, (unsigned long)va - (unsigned long)shm->kaddr, pa);
389 }
390 EXPORT_SYMBOL_GPL(tee_shm_va2pa);
391
392 /**
393  * tee_shm_pa2va() - Get virtual address of a physical address
394  * @shm:        Shared memory handle
395  * @pa:         Physical address to tranlsate
396  * @va:         Returned virtual address
397  * @returns 0 on success and < 0 on failure
398  */
399 int tee_shm_pa2va(struct tee_shm *shm, phys_addr_t pa, void **va)
400 {
401         if (!(shm->flags & TEE_SHM_MAPPED))
402                 return -EINVAL;
403         /* Check that we're in the range of the shm */
404         if (pa < shm->paddr)
405                 return -EINVAL;
406         if (pa >= (shm->paddr + shm->size))
407                 return -EINVAL;
408
409         if (va) {
410                 void *v = tee_shm_get_va(shm, pa - shm->paddr);
411
412                 if (IS_ERR(v))
413                         return PTR_ERR(v);
414                 *va = v;
415         }
416         return 0;
417 }
418 EXPORT_SYMBOL_GPL(tee_shm_pa2va);
419
420 /**
421  * tee_shm_get_va() - Get virtual address of a shared memory plus an offset
422  * @shm:        Shared memory handle
423  * @offs:       Offset from start of this shared memory
424  * @returns virtual address of the shared memory + offs if offs is within
425  *      the bounds of this shared memory, else an ERR_PTR
426  */
427 void *tee_shm_get_va(struct tee_shm *shm, size_t offs)
428 {
429         if (!(shm->flags & TEE_SHM_MAPPED))
430                 return ERR_PTR(-EINVAL);
431         if (offs >= shm->size)
432                 return ERR_PTR(-EINVAL);
433         return (char *)shm->kaddr + offs;
434 }
435 EXPORT_SYMBOL_GPL(tee_shm_get_va);
436
437 /**
438  * tee_shm_get_pa() - Get physical address of a shared memory plus an offset
439  * @shm:        Shared memory handle
440  * @offs:       Offset from start of this shared memory
441  * @pa:         Physical address to return
442  * @returns 0 if offs is within the bounds of this shared memory, else an
443  *      error code.
444  */
445 int tee_shm_get_pa(struct tee_shm *shm, size_t offs, phys_addr_t *pa)
446 {
447         if (offs >= shm->size)
448                 return -EINVAL;
449         if (pa)
450                 *pa = shm->paddr + offs;
451         return 0;
452 }
453 EXPORT_SYMBOL_GPL(tee_shm_get_pa);
454
455 /**
456  * tee_shm_get_from_id() - Find shared memory object and increase reference
457  * count
458  * @ctx:        Context owning the shared memory
459  * @id:         Id of shared memory object
460  * @returns a pointer to 'struct tee_shm' on success or an ERR_PTR on failure
461  */
462 struct tee_shm *tee_shm_get_from_id(struct tee_context *ctx, int id)
463 {
464         struct tee_device *teedev;
465         struct tee_shm *shm;
466
467         if (!ctx)
468                 return ERR_PTR(-EINVAL);
469
470         teedev = ctx->teedev;
471         mutex_lock(&teedev->mutex);
472         shm = idr_find(&teedev->idr, id);
473         if (!shm || shm->ctx != ctx)
474                 shm = ERR_PTR(-EINVAL);
475         else if (shm->flags & TEE_SHM_DMA_BUF)
476                 get_dma_buf(shm->dmabuf);
477         mutex_unlock(&teedev->mutex);
478         return shm;
479 }
480 EXPORT_SYMBOL_GPL(tee_shm_get_from_id);
481
482 /**
483  * tee_shm_put() - Decrease reference count on a shared memory handle
484  * @shm:        Shared memory handle
485  */
486 void tee_shm_put(struct tee_shm *shm)
487 {
488         if (shm->flags & TEE_SHM_DMA_BUF)
489                 dma_buf_put(shm->dmabuf);
490 }
491 EXPORT_SYMBOL_GPL(tee_shm_put);