xref: /optee_os/core/mm/mobj.c (revision 00361c1879106efbbe11e789e03b9efe0c43b0ca)
1185b4595SMarouene Boubakri // SPDX-License-Identifier: BSD-2-Clause
2185b4595SMarouene Boubakri /*
3d5ad7ccfSJens Wiklander  * Copyright (c) 2016-2021, Linaro Limited
4185b4595SMarouene Boubakri  */
5185b4595SMarouene Boubakri 
6185b4595SMarouene Boubakri #include <assert.h>
7185b4595SMarouene Boubakri #include <initcall.h>
8185b4595SMarouene Boubakri #include <keep.h>
9185b4595SMarouene Boubakri #include <kernel/linker.h>
10185b4595SMarouene Boubakri #include <kernel/mutex.h>
11185b4595SMarouene Boubakri #include <kernel/panic.h>
12185b4595SMarouene Boubakri #include <kernel/refcount.h>
13185b4595SMarouene Boubakri #include <kernel/spinlock.h>
14185b4595SMarouene Boubakri #include <kernel/tee_misc.h>
15185b4595SMarouene Boubakri #include <mm/core_mmu.h>
16185b4595SMarouene Boubakri #include <mm/mobj.h>
17185b4595SMarouene Boubakri #include <mm/tee_pager.h>
18185b4595SMarouene Boubakri #include <mm/vm.h>
19185b4595SMarouene Boubakri #include <optee_msg.h>
20185b4595SMarouene Boubakri #include <sm/optee_smc.h>
21185b4595SMarouene Boubakri #include <stdlib.h>
22185b4595SMarouene Boubakri #include <tee_api_types.h>
23185b4595SMarouene Boubakri #include <types_ext.h>
24185b4595SMarouene Boubakri #include <util.h>
25185b4595SMarouene Boubakri 
26185b4595SMarouene Boubakri struct mobj *mobj_sec_ddr;
27185b4595SMarouene Boubakri struct mobj *mobj_tee_ram;
28185b4595SMarouene Boubakri 
29185b4595SMarouene Boubakri /*
30185b4595SMarouene Boubakri  * mobj_phys implementation
31185b4595SMarouene Boubakri  */
32185b4595SMarouene Boubakri 
33185b4595SMarouene Boubakri struct mobj_phys {
34185b4595SMarouene Boubakri 	struct mobj mobj;
35185b4595SMarouene Boubakri 	enum buf_is_attr battr;
36185b4595SMarouene Boubakri 	uint32_t cattr; /* Defined by TEE_MATTR_CACHE_* in tee_mmu_types.h */
37185b4595SMarouene Boubakri 	vaddr_t va;
38185b4595SMarouene Boubakri 	paddr_t pa;
39185b4595SMarouene Boubakri };
40185b4595SMarouene Boubakri 
41185b4595SMarouene Boubakri static struct mobj_phys *to_mobj_phys(struct mobj *mobj);
42185b4595SMarouene Boubakri 
43185b4595SMarouene Boubakri static void *mobj_phys_get_va(struct mobj *mobj, size_t offset)
44185b4595SMarouene Boubakri {
45185b4595SMarouene Boubakri 	struct mobj_phys *moph = to_mobj_phys(mobj);
46185b4595SMarouene Boubakri 
47185b4595SMarouene Boubakri 	if (!moph->va || offset >= mobj->size)
48185b4595SMarouene Boubakri 		return NULL;
49185b4595SMarouene Boubakri 
50185b4595SMarouene Boubakri 	return (void *)(moph->va + offset);
51185b4595SMarouene Boubakri }
52185b4595SMarouene Boubakri 
53185b4595SMarouene Boubakri static TEE_Result mobj_phys_get_pa(struct mobj *mobj, size_t offs,
54185b4595SMarouene Boubakri 				   size_t granule, paddr_t *pa)
55185b4595SMarouene Boubakri {
56185b4595SMarouene Boubakri 	struct mobj_phys *moph = to_mobj_phys(mobj);
57185b4595SMarouene Boubakri 	paddr_t p;
58185b4595SMarouene Boubakri 
59185b4595SMarouene Boubakri 	if (!pa)
60185b4595SMarouene Boubakri 		return TEE_ERROR_GENERIC;
61185b4595SMarouene Boubakri 
62185b4595SMarouene Boubakri 	p = moph->pa + offs;
63185b4595SMarouene Boubakri 
64185b4595SMarouene Boubakri 	if (granule) {
65185b4595SMarouene Boubakri 		if (granule != SMALL_PAGE_SIZE &&
66185b4595SMarouene Boubakri 		    granule != CORE_MMU_PGDIR_SIZE)
67185b4595SMarouene Boubakri 			return TEE_ERROR_GENERIC;
68185b4595SMarouene Boubakri 		p &= ~(granule - 1);
69185b4595SMarouene Boubakri 	}
70185b4595SMarouene Boubakri 
71185b4595SMarouene Boubakri 	*pa = p;
72185b4595SMarouene Boubakri 	return TEE_SUCCESS;
73185b4595SMarouene Boubakri }
74185b4595SMarouene Boubakri DECLARE_KEEP_PAGER(mobj_phys_get_pa);
75185b4595SMarouene Boubakri 
76185b4595SMarouene Boubakri static TEE_Result mobj_phys_get_cattr(struct mobj *mobj, uint32_t *cattr)
77185b4595SMarouene Boubakri {
78185b4595SMarouene Boubakri 	struct mobj_phys *moph = to_mobj_phys(mobj);
79185b4595SMarouene Boubakri 
80185b4595SMarouene Boubakri 	if (!cattr)
81185b4595SMarouene Boubakri 		return TEE_ERROR_GENERIC;
82185b4595SMarouene Boubakri 
83185b4595SMarouene Boubakri 	*cattr = moph->cattr;
84185b4595SMarouene Boubakri 	return TEE_SUCCESS;
85185b4595SMarouene Boubakri }
86185b4595SMarouene Boubakri 
87185b4595SMarouene Boubakri static bool mobj_phys_matches(struct mobj *mobj, enum buf_is_attr attr)
88185b4595SMarouene Boubakri {
89185b4595SMarouene Boubakri 	struct mobj_phys *moph = to_mobj_phys(mobj);
90185b4595SMarouene Boubakri 	enum buf_is_attr a;
91185b4595SMarouene Boubakri 
92185b4595SMarouene Boubakri 	a = moph->battr;
93185b4595SMarouene Boubakri 
94185b4595SMarouene Boubakri 	switch (attr) {
95185b4595SMarouene Boubakri 	case CORE_MEM_SEC:
96185b4595SMarouene Boubakri 		return a == CORE_MEM_SEC || a == CORE_MEM_TEE_RAM ||
97185b4595SMarouene Boubakri 		       a == CORE_MEM_TA_RAM || a == CORE_MEM_SDP_MEM;
98185b4595SMarouene Boubakri 	case CORE_MEM_NON_SEC:
99185b4595SMarouene Boubakri 		return a == CORE_MEM_NSEC_SHM;
100185b4595SMarouene Boubakri 	case CORE_MEM_TEE_RAM:
101185b4595SMarouene Boubakri 	case CORE_MEM_TA_RAM:
102185b4595SMarouene Boubakri 	case CORE_MEM_NSEC_SHM:
103185b4595SMarouene Boubakri 	case CORE_MEM_SDP_MEM:
104185b4595SMarouene Boubakri 		return attr == a;
105185b4595SMarouene Boubakri 	default:
106185b4595SMarouene Boubakri 		return false;
107185b4595SMarouene Boubakri 	}
108185b4595SMarouene Boubakri }
109185b4595SMarouene Boubakri 
110185b4595SMarouene Boubakri static void mobj_phys_free(struct mobj *mobj)
111185b4595SMarouene Boubakri {
112185b4595SMarouene Boubakri 	struct mobj_phys *moph = to_mobj_phys(mobj);
113185b4595SMarouene Boubakri 
114185b4595SMarouene Boubakri 	free(moph);
115185b4595SMarouene Boubakri }
116185b4595SMarouene Boubakri 
117*00361c18SJens Wiklander /*
118*00361c18SJens Wiklander  * Note: this variable is weak just to ease breaking its dependency chain
119*00361c18SJens Wiklander  * when added to the unpaged area.
120*00361c18SJens Wiklander  */
121*00361c18SJens Wiklander const struct mobj_ops mobj_phys_ops __weak __rodata_unpaged("mobj_phys_ops") = {
122185b4595SMarouene Boubakri 	.get_va = mobj_phys_get_va,
123185b4595SMarouene Boubakri 	.get_pa = mobj_phys_get_pa,
124185b4595SMarouene Boubakri 	.get_phys_offs = NULL, /* only offset 0 */
125185b4595SMarouene Boubakri 	.get_cattr = mobj_phys_get_cattr,
126185b4595SMarouene Boubakri 	.matches = mobj_phys_matches,
127185b4595SMarouene Boubakri 	.free = mobj_phys_free,
128185b4595SMarouene Boubakri };
129185b4595SMarouene Boubakri 
130185b4595SMarouene Boubakri static struct mobj_phys *to_mobj_phys(struct mobj *mobj)
131185b4595SMarouene Boubakri {
132185b4595SMarouene Boubakri 	assert(mobj->ops == &mobj_phys_ops);
133185b4595SMarouene Boubakri 	return container_of(mobj, struct mobj_phys, mobj);
134185b4595SMarouene Boubakri }
135185b4595SMarouene Boubakri 
136185b4595SMarouene Boubakri struct mobj *mobj_phys_alloc(paddr_t pa, size_t size, uint32_t cattr,
137185b4595SMarouene Boubakri 			     enum buf_is_attr battr)
138185b4595SMarouene Boubakri {
139185b4595SMarouene Boubakri 	struct mobj_phys *moph;
140185b4595SMarouene Boubakri 	enum teecore_memtypes area_type;
141185b4595SMarouene Boubakri 	void *va;
142185b4595SMarouene Boubakri 
143185b4595SMarouene Boubakri 	if ((pa & CORE_MMU_USER_PARAM_MASK) ||
144185b4595SMarouene Boubakri 	    (size & CORE_MMU_USER_PARAM_MASK)) {
145185b4595SMarouene Boubakri 		DMSG("Expect %#x alignment", CORE_MMU_USER_PARAM_SIZE);
146185b4595SMarouene Boubakri 		return NULL;
147185b4595SMarouene Boubakri 	}
148185b4595SMarouene Boubakri 
149185b4595SMarouene Boubakri 	switch (battr) {
150185b4595SMarouene Boubakri 	case CORE_MEM_TEE_RAM:
151185b4595SMarouene Boubakri 		area_type = MEM_AREA_TEE_RAM_RW_DATA;
152185b4595SMarouene Boubakri 		break;
153185b4595SMarouene Boubakri 	case CORE_MEM_TA_RAM:
154185b4595SMarouene Boubakri 		area_type = MEM_AREA_TA_RAM;
155185b4595SMarouene Boubakri 		break;
156185b4595SMarouene Boubakri 	case CORE_MEM_NSEC_SHM:
157185b4595SMarouene Boubakri 		area_type = MEM_AREA_NSEC_SHM;
158185b4595SMarouene Boubakri 		break;
159185b4595SMarouene Boubakri 	case CORE_MEM_SDP_MEM:
160185b4595SMarouene Boubakri 		area_type = MEM_AREA_SDP_MEM;
161185b4595SMarouene Boubakri 		break;
162185b4595SMarouene Boubakri 	default:
163185b4595SMarouene Boubakri 		DMSG("can't allocate with specified attribute");
164185b4595SMarouene Boubakri 		return NULL;
165185b4595SMarouene Boubakri 	}
166185b4595SMarouene Boubakri 
167185b4595SMarouene Boubakri 	/* Only SDP memory may not have a virtual address */
168185b4595SMarouene Boubakri 	va = phys_to_virt(pa, area_type);
169185b4595SMarouene Boubakri 	if (!va && battr != CORE_MEM_SDP_MEM)
170185b4595SMarouene Boubakri 		return NULL;
171185b4595SMarouene Boubakri 
172185b4595SMarouene Boubakri 	moph = calloc(1, sizeof(*moph));
173185b4595SMarouene Boubakri 	if (!moph)
174185b4595SMarouene Boubakri 		return NULL;
175185b4595SMarouene Boubakri 
176185b4595SMarouene Boubakri 	moph->battr = battr;
177185b4595SMarouene Boubakri 	moph->cattr = cattr;
178185b4595SMarouene Boubakri 	moph->mobj.size = size;
179185b4595SMarouene Boubakri 	moph->mobj.ops = &mobj_phys_ops;
180185b4595SMarouene Boubakri 	refcount_set(&moph->mobj.refc, 1);
181185b4595SMarouene Boubakri 	moph->pa = pa;
182185b4595SMarouene Boubakri 	moph->va = (vaddr_t)va;
183185b4595SMarouene Boubakri 
184185b4595SMarouene Boubakri 	return &moph->mobj;
185185b4595SMarouene Boubakri }
186185b4595SMarouene Boubakri 
187185b4595SMarouene Boubakri /*
188185b4595SMarouene Boubakri  * mobj_virt implementation
189185b4595SMarouene Boubakri  */
190185b4595SMarouene Boubakri 
191185b4595SMarouene Boubakri static void mobj_virt_assert_type(struct mobj *mobj);
192185b4595SMarouene Boubakri 
193185b4595SMarouene Boubakri static void *mobj_virt_get_va(struct mobj *mobj, size_t offset)
194185b4595SMarouene Boubakri {
195185b4595SMarouene Boubakri 	mobj_virt_assert_type(mobj);
196185b4595SMarouene Boubakri 
197185b4595SMarouene Boubakri 	return (void *)(vaddr_t)offset;
198185b4595SMarouene Boubakri }
199185b4595SMarouene Boubakri 
200*00361c18SJens Wiklander /*
201*00361c18SJens Wiklander  * Note: this variable is weak just to ease breaking its dependency chain
202*00361c18SJens Wiklander  * when added to the unpaged area.
203*00361c18SJens Wiklander  */
204*00361c18SJens Wiklander const struct mobj_ops mobj_virt_ops __weak __rodata_unpaged("mobj_virt_ops") = {
205185b4595SMarouene Boubakri 	.get_va = mobj_virt_get_va,
206185b4595SMarouene Boubakri };
207185b4595SMarouene Boubakri 
208185b4595SMarouene Boubakri static void mobj_virt_assert_type(struct mobj *mobj __maybe_unused)
209185b4595SMarouene Boubakri {
210185b4595SMarouene Boubakri 	assert(mobj->ops == &mobj_virt_ops);
211185b4595SMarouene Boubakri }
212185b4595SMarouene Boubakri 
213185b4595SMarouene Boubakri struct mobj mobj_virt = { .ops = &mobj_virt_ops, .size = SIZE_MAX };
214185b4595SMarouene Boubakri 
215185b4595SMarouene Boubakri /*
216185b4595SMarouene Boubakri  * mobj_mm implementation
217185b4595SMarouene Boubakri  */
218185b4595SMarouene Boubakri 
219185b4595SMarouene Boubakri struct mobj_mm {
220185b4595SMarouene Boubakri 	tee_mm_entry_t *mm;
221185b4595SMarouene Boubakri 	struct mobj *parent_mobj;
222185b4595SMarouene Boubakri 	struct mobj mobj;
223185b4595SMarouene Boubakri };
224185b4595SMarouene Boubakri 
225185b4595SMarouene Boubakri static struct mobj_mm *to_mobj_mm(struct mobj *mobj);
226185b4595SMarouene Boubakri 
227185b4595SMarouene Boubakri static size_t mobj_mm_offs(struct mobj *mobj, size_t offs)
228185b4595SMarouene Boubakri {
229185b4595SMarouene Boubakri 	tee_mm_entry_t *mm = to_mobj_mm(mobj)->mm;
230185b4595SMarouene Boubakri 
231185b4595SMarouene Boubakri 	return (mm->offset << mm->pool->shift) + offs;
232185b4595SMarouene Boubakri }
233185b4595SMarouene Boubakri 
234185b4595SMarouene Boubakri static void *mobj_mm_get_va(struct mobj *mobj, size_t offs)
235185b4595SMarouene Boubakri {
236185b4595SMarouene Boubakri 	return mobj_get_va(to_mobj_mm(mobj)->parent_mobj,
237185b4595SMarouene Boubakri 			   mobj_mm_offs(mobj, offs));
238185b4595SMarouene Boubakri }
239185b4595SMarouene Boubakri 
240185b4595SMarouene Boubakri 
241185b4595SMarouene Boubakri static TEE_Result mobj_mm_get_pa(struct mobj *mobj, size_t offs,
242185b4595SMarouene Boubakri 				    size_t granule, paddr_t *pa)
243185b4595SMarouene Boubakri {
244185b4595SMarouene Boubakri 	return mobj_get_pa(to_mobj_mm(mobj)->parent_mobj,
245185b4595SMarouene Boubakri 			   mobj_mm_offs(mobj, offs), granule, pa);
246185b4595SMarouene Boubakri }
247185b4595SMarouene Boubakri DECLARE_KEEP_PAGER(mobj_mm_get_pa);
248185b4595SMarouene Boubakri 
249185b4595SMarouene Boubakri static size_t mobj_mm_get_phys_offs(struct mobj *mobj, size_t granule)
250185b4595SMarouene Boubakri {
251185b4595SMarouene Boubakri 	return mobj_get_phys_offs(to_mobj_mm(mobj)->parent_mobj, granule);
252185b4595SMarouene Boubakri }
253185b4595SMarouene Boubakri 
254185b4595SMarouene Boubakri static TEE_Result mobj_mm_get_cattr(struct mobj *mobj, uint32_t *cattr)
255185b4595SMarouene Boubakri {
256185b4595SMarouene Boubakri 	return mobj_get_cattr(to_mobj_mm(mobj)->parent_mobj, cattr);
257185b4595SMarouene Boubakri }
258185b4595SMarouene Boubakri 
259185b4595SMarouene Boubakri static bool mobj_mm_matches(struct mobj *mobj, enum buf_is_attr attr)
260185b4595SMarouene Boubakri {
261185b4595SMarouene Boubakri 	return mobj_matches(to_mobj_mm(mobj)->parent_mobj, attr);
262185b4595SMarouene Boubakri }
263185b4595SMarouene Boubakri 
264185b4595SMarouene Boubakri static void mobj_mm_free(struct mobj *mobj)
265185b4595SMarouene Boubakri {
266185b4595SMarouene Boubakri 	struct mobj_mm *m = to_mobj_mm(mobj);
267185b4595SMarouene Boubakri 
268185b4595SMarouene Boubakri 	tee_mm_free(m->mm);
269185b4595SMarouene Boubakri 	free(m);
270185b4595SMarouene Boubakri }
271185b4595SMarouene Boubakri 
272*00361c18SJens Wiklander /*
273*00361c18SJens Wiklander  * Note: this variable is weak just to ease breaking its dependency chain
274*00361c18SJens Wiklander  * when added to the unpaged area.
275*00361c18SJens Wiklander  */
276*00361c18SJens Wiklander const struct mobj_ops mobj_mm_ops __weak __rodata_unpaged("mobj_mm_ops") = {
277185b4595SMarouene Boubakri 	.get_va = mobj_mm_get_va,
278185b4595SMarouene Boubakri 	.get_pa = mobj_mm_get_pa,
279185b4595SMarouene Boubakri 	.get_phys_offs = mobj_mm_get_phys_offs,
280185b4595SMarouene Boubakri 	.get_cattr = mobj_mm_get_cattr,
281185b4595SMarouene Boubakri 	.matches = mobj_mm_matches,
282185b4595SMarouene Boubakri 	.free = mobj_mm_free,
283185b4595SMarouene Boubakri };
284185b4595SMarouene Boubakri 
285185b4595SMarouene Boubakri static struct mobj_mm *to_mobj_mm(struct mobj *mobj)
286185b4595SMarouene Boubakri {
287185b4595SMarouene Boubakri 	assert(mobj->ops == &mobj_mm_ops);
288185b4595SMarouene Boubakri 	return container_of(mobj, struct mobj_mm, mobj);
289185b4595SMarouene Boubakri }
290185b4595SMarouene Boubakri 
291185b4595SMarouene Boubakri struct mobj *mobj_mm_alloc(struct mobj *mobj_parent, size_t size,
292185b4595SMarouene Boubakri 			      tee_mm_pool_t *pool)
293185b4595SMarouene Boubakri {
294185b4595SMarouene Boubakri 	struct mobj_mm *m = calloc(1, sizeof(*m));
295185b4595SMarouene Boubakri 
296185b4595SMarouene Boubakri 	if (!m)
297185b4595SMarouene Boubakri 		return NULL;
298185b4595SMarouene Boubakri 
299185b4595SMarouene Boubakri 	m->mm = tee_mm_alloc(pool, size);
300185b4595SMarouene Boubakri 	if (!m->mm) {
301185b4595SMarouene Boubakri 		free(m);
302185b4595SMarouene Boubakri 		return NULL;
303185b4595SMarouene Boubakri 	}
304185b4595SMarouene Boubakri 
305185b4595SMarouene Boubakri 	m->parent_mobj = mobj_parent;
306185b4595SMarouene Boubakri 	m->mobj.size = size;
307185b4595SMarouene Boubakri 	m->mobj.ops = &mobj_mm_ops;
308185b4595SMarouene Boubakri 	refcount_set(&m->mobj.refc, 1);
309185b4595SMarouene Boubakri 
310185b4595SMarouene Boubakri 	return &m->mobj;
311185b4595SMarouene Boubakri }
312185b4595SMarouene Boubakri 
313185b4595SMarouene Boubakri 
314185b4595SMarouene Boubakri /*
315185b4595SMarouene Boubakri  * mobj_shm implementation. mobj_shm represents buffer in predefined shm region
316185b4595SMarouene Boubakri  * - it is physically contiguous.
317185b4595SMarouene Boubakri  * - it is identified in static physical layout as MEM_AREA_NSEC_SHM.
318185b4595SMarouene Boubakri  * - it creates mobjs that match specific CORE_MEM_NSEC_SHM and non secure
319185b4595SMarouene Boubakri  *   generic CORE_MEM_NON_SEC.
320185b4595SMarouene Boubakri  */
321185b4595SMarouene Boubakri 
322185b4595SMarouene Boubakri struct mobj_shm {
323185b4595SMarouene Boubakri 	struct mobj mobj;
324185b4595SMarouene Boubakri 	paddr_t pa;
325185b4595SMarouene Boubakri 	uint64_t cookie;
326185b4595SMarouene Boubakri };
327185b4595SMarouene Boubakri 
328185b4595SMarouene Boubakri static struct mobj_shm *to_mobj_shm(struct mobj *mobj);
329185b4595SMarouene Boubakri 
330185b4595SMarouene Boubakri static void *mobj_shm_get_va(struct mobj *mobj, size_t offset)
331185b4595SMarouene Boubakri {
332185b4595SMarouene Boubakri 	struct mobj_shm *m = to_mobj_shm(mobj);
333185b4595SMarouene Boubakri 
334185b4595SMarouene Boubakri 	if (offset >= mobj->size)
335185b4595SMarouene Boubakri 		return NULL;
336185b4595SMarouene Boubakri 
337185b4595SMarouene Boubakri 	return phys_to_virt(m->pa + offset, MEM_AREA_NSEC_SHM);
338185b4595SMarouene Boubakri }
339185b4595SMarouene Boubakri 
340185b4595SMarouene Boubakri static TEE_Result mobj_shm_get_pa(struct mobj *mobj, size_t offs,
341185b4595SMarouene Boubakri 				   size_t granule, paddr_t *pa)
342185b4595SMarouene Boubakri {
343185b4595SMarouene Boubakri 	struct mobj_shm *m = to_mobj_shm(mobj);
344185b4595SMarouene Boubakri 	paddr_t p;
345185b4595SMarouene Boubakri 
346185b4595SMarouene Boubakri 	if (!pa || offs >= mobj->size)
347185b4595SMarouene Boubakri 		return TEE_ERROR_GENERIC;
348185b4595SMarouene Boubakri 
349185b4595SMarouene Boubakri 	p = m->pa + offs;
350185b4595SMarouene Boubakri 
351185b4595SMarouene Boubakri 	if (granule) {
352185b4595SMarouene Boubakri 		if (granule != SMALL_PAGE_SIZE &&
353185b4595SMarouene Boubakri 		    granule != CORE_MMU_PGDIR_SIZE)
354185b4595SMarouene Boubakri 			return TEE_ERROR_GENERIC;
355185b4595SMarouene Boubakri 		p &= ~(granule - 1);
356185b4595SMarouene Boubakri 	}
357185b4595SMarouene Boubakri 
358185b4595SMarouene Boubakri 	*pa = p;
359185b4595SMarouene Boubakri 	return TEE_SUCCESS;
360185b4595SMarouene Boubakri }
361185b4595SMarouene Boubakri DECLARE_KEEP_PAGER(mobj_shm_get_pa);
362185b4595SMarouene Boubakri 
363185b4595SMarouene Boubakri static size_t mobj_shm_get_phys_offs(struct mobj *mobj, size_t granule)
364185b4595SMarouene Boubakri {
365185b4595SMarouene Boubakri 	assert(IS_POWER_OF_TWO(granule));
366185b4595SMarouene Boubakri 	return to_mobj_shm(mobj)->pa & (granule - 1);
367185b4595SMarouene Boubakri }
368185b4595SMarouene Boubakri 
369185b4595SMarouene Boubakri static bool mobj_shm_matches(struct mobj *mobj __unused, enum buf_is_attr attr)
370185b4595SMarouene Boubakri {
371185b4595SMarouene Boubakri 	return attr == CORE_MEM_NSEC_SHM || attr == CORE_MEM_NON_SEC;
372185b4595SMarouene Boubakri }
373185b4595SMarouene Boubakri 
374185b4595SMarouene Boubakri static void mobj_shm_free(struct mobj *mobj)
375185b4595SMarouene Boubakri {
376185b4595SMarouene Boubakri 	struct mobj_shm *m = to_mobj_shm(mobj);
377185b4595SMarouene Boubakri 
378185b4595SMarouene Boubakri 	free(m);
379185b4595SMarouene Boubakri }
380185b4595SMarouene Boubakri 
381185b4595SMarouene Boubakri static uint64_t mobj_shm_get_cookie(struct mobj *mobj)
382185b4595SMarouene Boubakri {
383185b4595SMarouene Boubakri 	return to_mobj_shm(mobj)->cookie;
384185b4595SMarouene Boubakri }
385185b4595SMarouene Boubakri 
386*00361c18SJens Wiklander /*
387*00361c18SJens Wiklander  * Note: this variable is weak just to ease breaking its dependency chain
388*00361c18SJens Wiklander  * when added to the unpaged area.
389*00361c18SJens Wiklander  */
390*00361c18SJens Wiklander const struct mobj_ops mobj_shm_ops __weak __rodata_unpaged("mobj_shm_ops") = {
391185b4595SMarouene Boubakri 	.get_va = mobj_shm_get_va,
392185b4595SMarouene Boubakri 	.get_pa = mobj_shm_get_pa,
393185b4595SMarouene Boubakri 	.get_phys_offs = mobj_shm_get_phys_offs,
394185b4595SMarouene Boubakri 	.matches = mobj_shm_matches,
395185b4595SMarouene Boubakri 	.free = mobj_shm_free,
396185b4595SMarouene Boubakri 	.get_cookie = mobj_shm_get_cookie,
397185b4595SMarouene Boubakri };
398185b4595SMarouene Boubakri 
399185b4595SMarouene Boubakri static struct mobj_shm *to_mobj_shm(struct mobj *mobj)
400185b4595SMarouene Boubakri {
401185b4595SMarouene Boubakri 	assert(mobj->ops == &mobj_shm_ops);
402185b4595SMarouene Boubakri 	return container_of(mobj, struct mobj_shm, mobj);
403185b4595SMarouene Boubakri }
404185b4595SMarouene Boubakri 
405185b4595SMarouene Boubakri struct mobj *mobj_shm_alloc(paddr_t pa, size_t size, uint64_t cookie)
406185b4595SMarouene Boubakri {
407185b4595SMarouene Boubakri 	struct mobj_shm *m;
408185b4595SMarouene Boubakri 
409185b4595SMarouene Boubakri 	if (!core_pbuf_is(CORE_MEM_NSEC_SHM, pa, size))
410185b4595SMarouene Boubakri 		return NULL;
411185b4595SMarouene Boubakri 
412185b4595SMarouene Boubakri 	m = calloc(1, sizeof(*m));
413185b4595SMarouene Boubakri 	if (!m)
414185b4595SMarouene Boubakri 		return NULL;
415185b4595SMarouene Boubakri 
416185b4595SMarouene Boubakri 	m->mobj.size = size;
417185b4595SMarouene Boubakri 	m->mobj.ops = &mobj_shm_ops;
418185b4595SMarouene Boubakri 	refcount_set(&m->mobj.refc, 1);
419185b4595SMarouene Boubakri 	m->pa = pa;
420185b4595SMarouene Boubakri 	m->cookie = cookie;
421185b4595SMarouene Boubakri 
422185b4595SMarouene Boubakri 	return &m->mobj;
423185b4595SMarouene Boubakri }
424185b4595SMarouene Boubakri 
425185b4595SMarouene Boubakri #ifdef CFG_PAGED_USER_TA
426185b4595SMarouene Boubakri /*
427185b4595SMarouene Boubakri  * mobj_seccpy_shm implementation
428185b4595SMarouene Boubakri  */
429185b4595SMarouene Boubakri 
430185b4595SMarouene Boubakri struct mobj_seccpy_shm {
431185b4595SMarouene Boubakri 	struct user_ta_ctx *utc;
432185b4595SMarouene Boubakri 	vaddr_t va;
433185b4595SMarouene Boubakri 	struct mobj mobj;
434185b4595SMarouene Boubakri 	struct fobj *fobj;
435185b4595SMarouene Boubakri };
436185b4595SMarouene Boubakri 
437185b4595SMarouene Boubakri static bool __maybe_unused mobj_is_seccpy_shm(struct mobj *mobj);
438185b4595SMarouene Boubakri 
439185b4595SMarouene Boubakri static struct mobj_seccpy_shm *to_mobj_seccpy_shm(struct mobj *mobj)
440185b4595SMarouene Boubakri {
441185b4595SMarouene Boubakri 	assert(mobj_is_seccpy_shm(mobj));
442185b4595SMarouene Boubakri 	return container_of(mobj, struct mobj_seccpy_shm, mobj);
443185b4595SMarouene Boubakri }
444185b4595SMarouene Boubakri 
445185b4595SMarouene Boubakri static void *mobj_seccpy_shm_get_va(struct mobj *mobj, size_t offs)
446185b4595SMarouene Boubakri {
447185b4595SMarouene Boubakri 	struct mobj_seccpy_shm *m = to_mobj_seccpy_shm(mobj);
448185b4595SMarouene Boubakri 
449185b4595SMarouene Boubakri 	if (&m->utc->ta_ctx.ts_ctx != thread_get_tsd()->ctx)
450185b4595SMarouene Boubakri 		return NULL;
451185b4595SMarouene Boubakri 
452185b4595SMarouene Boubakri 	if (offs >= mobj->size)
453185b4595SMarouene Boubakri 		return NULL;
454185b4595SMarouene Boubakri 	return (void *)(m->va + offs);
455185b4595SMarouene Boubakri }
456185b4595SMarouene Boubakri 
457185b4595SMarouene Boubakri static bool mobj_seccpy_shm_matches(struct mobj *mobj __maybe_unused,
458185b4595SMarouene Boubakri 				 enum buf_is_attr attr)
459185b4595SMarouene Boubakri {
460185b4595SMarouene Boubakri 	assert(mobj_is_seccpy_shm(mobj));
461185b4595SMarouene Boubakri 
462185b4595SMarouene Boubakri 	return attr == CORE_MEM_SEC || attr == CORE_MEM_TEE_RAM;
463185b4595SMarouene Boubakri }
464185b4595SMarouene Boubakri 
465185b4595SMarouene Boubakri static void mobj_seccpy_shm_free(struct mobj *mobj)
466185b4595SMarouene Boubakri {
467185b4595SMarouene Boubakri 	struct mobj_seccpy_shm *m = to_mobj_seccpy_shm(mobj);
468185b4595SMarouene Boubakri 
469185b4595SMarouene Boubakri 	tee_pager_rem_um_region(&m->utc->uctx, m->va, mobj->size);
470185b4595SMarouene Boubakri 	vm_rem_rwmem(&m->utc->uctx, mobj, m->va);
471185b4595SMarouene Boubakri 	fobj_put(m->fobj);
472185b4595SMarouene Boubakri 	free(m);
473185b4595SMarouene Boubakri }
474185b4595SMarouene Boubakri 
475185b4595SMarouene Boubakri static struct fobj *mobj_seccpy_shm_get_fobj(struct mobj *mobj)
476185b4595SMarouene Boubakri {
477185b4595SMarouene Boubakri 	return fobj_get(to_mobj_seccpy_shm(mobj)->fobj);
478185b4595SMarouene Boubakri }
479185b4595SMarouene Boubakri 
480*00361c18SJens Wiklander /*
481*00361c18SJens Wiklander  * Note: this variable is weak just to ease breaking its dependency chain
482*00361c18SJens Wiklander  * when added to the unpaged area.
483*00361c18SJens Wiklander  */
484*00361c18SJens Wiklander const struct mobj_ops mobj_seccpy_shm_ops
485*00361c18SJens Wiklander __weak __rodata_unpaged("mobj_seccpy_shm_ops") = {
486185b4595SMarouene Boubakri 	.get_va = mobj_seccpy_shm_get_va,
487185b4595SMarouene Boubakri 	.matches = mobj_seccpy_shm_matches,
488185b4595SMarouene Boubakri 	.free = mobj_seccpy_shm_free,
489185b4595SMarouene Boubakri 	.get_fobj = mobj_seccpy_shm_get_fobj,
490185b4595SMarouene Boubakri };
491185b4595SMarouene Boubakri 
492185b4595SMarouene Boubakri static bool mobj_is_seccpy_shm(struct mobj *mobj)
493185b4595SMarouene Boubakri {
494185b4595SMarouene Boubakri 	return mobj && mobj->ops == &mobj_seccpy_shm_ops;
495185b4595SMarouene Boubakri }
496185b4595SMarouene Boubakri 
497185b4595SMarouene Boubakri struct mobj *mobj_seccpy_shm_alloc(size_t size)
498185b4595SMarouene Boubakri {
499185b4595SMarouene Boubakri 	struct thread_specific_data *tsd = thread_get_tsd();
500185b4595SMarouene Boubakri 	struct mobj_seccpy_shm *m;
501185b4595SMarouene Boubakri 	struct user_ta_ctx *utc;
502185b4595SMarouene Boubakri 	vaddr_t va = 0;
503185b4595SMarouene Boubakri 
504185b4595SMarouene Boubakri 	if (!is_user_ta_ctx(tsd->ctx))
505185b4595SMarouene Boubakri 		return NULL;
506185b4595SMarouene Boubakri 	utc = to_user_ta_ctx(tsd->ctx);
507185b4595SMarouene Boubakri 
508185b4595SMarouene Boubakri 	m = calloc(1, sizeof(*m));
509185b4595SMarouene Boubakri 	if (!m)
510185b4595SMarouene Boubakri 		return NULL;
511185b4595SMarouene Boubakri 
512185b4595SMarouene Boubakri 	m->mobj.size = size;
513185b4595SMarouene Boubakri 	m->mobj.ops = &mobj_seccpy_shm_ops;
514185b4595SMarouene Boubakri 	refcount_set(&m->mobj.refc, 1);
515185b4595SMarouene Boubakri 
516185b4595SMarouene Boubakri 	if (vm_add_rwmem(&utc->uctx, &m->mobj, &va) != TEE_SUCCESS)
517185b4595SMarouene Boubakri 		goto bad;
518185b4595SMarouene Boubakri 
519185b4595SMarouene Boubakri 	m->fobj = fobj_rw_paged_alloc(ROUNDUP(size, SMALL_PAGE_SIZE) /
520185b4595SMarouene Boubakri 				      SMALL_PAGE_SIZE);
521d5ad7ccfSJens Wiklander 	if (tee_pager_add_um_region(&utc->uctx, va, m->fobj,
522185b4595SMarouene Boubakri 				    TEE_MATTR_PRW | TEE_MATTR_URW))
523185b4595SMarouene Boubakri 		goto bad;
524185b4595SMarouene Boubakri 
525185b4595SMarouene Boubakri 	m->va = va;
526185b4595SMarouene Boubakri 	m->utc = to_user_ta_ctx(tsd->ctx);
527185b4595SMarouene Boubakri 	return &m->mobj;
528185b4595SMarouene Boubakri bad:
529185b4595SMarouene Boubakri 	if (va)
530185b4595SMarouene Boubakri 		vm_rem_rwmem(&utc->uctx, &m->mobj, va);
531185b4595SMarouene Boubakri 	fobj_put(m->fobj);
532185b4595SMarouene Boubakri 	free(m);
533185b4595SMarouene Boubakri 	return NULL;
534185b4595SMarouene Boubakri }
535185b4595SMarouene Boubakri 
536185b4595SMarouene Boubakri 
537185b4595SMarouene Boubakri #endif /*CFG_PAGED_USER_TA*/
538185b4595SMarouene Boubakri 
539185b4595SMarouene Boubakri struct mobj_with_fobj {
540185b4595SMarouene Boubakri 	struct fobj *fobj;
541185b4595SMarouene Boubakri 	struct file *file;
542185b4595SMarouene Boubakri 	struct mobj mobj;
543185b4595SMarouene Boubakri };
544185b4595SMarouene Boubakri 
545*00361c18SJens Wiklander const struct mobj_ops mobj_with_fobj_ops;
546185b4595SMarouene Boubakri 
547185b4595SMarouene Boubakri struct mobj *mobj_with_fobj_alloc(struct fobj *fobj, struct file *file)
548185b4595SMarouene Boubakri {
549185b4595SMarouene Boubakri 	struct mobj_with_fobj *m = NULL;
550185b4595SMarouene Boubakri 
551185b4595SMarouene Boubakri 	if (!fobj)
552185b4595SMarouene Boubakri 		return NULL;
553185b4595SMarouene Boubakri 
554185b4595SMarouene Boubakri 	m = calloc(1, sizeof(*m));
555185b4595SMarouene Boubakri 	if (!m)
556185b4595SMarouene Boubakri 		return NULL;
557185b4595SMarouene Boubakri 
558185b4595SMarouene Boubakri 	m->mobj.ops = &mobj_with_fobj_ops;
559185b4595SMarouene Boubakri 	refcount_set(&m->mobj.refc, 1);
560185b4595SMarouene Boubakri 	m->mobj.size = fobj->num_pages * SMALL_PAGE_SIZE;
561185b4595SMarouene Boubakri 	m->mobj.phys_granule = SMALL_PAGE_SIZE;
562185b4595SMarouene Boubakri 	m->fobj = fobj_get(fobj);
563185b4595SMarouene Boubakri 	m->file = file_get(file);
564185b4595SMarouene Boubakri 
565185b4595SMarouene Boubakri 	return &m->mobj;
566185b4595SMarouene Boubakri }
567185b4595SMarouene Boubakri 
568185b4595SMarouene Boubakri static struct mobj_with_fobj *to_mobj_with_fobj(struct mobj *mobj)
569185b4595SMarouene Boubakri {
570185b4595SMarouene Boubakri 	assert(mobj && mobj->ops == &mobj_with_fobj_ops);
571185b4595SMarouene Boubakri 
572185b4595SMarouene Boubakri 	return container_of(mobj, struct mobj_with_fobj, mobj);
573185b4595SMarouene Boubakri }
574185b4595SMarouene Boubakri 
575185b4595SMarouene Boubakri static bool mobj_with_fobj_matches(struct mobj *mobj __maybe_unused,
576185b4595SMarouene Boubakri 				 enum buf_is_attr attr)
577185b4595SMarouene Boubakri {
578185b4595SMarouene Boubakri 	assert(to_mobj_with_fobj(mobj));
579185b4595SMarouene Boubakri 
580185b4595SMarouene Boubakri 	/*
581185b4595SMarouene Boubakri 	 * All fobjs are supposed to be mapped secure so classify it as
582185b4595SMarouene Boubakri 	 * CORE_MEM_SEC. Stay out of CORE_MEM_TEE_RAM etc, if that information
583185b4595SMarouene Boubakri 	 * needed it can probably be carried in another way than to put the
584185b4595SMarouene Boubakri 	 * burden directly on fobj.
585185b4595SMarouene Boubakri 	 */
586185b4595SMarouene Boubakri 	return attr == CORE_MEM_SEC;
587185b4595SMarouene Boubakri }
588185b4595SMarouene Boubakri 
589185b4595SMarouene Boubakri static void mobj_with_fobj_free(struct mobj *mobj)
590185b4595SMarouene Boubakri {
591185b4595SMarouene Boubakri 	struct mobj_with_fobj *m = to_mobj_with_fobj(mobj);
592185b4595SMarouene Boubakri 
593185b4595SMarouene Boubakri 	fobj_put(m->fobj);
594185b4595SMarouene Boubakri 	file_put(m->file);
595185b4595SMarouene Boubakri 	free(m);
596185b4595SMarouene Boubakri }
597185b4595SMarouene Boubakri 
598185b4595SMarouene Boubakri static struct fobj *mobj_with_fobj_get_fobj(struct mobj *mobj)
599185b4595SMarouene Boubakri {
600185b4595SMarouene Boubakri 	return fobj_get(to_mobj_with_fobj(mobj)->fobj);
601185b4595SMarouene Boubakri }
602185b4595SMarouene Boubakri 
603185b4595SMarouene Boubakri static TEE_Result mobj_with_fobj_get_cattr(struct mobj *mobj __unused,
604185b4595SMarouene Boubakri 					   uint32_t *cattr)
605185b4595SMarouene Boubakri {
606185b4595SMarouene Boubakri 	if (!cattr)
607185b4595SMarouene Boubakri 		return TEE_ERROR_GENERIC;
608185b4595SMarouene Boubakri 
609185b4595SMarouene Boubakri 	/* All fobjs are mapped as normal cached memory */
610185b4595SMarouene Boubakri 	*cattr = TEE_MATTR_CACHE_CACHED;
611185b4595SMarouene Boubakri 
612185b4595SMarouene Boubakri 	return TEE_SUCCESS;
613185b4595SMarouene Boubakri }
614185b4595SMarouene Boubakri 
615185b4595SMarouene Boubakri static TEE_Result mobj_with_fobj_get_pa(struct mobj *mobj, size_t offs,
616185b4595SMarouene Boubakri 					size_t granule, paddr_t *pa)
617185b4595SMarouene Boubakri {
618185b4595SMarouene Boubakri 	struct mobj_with_fobj *f = to_mobj_with_fobj(mobj);
619185b4595SMarouene Boubakri 	paddr_t p = 0;
620185b4595SMarouene Boubakri 
621185b4595SMarouene Boubakri 	if (!f->fobj->ops->get_pa) {
622185b4595SMarouene Boubakri 		assert(mobj_is_paged(mobj));
623185b4595SMarouene Boubakri 		return TEE_ERROR_NOT_SUPPORTED;
624185b4595SMarouene Boubakri 	}
625185b4595SMarouene Boubakri 
626185b4595SMarouene Boubakri 	p = f->fobj->ops->get_pa(f->fobj, offs / SMALL_PAGE_SIZE) +
627185b4595SMarouene Boubakri 	    offs % SMALL_PAGE_SIZE;
628185b4595SMarouene Boubakri 
629185b4595SMarouene Boubakri 	if (granule) {
630185b4595SMarouene Boubakri 		if (granule != SMALL_PAGE_SIZE &&
631185b4595SMarouene Boubakri 		    granule != CORE_MMU_PGDIR_SIZE)
632185b4595SMarouene Boubakri 			return TEE_ERROR_GENERIC;
633185b4595SMarouene Boubakri 		p &= ~(granule - 1);
634185b4595SMarouene Boubakri 	}
635185b4595SMarouene Boubakri 
636185b4595SMarouene Boubakri 	*pa = p;
637185b4595SMarouene Boubakri 
638185b4595SMarouene Boubakri 	return TEE_SUCCESS;
639185b4595SMarouene Boubakri }
640185b4595SMarouene Boubakri DECLARE_KEEP_PAGER(mobj_with_fobj_get_pa);
641185b4595SMarouene Boubakri 
642*00361c18SJens Wiklander /*
643*00361c18SJens Wiklander  * Note: this variable is weak just to ease breaking its dependency chain
644*00361c18SJens Wiklander  * when added to the unpaged area.
645*00361c18SJens Wiklander  */
646*00361c18SJens Wiklander const struct mobj_ops mobj_with_fobj_ops
647*00361c18SJens Wiklander __weak __rodata_unpaged("mobj_with_fobj_ops") = {
648185b4595SMarouene Boubakri 	.matches = mobj_with_fobj_matches,
649185b4595SMarouene Boubakri 	.free = mobj_with_fobj_free,
650185b4595SMarouene Boubakri 	.get_fobj = mobj_with_fobj_get_fobj,
651185b4595SMarouene Boubakri 	.get_cattr = mobj_with_fobj_get_cattr,
652185b4595SMarouene Boubakri 	.get_pa = mobj_with_fobj_get_pa,
653185b4595SMarouene Boubakri };
654185b4595SMarouene Boubakri 
655185b4595SMarouene Boubakri #ifdef CFG_PAGED_USER_TA
656185b4595SMarouene Boubakri bool mobj_is_paged(struct mobj *mobj)
657185b4595SMarouene Boubakri {
658185b4595SMarouene Boubakri 	if (mobj->ops == &mobj_seccpy_shm_ops)
659185b4595SMarouene Boubakri 		return true;
660185b4595SMarouene Boubakri 
661185b4595SMarouene Boubakri 	if (mobj->ops == &mobj_with_fobj_ops &&
662185b4595SMarouene Boubakri 	    !to_mobj_with_fobj(mobj)->fobj->ops->get_pa)
663185b4595SMarouene Boubakri 		return true;
664185b4595SMarouene Boubakri 
665185b4595SMarouene Boubakri 	return false;
666185b4595SMarouene Boubakri }
667185b4595SMarouene Boubakri #endif /*CFG_PAGED_USER_TA*/
668185b4595SMarouene Boubakri 
669185b4595SMarouene Boubakri static TEE_Result mobj_init(void)
670185b4595SMarouene Boubakri {
671185b4595SMarouene Boubakri 	mobj_sec_ddr = mobj_phys_alloc(tee_mm_sec_ddr.lo,
672185b4595SMarouene Boubakri 				       tee_mm_sec_ddr.hi - tee_mm_sec_ddr.lo,
673185b4595SMarouene Boubakri 				       OPTEE_SMC_SHM_CACHED, CORE_MEM_TA_RAM);
674185b4595SMarouene Boubakri 	if (!mobj_sec_ddr)
675185b4595SMarouene Boubakri 		panic("Failed to register secure ta ram");
676185b4595SMarouene Boubakri 
677185b4595SMarouene Boubakri 	mobj_tee_ram = mobj_phys_alloc(TEE_RAM_START,
678185b4595SMarouene Boubakri 				       VCORE_UNPG_RW_PA + VCORE_UNPG_RW_SZ -
679185b4595SMarouene Boubakri 						TEE_RAM_START,
680185b4595SMarouene Boubakri 				       TEE_MATTR_CACHE_CACHED,
681185b4595SMarouene Boubakri 				       CORE_MEM_TEE_RAM);
682185b4595SMarouene Boubakri 	if (!mobj_tee_ram)
683185b4595SMarouene Boubakri 		panic("Failed to register tee ram");
684185b4595SMarouene Boubakri 
685185b4595SMarouene Boubakri 	return TEE_SUCCESS;
686185b4595SMarouene Boubakri }
687185b4595SMarouene Boubakri 
688185b4595SMarouene Boubakri driver_init_late(mobj_init);
689