xref: /optee_os/core/mm/mobj.c (revision 003383344c26be3589383acc87c1ebb2860e9317)
1185b4595SMarouene Boubakri // SPDX-License-Identifier: BSD-2-Clause
2185b4595SMarouene Boubakri /*
36105aa86SJens Wiklander  * Copyright (c) 2016-2022, Linaro Limited
4185b4595SMarouene Boubakri  */
5185b4595SMarouene Boubakri 
6185b4595SMarouene Boubakri #include <assert.h>
7ff01e245SAnton Rybakov #include <config.h>
8185b4595SMarouene Boubakri #include <initcall.h>
9185b4595SMarouene Boubakri #include <keep.h>
10185b4595SMarouene Boubakri #include <kernel/linker.h>
11185b4595SMarouene Boubakri #include <kernel/mutex.h>
12185b4595SMarouene Boubakri #include <kernel/panic.h>
13185b4595SMarouene Boubakri #include <kernel/refcount.h>
14185b4595SMarouene Boubakri #include <kernel/spinlock.h>
15185b4595SMarouene Boubakri #include <mm/core_mmu.h>
16185b4595SMarouene Boubakri #include <mm/mobj.h>
17185b4595SMarouene Boubakri #include <mm/tee_pager.h>
18185b4595SMarouene Boubakri #include <optee_msg.h>
19185b4595SMarouene Boubakri #include <stdlib.h>
20185b4595SMarouene Boubakri #include <tee_api_types.h>
21185b4595SMarouene Boubakri #include <types_ext.h>
22185b4595SMarouene Boubakri #include <util.h>
23185b4595SMarouene Boubakri 
24ff01e245SAnton Rybakov struct mobj *mobj_tee_ram_rx;
25ff01e245SAnton Rybakov struct mobj *mobj_tee_ram_rw;
26185b4595SMarouene Boubakri 
27185b4595SMarouene Boubakri /*
28185b4595SMarouene Boubakri  * mobj_phys implementation
29185b4595SMarouene Boubakri  */
30185b4595SMarouene Boubakri 
31185b4595SMarouene Boubakri struct mobj_phys {
32185b4595SMarouene Boubakri 	struct mobj mobj;
33185b4595SMarouene Boubakri 	enum buf_is_attr battr;
348afe7a7cSJens Wiklander 	/* Defined by TEE_MATTR_MEM_TYPE_* in tee_mmu_types.h */
358afe7a7cSJens Wiklander 	uint32_t mem_type;
36185b4595SMarouene Boubakri 	vaddr_t va;
37185b4595SMarouene Boubakri 	paddr_t pa;
38185b4595SMarouene Boubakri };
39185b4595SMarouene Boubakri 
40185b4595SMarouene Boubakri static struct mobj_phys *to_mobj_phys(struct mobj *mobj);
41185b4595SMarouene Boubakri 
mobj_phys_get_va(struct mobj * mobj,size_t offset,size_t len)429c4aaf67SJens Wiklander static void *mobj_phys_get_va(struct mobj *mobj, size_t offset, size_t len)
43185b4595SMarouene Boubakri {
44185b4595SMarouene Boubakri 	struct mobj_phys *moph = to_mobj_phys(mobj);
45185b4595SMarouene Boubakri 
469c4aaf67SJens Wiklander 	if (!moph->va || !mobj_check_offset_and_len(mobj, offset, len))
47185b4595SMarouene Boubakri 		return NULL;
48185b4595SMarouene Boubakri 
49185b4595SMarouene Boubakri 	return (void *)(moph->va + offset);
50185b4595SMarouene Boubakri }
51185b4595SMarouene Boubakri 
mobj_phys_get_pa(struct mobj * mobj,size_t offs,size_t granule,paddr_t * pa)52185b4595SMarouene Boubakri static TEE_Result mobj_phys_get_pa(struct mobj *mobj, size_t offs,
53185b4595SMarouene Boubakri 				   size_t granule, paddr_t *pa)
54185b4595SMarouene Boubakri {
55185b4595SMarouene Boubakri 	struct mobj_phys *moph = to_mobj_phys(mobj);
56185b4595SMarouene Boubakri 	paddr_t p;
57185b4595SMarouene Boubakri 
58185b4595SMarouene Boubakri 	if (!pa)
59185b4595SMarouene Boubakri 		return TEE_ERROR_GENERIC;
60185b4595SMarouene Boubakri 
61185b4595SMarouene Boubakri 	p = moph->pa + offs;
62185b4595SMarouene Boubakri 
63185b4595SMarouene Boubakri 	if (granule) {
64185b4595SMarouene Boubakri 		if (granule != SMALL_PAGE_SIZE &&
65185b4595SMarouene Boubakri 		    granule != CORE_MMU_PGDIR_SIZE)
66185b4595SMarouene Boubakri 			return TEE_ERROR_GENERIC;
67185b4595SMarouene Boubakri 		p &= ~(granule - 1);
68185b4595SMarouene Boubakri 	}
69185b4595SMarouene Boubakri 
70185b4595SMarouene Boubakri 	*pa = p;
71185b4595SMarouene Boubakri 	return TEE_SUCCESS;
72185b4595SMarouene Boubakri }
73185b4595SMarouene Boubakri DECLARE_KEEP_PAGER(mobj_phys_get_pa);
74185b4595SMarouene Boubakri 
mobj_phys_get_mem_type(struct mobj * mobj,uint32_t * mem_type)758afe7a7cSJens Wiklander static TEE_Result mobj_phys_get_mem_type(struct mobj *mobj, uint32_t *mem_type)
76185b4595SMarouene Boubakri {
77185b4595SMarouene Boubakri 	struct mobj_phys *moph = to_mobj_phys(mobj);
78185b4595SMarouene Boubakri 
798afe7a7cSJens Wiklander 	if (!mem_type)
80185b4595SMarouene Boubakri 		return TEE_ERROR_GENERIC;
81185b4595SMarouene Boubakri 
828afe7a7cSJens Wiklander 	*mem_type = moph->mem_type;
83185b4595SMarouene Boubakri 	return TEE_SUCCESS;
84185b4595SMarouene Boubakri }
85185b4595SMarouene Boubakri 
mobj_phys_matches(struct mobj * mobj,enum buf_is_attr attr)86185b4595SMarouene Boubakri static bool mobj_phys_matches(struct mobj *mobj, enum buf_is_attr attr)
87185b4595SMarouene Boubakri {
88185b4595SMarouene Boubakri 	struct mobj_phys *moph = to_mobj_phys(mobj);
89185b4595SMarouene Boubakri 	enum buf_is_attr a;
90185b4595SMarouene Boubakri 
91185b4595SMarouene Boubakri 	a = moph->battr;
92185b4595SMarouene Boubakri 
93185b4595SMarouene Boubakri 	switch (attr) {
94185b4595SMarouene Boubakri 	case CORE_MEM_SEC:
95185b4595SMarouene Boubakri 		return a == CORE_MEM_SEC || a == CORE_MEM_TEE_RAM ||
961fbe848cSJens Wiklander 		       a == CORE_MEM_SDP_MEM;
97185b4595SMarouene Boubakri 	case CORE_MEM_NON_SEC:
98185b4595SMarouene Boubakri 		return a == CORE_MEM_NSEC_SHM;
99185b4595SMarouene Boubakri 	case CORE_MEM_TEE_RAM:
100185b4595SMarouene Boubakri 	case CORE_MEM_NSEC_SHM:
101185b4595SMarouene Boubakri 	case CORE_MEM_SDP_MEM:
102185b4595SMarouene Boubakri 		return attr == a;
103185b4595SMarouene Boubakri 	default:
104185b4595SMarouene Boubakri 		return false;
105185b4595SMarouene Boubakri 	}
106185b4595SMarouene Boubakri }
107185b4595SMarouene Boubakri 
mobj_phys_free(struct mobj * mobj)108185b4595SMarouene Boubakri static void mobj_phys_free(struct mobj *mobj)
109185b4595SMarouene Boubakri {
110185b4595SMarouene Boubakri 	struct mobj_phys *moph = to_mobj_phys(mobj);
111185b4595SMarouene Boubakri 
112185b4595SMarouene Boubakri 	free(moph);
113185b4595SMarouene Boubakri }
114185b4595SMarouene Boubakri 
11500361c18SJens Wiklander /*
11600361c18SJens Wiklander  * Note: this variable is weak just to ease breaking its dependency chain
11700361c18SJens Wiklander  * when added to the unpaged area.
11800361c18SJens Wiklander  */
11939e8c200SJerome Forissier const struct mobj_ops mobj_phys_ops
12039e8c200SJerome Forissier __weak __relrodata_unpaged("mobj_phys_ops") = {
121185b4595SMarouene Boubakri 	.get_va = mobj_phys_get_va,
122185b4595SMarouene Boubakri 	.get_pa = mobj_phys_get_pa,
123185b4595SMarouene Boubakri 	.get_phys_offs = NULL, /* only offset 0 */
1248afe7a7cSJens Wiklander 	.get_mem_type = mobj_phys_get_mem_type,
125185b4595SMarouene Boubakri 	.matches = mobj_phys_matches,
126185b4595SMarouene Boubakri 	.free = mobj_phys_free,
127185b4595SMarouene Boubakri };
128185b4595SMarouene Boubakri 
to_mobj_phys(struct mobj * mobj)129185b4595SMarouene Boubakri static struct mobj_phys *to_mobj_phys(struct mobj *mobj)
130185b4595SMarouene Boubakri {
131185b4595SMarouene Boubakri 	assert(mobj->ops == &mobj_phys_ops);
132185b4595SMarouene Boubakri 	return container_of(mobj, struct mobj_phys, mobj);
133185b4595SMarouene Boubakri }
134185b4595SMarouene Boubakri 
mobj_phys_init(paddr_t pa,size_t size,uint32_t mem_type,enum buf_is_attr battr,enum teecore_memtypes area_type)1358afe7a7cSJens Wiklander static struct mobj *mobj_phys_init(paddr_t pa, size_t size, uint32_t mem_type,
136ff01e245SAnton Rybakov 				   enum buf_is_attr battr,
137ff01e245SAnton Rybakov 				   enum teecore_memtypes area_type)
138185b4595SMarouene Boubakri {
139ff01e245SAnton Rybakov 	void *va = NULL;
140ff01e245SAnton Rybakov 	struct mobj_phys *moph = NULL;
141b715a420SAnton Rybakov 	struct tee_mmap_region *map = NULL;
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 
149b715a420SAnton Rybakov 	if (pa) {
150c2e4eb43SAnton Rybakov 		va = phys_to_virt(pa, area_type, size);
151b715a420SAnton Rybakov 	} else {
152b715a420SAnton Rybakov 		map = core_mmu_find_mapping_exclusive(area_type, size);
153b715a420SAnton Rybakov 		if (!map)
154b715a420SAnton Rybakov 			return NULL;
155b715a420SAnton Rybakov 
156b715a420SAnton Rybakov 		pa = map->pa;
157b715a420SAnton Rybakov 		va = (void *)map->va;
158b715a420SAnton Rybakov 	}
159b715a420SAnton Rybakov 
160b715a420SAnton Rybakov 	/* Only SDP memory may not have a virtual address */
161185b4595SMarouene Boubakri 	if (!va && battr != CORE_MEM_SDP_MEM)
162185b4595SMarouene Boubakri 		return NULL;
163185b4595SMarouene Boubakri 
164185b4595SMarouene Boubakri 	moph = calloc(1, sizeof(*moph));
165185b4595SMarouene Boubakri 	if (!moph)
166185b4595SMarouene Boubakri 		return NULL;
167185b4595SMarouene Boubakri 
168185b4595SMarouene Boubakri 	moph->battr = battr;
1698afe7a7cSJens Wiklander 	moph->mem_type = mem_type;
170185b4595SMarouene Boubakri 	moph->mobj.size = size;
171185b4595SMarouene Boubakri 	moph->mobj.ops = &mobj_phys_ops;
172185b4595SMarouene Boubakri 	refcount_set(&moph->mobj.refc, 1);
173185b4595SMarouene Boubakri 	moph->pa = pa;
174185b4595SMarouene Boubakri 	moph->va = (vaddr_t)va;
175185b4595SMarouene Boubakri 
176185b4595SMarouene Boubakri 	return &moph->mobj;
177185b4595SMarouene Boubakri }
178185b4595SMarouene Boubakri 
mobj_phys_alloc(paddr_t pa,size_t size,uint32_t mem_type,enum buf_is_attr battr)1798afe7a7cSJens Wiklander struct mobj *mobj_phys_alloc(paddr_t pa, size_t size, uint32_t mem_type,
180ff01e245SAnton Rybakov 			     enum buf_is_attr battr)
181ff01e245SAnton Rybakov {
182ff01e245SAnton Rybakov 	enum teecore_memtypes area_type;
183ff01e245SAnton Rybakov 
184ff01e245SAnton Rybakov 	switch (battr) {
185ff01e245SAnton Rybakov 	case CORE_MEM_NSEC_SHM:
186ff01e245SAnton Rybakov 		area_type = MEM_AREA_NSEC_SHM;
187ff01e245SAnton Rybakov 		break;
188ff01e245SAnton Rybakov 	case CORE_MEM_SDP_MEM:
189ff01e245SAnton Rybakov 		area_type = MEM_AREA_SDP_MEM;
190ff01e245SAnton Rybakov 		break;
191ff01e245SAnton Rybakov 	default:
192ff01e245SAnton Rybakov 		DMSG("can't allocate with specified attribute");
193ff01e245SAnton Rybakov 		return NULL;
194ff01e245SAnton Rybakov 	}
195ff01e245SAnton Rybakov 
1968afe7a7cSJens Wiklander 	return mobj_phys_init(pa, size, mem_type, battr, area_type);
197ff01e245SAnton Rybakov }
198ff01e245SAnton Rybakov 
199185b4595SMarouene Boubakri /*
200185b4595SMarouene Boubakri  * mobj_virt implementation
201185b4595SMarouene Boubakri  */
202185b4595SMarouene Boubakri 
203185b4595SMarouene Boubakri static void mobj_virt_assert_type(struct mobj *mobj);
204185b4595SMarouene Boubakri 
mobj_virt_get_va(struct mobj * mobj,size_t offset,size_t len __maybe_unused)2059c4aaf67SJens Wiklander static void *mobj_virt_get_va(struct mobj *mobj, size_t offset,
2069c4aaf67SJens Wiklander 			      size_t len __maybe_unused)
207185b4595SMarouene Boubakri {
208185b4595SMarouene Boubakri 	mobj_virt_assert_type(mobj);
2099c4aaf67SJens Wiklander 	assert(mobj_check_offset_and_len(mobj, offset, len));
210185b4595SMarouene Boubakri 
211185b4595SMarouene Boubakri 	return (void *)(vaddr_t)offset;
212185b4595SMarouene Boubakri }
213185b4595SMarouene Boubakri 
21400361c18SJens Wiklander /*
21500361c18SJens Wiklander  * Note: this variable is weak just to ease breaking its dependency chain
21600361c18SJens Wiklander  * when added to the unpaged area.
21700361c18SJens Wiklander  */
21839e8c200SJerome Forissier const struct mobj_ops mobj_virt_ops
21939e8c200SJerome Forissier __weak __relrodata_unpaged("mobj_virt_ops") = {
220185b4595SMarouene Boubakri 	.get_va = mobj_virt_get_va,
221185b4595SMarouene Boubakri };
222185b4595SMarouene Boubakri 
mobj_virt_assert_type(struct mobj * mobj __maybe_unused)223185b4595SMarouene Boubakri static void mobj_virt_assert_type(struct mobj *mobj __maybe_unused)
224185b4595SMarouene Boubakri {
225185b4595SMarouene Boubakri 	assert(mobj->ops == &mobj_virt_ops);
226185b4595SMarouene Boubakri }
227185b4595SMarouene Boubakri 
228185b4595SMarouene Boubakri struct mobj mobj_virt = { .ops = &mobj_virt_ops, .size = SIZE_MAX };
229185b4595SMarouene Boubakri 
230185b4595SMarouene Boubakri /*
231185b4595SMarouene Boubakri  * mobj_shm implementation. mobj_shm represents buffer in predefined shm region
232185b4595SMarouene Boubakri  * - it is physically contiguous.
233185b4595SMarouene Boubakri  * - it is identified in static physical layout as MEM_AREA_NSEC_SHM.
234185b4595SMarouene Boubakri  * - it creates mobjs that match specific CORE_MEM_NSEC_SHM and non secure
235185b4595SMarouene Boubakri  *   generic CORE_MEM_NON_SEC.
236185b4595SMarouene Boubakri  */
237185b4595SMarouene Boubakri 
238185b4595SMarouene Boubakri struct mobj_shm {
239185b4595SMarouene Boubakri 	struct mobj mobj;
240185b4595SMarouene Boubakri 	paddr_t pa;
241185b4595SMarouene Boubakri 	uint64_t cookie;
242185b4595SMarouene Boubakri };
243185b4595SMarouene Boubakri 
244185b4595SMarouene Boubakri static struct mobj_shm *to_mobj_shm(struct mobj *mobj);
245185b4595SMarouene Boubakri 
mobj_shm_get_va(struct mobj * mobj,size_t offset,size_t len)2469c4aaf67SJens Wiklander static void *mobj_shm_get_va(struct mobj *mobj, size_t offset, size_t len)
247185b4595SMarouene Boubakri {
248185b4595SMarouene Boubakri 	struct mobj_shm *m = to_mobj_shm(mobj);
249185b4595SMarouene Boubakri 
2509c4aaf67SJens Wiklander 	if (!mobj_check_offset_and_len(mobj, offset, len))
251185b4595SMarouene Boubakri 		return NULL;
252185b4595SMarouene Boubakri 
253c2e4eb43SAnton Rybakov 	return phys_to_virt(m->pa + offset, MEM_AREA_NSEC_SHM,
254c2e4eb43SAnton Rybakov 			    mobj->size - offset);
255185b4595SMarouene Boubakri }
256185b4595SMarouene Boubakri 
mobj_shm_get_pa(struct mobj * mobj,size_t offs,size_t granule,paddr_t * pa)257185b4595SMarouene Boubakri static TEE_Result mobj_shm_get_pa(struct mobj *mobj, size_t offs,
258185b4595SMarouene Boubakri 				   size_t granule, paddr_t *pa)
259185b4595SMarouene Boubakri {
260185b4595SMarouene Boubakri 	struct mobj_shm *m = to_mobj_shm(mobj);
261185b4595SMarouene Boubakri 	paddr_t p;
262185b4595SMarouene Boubakri 
263185b4595SMarouene Boubakri 	if (!pa || offs >= mobj->size)
264185b4595SMarouene Boubakri 		return TEE_ERROR_GENERIC;
265185b4595SMarouene Boubakri 
266185b4595SMarouene Boubakri 	p = m->pa + offs;
267185b4595SMarouene Boubakri 
268185b4595SMarouene Boubakri 	if (granule) {
269185b4595SMarouene Boubakri 		if (granule != SMALL_PAGE_SIZE &&
270185b4595SMarouene Boubakri 		    granule != CORE_MMU_PGDIR_SIZE)
271185b4595SMarouene Boubakri 			return TEE_ERROR_GENERIC;
272185b4595SMarouene Boubakri 		p &= ~(granule - 1);
273185b4595SMarouene Boubakri 	}
274185b4595SMarouene Boubakri 
275185b4595SMarouene Boubakri 	*pa = p;
276185b4595SMarouene Boubakri 	return TEE_SUCCESS;
277185b4595SMarouene Boubakri }
278185b4595SMarouene Boubakri DECLARE_KEEP_PAGER(mobj_shm_get_pa);
279185b4595SMarouene Boubakri 
mobj_shm_get_phys_offs(struct mobj * mobj,size_t granule)280185b4595SMarouene Boubakri static size_t mobj_shm_get_phys_offs(struct mobj *mobj, size_t granule)
281185b4595SMarouene Boubakri {
282185b4595SMarouene Boubakri 	assert(IS_POWER_OF_TWO(granule));
283185b4595SMarouene Boubakri 	return to_mobj_shm(mobj)->pa & (granule - 1);
284185b4595SMarouene Boubakri }
285185b4595SMarouene Boubakri 
mobj_shm_matches(struct mobj * mobj __unused,enum buf_is_attr attr)286185b4595SMarouene Boubakri static bool mobj_shm_matches(struct mobj *mobj __unused, enum buf_is_attr attr)
287185b4595SMarouene Boubakri {
288185b4595SMarouene Boubakri 	return attr == CORE_MEM_NSEC_SHM || attr == CORE_MEM_NON_SEC;
289185b4595SMarouene Boubakri }
290185b4595SMarouene Boubakri 
mobj_shm_get_mem_type(struct mobj * mobj __unused,uint32_t * mem_type)2918afe7a7cSJens Wiklander static TEE_Result mobj_shm_get_mem_type(struct mobj *mobj __unused,
2928afe7a7cSJens Wiklander 					uint32_t *mem_type)
293e31a75b3SLejia Zhang {
2948afe7a7cSJens Wiklander 	if (!mem_type)
295e31a75b3SLejia Zhang 		return TEE_ERROR_GENERIC;
296e31a75b3SLejia Zhang 
2978afe7a7cSJens Wiklander 	*mem_type = TEE_MATTR_MEM_TYPE_CACHED;
298e31a75b3SLejia Zhang 
299e31a75b3SLejia Zhang 	return TEE_SUCCESS;
300e31a75b3SLejia Zhang }
301e31a75b3SLejia Zhang 
mobj_shm_free(struct mobj * mobj)302185b4595SMarouene Boubakri static void mobj_shm_free(struct mobj *mobj)
303185b4595SMarouene Boubakri {
304185b4595SMarouene Boubakri 	struct mobj_shm *m = to_mobj_shm(mobj);
305185b4595SMarouene Boubakri 
306185b4595SMarouene Boubakri 	free(m);
307185b4595SMarouene Boubakri }
308185b4595SMarouene Boubakri 
mobj_shm_get_cookie(struct mobj * mobj)309185b4595SMarouene Boubakri static uint64_t mobj_shm_get_cookie(struct mobj *mobj)
310185b4595SMarouene Boubakri {
311185b4595SMarouene Boubakri 	return to_mobj_shm(mobj)->cookie;
312185b4595SMarouene Boubakri }
313185b4595SMarouene Boubakri 
31400361c18SJens Wiklander /*
31500361c18SJens Wiklander  * Note: this variable is weak just to ease breaking its dependency chain
31600361c18SJens Wiklander  * when added to the unpaged area.
31700361c18SJens Wiklander  */
31839e8c200SJerome Forissier const struct mobj_ops mobj_shm_ops
31939e8c200SJerome Forissier __weak __relrodata_unpaged("mobj_shm_ops") = {
320185b4595SMarouene Boubakri 	.get_va = mobj_shm_get_va,
321185b4595SMarouene Boubakri 	.get_pa = mobj_shm_get_pa,
322185b4595SMarouene Boubakri 	.get_phys_offs = mobj_shm_get_phys_offs,
3238afe7a7cSJens Wiklander 	.get_mem_type = mobj_shm_get_mem_type,
324185b4595SMarouene Boubakri 	.matches = mobj_shm_matches,
325185b4595SMarouene Boubakri 	.free = mobj_shm_free,
326185b4595SMarouene Boubakri 	.get_cookie = mobj_shm_get_cookie,
327185b4595SMarouene Boubakri };
328185b4595SMarouene Boubakri 
to_mobj_shm(struct mobj * mobj)329185b4595SMarouene Boubakri static struct mobj_shm *to_mobj_shm(struct mobj *mobj)
330185b4595SMarouene Boubakri {
331185b4595SMarouene Boubakri 	assert(mobj->ops == &mobj_shm_ops);
332185b4595SMarouene Boubakri 	return container_of(mobj, struct mobj_shm, mobj);
333185b4595SMarouene Boubakri }
334185b4595SMarouene Boubakri 
mobj_shm_alloc(paddr_t pa,size_t size,uint64_t cookie)335185b4595SMarouene Boubakri struct mobj *mobj_shm_alloc(paddr_t pa, size_t size, uint64_t cookie)
336185b4595SMarouene Boubakri {
337185b4595SMarouene Boubakri 	struct mobj_shm *m;
338185b4595SMarouene Boubakri 
339185b4595SMarouene Boubakri 	if (!core_pbuf_is(CORE_MEM_NSEC_SHM, pa, size))
340185b4595SMarouene Boubakri 		return NULL;
341185b4595SMarouene Boubakri 
342185b4595SMarouene Boubakri 	m = calloc(1, sizeof(*m));
343185b4595SMarouene Boubakri 	if (!m)
344185b4595SMarouene Boubakri 		return NULL;
345185b4595SMarouene Boubakri 
346185b4595SMarouene Boubakri 	m->mobj.size = size;
347185b4595SMarouene Boubakri 	m->mobj.ops = &mobj_shm_ops;
348e31a75b3SLejia Zhang 	m->mobj.phys_granule = SMALL_PAGE_SIZE;
349185b4595SMarouene Boubakri 	refcount_set(&m->mobj.refc, 1);
350185b4595SMarouene Boubakri 	m->pa = pa;
351185b4595SMarouene Boubakri 	m->cookie = cookie;
352185b4595SMarouene Boubakri 
353185b4595SMarouene Boubakri 	return &m->mobj;
354185b4595SMarouene Boubakri }
355185b4595SMarouene Boubakri 
356185b4595SMarouene Boubakri struct mobj_with_fobj {
357185b4595SMarouene Boubakri 	struct fobj *fobj;
358185b4595SMarouene Boubakri 	struct file *file;
359185b4595SMarouene Boubakri 	struct mobj mobj;
3606105aa86SJens Wiklander 	uint8_t mem_type;
361185b4595SMarouene Boubakri };
362185b4595SMarouene Boubakri 
36300361c18SJens Wiklander const struct mobj_ops mobj_with_fobj_ops;
364185b4595SMarouene Boubakri 
mobj_with_fobj_alloc(struct fobj * fobj,struct file * file,uint32_t mem_type)3656105aa86SJens Wiklander struct mobj *mobj_with_fobj_alloc(struct fobj *fobj, struct file *file,
3666105aa86SJens Wiklander 				  uint32_t mem_type)
367185b4595SMarouene Boubakri {
368185b4595SMarouene Boubakri 	struct mobj_with_fobj *m = NULL;
369185b4595SMarouene Boubakri 
3706105aa86SJens Wiklander 	assert(!(mem_type & ~TEE_MATTR_MEM_TYPE_MASK));
3716105aa86SJens Wiklander 
372185b4595SMarouene Boubakri 	if (!fobj)
373185b4595SMarouene Boubakri 		return NULL;
3746105aa86SJens Wiklander 	if (mem_type > UINT8_MAX)
3756105aa86SJens Wiklander 		return NULL;
376185b4595SMarouene Boubakri 
377185b4595SMarouene Boubakri 	m = calloc(1, sizeof(*m));
378185b4595SMarouene Boubakri 	if (!m)
379185b4595SMarouene Boubakri 		return NULL;
380185b4595SMarouene Boubakri 
381185b4595SMarouene Boubakri 	m->mobj.ops = &mobj_with_fobj_ops;
382185b4595SMarouene Boubakri 	refcount_set(&m->mobj.refc, 1);
383185b4595SMarouene Boubakri 	m->mobj.size = fobj->num_pages * SMALL_PAGE_SIZE;
384185b4595SMarouene Boubakri 	m->mobj.phys_granule = SMALL_PAGE_SIZE;
385185b4595SMarouene Boubakri 	m->fobj = fobj_get(fobj);
386185b4595SMarouene Boubakri 	m->file = file_get(file);
3876105aa86SJens Wiklander 	m->mem_type = mem_type;
388185b4595SMarouene Boubakri 
389185b4595SMarouene Boubakri 	return &m->mobj;
390185b4595SMarouene Boubakri }
391185b4595SMarouene Boubakri 
to_mobj_with_fobj(struct mobj * mobj)392185b4595SMarouene Boubakri static struct mobj_with_fobj *to_mobj_with_fobj(struct mobj *mobj)
393185b4595SMarouene Boubakri {
394185b4595SMarouene Boubakri 	assert(mobj && mobj->ops == &mobj_with_fobj_ops);
395185b4595SMarouene Boubakri 
396185b4595SMarouene Boubakri 	return container_of(mobj, struct mobj_with_fobj, mobj);
397185b4595SMarouene Boubakri }
398185b4595SMarouene Boubakri 
mobj_with_fobj_matches(struct mobj * mobj __maybe_unused,enum buf_is_attr attr)399185b4595SMarouene Boubakri static bool mobj_with_fobj_matches(struct mobj *mobj __maybe_unused,
400185b4595SMarouene Boubakri 				 enum buf_is_attr attr)
401185b4595SMarouene Boubakri {
402185b4595SMarouene Boubakri 	assert(to_mobj_with_fobj(mobj));
403185b4595SMarouene Boubakri 
404185b4595SMarouene Boubakri 	/*
405185b4595SMarouene Boubakri 	 * All fobjs are supposed to be mapped secure so classify it as
406185b4595SMarouene Boubakri 	 * CORE_MEM_SEC. Stay out of CORE_MEM_TEE_RAM etc, if that information
407185b4595SMarouene Boubakri 	 * needed it can probably be carried in another way than to put the
408185b4595SMarouene Boubakri 	 * burden directly on fobj.
409185b4595SMarouene Boubakri 	 */
410185b4595SMarouene Boubakri 	return attr == CORE_MEM_SEC;
411185b4595SMarouene Boubakri }
412185b4595SMarouene Boubakri 
mobj_with_fobj_free(struct mobj * mobj)413185b4595SMarouene Boubakri static void mobj_with_fobj_free(struct mobj *mobj)
414185b4595SMarouene Boubakri {
415185b4595SMarouene Boubakri 	struct mobj_with_fobj *m = to_mobj_with_fobj(mobj);
416185b4595SMarouene Boubakri 
417185b4595SMarouene Boubakri 	fobj_put(m->fobj);
418185b4595SMarouene Boubakri 	file_put(m->file);
419185b4595SMarouene Boubakri 	free(m);
420185b4595SMarouene Boubakri }
421185b4595SMarouene Boubakri 
mobj_with_fobj_get_fobj(struct mobj * mobj)422185b4595SMarouene Boubakri static struct fobj *mobj_with_fobj_get_fobj(struct mobj *mobj)
423185b4595SMarouene Boubakri {
424185b4595SMarouene Boubakri 	return fobj_get(to_mobj_with_fobj(mobj)->fobj);
425185b4595SMarouene Boubakri }
426185b4595SMarouene Boubakri 
mobj_with_fobj_get_mem_type(struct mobj * mobj,uint32_t * mem_type)4276105aa86SJens Wiklander static TEE_Result mobj_with_fobj_get_mem_type(struct mobj *mobj,
4288afe7a7cSJens Wiklander 					      uint32_t *mem_type)
429185b4595SMarouene Boubakri {
4306105aa86SJens Wiklander 	struct mobj_with_fobj *m = to_mobj_with_fobj(mobj);
4316105aa86SJens Wiklander 
4328afe7a7cSJens Wiklander 	if (!mem_type)
433185b4595SMarouene Boubakri 		return TEE_ERROR_GENERIC;
434185b4595SMarouene Boubakri 
4356105aa86SJens Wiklander 	*mem_type = m->mem_type;
436185b4595SMarouene Boubakri 
437185b4595SMarouene Boubakri 	return TEE_SUCCESS;
438185b4595SMarouene Boubakri }
439185b4595SMarouene Boubakri 
mobj_with_fobj_get_pa(struct mobj * mobj,size_t offs,size_t granule,paddr_t * pa)440185b4595SMarouene Boubakri static TEE_Result mobj_with_fobj_get_pa(struct mobj *mobj, size_t offs,
441185b4595SMarouene Boubakri 					size_t granule, paddr_t *pa)
442185b4595SMarouene Boubakri {
443185b4595SMarouene Boubakri 	struct mobj_with_fobj *f = to_mobj_with_fobj(mobj);
444185b4595SMarouene Boubakri 	paddr_t p = 0;
445185b4595SMarouene Boubakri 
446185b4595SMarouene Boubakri 	if (!f->fobj->ops->get_pa) {
447185b4595SMarouene Boubakri 		assert(mobj_is_paged(mobj));
448185b4595SMarouene Boubakri 		return TEE_ERROR_NOT_SUPPORTED;
449185b4595SMarouene Boubakri 	}
450185b4595SMarouene Boubakri 
451185b4595SMarouene Boubakri 	p = f->fobj->ops->get_pa(f->fobj, offs / SMALL_PAGE_SIZE) +
452185b4595SMarouene Boubakri 	    offs % SMALL_PAGE_SIZE;
453185b4595SMarouene Boubakri 
454185b4595SMarouene Boubakri 	if (granule) {
455185b4595SMarouene Boubakri 		if (granule != SMALL_PAGE_SIZE &&
456185b4595SMarouene Boubakri 		    granule != CORE_MMU_PGDIR_SIZE)
457185b4595SMarouene Boubakri 			return TEE_ERROR_GENERIC;
458185b4595SMarouene Boubakri 		p &= ~(granule - 1);
459185b4595SMarouene Boubakri 	}
460185b4595SMarouene Boubakri 
461185b4595SMarouene Boubakri 	*pa = p;
462185b4595SMarouene Boubakri 
463185b4595SMarouene Boubakri 	return TEE_SUCCESS;
464185b4595SMarouene Boubakri }
465185b4595SMarouene Boubakri DECLARE_KEEP_PAGER(mobj_with_fobj_get_pa);
466185b4595SMarouene Boubakri 
46700361c18SJens Wiklander /*
46800361c18SJens Wiklander  * Note: this variable is weak just to ease breaking its dependency chain
46900361c18SJens Wiklander  * when added to the unpaged area.
47000361c18SJens Wiklander  */
47100361c18SJens Wiklander const struct mobj_ops mobj_with_fobj_ops
47239e8c200SJerome Forissier __weak __relrodata_unpaged("mobj_with_fobj_ops") = {
473185b4595SMarouene Boubakri 	.matches = mobj_with_fobj_matches,
474185b4595SMarouene Boubakri 	.free = mobj_with_fobj_free,
475185b4595SMarouene Boubakri 	.get_fobj = mobj_with_fobj_get_fobj,
4768afe7a7cSJens Wiklander 	.get_mem_type = mobj_with_fobj_get_mem_type,
477185b4595SMarouene Boubakri 	.get_pa = mobj_with_fobj_get_pa,
478185b4595SMarouene Boubakri };
479185b4595SMarouene Boubakri 
480185b4595SMarouene Boubakri #ifdef CFG_PAGED_USER_TA
mobj_is_paged(struct mobj * mobj)481185b4595SMarouene Boubakri bool mobj_is_paged(struct mobj *mobj)
482185b4595SMarouene Boubakri {
483185b4595SMarouene Boubakri 	if (mobj->ops == &mobj_with_fobj_ops &&
484185b4595SMarouene Boubakri 	    !to_mobj_with_fobj(mobj)->fobj->ops->get_pa)
485185b4595SMarouene Boubakri 		return true;
486185b4595SMarouene Boubakri 
487185b4595SMarouene Boubakri 	return false;
488185b4595SMarouene Boubakri }
489185b4595SMarouene Boubakri #endif /*CFG_PAGED_USER_TA*/
490185b4595SMarouene Boubakri 
mobj_init(void)491185b4595SMarouene Boubakri static TEE_Result mobj_init(void)
492185b4595SMarouene Boubakri {
493ff01e245SAnton Rybakov 	if (IS_ENABLED(CFG_CORE_RWDATA_NOEXEC)) {
494b715a420SAnton Rybakov 		mobj_tee_ram_rx = mobj_phys_init(0,
495ff01e245SAnton Rybakov 						 VCORE_UNPG_RX_SZ,
4968b427282SJelle Sels 						 TEE_MATTR_MEM_TYPE_CACHED,
497ff01e245SAnton Rybakov 						 CORE_MEM_TEE_RAM,
498ff01e245SAnton Rybakov 						 MEM_AREA_TEE_RAM_RX);
499ff01e245SAnton Rybakov 		if (!mobj_tee_ram_rx)
500ff01e245SAnton Rybakov 			panic("Failed to register tee ram rx");
501ff01e245SAnton Rybakov 
502b715a420SAnton Rybakov 		mobj_tee_ram_rw = mobj_phys_init(0,
503ff01e245SAnton Rybakov 						 VCORE_UNPG_RW_SZ,
5048b427282SJelle Sels 						 TEE_MATTR_MEM_TYPE_CACHED,
505ff01e245SAnton Rybakov 						 CORE_MEM_TEE_RAM,
506ff01e245SAnton Rybakov 						 MEM_AREA_TEE_RAM_RW_DATA);
507ff01e245SAnton Rybakov 		if (!mobj_tee_ram_rw)
508ff01e245SAnton Rybakov 			panic("Failed to register tee ram rw");
509ff01e245SAnton Rybakov 	} else {
510ff01e245SAnton Rybakov 		mobj_tee_ram_rw = mobj_phys_init(TEE_RAM_START,
511ff01e245SAnton Rybakov 						 VCORE_UNPG_RW_PA +
512ff01e245SAnton Rybakov 						 VCORE_UNPG_RW_SZ -
5133de913f6SJens Wiklander 						 VCORE_START_VA,
5148b427282SJelle Sels 						 TEE_MATTR_MEM_TYPE_CACHED,
515ff01e245SAnton Rybakov 						 CORE_MEM_TEE_RAM,
516ff01e245SAnton Rybakov 						 MEM_AREA_TEE_RAM_RW_DATA);
517ff01e245SAnton Rybakov 		if (!mobj_tee_ram_rw)
518185b4595SMarouene Boubakri 			panic("Failed to register tee ram");
519185b4595SMarouene Boubakri 
520ff01e245SAnton Rybakov 		mobj_tee_ram_rx = mobj_tee_ram_rw;
521ff01e245SAnton Rybakov 	}
522ff01e245SAnton Rybakov 
523185b4595SMarouene Boubakri 	return TEE_SUCCESS;
524185b4595SMarouene Boubakri }
525185b4595SMarouene Boubakri 
526185b4595SMarouene Boubakri driver_init_late(mobj_init);
527*00338334SJens Wiklander 
528*00338334SJens Wiklander #if defined(CFG_CORE_DYN_PROTMEM)
529*00338334SJens Wiklander #if defined(CFG_INSECURE)
530*00338334SJens Wiklander /*
531*00338334SJens Wiklander  * This function requires CFG_INSECURE=y since it's stubbed and could cause
532*00338334SJens Wiklander  * a silent security error.
533*00338334SJens Wiklander  */
plat_set_protmem_range(enum mobj_use_case use_case __unused,paddr_t pa __unused,paddr_size_t sz __unused)534*00338334SJens Wiklander TEE_Result __weak plat_set_protmem_range(enum mobj_use_case use_case __unused,
535*00338334SJens Wiklander 					 paddr_t pa __unused,
536*00338334SJens Wiklander 					 paddr_size_t sz __unused)
537*00338334SJens Wiklander {
538*00338334SJens Wiklander 	static bool once;
539*00338334SJens Wiklander 
540*00338334SJens Wiklander 	if (!once) {
541*00338334SJens Wiklander 		IMSG("WARNING (insecure configuration): platform does not support to dynamically protected memory");
542*00338334SJens Wiklander 		once = true;
543*00338334SJens Wiklander 	}
544*00338334SJens Wiklander 
545*00338334SJens Wiklander 	return TEE_SUCCESS;
546*00338334SJens Wiklander }
547*00338334SJens Wiklander #endif /*defined(CFG_INSECURE)*/
548*00338334SJens Wiklander 
plat_get_protmem_config(enum mobj_use_case use_case,size_t * min_mem_sz,size_t * min_mem_align)549*00338334SJens Wiklander TEE_Result __weak plat_get_protmem_config(enum mobj_use_case use_case,
550*00338334SJens Wiklander 					  size_t *min_mem_sz,
551*00338334SJens Wiklander 					  size_t *min_mem_align)
552*00338334SJens Wiklander {
553*00338334SJens Wiklander 	if (use_case != MOBJ_USE_CASE_SEC_VIDEO_PLAY)
554*00338334SJens Wiklander 		return TEE_ERROR_BAD_PARAMETERS;
555*00338334SJens Wiklander 
556*00338334SJens Wiklander 	/*
557*00338334SJens Wiklander 	 * This memory is only shared with OP-TEE and TAs, a dummy
558*00338334SJens Wiklander 	 * configuration for now. This will be configured by platform
559*00338334SJens Wiklander 	 * specific function.
560*00338334SJens Wiklander 	 */
561*00338334SJens Wiklander 	*min_mem_sz = SIZE_1M;
562*00338334SJens Wiklander 	*min_mem_align = SMALL_PAGE_SIZE;
563*00338334SJens Wiklander 
564*00338334SJens Wiklander 	return TEE_SUCCESS;
565*00338334SJens Wiklander }
566*00338334SJens Wiklander #endif /*defined(CFG_CORE_DYN_PROTMEM)*/
567