GNU Linux-libre 4.14.290-gnu1
[releases.git] / drivers / tee / tee_shm.c
1 /*
2  * Copyright (c) 2015-2017, 2019-2021 Linaro Limited
3  *
4  * This software is licensed under the terms of the GNU General Public
5  * License version 2, as published by the Free Software Foundation, and
6  * may be copied, distributed, and modified under those terms.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  */
14 #include <linux/anon_inodes.h>
15 #include <linux/device.h>
16 #include <linux/idr.h>
17 #include <linux/mm.h>
18 #include <linux/sched.h>
19 #include <linux/slab.h>
20 #include <linux/tee_drv.h>
21 #include "tee_private.h"
22
23 static void tee_shm_release(struct tee_device *teedev, struct tee_shm *shm)
24 {
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         kfree(shm);
34
35         tee_device_put(teedev);
36 }
37
38 /**
39  * tee_shm_alloc() - Allocate shared memory
40  * @ctx:        Context that allocates the shared memory
41  * @size:       Requested size of shared memory
42  * @flags:      Flags setting properties for the requested shared memory.
43  *
44  * Memory allocated as global shared memory is automatically freed when the
45  * TEE file pointer is closed. The @flags field uses the bits defined by
46  * TEE_SHM_* in <linux/tee_drv.h>. TEE_SHM_MAPPED must currently always be
47  * set. If TEE_SHM_DMA_BUF global shared memory will be allocated and
48  * associated with a dma-buf handle, else driver private memory.
49  */
50 struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags)
51 {
52         struct tee_device *teedev = ctx->teedev;
53         struct tee_shm_pool_mgr *poolm = NULL;
54         struct tee_shm *shm;
55         void *ret;
56         int rc;
57
58         if (!(flags & TEE_SHM_MAPPED)) {
59                 dev_err(teedev->dev.parent,
60                         "only mapped allocations supported\n");
61                 return ERR_PTR(-EINVAL);
62         }
63
64         if ((flags & ~(TEE_SHM_MAPPED | TEE_SHM_DMA_BUF))) {
65                 dev_err(teedev->dev.parent, "invalid shm flags 0x%x", flags);
66                 return ERR_PTR(-EINVAL);
67         }
68
69         if (!tee_device_get(teedev))
70                 return ERR_PTR(-EINVAL);
71
72         if (!teedev->pool) {
73                 /* teedev has been detached from driver */
74                 ret = ERR_PTR(-EINVAL);
75                 goto err_dev_put;
76         }
77
78         shm = kzalloc(sizeof(*shm), GFP_KERNEL);
79         if (!shm) {
80                 ret = ERR_PTR(-ENOMEM);
81                 goto err_dev_put;
82         }
83
84         refcount_set(&shm->refcount, 1);
85         shm->flags = flags;
86         shm->teedev = teedev;
87         shm->ctx = ctx;
88         if (flags & TEE_SHM_DMA_BUF)
89                 poolm = &teedev->pool->dma_buf_mgr;
90         else
91                 poolm = &teedev->pool->private_mgr;
92
93         rc = poolm->ops->alloc(poolm, shm, size);
94         if (rc) {
95                 ret = ERR_PTR(rc);
96                 goto err_kfree;
97         }
98
99         mutex_lock(&teedev->mutex);
100         shm->id = idr_alloc(&teedev->idr, shm, 1, 0, GFP_KERNEL);
101         mutex_unlock(&teedev->mutex);
102         if (shm->id < 0) {
103                 ret = ERR_PTR(shm->id);
104                 goto err_pool_free;
105         }
106
107         mutex_lock(&teedev->mutex);
108         list_add_tail(&shm->link, &ctx->list_shm);
109         mutex_unlock(&teedev->mutex);
110
111         return shm;
112 err_pool_free:
113         poolm->ops->free(poolm, shm);
114 err_kfree:
115         kfree(shm);
116 err_dev_put:
117         tee_device_put(teedev);
118         return ret;
119 }
120 EXPORT_SYMBOL_GPL(tee_shm_alloc);
121
122 static int tee_shm_fop_release(struct inode *inode, struct file *filp)
123 {
124         tee_shm_put(filp->private_data);
125         return 0;
126 }
127
128 static int tee_shm_fop_mmap(struct file *filp, struct vm_area_struct *vma)
129 {
130         struct tee_shm *shm = filp->private_data;
131         size_t size = vma->vm_end - vma->vm_start;
132
133         /* check for overflowing the buffer's size */
134         if (vma->vm_pgoff + vma_pages(vma) > shm->size >> PAGE_SHIFT)
135                 return -EINVAL;
136
137         return remap_pfn_range(vma, vma->vm_start, shm->paddr >> PAGE_SHIFT,
138                                size, vma->vm_page_prot);
139 }
140
141 static const struct file_operations tee_shm_fops = {
142         .owner = THIS_MODULE,
143         .release = tee_shm_fop_release,
144         .mmap = tee_shm_fop_mmap,
145 };
146
147 /**
148  * tee_shm_get_fd() - Increase reference count and return file descriptor
149  * @shm:        Shared memory handle
150  * @returns user space file descriptor to shared memory
151  */
152 int tee_shm_get_fd(struct tee_shm *shm)
153 {
154         u32 req_flags = TEE_SHM_MAPPED | TEE_SHM_DMA_BUF;
155         int fd;
156
157         if ((shm->flags & req_flags) != req_flags)
158                 return -EINVAL;
159
160         /* matched by tee_shm_put() in tee_shm_op_release() */
161         refcount_inc(&shm->refcount);
162         fd = anon_inode_getfd("tee_shm", &tee_shm_fops, shm, O_RDWR);
163         if (fd < 0)
164                 tee_shm_put(shm);
165         return fd;
166 }
167
168 /**
169  * tee_shm_free() - Free shared memory
170  * @shm:        Handle to shared memory to free
171  */
172 void tee_shm_free(struct tee_shm *shm)
173 {
174         tee_shm_put(shm);
175 }
176 EXPORT_SYMBOL_GPL(tee_shm_free);
177
178 /**
179  * tee_shm_va2pa() - Get physical address of a virtual address
180  * @shm:        Shared memory handle
181  * @va:         Virtual address to tranlsate
182  * @pa:         Returned physical address
183  * @returns 0 on success and < 0 on failure
184  */
185 int tee_shm_va2pa(struct tee_shm *shm, void *va, phys_addr_t *pa)
186 {
187         /* Check that we're in the range of the shm */
188         if ((char *)va < (char *)shm->kaddr)
189                 return -EINVAL;
190         if ((char *)va >= ((char *)shm->kaddr + shm->size))
191                 return -EINVAL;
192
193         return tee_shm_get_pa(
194                         shm, (unsigned long)va - (unsigned long)shm->kaddr, pa);
195 }
196 EXPORT_SYMBOL_GPL(tee_shm_va2pa);
197
198 /**
199  * tee_shm_pa2va() - Get virtual address of a physical address
200  * @shm:        Shared memory handle
201  * @pa:         Physical address to tranlsate
202  * @va:         Returned virtual address
203  * @returns 0 on success and < 0 on failure
204  */
205 int tee_shm_pa2va(struct tee_shm *shm, phys_addr_t pa, void **va)
206 {
207         /* Check that we're in the range of the shm */
208         if (pa < shm->paddr)
209                 return -EINVAL;
210         if (pa >= (shm->paddr + shm->size))
211                 return -EINVAL;
212
213         if (va) {
214                 void *v = tee_shm_get_va(shm, pa - shm->paddr);
215
216                 if (IS_ERR(v))
217                         return PTR_ERR(v);
218                 *va = v;
219         }
220         return 0;
221 }
222 EXPORT_SYMBOL_GPL(tee_shm_pa2va);
223
224 /**
225  * tee_shm_get_va() - Get virtual address of a shared memory plus an offset
226  * @shm:        Shared memory handle
227  * @offs:       Offset from start of this shared memory
228  * @returns virtual address of the shared memory + offs if offs is within
229  *      the bounds of this shared memory, else an ERR_PTR
230  */
231 void *tee_shm_get_va(struct tee_shm *shm, size_t offs)
232 {
233         if (offs >= shm->size)
234                 return ERR_PTR(-EINVAL);
235         return (char *)shm->kaddr + offs;
236 }
237 EXPORT_SYMBOL_GPL(tee_shm_get_va);
238
239 /**
240  * tee_shm_get_pa() - Get physical address of a shared memory plus an offset
241  * @shm:        Shared memory handle
242  * @offs:       Offset from start of this shared memory
243  * @pa:         Physical address to return
244  * @returns 0 if offs is within the bounds of this shared memory, else an
245  *      error code.
246  */
247 int tee_shm_get_pa(struct tee_shm *shm, size_t offs, phys_addr_t *pa)
248 {
249         if (offs >= shm->size)
250                 return -EINVAL;
251         if (pa)
252                 *pa = shm->paddr + offs;
253         return 0;
254 }
255 EXPORT_SYMBOL_GPL(tee_shm_get_pa);
256
257 /**
258  * tee_shm_get_from_id() - Find shared memory object and increase reference
259  * count
260  * @ctx:        Context owning the shared memory
261  * @id:         Id of shared memory object
262  * @returns a pointer to 'struct tee_shm' on success or an ERR_PTR on failure
263  */
264 struct tee_shm *tee_shm_get_from_id(struct tee_context *ctx, int id)
265 {
266         struct tee_device *teedev;
267         struct tee_shm *shm;
268
269         if (!ctx)
270                 return ERR_PTR(-EINVAL);
271
272         teedev = ctx->teedev;
273         mutex_lock(&teedev->mutex);
274         shm = idr_find(&teedev->idr, id);
275         /*
276          * If the tee_shm was found in the IDR it must have a refcount
277          * larger than 0 due to the guarantee in tee_shm_put() below. So
278          * it's safe to use refcount_inc().
279          */
280         if (!shm || shm->ctx != ctx)
281                 shm = ERR_PTR(-EINVAL);
282         else
283                 refcount_inc(&shm->refcount);
284         mutex_unlock(&teedev->mutex);
285         return shm;
286 }
287 EXPORT_SYMBOL_GPL(tee_shm_get_from_id);
288
289 /**
290  * tee_shm_get_id() - Get id of a shared memory object
291  * @shm:        Shared memory handle
292  * @returns id
293  */
294 int tee_shm_get_id(struct tee_shm *shm)
295 {
296         return shm->id;
297 }
298 EXPORT_SYMBOL_GPL(tee_shm_get_id);
299
300 /**
301  * tee_shm_put() - Decrease reference count on a shared memory handle
302  * @shm:        Shared memory handle
303  */
304 void tee_shm_put(struct tee_shm *shm)
305 {
306         struct tee_device *teedev = shm->teedev;
307         bool do_release = false;
308
309         mutex_lock(&teedev->mutex);
310         if (refcount_dec_and_test(&shm->refcount)) {
311                 /*
312                  * refcount has reached 0, we must now remove it from the
313                  * IDR before releasing the mutex.  This will guarantee
314                  * that the refcount_inc() in tee_shm_get_from_id() never
315                  * starts from 0.
316                  */
317                 if (shm->ctx)
318                         list_del(&shm->link);
319                 do_release = true;
320         }
321         mutex_unlock(&teedev->mutex);
322
323         if (do_release)
324                 tee_shm_release(teedev, shm);
325 }
326 EXPORT_SYMBOL_GPL(tee_shm_put);