xref: /optee_os/core/mm/fobj.c (revision 3639b55f101b2c3bba33740ec7bf5440b3125efc)
1ee546289SJens Wiklander // SPDX-License-Identifier: BSD-2-Clause
2ee546289SJens Wiklander /*
3ee546289SJens Wiklander  * Copyright (c) 2019, Linaro Limited
4ee546289SJens Wiklander  */
5ee546289SJens Wiklander 
6ee546289SJens Wiklander #include <crypto/crypto.h>
7ee546289SJens Wiklander #include <crypto/internal_aes-gcm.h>
8c6744caaSJens Wiklander #include <kernel/generic_boot.h>
9ee546289SJens Wiklander #include <kernel/panic.h>
10ee546289SJens Wiklander #include <mm/core_memprot.h>
11ee546289SJens Wiklander #include <mm/core_mmu.h>
12ee546289SJens Wiklander #include <mm/fobj.h>
13ee546289SJens Wiklander #include <mm/tee_mm.h>
14ee546289SJens Wiklander #include <stdlib.h>
15ee546289SJens Wiklander #include <string.h>
16ee546289SJens Wiklander #include <tee_api_types.h>
17ee546289SJens Wiklander #include <types_ext.h>
18ee546289SJens Wiklander #include <util.h>
19ee546289SJens Wiklander 
20ee546289SJens Wiklander #ifdef CFG_WITH_PAGER
21ee546289SJens Wiklander 
22ee546289SJens Wiklander #define RWP_AE_KEY_BITS		256
23ee546289SJens Wiklander 
24ee546289SJens Wiklander struct rwp_aes_gcm_iv {
25ee546289SJens Wiklander 	uint32_t iv[3];
26ee546289SJens Wiklander };
27ee546289SJens Wiklander 
28ee546289SJens Wiklander #define RWP_AES_GCM_TAG_LEN	16
29ee546289SJens Wiklander 
30ee546289SJens Wiklander struct rwp_state {
31ee546289SJens Wiklander 	uint64_t iv;
32ee546289SJens Wiklander 	uint8_t tag[RWP_AES_GCM_TAG_LEN];
33ee546289SJens Wiklander };
34ee546289SJens Wiklander 
35ee546289SJens Wiklander struct fobj_rwp {
36ee546289SJens Wiklander 	uint8_t *store;
37ee546289SJens Wiklander 	struct rwp_state *state;
38ee546289SJens Wiklander 	struct fobj fobj;
39ee546289SJens Wiklander };
40ee546289SJens Wiklander 
41c6744caaSJens Wiklander static const struct fobj_ops ops_rw_paged;
42ee546289SJens Wiklander 
43ee546289SJens Wiklander static struct internal_aes_gcm_key rwp_ae_key;
44ee546289SJens Wiklander 
45ee546289SJens Wiklander void fobj_generate_authenc_key(void)
46ee546289SJens Wiklander {
47ee546289SJens Wiklander 	uint8_t key[RWP_AE_KEY_BITS / 8] = { 0 };
48ee546289SJens Wiklander 
49ee546289SJens Wiklander 	if (crypto_rng_read(key, sizeof(key)) != TEE_SUCCESS)
50ee546289SJens Wiklander 		panic("failed to generate random");
517395539fSJens Wiklander 	if (crypto_aes_expand_enc_key(key, sizeof(key), rwp_ae_key.data,
527395539fSJens Wiklander 				      sizeof(rwp_ae_key.data),
537395539fSJens Wiklander 				      &rwp_ae_key.rounds))
54ee546289SJens Wiklander 		panic("failed to expand key");
55ee546289SJens Wiklander }
56ee546289SJens Wiklander 
57ee546289SJens Wiklander static void fobj_init(struct fobj *fobj, const struct fobj_ops *ops,
58ee546289SJens Wiklander 		      unsigned int num_pages)
59ee546289SJens Wiklander {
60ee546289SJens Wiklander 	fobj->ops = ops;
61ee546289SJens Wiklander 	fobj->num_pages = num_pages;
62ee546289SJens Wiklander 	refcount_set(&fobj->refc, 1);
63b83c0d5fSJens Wiklander 	TAILQ_INIT(&fobj->areas);
64ee546289SJens Wiklander }
65ee546289SJens Wiklander 
66ee546289SJens Wiklander static void fobj_uninit(struct fobj *fobj)
67ee546289SJens Wiklander {
68ee546289SJens Wiklander 	assert(!refcount_val(&fobj->refc));
69b83c0d5fSJens Wiklander 	assert(TAILQ_EMPTY(&fobj->areas));
70b83c0d5fSJens Wiklander 	tee_pager_invalidate_fobj(fobj);
71ee546289SJens Wiklander }
72ee546289SJens Wiklander 
73ee546289SJens Wiklander struct fobj *fobj_rw_paged_alloc(unsigned int num_pages)
74ee546289SJens Wiklander {
75ee546289SJens Wiklander 	tee_mm_entry_t *mm = NULL;
76ee546289SJens Wiklander 	struct fobj_rwp *rwp = NULL;
77ee546289SJens Wiklander 	size_t size = 0;
78ee546289SJens Wiklander 
79ee546289SJens Wiklander 	assert(num_pages);
80ee546289SJens Wiklander 
81ee546289SJens Wiklander 	rwp = calloc(1, sizeof(*rwp));
82ee546289SJens Wiklander 	if (!rwp)
83ee546289SJens Wiklander 		return NULL;
84ee546289SJens Wiklander 
85ee546289SJens Wiklander 	rwp->state = calloc(num_pages, sizeof(*rwp->state));
86ee546289SJens Wiklander 	if (!rwp->state)
87ee546289SJens Wiklander 		goto err;
88ee546289SJens Wiklander 
89ee546289SJens Wiklander 	if (MUL_OVERFLOW(num_pages, SMALL_PAGE_SIZE, &size))
90ee546289SJens Wiklander 		goto err;
91ee546289SJens Wiklander 	mm = tee_mm_alloc(&tee_mm_sec_ddr, size);
92ee546289SJens Wiklander 	if (!mm)
93ee546289SJens Wiklander 		goto err;
94ee546289SJens Wiklander 	rwp->store = phys_to_virt(tee_mm_get_smem(mm), MEM_AREA_TA_RAM);
95ee546289SJens Wiklander 	assert(rwp->store); /* to assist debugging if it would ever happen */
96ee546289SJens Wiklander 	if (!rwp->store)
97ee546289SJens Wiklander 		goto err;
98ee546289SJens Wiklander 
99ee546289SJens Wiklander 	fobj_init(&rwp->fobj, &ops_rw_paged, num_pages);
100ee546289SJens Wiklander 
101ee546289SJens Wiklander 	return &rwp->fobj;
102ee546289SJens Wiklander 
103ee546289SJens Wiklander err:
104ee546289SJens Wiklander 	tee_mm_free(mm);
105ee546289SJens Wiklander 	free(rwp->state);
106ee546289SJens Wiklander 	free(rwp);
107ee546289SJens Wiklander 
108ee546289SJens Wiklander 	return NULL;
109ee546289SJens Wiklander }
110ee546289SJens Wiklander 
111ee546289SJens Wiklander static struct fobj_rwp *to_rwp(struct fobj *fobj)
112ee546289SJens Wiklander {
113ee546289SJens Wiklander 	assert(fobj->ops == &ops_rw_paged);
114ee546289SJens Wiklander 
115ee546289SJens Wiklander 	return container_of(fobj, struct fobj_rwp, fobj);
116ee546289SJens Wiklander }
117ee546289SJens Wiklander 
118ee546289SJens Wiklander static void rwp_free(struct fobj *fobj)
119ee546289SJens Wiklander {
120ee546289SJens Wiklander 	struct fobj_rwp *rwp = to_rwp(fobj);
121ee546289SJens Wiklander 
122ee546289SJens Wiklander 	fobj_uninit(fobj);
123ee546289SJens Wiklander 	tee_mm_free(tee_mm_find(&tee_mm_sec_ddr, virt_to_phys(rwp->store)));
124ee546289SJens Wiklander 	free(rwp->state);
125ee546289SJens Wiklander 	free(rwp);
126ee546289SJens Wiklander }
127ee546289SJens Wiklander 
128ee546289SJens Wiklander static TEE_Result rwp_load_page(struct fobj *fobj, unsigned int page_idx,
129ee546289SJens Wiklander 				void *va)
130ee546289SJens Wiklander {
131ee546289SJens Wiklander 	struct fobj_rwp *rwp = to_rwp(fobj);
132ee546289SJens Wiklander 	struct rwp_state *state = rwp->state + page_idx;
133ee546289SJens Wiklander 	uint8_t *src = rwp->store + page_idx * SMALL_PAGE_SIZE;
134ee546289SJens Wiklander 	struct rwp_aes_gcm_iv iv = {
135ee546289SJens Wiklander 		.iv = { (vaddr_t)state, state->iv >> 32, state->iv }
136ee546289SJens Wiklander 	};
137ee546289SJens Wiklander 
138ee546289SJens Wiklander 	assert(refcount_val(&fobj->refc));
139ee546289SJens Wiklander 	assert(page_idx < fobj->num_pages);
140ee546289SJens Wiklander 
141ee546289SJens Wiklander 	if (!state->iv) {
142ee546289SJens Wiklander 		/*
143ee546289SJens Wiklander 		 * iv still zero which means that this is previously unused
144ee546289SJens Wiklander 		 * page.
145ee546289SJens Wiklander 		 */
146ee546289SJens Wiklander 		memset(va, 0, SMALL_PAGE_SIZE);
147ee546289SJens Wiklander 		return TEE_SUCCESS;
148ee546289SJens Wiklander 	}
149ee546289SJens Wiklander 
150ee546289SJens Wiklander 	return internal_aes_gcm_dec(&rwp_ae_key, &iv, sizeof(iv),
151ee546289SJens Wiklander 				    NULL, 0, src, SMALL_PAGE_SIZE, va,
152ee546289SJens Wiklander 				    state->tag, sizeof(state->tag));
153ee546289SJens Wiklander }
154*3639b55fSJerome Forissier DECLARE_KEEP_PAGER(rwp_load_page);
155ee546289SJens Wiklander 
156ee546289SJens Wiklander static TEE_Result rwp_save_page(struct fobj *fobj, unsigned int page_idx,
157ee546289SJens Wiklander 				const void *va)
158ee546289SJens Wiklander {
159ee546289SJens Wiklander 	struct fobj_rwp *rwp = to_rwp(fobj);
160ee546289SJens Wiklander 	struct rwp_state *state = rwp->state + page_idx;
161ee546289SJens Wiklander 	size_t tag_len = sizeof(state->tag);
162ee546289SJens Wiklander 	uint8_t *dst = rwp->store + page_idx * SMALL_PAGE_SIZE;
163ee546289SJens Wiklander 	struct rwp_aes_gcm_iv iv;
164ee546289SJens Wiklander 
165ee546289SJens Wiklander 	memset(&iv, 0, sizeof(iv));
166b83c0d5fSJens Wiklander 
167b83c0d5fSJens Wiklander 	if (!refcount_val(&fobj->refc)) {
168b83c0d5fSJens Wiklander 		/*
169b83c0d5fSJens Wiklander 		 * This fobj is being teared down, it just hasn't had the time
170b83c0d5fSJens Wiklander 		 * to call tee_pager_invalidate_fobj() yet.
171b83c0d5fSJens Wiklander 		 */
172b83c0d5fSJens Wiklander 		assert(TAILQ_EMPTY(&fobj->areas));
173b83c0d5fSJens Wiklander 		return TEE_SUCCESS;
174b83c0d5fSJens Wiklander 	}
175b83c0d5fSJens Wiklander 
176ee546289SJens Wiklander 	assert(page_idx < fobj->num_pages);
177ee546289SJens Wiklander 	assert(state->iv + 1 > state->iv);
178ee546289SJens Wiklander 
179ee546289SJens Wiklander 	state->iv++;
180ee546289SJens Wiklander 	/*
181ee546289SJens Wiklander 	 * IV is constructed as recommended in section "8.2.1 Deterministic
182ee546289SJens Wiklander 	 * Construction" of "Recommendation for Block Cipher Modes of
183ee546289SJens Wiklander 	 * Operation: Galois/Counter Mode (GCM) and GMAC",
184ee546289SJens Wiklander 	 * http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf
185ee546289SJens Wiklander 	 */
186ee546289SJens Wiklander 
187ee546289SJens Wiklander 	iv.iv[0] = (vaddr_t)state;
188ee546289SJens Wiklander 	iv.iv[1] = state->iv >> 32;
189ee546289SJens Wiklander 	iv.iv[2] = state->iv;
190ee546289SJens Wiklander 
191ee546289SJens Wiklander 	return internal_aes_gcm_enc(&rwp_ae_key, &iv, sizeof(iv),
192ee546289SJens Wiklander 				    NULL, 0, va, SMALL_PAGE_SIZE, dst,
193ee546289SJens Wiklander 				    state->tag, &tag_len);
194ee546289SJens Wiklander }
195*3639b55fSJerome Forissier DECLARE_KEEP_PAGER(rwp_save_page);
196ee546289SJens Wiklander 
197c6744caaSJens Wiklander static const struct fobj_ops ops_rw_paged __rodata_unpaged = {
198ee546289SJens Wiklander 	.free = rwp_free,
199ee546289SJens Wiklander 	.load_page = rwp_load_page,
200ee546289SJens Wiklander 	.save_page = rwp_save_page,
201ee546289SJens Wiklander };
202ee546289SJens Wiklander 
203ee546289SJens Wiklander struct fobj_rop {
204ee546289SJens Wiklander 	uint8_t *hashes;
205ee546289SJens Wiklander 	uint8_t *store;
206ee546289SJens Wiklander 	struct fobj fobj;
207ee546289SJens Wiklander };
208ee546289SJens Wiklander 
209c6744caaSJens Wiklander static const struct fobj_ops ops_ro_paged;
210c6744caaSJens Wiklander 
211c6744caaSJens Wiklander static void rop_init(struct fobj_rop *rop, const struct fobj_ops *ops,
212c6744caaSJens Wiklander 		     unsigned int num_pages, void *hashes, void *store)
213c6744caaSJens Wiklander {
214c6744caaSJens Wiklander 	rop->hashes = hashes;
215c6744caaSJens Wiklander 	rop->store = store;
216c6744caaSJens Wiklander 	fobj_init(&rop->fobj, ops, num_pages);
217c6744caaSJens Wiklander }
218ee546289SJens Wiklander 
219ee546289SJens Wiklander struct fobj *fobj_ro_paged_alloc(unsigned int num_pages, void *hashes,
220ee546289SJens Wiklander 				 void *store)
221ee546289SJens Wiklander {
222ee546289SJens Wiklander 	struct fobj_rop *rop = NULL;
223ee546289SJens Wiklander 
224ee546289SJens Wiklander 	assert(num_pages && hashes && store);
225ee546289SJens Wiklander 
226ee546289SJens Wiklander 	rop = calloc(1, sizeof(*rop));
227ee546289SJens Wiklander 	if (!rop)
228ee546289SJens Wiklander 		return NULL;
229ee546289SJens Wiklander 
230c6744caaSJens Wiklander 	rop_init(rop, &ops_ro_paged, num_pages, hashes, store);
231ee546289SJens Wiklander 
232ee546289SJens Wiklander 	return &rop->fobj;
233ee546289SJens Wiklander }
234ee546289SJens Wiklander 
235ee546289SJens Wiklander static struct fobj_rop *to_rop(struct fobj *fobj)
236ee546289SJens Wiklander {
237ee546289SJens Wiklander 	assert(fobj->ops == &ops_ro_paged);
238ee546289SJens Wiklander 
239ee546289SJens Wiklander 	return container_of(fobj, struct fobj_rop, fobj);
240ee546289SJens Wiklander }
241ee546289SJens Wiklander 
242c6744caaSJens Wiklander static void rop_uninit(struct fobj_rop *rop)
243c6744caaSJens Wiklander {
244c6744caaSJens Wiklander 	fobj_uninit(&rop->fobj);
245c6744caaSJens Wiklander 	tee_mm_free(tee_mm_find(&tee_mm_sec_ddr, virt_to_phys(rop->store)));
246c6744caaSJens Wiklander 	free(rop->hashes);
247c6744caaSJens Wiklander }
248c6744caaSJens Wiklander 
249ee546289SJens Wiklander static void rop_free(struct fobj *fobj)
250ee546289SJens Wiklander {
251ee546289SJens Wiklander 	struct fobj_rop *rop = to_rop(fobj);
252ee546289SJens Wiklander 
253c6744caaSJens Wiklander 	rop_uninit(rop);
254ee546289SJens Wiklander 	free(rop);
255ee546289SJens Wiklander }
256ee546289SJens Wiklander 
257c6744caaSJens Wiklander static TEE_Result rop_load_page_helper(struct fobj_rop *rop,
258c6744caaSJens Wiklander 				       unsigned int page_idx, void *va)
259c6744caaSJens Wiklander {
260c6744caaSJens Wiklander 	const uint8_t *hash = rop->hashes + page_idx * TEE_SHA256_HASH_SIZE;
261c6744caaSJens Wiklander 	const uint8_t *src = rop->store + page_idx * SMALL_PAGE_SIZE;
262c6744caaSJens Wiklander 
263c6744caaSJens Wiklander 	assert(refcount_val(&rop->fobj.refc));
264c6744caaSJens Wiklander 	assert(page_idx < rop->fobj.num_pages);
265c6744caaSJens Wiklander 	memcpy(va, src, SMALL_PAGE_SIZE);
266c6744caaSJens Wiklander 
267c6744caaSJens Wiklander 	return hash_sha256_check(hash, va, SMALL_PAGE_SIZE);
268c6744caaSJens Wiklander }
269c6744caaSJens Wiklander 
270ee546289SJens Wiklander static TEE_Result rop_load_page(struct fobj *fobj, unsigned int page_idx,
271ee546289SJens Wiklander 				void *va)
272ee546289SJens Wiklander {
273c6744caaSJens Wiklander 	return rop_load_page_helper(to_rop(fobj), page_idx, va);
274ee546289SJens Wiklander }
275*3639b55fSJerome Forissier DECLARE_KEEP_PAGER(rop_load_page);
276ee546289SJens Wiklander 
277ee546289SJens Wiklander static TEE_Result rop_save_page(struct fobj *fobj __unused,
278ee546289SJens Wiklander 				unsigned int page_idx __unused,
279ee546289SJens Wiklander 				const void *va __unused)
280ee546289SJens Wiklander {
281ee546289SJens Wiklander 	return TEE_ERROR_GENERIC;
282ee546289SJens Wiklander }
283*3639b55fSJerome Forissier DECLARE_KEEP_PAGER(rop_save_page);
284ee546289SJens Wiklander 
285c6744caaSJens Wiklander static const struct fobj_ops ops_ro_paged __rodata_unpaged = {
286ee546289SJens Wiklander 	.free = rop_free,
287ee546289SJens Wiklander 	.load_page = rop_load_page,
288ee546289SJens Wiklander 	.save_page = rop_save_page,
289ee546289SJens Wiklander };
290ee546289SJens Wiklander 
291c6744caaSJens Wiklander #ifdef CFG_CORE_ASLR
292c6744caaSJens Wiklander /*
293c6744caaSJens Wiklander  * When using relocated pages the relocation information must be applied
294c6744caaSJens Wiklander  * before the pages can be used. With read-only paging the content is only
295c6744caaSJens Wiklander  * integrity protected so relocation cannot be applied on pages in the less
296c6744caaSJens Wiklander  * secure "store" or the load_address selected by ASLR could be given away.
297c6744caaSJens Wiklander  * This means that each time a page has been loaded and verified it has to
298c6744caaSJens Wiklander  * have its relocation information applied before it can be used.
299c6744caaSJens Wiklander  *
300c6744caaSJens Wiklander  * Only the relative relocations are supported, this allows a rather compact
301c6744caaSJens Wiklander  * represenation of the needed relocation information in this struct.
302c6744caaSJens Wiklander  * r_offset is replaced with the offset into the page that need to be updated,
303c6744caaSJens Wiklander  * this number can never be larger than SMALL_PAGE_SIZE so a uint16_t can be
304c6744caaSJens Wiklander  * used to represent it.
305c6744caaSJens Wiklander  *
306c6744caaSJens Wiklander  * All relocations are converted and stored in @relocs. @page_reloc_idx is
307c6744caaSJens Wiklander  * an array of length @rop.fobj.num_pages with an entry for each page. If
308c6744caaSJens Wiklander  * @page_reloc_idx[page_idx] isn't UINT16_MAX it's an index into @relocs.
309c6744caaSJens Wiklander  */
310c6744caaSJens Wiklander struct fobj_ro_reloc_paged {
311c6744caaSJens Wiklander 	uint16_t *page_reloc_idx;
312c6744caaSJens Wiklander 	uint16_t *relocs;
313c6744caaSJens Wiklander 	unsigned int num_relocs;
314c6744caaSJens Wiklander 	struct fobj_rop rop;
315c6744caaSJens Wiklander };
316c6744caaSJens Wiklander 
317c6744caaSJens Wiklander static const struct fobj_ops ops_ro_reloc_paged;
318c6744caaSJens Wiklander 
319c6744caaSJens Wiklander static unsigned int get_num_rels(unsigned int num_pages,
320c6744caaSJens Wiklander 				 unsigned int reloc_offs,
321c6744caaSJens Wiklander 				 const uint32_t *reloc, unsigned int num_relocs)
322c6744caaSJens Wiklander {
323c6744caaSJens Wiklander 	const unsigned int align_mask __maybe_unused = sizeof(long) - 1;
324c6744caaSJens Wiklander 	unsigned int nrels = 0;
325c6744caaSJens Wiklander 	unsigned int n = 0;
326c6744caaSJens Wiklander 	vaddr_t offs = 0;
327c6744caaSJens Wiklander 
328c6744caaSJens Wiklander 	/*
329c6744caaSJens Wiklander 	 * Count the number of relocations which are needed for these
330c6744caaSJens Wiklander 	 * pages.  Also check that the data is well formed, only expected
331c6744caaSJens Wiklander 	 * relocations and sorted in order of address which it applies to.
332c6744caaSJens Wiklander 	 */
333c6744caaSJens Wiklander 	for (; n < num_relocs; n++) {
334c6744caaSJens Wiklander 		assert(ALIGNMENT_IS_OK(reloc[n], unsigned long));
335c6744caaSJens Wiklander 		assert(offs < reloc[n]);	/* check that it's sorted */
336c6744caaSJens Wiklander 		offs = reloc[n];
337c6744caaSJens Wiklander 		if (offs >= reloc_offs &&
338c6744caaSJens Wiklander 		    offs <= reloc_offs + num_pages * SMALL_PAGE_SIZE)
339c6744caaSJens Wiklander 			nrels++;
340c6744caaSJens Wiklander 	}
341c6744caaSJens Wiklander 
342c6744caaSJens Wiklander 	return nrels;
343c6744caaSJens Wiklander }
344c6744caaSJens Wiklander 
345c6744caaSJens Wiklander static void init_rels(struct fobj_ro_reloc_paged *rrp, unsigned int reloc_offs,
346c6744caaSJens Wiklander 		      const uint32_t *reloc, unsigned int num_relocs)
347c6744caaSJens Wiklander {
348c6744caaSJens Wiklander 	unsigned int npg = rrp->rop.fobj.num_pages;
349c6744caaSJens Wiklander 	unsigned int pg_idx = 0;
350c6744caaSJens Wiklander 	unsigned int reln = 0;
351c6744caaSJens Wiklander 	unsigned int n = 0;
352c6744caaSJens Wiklander 	uint32_t r = 0;
353c6744caaSJens Wiklander 
354c6744caaSJens Wiklander 	for (n = 0; n < npg; n++)
355c6744caaSJens Wiklander 		rrp->page_reloc_idx[n] = UINT16_MAX;
356c6744caaSJens Wiklander 
357c6744caaSJens Wiklander 	for (n = 0; n < num_relocs ; n++) {
358c6744caaSJens Wiklander 		if (reloc[n] < reloc_offs)
359c6744caaSJens Wiklander 			continue;
360c6744caaSJens Wiklander 
361c6744caaSJens Wiklander 		/* r is the offset from beginning of this fobj */
362c6744caaSJens Wiklander 		r = reloc[n] - reloc_offs;
363c6744caaSJens Wiklander 
364c6744caaSJens Wiklander 		pg_idx = r / SMALL_PAGE_SIZE;
365c6744caaSJens Wiklander 		if (pg_idx >= npg)
366c6744caaSJens Wiklander 			break;
367c6744caaSJens Wiklander 
368c6744caaSJens Wiklander 		if (rrp->page_reloc_idx[pg_idx] == UINT16_MAX)
369c6744caaSJens Wiklander 			rrp->page_reloc_idx[pg_idx] = reln;
370c6744caaSJens Wiklander 		rrp->relocs[reln] = r - pg_idx * SMALL_PAGE_SIZE;
371c6744caaSJens Wiklander 		reln++;
372c6744caaSJens Wiklander 	}
373c6744caaSJens Wiklander 
374c6744caaSJens Wiklander 	assert(reln == rrp->num_relocs);
375c6744caaSJens Wiklander }
376c6744caaSJens Wiklander 
377c6744caaSJens Wiklander struct fobj *fobj_ro_reloc_paged_alloc(unsigned int num_pages, void *hashes,
378c6744caaSJens Wiklander 				       unsigned int reloc_offs,
379c6744caaSJens Wiklander 				       const void *reloc,
380c6744caaSJens Wiklander 				       unsigned int reloc_len, void *store)
381c6744caaSJens Wiklander {
382c6744caaSJens Wiklander 	struct fobj_ro_reloc_paged *rrp = NULL;
383c6744caaSJens Wiklander 	const unsigned int num_relocs = reloc_len / sizeof(uint32_t);
384c6744caaSJens Wiklander 	unsigned int nrels = 0;
385c6744caaSJens Wiklander 
386c6744caaSJens Wiklander 	assert(ALIGNMENT_IS_OK(reloc, uint32_t));
387c6744caaSJens Wiklander 	assert(ALIGNMENT_IS_OK(reloc_len, uint32_t));
388c6744caaSJens Wiklander 	assert(num_pages && hashes && store);
389c6744caaSJens Wiklander 	if (!reloc_len) {
390c6744caaSJens Wiklander 		assert(!reloc);
391c6744caaSJens Wiklander 		return fobj_ro_paged_alloc(num_pages, hashes, store);
392c6744caaSJens Wiklander 	}
393c6744caaSJens Wiklander 	assert(reloc);
394c6744caaSJens Wiklander 
395c6744caaSJens Wiklander 	nrels = get_num_rels(num_pages, reloc_offs, reloc, num_relocs);
396c6744caaSJens Wiklander 	if (!nrels)
397c6744caaSJens Wiklander 		return fobj_ro_paged_alloc(num_pages, hashes, store);
398c6744caaSJens Wiklander 
399c6744caaSJens Wiklander 	rrp = calloc(1, sizeof(*rrp) + num_pages * sizeof(uint16_t) +
400c6744caaSJens Wiklander 			nrels * sizeof(uint16_t));
401c6744caaSJens Wiklander 	if (!rrp)
402c6744caaSJens Wiklander 		return NULL;
403c6744caaSJens Wiklander 	rop_init(&rrp->rop, &ops_ro_reloc_paged, num_pages, hashes, store);
404c6744caaSJens Wiklander 	rrp->page_reloc_idx = (uint16_t *)(rrp + 1);
405c6744caaSJens Wiklander 	rrp->relocs = rrp->page_reloc_idx + num_pages;
406c6744caaSJens Wiklander 	rrp->num_relocs = nrels;
407c6744caaSJens Wiklander 	init_rels(rrp, reloc_offs, reloc, num_relocs);
408c6744caaSJens Wiklander 
409c6744caaSJens Wiklander 	return &rrp->rop.fobj;
410c6744caaSJens Wiklander }
411c6744caaSJens Wiklander 
412c6744caaSJens Wiklander static struct fobj_ro_reloc_paged *to_rrp(struct fobj *fobj)
413c6744caaSJens Wiklander {
414c6744caaSJens Wiklander 	assert(fobj->ops == &ops_ro_reloc_paged);
415c6744caaSJens Wiklander 
416c6744caaSJens Wiklander 	return container_of(fobj, struct fobj_ro_reloc_paged, rop.fobj);
417c6744caaSJens Wiklander }
418c6744caaSJens Wiklander 
419c6744caaSJens Wiklander static void rrp_free(struct fobj *fobj)
420c6744caaSJens Wiklander {
421c6744caaSJens Wiklander 	struct fobj_ro_reloc_paged *rrp = to_rrp(fobj);
422c6744caaSJens Wiklander 
423c6744caaSJens Wiklander 	rop_uninit(&rrp->rop);
424c6744caaSJens Wiklander 	free(rrp);
425c6744caaSJens Wiklander }
426c6744caaSJens Wiklander 
427c6744caaSJens Wiklander static TEE_Result rrp_load_page(struct fobj *fobj, unsigned int page_idx,
428c6744caaSJens Wiklander 				void *va)
429c6744caaSJens Wiklander {
430c6744caaSJens Wiklander 	struct fobj_ro_reloc_paged *rrp = to_rrp(fobj);
431c6744caaSJens Wiklander 	unsigned int end_rel = rrp->num_relocs;
432c6744caaSJens Wiklander 	TEE_Result res = TEE_SUCCESS;
433c6744caaSJens Wiklander 	unsigned long *where = NULL;
434c6744caaSJens Wiklander 	unsigned int n = 0;
435c6744caaSJens Wiklander 
436c6744caaSJens Wiklander 	res = rop_load_page_helper(&rrp->rop, page_idx, va);
437c6744caaSJens Wiklander 	if (res)
438c6744caaSJens Wiklander 		return res;
439c6744caaSJens Wiklander 
440c6744caaSJens Wiklander 	/* Find the reloc index of the next page to tell when we're done */
441c6744caaSJens Wiklander 	for (n = page_idx + 1; n < fobj->num_pages; n++) {
442c6744caaSJens Wiklander 		if (rrp->page_reloc_idx[n] != UINT16_MAX) {
443c6744caaSJens Wiklander 			end_rel = rrp->page_reloc_idx[n];
444c6744caaSJens Wiklander 			break;
445c6744caaSJens Wiklander 		}
446c6744caaSJens Wiklander 	}
447c6744caaSJens Wiklander 
448c6744caaSJens Wiklander 	for (n = rrp->page_reloc_idx[page_idx]; n < end_rel; n++) {
449c6744caaSJens Wiklander 		where = (void *)((vaddr_t)va + rrp->relocs[n]);
450c6744caaSJens Wiklander 		*where += boot_mmu_config.load_offset;
451c6744caaSJens Wiklander 	}
452c6744caaSJens Wiklander 
453c6744caaSJens Wiklander 	return TEE_SUCCESS;
454c6744caaSJens Wiklander }
455*3639b55fSJerome Forissier DECLARE_KEEP_PAGER(rrp_load_page);
456c6744caaSJens Wiklander 
457c6744caaSJens Wiklander static const struct fobj_ops ops_ro_reloc_paged __rodata_unpaged = {
458c6744caaSJens Wiklander 	.free = rrp_free,
459c6744caaSJens Wiklander 	.load_page = rrp_load_page,
460c6744caaSJens Wiklander 	.save_page = rop_save_page, /* Direct reuse */
461c6744caaSJens Wiklander };
462c6744caaSJens Wiklander #endif /*CFG_CORE_ASLR*/
463c6744caaSJens Wiklander 
464c6744caaSJens Wiklander static const struct fobj_ops ops_locked_paged;
465ee546289SJens Wiklander 
466ee546289SJens Wiklander struct fobj *fobj_locked_paged_alloc(unsigned int num_pages)
467ee546289SJens Wiklander {
468ee546289SJens Wiklander 	struct fobj *f = NULL;
469ee546289SJens Wiklander 
470ee546289SJens Wiklander 	assert(num_pages);
471ee546289SJens Wiklander 
472ee546289SJens Wiklander 	f = calloc(1, sizeof(*f));
473ee546289SJens Wiklander 	if (!f)
474ee546289SJens Wiklander 		return NULL;
475ee546289SJens Wiklander 
476ee546289SJens Wiklander 	fobj_init(f, &ops_locked_paged, num_pages);
477ee546289SJens Wiklander 
478ee546289SJens Wiklander 	return f;
479ee546289SJens Wiklander }
480ee546289SJens Wiklander 
481ee546289SJens Wiklander static void lop_free(struct fobj *fobj)
482ee546289SJens Wiklander {
483ee546289SJens Wiklander 	assert(fobj->ops == &ops_locked_paged);
484ee546289SJens Wiklander 	fobj_uninit(fobj);
485ee546289SJens Wiklander 	free(fobj);
486ee546289SJens Wiklander }
487ee546289SJens Wiklander 
488ee546289SJens Wiklander static TEE_Result lop_load_page(struct fobj *fobj __maybe_unused,
489ee546289SJens Wiklander 				unsigned int page_idx __maybe_unused,
490ee546289SJens Wiklander 				void *va)
491ee546289SJens Wiklander {
492ee546289SJens Wiklander 	assert(fobj->ops == &ops_locked_paged);
493ee546289SJens Wiklander 	assert(refcount_val(&fobj->refc));
494ee546289SJens Wiklander 	assert(page_idx < fobj->num_pages);
495ee546289SJens Wiklander 
496ee546289SJens Wiklander 	memset(va, 0, SMALL_PAGE_SIZE);
497ee546289SJens Wiklander 
498ee546289SJens Wiklander 	return TEE_SUCCESS;
499ee546289SJens Wiklander }
500*3639b55fSJerome Forissier DECLARE_KEEP_PAGER(lop_load_page);
501ee546289SJens Wiklander 
502ee546289SJens Wiklander static TEE_Result lop_save_page(struct fobj *fobj __unused,
503ee546289SJens Wiklander 				unsigned int page_idx __unused,
504ee546289SJens Wiklander 				const void *va __unused)
505ee546289SJens Wiklander {
506ee546289SJens Wiklander 	return TEE_ERROR_GENERIC;
507ee546289SJens Wiklander }
508*3639b55fSJerome Forissier DECLARE_KEEP_PAGER(lop_save_page);
509ee546289SJens Wiklander 
510c6744caaSJens Wiklander static const struct fobj_ops ops_locked_paged __rodata_unpaged = {
511ee546289SJens Wiklander 	.free = lop_free,
512ee546289SJens Wiklander 	.load_page = lop_load_page,
513ee546289SJens Wiklander 	.save_page = lop_save_page,
514ee546289SJens Wiklander };
515ee546289SJens Wiklander #endif /*CFG_WITH_PAGER*/
516fbcaa411SJens Wiklander 
517fbcaa411SJens Wiklander #ifndef CFG_PAGED_USER_TA
518fbcaa411SJens Wiklander 
519fbcaa411SJens Wiklander struct fobj_sec_mem {
520fbcaa411SJens Wiklander 	tee_mm_entry_t *mm;
521fbcaa411SJens Wiklander 	struct fobj fobj;
522fbcaa411SJens Wiklander };
523fbcaa411SJens Wiklander 
524fbcaa411SJens Wiklander static struct fobj_ops ops_sec_mem;
525fbcaa411SJens Wiklander 
526fbcaa411SJens Wiklander struct fobj *fobj_sec_mem_alloc(unsigned int num_pages)
527fbcaa411SJens Wiklander {
528fbcaa411SJens Wiklander 	struct fobj_sec_mem *f = calloc(1, sizeof(*f));
529fbcaa411SJens Wiklander 	size_t size = 0;
530fbcaa411SJens Wiklander 	void *va = NULL;
531fbcaa411SJens Wiklander 
532fbcaa411SJens Wiklander 	if (!f)
533fbcaa411SJens Wiklander 		return NULL;
534fbcaa411SJens Wiklander 
535fbcaa411SJens Wiklander 	if (MUL_OVERFLOW(num_pages, SMALL_PAGE_SIZE, &size))
536fbcaa411SJens Wiklander 		goto err;
537fbcaa411SJens Wiklander 
538fbcaa411SJens Wiklander 	f->mm = tee_mm_alloc(&tee_mm_sec_ddr, size);
539fbcaa411SJens Wiklander 	if (!f->mm)
540fbcaa411SJens Wiklander 		goto err;
541fbcaa411SJens Wiklander 
542fbcaa411SJens Wiklander 	va = phys_to_virt(tee_mm_get_smem(f->mm), MEM_AREA_TA_RAM);
543fbcaa411SJens Wiklander 	if (!va)
544fbcaa411SJens Wiklander 		goto err;
545fbcaa411SJens Wiklander 
546fbcaa411SJens Wiklander 	memset(va, 0, size);
547fbcaa411SJens Wiklander 	f->fobj.ops = &ops_sec_mem;
548fbcaa411SJens Wiklander 	f->fobj.num_pages = num_pages;
549fbcaa411SJens Wiklander 	refcount_set(&f->fobj.refc, 1);
550fbcaa411SJens Wiklander 
551fbcaa411SJens Wiklander 	return &f->fobj;
552fbcaa411SJens Wiklander err:
553fbcaa411SJens Wiklander 	tee_mm_free(f->mm);
554fbcaa411SJens Wiklander 	free(f);
555fbcaa411SJens Wiklander 
556fbcaa411SJens Wiklander 	return NULL;
557fbcaa411SJens Wiklander }
558fbcaa411SJens Wiklander 
559fbcaa411SJens Wiklander static struct fobj_sec_mem *to_sec_mem(struct fobj *fobj)
560fbcaa411SJens Wiklander {
561fbcaa411SJens Wiklander 	assert(fobj->ops == &ops_sec_mem);
562fbcaa411SJens Wiklander 
563fbcaa411SJens Wiklander 	return container_of(fobj, struct fobj_sec_mem, fobj);
564fbcaa411SJens Wiklander }
565fbcaa411SJens Wiklander 
566fbcaa411SJens Wiklander static void sec_mem_free(struct fobj *fobj)
567fbcaa411SJens Wiklander {
568fbcaa411SJens Wiklander 	struct fobj_sec_mem *f = to_sec_mem(fobj);
569fbcaa411SJens Wiklander 
570fbcaa411SJens Wiklander 	assert(!refcount_val(&fobj->refc));
571fbcaa411SJens Wiklander 	tee_mm_free(f->mm);
572fbcaa411SJens Wiklander 	free(f);
573fbcaa411SJens Wiklander }
574fbcaa411SJens Wiklander 
575fbcaa411SJens Wiklander static paddr_t sec_mem_get_pa(struct fobj *fobj, unsigned int page_idx)
576fbcaa411SJens Wiklander {
577fbcaa411SJens Wiklander 	struct fobj_sec_mem *f = to_sec_mem(fobj);
578fbcaa411SJens Wiklander 
579fbcaa411SJens Wiklander 	assert(refcount_val(&fobj->refc));
580fbcaa411SJens Wiklander 	assert(page_idx < fobj->num_pages);
581fbcaa411SJens Wiklander 
582fbcaa411SJens Wiklander 	return tee_mm_get_smem(f->mm) + page_idx * SMALL_PAGE_SIZE;
583fbcaa411SJens Wiklander }
584fbcaa411SJens Wiklander 
585fbcaa411SJens Wiklander static struct fobj_ops ops_sec_mem __rodata_unpaged = {
586fbcaa411SJens Wiklander 	.free = sec_mem_free,
587fbcaa411SJens Wiklander 	.get_pa = sec_mem_get_pa,
588fbcaa411SJens Wiklander };
589fbcaa411SJens Wiklander 
590fbcaa411SJens Wiklander #endif /*PAGED_USER_TA*/
591