Update from upstream to 2.4.0 version
[platform/core/security/tef-optee_os.git] / core / arch / arm / mm / mobj.c
1 /*
2  * Copyright (c) 2016-2017, Linaro Limited
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include <assert.h>
29 #include <keep.h>
30 #include <kernel/mutex.h>
31 #include <kernel/panic.h>
32 #include <kernel/tee_misc.h>
33 #include <mm/core_mmu.h>
34 #include <mm/mobj.h>
35 #include <mm/tee_mmu.h>
36 #include <mm/tee_pager.h>
37 #include <optee_msg.h>
38 #include <sm/optee_smc.h>
39 #include <stdlib.h>
40 #include <tee_api_types.h>
41 #include <types_ext.h>
42 #include <util.h>
43
44 struct mobj *mobj_sec_ddr;
45
46 /*
47  * mobj_phys implementation
48  */
49
50 struct mobj_phys {
51         struct mobj mobj;
52         enum buf_is_attr battr;
53         uint32_t cattr; /* Defined by TEE_MATTR_CACHE_* in tee_mmu_types.h */
54         vaddr_t va;
55         paddr_t pa;
56 };
57
58 static struct mobj_phys *to_mobj_phys(struct mobj *mobj);
59
60 static void *mobj_phys_get_va(struct mobj *mobj, size_t offset)
61 {
62         struct mobj_phys *moph = to_mobj_phys(mobj);
63
64         if (!moph->va)
65                 return NULL;
66
67         return (void *)(moph->va + offset);
68 }
69
70 static TEE_Result mobj_phys_get_pa(struct mobj *mobj, size_t offs,
71                                    size_t granule, paddr_t *pa)
72 {
73         struct mobj_phys *moph = to_mobj_phys(mobj);
74         paddr_t p;
75
76         if (!pa)
77                 return TEE_ERROR_GENERIC;
78
79         p = moph->pa + offs;
80
81         if (granule) {
82                 if (granule != SMALL_PAGE_SIZE &&
83                     granule != CORE_MMU_PGDIR_SIZE)
84                         return TEE_ERROR_GENERIC;
85                 p &= ~(granule - 1);
86         }
87
88         *pa = p;
89         return TEE_SUCCESS;
90 }
91 /* ifndef due to an asserting AArch64 linker */
92 #ifndef ARM64
93 KEEP_PAGER(mobj_phys_get_pa);
94 #endif
95
96 static TEE_Result mobj_phys_get_cattr(struct mobj *mobj, uint32_t *cattr)
97 {
98         struct mobj_phys *moph = to_mobj_phys(mobj);
99
100         if (!cattr)
101                 return TEE_ERROR_GENERIC;
102
103         *cattr = moph->cattr;
104         return TEE_SUCCESS;
105 }
106
107 static bool mobj_phys_matches(struct mobj *mobj, enum buf_is_attr attr)
108 {
109         struct mobj_phys *moph = to_mobj_phys(mobj);
110         enum buf_is_attr a;
111
112         a = moph->battr;
113
114         switch (attr) {
115         case CORE_MEM_SEC:
116                 return a == CORE_MEM_SEC || a == CORE_MEM_TEE_RAM ||
117                        a == CORE_MEM_TA_RAM || a == CORE_MEM_SDP_MEM;
118         case CORE_MEM_NON_SEC:
119                 return a == CORE_MEM_NSEC_SHM;
120         case CORE_MEM_TEE_RAM:
121         case CORE_MEM_TA_RAM:
122         case CORE_MEM_NSEC_SHM:
123         case CORE_MEM_SDP_MEM:
124                 return attr == a;
125         default:
126                 return false;
127         }
128 }
129
130 static void mobj_phys_free(struct mobj *mobj)
131 {
132         struct mobj_phys *moph = to_mobj_phys(mobj);
133
134         free(moph);
135 }
136
137 static const struct mobj_ops mobj_phys_ops __rodata_unpaged = {
138         .get_va = mobj_phys_get_va,
139         .get_pa = mobj_phys_get_pa,
140         .get_cattr = mobj_phys_get_cattr,
141         .matches = mobj_phys_matches,
142         .free = mobj_phys_free,
143 };
144
145 static struct mobj_phys *to_mobj_phys(struct mobj *mobj)
146 {
147         assert(mobj->ops == &mobj_phys_ops);
148         return container_of(mobj, struct mobj_phys, mobj);
149 }
150
151 struct mobj *mobj_phys_alloc(paddr_t pa, size_t size, uint32_t cattr,
152                              enum buf_is_attr battr)
153 {
154         struct mobj_phys *moph;
155         enum teecore_memtypes area_type;
156         void *va;
157
158         if ((pa & CORE_MMU_USER_PARAM_MASK) ||
159             (size & CORE_MMU_USER_PARAM_MASK)) {
160                 DMSG("Expect %#x alignment", CORE_MMU_USER_PARAM_SIZE);
161                 return NULL;
162         }
163
164         switch (battr) {
165         case CORE_MEM_TEE_RAM:
166                 area_type = MEM_AREA_TEE_RAM;
167                 break;
168         case CORE_MEM_TA_RAM:
169                 area_type = MEM_AREA_TA_RAM;
170                 break;
171         case CORE_MEM_NSEC_SHM:
172                 area_type = MEM_AREA_NSEC_SHM;
173                 break;
174         case CORE_MEM_SDP_MEM:
175                 area_type = MEM_AREA_SDP_MEM;
176                 break;
177         default:
178                 DMSG("can't allocate with specified attribute");
179                 return NULL;
180         }
181
182         /* Only SDP memory may not have a virtual address */
183         va = phys_to_virt(pa, area_type);
184         if (!va && battr != CORE_MEM_SDP_MEM)
185                 return NULL;
186
187         moph = calloc(1, sizeof(*moph));
188         if (!moph)
189                 return NULL;
190
191         moph->battr = battr;
192         moph->cattr = cattr;
193         moph->mobj.size = size;
194         moph->mobj.ops = &mobj_phys_ops;
195         moph->pa = pa;
196         moph->va = (vaddr_t)va;
197
198         return &moph->mobj;
199 }
200
201 /*
202  * mobj_virt implementation
203  */
204
205 static void mobj_virt_assert_type(struct mobj *mobj);
206
207 static void *mobj_virt_get_va(struct mobj *mobj, size_t offset)
208 {
209         mobj_virt_assert_type(mobj);
210
211         return (void *)(vaddr_t)offset;
212 }
213
214 static const struct mobj_ops mobj_virt_ops __rodata_unpaged = {
215         .get_va = mobj_virt_get_va,
216 };
217
218 static void mobj_virt_assert_type(struct mobj *mobj __maybe_unused)
219 {
220         assert(mobj->ops == &mobj_virt_ops);
221 }
222
223 struct mobj mobj_virt = { .ops = &mobj_virt_ops, .size = SIZE_MAX };
224
225 /*
226  * mobj_mm implementation
227  */
228
229 struct mobj_mm {
230         tee_mm_entry_t *mm;
231         struct mobj *parent_mobj;
232         struct mobj mobj;
233 };
234
235 static struct mobj_mm *to_mobj_mm(struct mobj *mobj);
236
237 static size_t mobj_mm_offs(struct mobj *mobj, size_t offs)
238 {
239         tee_mm_entry_t *mm = to_mobj_mm(mobj)->mm;
240
241         return (mm->offset << mm->pool->shift) + offs;
242 }
243
244 static void *mobj_mm_get_va(struct mobj *mobj, size_t offs)
245 {
246         return mobj_get_va(to_mobj_mm(mobj)->parent_mobj,
247                            mobj_mm_offs(mobj, offs));
248 }
249
250
251 static TEE_Result mobj_mm_get_pa(struct mobj *mobj, size_t offs,
252                                     size_t granule, paddr_t *pa)
253 {
254         return mobj_get_pa(to_mobj_mm(mobj)->parent_mobj,
255                            mobj_mm_offs(mobj, offs), granule, pa);
256 }
257 /* ifndef due to an asserting AArch64 linker */
258 #ifndef ARM64
259 KEEP_PAGER(mobj_mm_get_pa);
260 #endif
261
262 static TEE_Result mobj_mm_get_cattr(struct mobj *mobj, uint32_t *cattr)
263 {
264         return mobj_get_cattr(to_mobj_mm(mobj)->parent_mobj, cattr);
265 }
266
267 static bool mobj_mm_matches(struct mobj *mobj, enum buf_is_attr attr)
268 {
269         return mobj_matches(to_mobj_mm(mobj)->parent_mobj, attr);
270 }
271
272 static void mobj_mm_free(struct mobj *mobj)
273 {
274         struct mobj_mm *m = to_mobj_mm(mobj);
275
276         tee_mm_free(m->mm);
277         free(m);
278 }
279
280 static const struct mobj_ops mobj_mm_ops __rodata_unpaged = {
281         .get_va = mobj_mm_get_va,
282         .get_pa = mobj_mm_get_pa,
283         .get_cattr = mobj_mm_get_cattr,
284         .matches = mobj_mm_matches,
285         .free = mobj_mm_free,
286 };
287
288 static struct mobj_mm *to_mobj_mm(struct mobj *mobj)
289 {
290         assert(mobj->ops == &mobj_mm_ops);
291         return container_of(mobj, struct mobj_mm, mobj);
292 }
293
294 struct mobj *mobj_mm_alloc(struct mobj *mobj_parent, size_t size,
295                               tee_mm_pool_t *pool)
296 {
297         struct mobj_mm *m = calloc(1, sizeof(*m));
298
299         if (!m)
300                 return NULL;
301
302         m->mm = tee_mm_alloc(pool, size);
303         if (!m->mm) {
304                 free(m);
305                 return NULL;
306         }
307
308         m->parent_mobj = mobj_parent;
309         m->mobj.size = size;
310         m->mobj.ops = &mobj_mm_ops;
311
312         return &m->mobj;
313 }
314
315 #ifdef CFG_PAGED_USER_TA
316 /*
317  * mobj_paged implementation
318  */
319
320 static void mobj_paged_free(struct mobj *mobj);
321
322 static const struct mobj_ops mobj_paged_ops __rodata_unpaged = {
323         .free = mobj_paged_free,
324 };
325
326 static void mobj_paged_free(struct mobj *mobj)
327 {
328         assert(mobj->ops == &mobj_paged_ops);
329         free(mobj);
330 }
331
332 struct mobj *mobj_paged_alloc(size_t size)
333 {
334         struct mobj *mobj = calloc(1, sizeof(*mobj));
335
336         if (mobj) {
337                 mobj->size = size;
338                 mobj->ops = &mobj_paged_ops;
339         }
340         return mobj;
341 }
342
343 /*
344  * mobj_seccpy_shm implementation
345  */
346
347 struct mobj_seccpy_shm {
348         struct user_ta_ctx *utc;
349         vaddr_t va;
350         size_t pgdir_offset;
351         struct mobj mobj;
352 };
353
354 static bool __maybe_unused mobj_is_seccpy_shm(struct mobj *mobj);
355
356 static struct mobj_seccpy_shm *to_mobj_seccpy_shm(struct mobj *mobj)
357 {
358         assert(mobj_is_seccpy_shm(mobj));
359         return container_of(mobj, struct mobj_seccpy_shm, mobj);
360 }
361
362 static void *mobj_seccpy_shm_get_va(struct mobj *mobj, size_t offs)
363 {
364         struct mobj_seccpy_shm *m = to_mobj_seccpy_shm(mobj);
365
366         if (&m->utc->ctx != thread_get_tsd()->ctx)
367                 return NULL;
368
369         if (offs >= mobj->size)
370                 return NULL;
371         return (void *)(m->va + offs);
372 }
373
374 static bool mobj_seccpy_shm_matches(struct mobj *mobj __maybe_unused,
375                                  enum buf_is_attr attr)
376 {
377         assert(mobj_is_seccpy_shm(mobj));
378
379         return attr == CORE_MEM_SEC || attr == CORE_MEM_TEE_RAM;
380 }
381
382 static void mobj_seccpy_shm_free(struct mobj *mobj)
383 {
384         struct mobj_seccpy_shm *m = to_mobj_seccpy_shm(mobj);
385
386         tee_pager_rem_uta_region(m->utc, m->va, mobj->size);
387         tee_mmu_rem_rwmem(m->utc, mobj, m->va);
388         free(m);
389 }
390
391 static void mobj_seccpy_shm_update_mapping(struct mobj *mobj,
392                                         struct user_ta_ctx *utc, vaddr_t va)
393 {
394         struct thread_specific_data *tsd = thread_get_tsd();
395         struct mobj_seccpy_shm *m = to_mobj_seccpy_shm(mobj);
396         size_t s;
397
398         if (utc == m->utc && va == m->va)
399                 return;
400
401         s = ROUNDUP(mobj->size, SMALL_PAGE_SIZE);
402         pgt_transfer(&tsd->pgt_cache, &m->utc->ctx, m->va, &utc->ctx, va, s);
403
404         m->va = va;
405         m->utc = utc;
406 }
407
408 static const struct mobj_ops mobj_seccpy_shm_ops __rodata_unpaged = {
409         .get_va = mobj_seccpy_shm_get_va,
410         .matches = mobj_seccpy_shm_matches,
411         .free = mobj_seccpy_shm_free,
412         .update_mapping = mobj_seccpy_shm_update_mapping,
413 };
414
415 static bool mobj_is_seccpy_shm(struct mobj *mobj)
416 {
417         return mobj && mobj->ops == &mobj_seccpy_shm_ops;
418 }
419
420 struct mobj *mobj_seccpy_shm_alloc(size_t size)
421 {
422         struct thread_specific_data *tsd = thread_get_tsd();
423         struct mobj_seccpy_shm *m;
424         struct user_ta_ctx *utc;
425         vaddr_t va = 0;
426
427         if (!is_user_ta_ctx(tsd->ctx))
428                 return NULL;
429         utc = to_user_ta_ctx(tsd->ctx);
430
431         m = calloc(1, sizeof(*m));
432         if (!m)
433                 return NULL;
434
435         m->mobj.size = size;
436         m->mobj.ops = &mobj_seccpy_shm_ops;
437
438         if (tee_mmu_add_rwmem(utc, &m->mobj, -1, &va) != TEE_SUCCESS)
439                 goto bad;
440
441         if (!tee_pager_add_uta_area(utc, va, size))
442                 goto bad;
443
444         m->va = va;
445         m->pgdir_offset = va & CORE_MMU_PGDIR_MASK;
446         m->utc = to_user_ta_ctx(tsd->ctx);
447         return &m->mobj;
448 bad:
449         if (va)
450                 tee_mmu_rem_rwmem(utc, &m->mobj, va);
451         free(m);
452         return NULL;
453 }
454
455 bool mobj_is_paged(struct mobj *mobj)
456 {
457         return mobj->ops == &mobj_paged_ops ||
458                mobj->ops == &mobj_seccpy_shm_ops;
459 }
460 #endif /*CFG_PAGED_USER_TA*/