xref: /optee_os/core/mm/fobj.c (revision c79fb6d48c8f58eb3b9a6246a9931c5b07e47177)
1ee546289SJens Wiklander // SPDX-License-Identifier: BSD-2-Clause
2ee546289SJens Wiklander /*
36105aa86SJens Wiklander  * Copyright (c) 2019-2022, Linaro Limited
4ee546289SJens Wiklander  */
5ee546289SJens Wiklander 
6b757e307SJens Wiklander #include <config.h>
7ee546289SJens Wiklander #include <crypto/crypto.h>
8ee546289SJens Wiklander #include <crypto/internal_aes-gcm.h>
9cfde90a6SJens Wiklander #include <initcall.h>
1065401337SJens Wiklander #include <kernel/boot.h>
11ee546289SJens Wiklander #include <kernel/panic.h>
12a0e8ffe9SJens Wiklander #include <memtag.h>
13ee546289SJens Wiklander #include <mm/core_memprot.h>
14ee546289SJens Wiklander #include <mm/core_mmu.h>
15ee546289SJens Wiklander #include <mm/fobj.h>
16ee546289SJens Wiklander #include <mm/tee_mm.h>
17ee546289SJens Wiklander #include <stdlib.h>
18ee546289SJens Wiklander #include <string.h>
19ee546289SJens Wiklander #include <tee_api_types.h>
20ee546289SJens Wiklander #include <types_ext.h>
21ee546289SJens Wiklander #include <util.h>
22ee546289SJens Wiklander 
23ee546289SJens Wiklander #ifdef CFG_WITH_PAGER
24ee546289SJens Wiklander 
25ee546289SJens Wiklander #define RWP_AE_KEY_BITS		256
26ee546289SJens Wiklander 
27ee546289SJens Wiklander struct rwp_aes_gcm_iv {
28ee546289SJens Wiklander 	uint32_t iv[3];
29ee546289SJens Wiklander };
30ee546289SJens Wiklander 
31ee546289SJens Wiklander #define RWP_AES_GCM_TAG_LEN	16
32ee546289SJens Wiklander 
33ee546289SJens Wiklander struct rwp_state {
34ee546289SJens Wiklander 	uint64_t iv;
35ee546289SJens Wiklander 	uint8_t tag[RWP_AES_GCM_TAG_LEN];
36ee546289SJens Wiklander };
37ee546289SJens Wiklander 
38aad1cf6bSJens Wiklander /*
39aad1cf6bSJens Wiklander  * Note that this struct is padded to a size which is a power of 2, this
40aad1cf6bSJens Wiklander  * guarantees that this state will not span two pages. This avoids a corner
41aad1cf6bSJens Wiklander  * case in the pager when making the state available.
42aad1cf6bSJens Wiklander  */
43aad1cf6bSJens Wiklander struct rwp_state_padded {
44aad1cf6bSJens Wiklander 	struct rwp_state state;
45aad1cf6bSJens Wiklander 	uint64_t pad;
46aad1cf6bSJens Wiklander };
47aad1cf6bSJens Wiklander 
48aad1cf6bSJens Wiklander struct fobj_rwp_unpaged_iv {
49ee546289SJens Wiklander 	uint8_t *store;
50ee546289SJens Wiklander 	struct rwp_state *state;
51ee546289SJens Wiklander 	struct fobj fobj;
52ee546289SJens Wiklander };
53ee546289SJens Wiklander 
54aad1cf6bSJens Wiklander struct fobj_rwp_paged_iv {
55aad1cf6bSJens Wiklander 	size_t idx;
56aad1cf6bSJens Wiklander 	struct fobj fobj;
57aad1cf6bSJens Wiklander };
58aad1cf6bSJens Wiklander 
5900361c18SJens Wiklander const struct fobj_ops ops_rwp_paged_iv;
6000361c18SJens Wiklander const struct fobj_ops ops_rwp_unpaged_iv;
61ee546289SJens Wiklander 
62ee546289SJens Wiklander static struct internal_aes_gcm_key rwp_ae_key;
63ee546289SJens Wiklander 
64aad1cf6bSJens Wiklander static struct rwp_state_padded *rwp_state_base;
65aad1cf6bSJens Wiklander static uint8_t *rwp_store_base;
66ee546289SJens Wiklander 
67ee546289SJens Wiklander static void fobj_init(struct fobj *fobj, const struct fobj_ops *ops,
68ee546289SJens Wiklander 		      unsigned int num_pages)
69ee546289SJens Wiklander {
70ee546289SJens Wiklander 	fobj->ops = ops;
71ee546289SJens Wiklander 	fobj->num_pages = num_pages;
72ee546289SJens Wiklander 	refcount_set(&fobj->refc, 1);
73d5ad7ccfSJens Wiklander 	TAILQ_INIT(&fobj->regions);
74ee546289SJens Wiklander }
75ee546289SJens Wiklander 
76ee546289SJens Wiklander static void fobj_uninit(struct fobj *fobj)
77ee546289SJens Wiklander {
78ee546289SJens Wiklander 	assert(!refcount_val(&fobj->refc));
79d5ad7ccfSJens Wiklander 	assert(TAILQ_EMPTY(&fobj->regions));
80b83c0d5fSJens Wiklander 	tee_pager_invalidate_fobj(fobj);
81ee546289SJens Wiklander }
82ee546289SJens Wiklander 
83aad1cf6bSJens Wiklander static TEE_Result rwp_load_page(void *va, struct rwp_state *state,
84aad1cf6bSJens Wiklander 				const uint8_t *src)
85ee546289SJens Wiklander {
86ee546289SJens Wiklander 	struct rwp_aes_gcm_iv iv = {
87ee546289SJens Wiklander 		.iv = { (vaddr_t)state, state->iv >> 32, state->iv }
88ee546289SJens Wiklander 	};
89ee546289SJens Wiklander 
90ee546289SJens Wiklander 	if (!state->iv) {
91ee546289SJens Wiklander 		/*
92aad1cf6bSJens Wiklander 		 * IV still zero which means that this is previously unused
93ee546289SJens Wiklander 		 * page.
94ee546289SJens Wiklander 		 */
95ee546289SJens Wiklander 		memset(va, 0, SMALL_PAGE_SIZE);
96ee546289SJens Wiklander 		return TEE_SUCCESS;
97ee546289SJens Wiklander 	}
98ee546289SJens Wiklander 
99ee546289SJens Wiklander 	return internal_aes_gcm_dec(&rwp_ae_key, &iv, sizeof(iv),
100ee546289SJens Wiklander 				    NULL, 0, src, SMALL_PAGE_SIZE, va,
101ee546289SJens Wiklander 				    state->tag, sizeof(state->tag));
102ee546289SJens Wiklander }
103ee546289SJens Wiklander 
104aad1cf6bSJens Wiklander static TEE_Result rwp_save_page(const void *va, struct rwp_state *state,
105aad1cf6bSJens Wiklander 				uint8_t *dst)
106ee546289SJens Wiklander {
107ee546289SJens Wiklander 	size_t tag_len = sizeof(state->tag);
108aad1cf6bSJens Wiklander 	struct rwp_aes_gcm_iv iv = { };
109ee546289SJens Wiklander 
110aad1cf6bSJens Wiklander 	assert(state->iv + 1 > state->iv);
111aad1cf6bSJens Wiklander 
112aad1cf6bSJens Wiklander 	state->iv++;
113aad1cf6bSJens Wiklander 
114aad1cf6bSJens Wiklander 	/*
115aad1cf6bSJens Wiklander 	 * IV is constructed as recommended in section "8.2.1 Deterministic
116aad1cf6bSJens Wiklander 	 * Construction" of "Recommendation for Block Cipher Modes of
117aad1cf6bSJens Wiklander 	 * Operation: Galois/Counter Mode (GCM) and GMAC",
118aad1cf6bSJens Wiklander 	 * http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf
119aad1cf6bSJens Wiklander 	 */
120aad1cf6bSJens Wiklander 	iv.iv[0] = (vaddr_t)state;
121aad1cf6bSJens Wiklander 	iv.iv[1] = state->iv >> 32;
122aad1cf6bSJens Wiklander 	iv.iv[2] = state->iv;
123aad1cf6bSJens Wiklander 
124aad1cf6bSJens Wiklander 	return internal_aes_gcm_enc(&rwp_ae_key, &iv, sizeof(iv),
125aad1cf6bSJens Wiklander 				    NULL, 0, va, SMALL_PAGE_SIZE, dst,
126aad1cf6bSJens Wiklander 				    state->tag, &tag_len);
127aad1cf6bSJens Wiklander }
128aad1cf6bSJens Wiklander 
129aad1cf6bSJens Wiklander static struct rwp_state_padded *idx_to_state_padded(size_t idx)
130aad1cf6bSJens Wiklander {
131aad1cf6bSJens Wiklander 	assert(rwp_state_base);
132aad1cf6bSJens Wiklander 	return rwp_state_base + idx;
133aad1cf6bSJens Wiklander }
134aad1cf6bSJens Wiklander 
135aad1cf6bSJens Wiklander static uint8_t *idx_to_store(size_t idx)
136aad1cf6bSJens Wiklander {
137aad1cf6bSJens Wiklander 	assert(rwp_store_base);
138aad1cf6bSJens Wiklander 	return rwp_store_base + idx * SMALL_PAGE_SIZE;
139aad1cf6bSJens Wiklander }
140aad1cf6bSJens Wiklander 
141b757e307SJens Wiklander static struct fobj *rwp_paged_iv_alloc(unsigned int num_pages)
142aad1cf6bSJens Wiklander {
143aad1cf6bSJens Wiklander 	struct fobj_rwp_paged_iv *rwp = NULL;
144aad1cf6bSJens Wiklander 	tee_mm_entry_t *mm = NULL;
145aad1cf6bSJens Wiklander 	size_t size = 0;
146aad1cf6bSJens Wiklander 
147aad1cf6bSJens Wiklander 	COMPILE_TIME_ASSERT(IS_POWER_OF_TWO(sizeof(struct rwp_state_padded)));
148aad1cf6bSJens Wiklander 
149aad1cf6bSJens Wiklander 	rwp = calloc(1, sizeof(*rwp));
150aad1cf6bSJens Wiklander 	if (!rwp)
151aad1cf6bSJens Wiklander 		return NULL;
152aad1cf6bSJens Wiklander 
153aad1cf6bSJens Wiklander 	if (MUL_OVERFLOW(num_pages, SMALL_PAGE_SIZE, &size))
154aad1cf6bSJens Wiklander 		goto err;
155aad1cf6bSJens Wiklander 	mm = tee_mm_alloc(&tee_mm_sec_ddr, size);
156aad1cf6bSJens Wiklander 	if (!mm)
157aad1cf6bSJens Wiklander 		goto err;
158aad1cf6bSJens Wiklander 	rwp->idx = (tee_mm_get_smem(mm) - tee_mm_sec_ddr.lo) / SMALL_PAGE_SIZE;
159aad1cf6bSJens Wiklander 
160aad1cf6bSJens Wiklander 	memset(idx_to_state_padded(rwp->idx), 0,
161aad1cf6bSJens Wiklander 	       num_pages * sizeof(struct rwp_state_padded));
162aad1cf6bSJens Wiklander 
163aad1cf6bSJens Wiklander 	fobj_init(&rwp->fobj, &ops_rwp_paged_iv, num_pages);
164aad1cf6bSJens Wiklander 
165aad1cf6bSJens Wiklander 	return &rwp->fobj;
166aad1cf6bSJens Wiklander err:
167aad1cf6bSJens Wiklander 	tee_mm_free(mm);
168aad1cf6bSJens Wiklander 	free(rwp);
169aad1cf6bSJens Wiklander 
170aad1cf6bSJens Wiklander 	return NULL;
171aad1cf6bSJens Wiklander }
172aad1cf6bSJens Wiklander 
173aad1cf6bSJens Wiklander static struct fobj_rwp_paged_iv *to_rwp_paged_iv(struct fobj *fobj)
174aad1cf6bSJens Wiklander {
175aad1cf6bSJens Wiklander 	assert(fobj->ops == &ops_rwp_paged_iv);
176aad1cf6bSJens Wiklander 
177aad1cf6bSJens Wiklander 	return container_of(fobj, struct fobj_rwp_paged_iv, fobj);
178aad1cf6bSJens Wiklander }
179aad1cf6bSJens Wiklander 
180aad1cf6bSJens Wiklander static TEE_Result rwp_paged_iv_load_page(struct fobj *fobj,
181aad1cf6bSJens Wiklander 					 unsigned int page_idx, void *va)
182aad1cf6bSJens Wiklander {
183aad1cf6bSJens Wiklander 	struct fobj_rwp_paged_iv *rwp = to_rwp_paged_iv(fobj);
184aad1cf6bSJens Wiklander 	uint8_t *src = idx_to_store(rwp->idx) + page_idx * SMALL_PAGE_SIZE;
185aad1cf6bSJens Wiklander 	struct rwp_state_padded *st = idx_to_state_padded(rwp->idx + page_idx);
186aad1cf6bSJens Wiklander 
187aad1cf6bSJens Wiklander 	assert(refcount_val(&fobj->refc));
188aad1cf6bSJens Wiklander 	assert(page_idx < fobj->num_pages);
189aad1cf6bSJens Wiklander 
190aad1cf6bSJens Wiklander 	return rwp_load_page(va, &st->state, src);
191aad1cf6bSJens Wiklander }
192aad1cf6bSJens Wiklander DECLARE_KEEP_PAGER(rwp_paged_iv_load_page);
193aad1cf6bSJens Wiklander 
194aad1cf6bSJens Wiklander static TEE_Result rwp_paged_iv_save_page(struct fobj *fobj,
195aad1cf6bSJens Wiklander 					 unsigned int page_idx, const void *va)
196aad1cf6bSJens Wiklander {
197aad1cf6bSJens Wiklander 	struct fobj_rwp_paged_iv *rwp = to_rwp_paged_iv(fobj);
198aad1cf6bSJens Wiklander 	uint8_t *dst = idx_to_store(rwp->idx) + page_idx * SMALL_PAGE_SIZE;
199aad1cf6bSJens Wiklander 	struct rwp_state_padded *st = idx_to_state_padded(rwp->idx + page_idx);
200aad1cf6bSJens Wiklander 
201aad1cf6bSJens Wiklander 	assert(page_idx < fobj->num_pages);
202b83c0d5fSJens Wiklander 
203b83c0d5fSJens Wiklander 	if (!refcount_val(&fobj->refc)) {
204b83c0d5fSJens Wiklander 		/*
205b83c0d5fSJens Wiklander 		 * This fobj is being teared down, it just hasn't had the time
206b83c0d5fSJens Wiklander 		 * to call tee_pager_invalidate_fobj() yet.
207b83c0d5fSJens Wiklander 		 */
208d5ad7ccfSJens Wiklander 		assert(TAILQ_EMPTY(&fobj->regions));
209b83c0d5fSJens Wiklander 		return TEE_SUCCESS;
210b83c0d5fSJens Wiklander 	}
211b83c0d5fSJens Wiklander 
212aad1cf6bSJens Wiklander 	return rwp_save_page(va, &st->state, dst);
213aad1cf6bSJens Wiklander }
214aad1cf6bSJens Wiklander DECLARE_KEEP_PAGER(rwp_paged_iv_save_page);
215ee546289SJens Wiklander 
216aad1cf6bSJens Wiklander static void rwp_paged_iv_free(struct fobj *fobj)
217aad1cf6bSJens Wiklander {
218aad1cf6bSJens Wiklander 	struct fobj_rwp_paged_iv *rwp = to_rwp_paged_iv(fobj);
219aad1cf6bSJens Wiklander 	paddr_t pa = rwp->idx * SMALL_PAGE_SIZE + tee_mm_sec_ddr.lo;
220aad1cf6bSJens Wiklander 	tee_mm_entry_t *mm = tee_mm_find(&tee_mm_sec_ddr, pa);
221aad1cf6bSJens Wiklander 
222aad1cf6bSJens Wiklander 	assert(mm);
223aad1cf6bSJens Wiklander 
224aad1cf6bSJens Wiklander 	fobj_uninit(fobj);
225aad1cf6bSJens Wiklander 	tee_mm_free(mm);
226aad1cf6bSJens Wiklander 	free(rwp);
227aad1cf6bSJens Wiklander }
228aad1cf6bSJens Wiklander 
229aad1cf6bSJens Wiklander static vaddr_t rwp_paged_iv_get_iv_vaddr(struct fobj *fobj,
230aad1cf6bSJens Wiklander 					 unsigned int page_idx)
231aad1cf6bSJens Wiklander {
232aad1cf6bSJens Wiklander 	struct fobj_rwp_paged_iv *rwp = to_rwp_paged_iv(fobj);
233aad1cf6bSJens Wiklander 	struct rwp_state_padded *st = idx_to_state_padded(rwp->idx + page_idx);
234aad1cf6bSJens Wiklander 
235aad1cf6bSJens Wiklander 	assert(page_idx < fobj->num_pages);
236aad1cf6bSJens Wiklander 	return (vaddr_t)&st->state & ~SMALL_PAGE_MASK;
237aad1cf6bSJens Wiklander }
238aad1cf6bSJens Wiklander DECLARE_KEEP_PAGER(rwp_paged_iv_get_iv_vaddr);
239aad1cf6bSJens Wiklander 
24000361c18SJens Wiklander /*
24100361c18SJens Wiklander  * Note: this variable is weak just to ease breaking its dependency chain
24200361c18SJens Wiklander  * when added to the unpaged area.
24300361c18SJens Wiklander  */
24400361c18SJens Wiklander const struct fobj_ops ops_rwp_paged_iv
24539e8c200SJerome Forissier __weak __relrodata_unpaged("ops_rwp_paged_iv") = {
246aad1cf6bSJens Wiklander 	.free = rwp_paged_iv_free,
247aad1cf6bSJens Wiklander 	.load_page = rwp_paged_iv_load_page,
248aad1cf6bSJens Wiklander 	.save_page = rwp_paged_iv_save_page,
249aad1cf6bSJens Wiklander 	.get_iv_vaddr = rwp_paged_iv_get_iv_vaddr,
250aad1cf6bSJens Wiklander };
251aad1cf6bSJens Wiklander 
252b757e307SJens Wiklander static struct fobj *rwp_unpaged_iv_alloc(unsigned int num_pages)
253b757e307SJens Wiklander {
254b757e307SJens Wiklander 	struct fobj_rwp_unpaged_iv *rwp = NULL;
255b757e307SJens Wiklander 	tee_mm_entry_t *mm = NULL;
256b757e307SJens Wiklander 	size_t size = 0;
257b757e307SJens Wiklander 
258b757e307SJens Wiklander 	rwp = calloc(1, sizeof(*rwp));
259b757e307SJens Wiklander 	if (!rwp)
260b757e307SJens Wiklander 		return NULL;
261b757e307SJens Wiklander 
262b757e307SJens Wiklander 	rwp->state = calloc(num_pages, sizeof(*rwp->state));
263b757e307SJens Wiklander 	if (!rwp->state)
264b757e307SJens Wiklander 		goto err_free_rwp;
265b757e307SJens Wiklander 
266b757e307SJens Wiklander 	if (MUL_OVERFLOW(num_pages, SMALL_PAGE_SIZE, &size))
267b757e307SJens Wiklander 		goto err_free_state;
268b757e307SJens Wiklander 	mm = tee_mm_alloc(&tee_mm_sec_ddr, size);
269b757e307SJens Wiklander 	if (!mm)
270b757e307SJens Wiklander 		goto err_free_state;
271c2e4eb43SAnton Rybakov 	rwp->store = phys_to_virt(tee_mm_get_smem(mm), MEM_AREA_TA_RAM, size);
272b757e307SJens Wiklander 	assert(rwp->store);
273b757e307SJens Wiklander 
274b757e307SJens Wiklander 	fobj_init(&rwp->fobj, &ops_rwp_unpaged_iv, num_pages);
275b757e307SJens Wiklander 
276b757e307SJens Wiklander 	return &rwp->fobj;
277b757e307SJens Wiklander 
278b757e307SJens Wiklander err_free_state:
279b757e307SJens Wiklander 	free(rwp->state);
280b757e307SJens Wiklander err_free_rwp:
281b757e307SJens Wiklander 	free(rwp);
282b757e307SJens Wiklander 	return NULL;
283b757e307SJens Wiklander }
284b757e307SJens Wiklander 
285aad1cf6bSJens Wiklander static struct fobj_rwp_unpaged_iv *to_rwp_unpaged_iv(struct fobj *fobj)
286aad1cf6bSJens Wiklander {
287aad1cf6bSJens Wiklander 	assert(fobj->ops == &ops_rwp_unpaged_iv);
288aad1cf6bSJens Wiklander 
289aad1cf6bSJens Wiklander 	return container_of(fobj, struct fobj_rwp_unpaged_iv, fobj);
290aad1cf6bSJens Wiklander }
291aad1cf6bSJens Wiklander 
292aad1cf6bSJens Wiklander static TEE_Result rwp_unpaged_iv_load_page(struct fobj *fobj,
293aad1cf6bSJens Wiklander 					   unsigned int page_idx, void *va)
294aad1cf6bSJens Wiklander {
295aad1cf6bSJens Wiklander 	struct fobj_rwp_unpaged_iv *rwp = to_rwp_unpaged_iv(fobj);
296aad1cf6bSJens Wiklander 	uint8_t *src = rwp->store + page_idx * SMALL_PAGE_SIZE;
297aad1cf6bSJens Wiklander 
298aad1cf6bSJens Wiklander 	assert(refcount_val(&fobj->refc));
299aad1cf6bSJens Wiklander 	assert(page_idx < fobj->num_pages);
300aad1cf6bSJens Wiklander 
301aad1cf6bSJens Wiklander 	return rwp_load_page(va, rwp->state + page_idx, src);
302aad1cf6bSJens Wiklander }
303aad1cf6bSJens Wiklander DECLARE_KEEP_PAGER(rwp_unpaged_iv_load_page);
304aad1cf6bSJens Wiklander 
305aad1cf6bSJens Wiklander static TEE_Result rwp_unpaged_iv_save_page(struct fobj *fobj,
306aad1cf6bSJens Wiklander 					   unsigned int page_idx,
307aad1cf6bSJens Wiklander 					   const void *va)
308aad1cf6bSJens Wiklander {
309aad1cf6bSJens Wiklander 	struct fobj_rwp_unpaged_iv *rwp = to_rwp_unpaged_iv(fobj);
310aad1cf6bSJens Wiklander 	uint8_t *dst = rwp->store + page_idx * SMALL_PAGE_SIZE;
311aad1cf6bSJens Wiklander 
312aad1cf6bSJens Wiklander 	assert(page_idx < fobj->num_pages);
313aad1cf6bSJens Wiklander 
314aad1cf6bSJens Wiklander 	if (!refcount_val(&fobj->refc)) {
315ee546289SJens Wiklander 		/*
316aad1cf6bSJens Wiklander 		 * This fobj is being teared down, it just hasn't had the time
317aad1cf6bSJens Wiklander 		 * to call tee_pager_invalidate_fobj() yet.
318aad1cf6bSJens Wiklander 		 */
319d5ad7ccfSJens Wiklander 		assert(TAILQ_EMPTY(&fobj->regions));
320aad1cf6bSJens Wiklander 		return TEE_SUCCESS;
321aad1cf6bSJens Wiklander 	}
322aad1cf6bSJens Wiklander 
323aad1cf6bSJens Wiklander 	return rwp_save_page(va, rwp->state + page_idx, dst);
324aad1cf6bSJens Wiklander }
325aad1cf6bSJens Wiklander DECLARE_KEEP_PAGER(rwp_unpaged_iv_save_page);
326aad1cf6bSJens Wiklander 
327b757e307SJens Wiklander static void rwp_unpaged_iv_free(struct fobj *fobj)
328aad1cf6bSJens Wiklander {
329b757e307SJens Wiklander 	struct fobj_rwp_unpaged_iv *rwp = NULL;
330b757e307SJens Wiklander 	tee_mm_entry_t *mm = NULL;
331b757e307SJens Wiklander 
332b757e307SJens Wiklander 	if (IS_ENABLED(CFG_CORE_PAGE_TAG_AND_IV))
333aad1cf6bSJens Wiklander 		panic();
334b757e307SJens Wiklander 
335b757e307SJens Wiklander 	rwp = to_rwp_unpaged_iv(fobj);
336b757e307SJens Wiklander 	mm = tee_mm_find(&tee_mm_sec_ddr, virt_to_phys(rwp->store));
337b757e307SJens Wiklander 
338b757e307SJens Wiklander 	assert(mm);
339b757e307SJens Wiklander 
340b757e307SJens Wiklander 	fobj_uninit(fobj);
341b757e307SJens Wiklander 	tee_mm_free(mm);
342b757e307SJens Wiklander 	free(rwp->state);
343b757e307SJens Wiklander 	free(rwp);
344aad1cf6bSJens Wiklander }
345aad1cf6bSJens Wiklander 
34600361c18SJens Wiklander /*
34700361c18SJens Wiklander  * Note: this variable is weak just to ease breaking its dependency chain
34800361c18SJens Wiklander  * when added to the unpaged area.
34900361c18SJens Wiklander  */
35000361c18SJens Wiklander const struct fobj_ops ops_rwp_unpaged_iv
35139e8c200SJerome Forissier __weak __relrodata_unpaged("ops_rwp_unpaged_iv") = {
352aad1cf6bSJens Wiklander 	.free = rwp_unpaged_iv_free,
353aad1cf6bSJens Wiklander 	.load_page = rwp_unpaged_iv_load_page,
354aad1cf6bSJens Wiklander 	.save_page = rwp_unpaged_iv_save_page,
355aad1cf6bSJens Wiklander };
356aad1cf6bSJens Wiklander 
357aad1cf6bSJens Wiklander static TEE_Result rwp_init(void)
358aad1cf6bSJens Wiklander {
359aad1cf6bSJens Wiklander 	uint8_t key[RWP_AE_KEY_BITS / 8] = { 0 };
360b757e307SJens Wiklander 	struct fobj *fobj = NULL;
361aad1cf6bSJens Wiklander 	size_t num_pool_pages = 0;
362aad1cf6bSJens Wiklander 	size_t num_fobj_pages = 0;
363aad1cf6bSJens Wiklander 
364aad1cf6bSJens Wiklander 	if (crypto_rng_read(key, sizeof(key)) != TEE_SUCCESS)
365aad1cf6bSJens Wiklander 		panic("failed to generate random");
366aad1cf6bSJens Wiklander 	if (crypto_aes_expand_enc_key(key, sizeof(key), rwp_ae_key.data,
367aad1cf6bSJens Wiklander 				      sizeof(rwp_ae_key.data),
368aad1cf6bSJens Wiklander 				      &rwp_ae_key.rounds))
369aad1cf6bSJens Wiklander 		panic("failed to expand key");
370aad1cf6bSJens Wiklander 
371b757e307SJens Wiklander 	if (!IS_ENABLED(CFG_CORE_PAGE_TAG_AND_IV))
372b757e307SJens Wiklander 		return TEE_SUCCESS;
373b757e307SJens Wiklander 
3742380d700SLionel Debieve 	assert(tee_mm_sec_ddr.size && !(tee_mm_sec_ddr.size & SMALL_PAGE_SIZE));
375aad1cf6bSJens Wiklander 
3762380d700SLionel Debieve 	num_pool_pages = tee_mm_sec_ddr.size / SMALL_PAGE_SIZE;
377aad1cf6bSJens Wiklander 	num_fobj_pages = ROUNDUP(num_pool_pages * sizeof(*rwp_state_base),
378aad1cf6bSJens Wiklander 				 SMALL_PAGE_SIZE) / SMALL_PAGE_SIZE;
379aad1cf6bSJens Wiklander 
380aad1cf6bSJens Wiklander 	/*
381aad1cf6bSJens Wiklander 	 * Each page in the pool needs a struct rwp_state.
382aad1cf6bSJens Wiklander 	 *
383aad1cf6bSJens Wiklander 	 * This isn't entirely true, the pages not used by
384aad1cf6bSJens Wiklander 	 * fobj_rw_paged_alloc() don't need any. A future optimization
385aad1cf6bSJens Wiklander 	 * may try to avoid allocating for such pages.
386ee546289SJens Wiklander 	 */
387b757e307SJens Wiklander 	fobj = rwp_unpaged_iv_alloc(num_fobj_pages);
388b757e307SJens Wiklander 	if (!fobj)
389aad1cf6bSJens Wiklander 		panic();
390ee546289SJens Wiklander 
391d5ad7ccfSJens Wiklander 	rwp_state_base = (void *)tee_pager_init_iv_region(fobj);
392aad1cf6bSJens Wiklander 	assert(rwp_state_base);
393aad1cf6bSJens Wiklander 
3942380d700SLionel Debieve 	rwp_store_base = phys_to_virt(tee_mm_sec_ddr.lo, MEM_AREA_TA_RAM,
3952380d700SLionel Debieve 				      tee_mm_sec_ddr.size);
396aad1cf6bSJens Wiklander 	assert(rwp_store_base);
397aad1cf6bSJens Wiklander 
398aad1cf6bSJens Wiklander 	return TEE_SUCCESS;
399ee546289SJens Wiklander }
400aad1cf6bSJens Wiklander driver_init_late(rwp_init);
401ee546289SJens Wiklander 
402b757e307SJens Wiklander struct fobj *fobj_rw_paged_alloc(unsigned int num_pages)
403b757e307SJens Wiklander {
404b757e307SJens Wiklander 	assert(num_pages);
405b757e307SJens Wiklander 
406b757e307SJens Wiklander 	if (IS_ENABLED(CFG_CORE_PAGE_TAG_AND_IV))
407b757e307SJens Wiklander 		return rwp_paged_iv_alloc(num_pages);
408b757e307SJens Wiklander 	else
409b757e307SJens Wiklander 		return rwp_unpaged_iv_alloc(num_pages);
410b757e307SJens Wiklander }
411b757e307SJens Wiklander 
412ee546289SJens Wiklander struct fobj_rop {
413ee546289SJens Wiklander 	uint8_t *hashes;
414ee546289SJens Wiklander 	uint8_t *store;
415ee546289SJens Wiklander 	struct fobj fobj;
416ee546289SJens Wiklander };
417ee546289SJens Wiklander 
41800361c18SJens Wiklander const struct fobj_ops ops_ro_paged;
419c6744caaSJens Wiklander 
420c6744caaSJens Wiklander static void rop_init(struct fobj_rop *rop, const struct fobj_ops *ops,
421c6744caaSJens Wiklander 		     unsigned int num_pages, void *hashes, void *store)
422c6744caaSJens Wiklander {
423c6744caaSJens Wiklander 	rop->hashes = hashes;
424c6744caaSJens Wiklander 	rop->store = store;
425c6744caaSJens Wiklander 	fobj_init(&rop->fobj, ops, num_pages);
426c6744caaSJens Wiklander }
427ee546289SJens Wiklander 
428ee546289SJens Wiklander struct fobj *fobj_ro_paged_alloc(unsigned int num_pages, void *hashes,
429ee546289SJens Wiklander 				 void *store)
430ee546289SJens Wiklander {
431ee546289SJens Wiklander 	struct fobj_rop *rop = NULL;
432ee546289SJens Wiklander 
433ee546289SJens Wiklander 	assert(num_pages && hashes && store);
434ee546289SJens Wiklander 
435ee546289SJens Wiklander 	rop = calloc(1, sizeof(*rop));
436ee546289SJens Wiklander 	if (!rop)
437ee546289SJens Wiklander 		return NULL;
438ee546289SJens Wiklander 
439c6744caaSJens Wiklander 	rop_init(rop, &ops_ro_paged, num_pages, hashes, store);
440ee546289SJens Wiklander 
441ee546289SJens Wiklander 	return &rop->fobj;
442ee546289SJens Wiklander }
443ee546289SJens Wiklander 
444ee546289SJens Wiklander static struct fobj_rop *to_rop(struct fobj *fobj)
445ee546289SJens Wiklander {
446ee546289SJens Wiklander 	assert(fobj->ops == &ops_ro_paged);
447ee546289SJens Wiklander 
448ee546289SJens Wiklander 	return container_of(fobj, struct fobj_rop, fobj);
449ee546289SJens Wiklander }
450ee546289SJens Wiklander 
451c6744caaSJens Wiklander static void rop_uninit(struct fobj_rop *rop)
452c6744caaSJens Wiklander {
453c6744caaSJens Wiklander 	fobj_uninit(&rop->fobj);
454c6744caaSJens Wiklander 	tee_mm_free(tee_mm_find(&tee_mm_sec_ddr, virt_to_phys(rop->store)));
455c6744caaSJens Wiklander 	free(rop->hashes);
456c6744caaSJens Wiklander }
457c6744caaSJens Wiklander 
458ee546289SJens Wiklander static void rop_free(struct fobj *fobj)
459ee546289SJens Wiklander {
460ee546289SJens Wiklander 	struct fobj_rop *rop = to_rop(fobj);
461ee546289SJens Wiklander 
462c6744caaSJens Wiklander 	rop_uninit(rop);
463ee546289SJens Wiklander 	free(rop);
464ee546289SJens Wiklander }
465ee546289SJens Wiklander 
466c6744caaSJens Wiklander static TEE_Result rop_load_page_helper(struct fobj_rop *rop,
467c6744caaSJens Wiklander 				       unsigned int page_idx, void *va)
468c6744caaSJens Wiklander {
469c6744caaSJens Wiklander 	const uint8_t *hash = rop->hashes + page_idx * TEE_SHA256_HASH_SIZE;
470c6744caaSJens Wiklander 	const uint8_t *src = rop->store + page_idx * SMALL_PAGE_SIZE;
471c6744caaSJens Wiklander 
472c6744caaSJens Wiklander 	assert(refcount_val(&rop->fobj.refc));
473c6744caaSJens Wiklander 	assert(page_idx < rop->fobj.num_pages);
474c6744caaSJens Wiklander 	memcpy(va, src, SMALL_PAGE_SIZE);
475c6744caaSJens Wiklander 
476c6744caaSJens Wiklander 	return hash_sha256_check(hash, va, SMALL_PAGE_SIZE);
477c6744caaSJens Wiklander }
478c6744caaSJens Wiklander 
479ee546289SJens Wiklander static TEE_Result rop_load_page(struct fobj *fobj, unsigned int page_idx,
480ee546289SJens Wiklander 				void *va)
481ee546289SJens Wiklander {
482c6744caaSJens Wiklander 	return rop_load_page_helper(to_rop(fobj), page_idx, va);
483ee546289SJens Wiklander }
4843639b55fSJerome Forissier DECLARE_KEEP_PAGER(rop_load_page);
485ee546289SJens Wiklander 
486ee546289SJens Wiklander static TEE_Result rop_save_page(struct fobj *fobj __unused,
487ee546289SJens Wiklander 				unsigned int page_idx __unused,
488ee546289SJens Wiklander 				const void *va __unused)
489ee546289SJens Wiklander {
490ee546289SJens Wiklander 	return TEE_ERROR_GENERIC;
491ee546289SJens Wiklander }
4923639b55fSJerome Forissier DECLARE_KEEP_PAGER(rop_save_page);
493ee546289SJens Wiklander 
49400361c18SJens Wiklander /*
49500361c18SJens Wiklander  * Note: this variable is weak just to ease breaking its dependency chain
49600361c18SJens Wiklander  * when added to the unpaged area.
49700361c18SJens Wiklander  */
49839e8c200SJerome Forissier const struct fobj_ops ops_ro_paged
49939e8c200SJerome Forissier __weak __relrodata_unpaged("ops_ro_paged") = {
500ee546289SJens Wiklander 	.free = rop_free,
501ee546289SJens Wiklander 	.load_page = rop_load_page,
502ee546289SJens Wiklander 	.save_page = rop_save_page,
503ee546289SJens Wiklander };
504ee546289SJens Wiklander 
505c6744caaSJens Wiklander #ifdef CFG_CORE_ASLR
506c6744caaSJens Wiklander /*
507c6744caaSJens Wiklander  * When using relocated pages the relocation information must be applied
508c6744caaSJens Wiklander  * before the pages can be used. With read-only paging the content is only
509c6744caaSJens Wiklander  * integrity protected so relocation cannot be applied on pages in the less
510c6744caaSJens Wiklander  * secure "store" or the load_address selected by ASLR could be given away.
511c6744caaSJens Wiklander  * This means that each time a page has been loaded and verified it has to
512c6744caaSJens Wiklander  * have its relocation information applied before it can be used.
513c6744caaSJens Wiklander  *
514c6744caaSJens Wiklander  * Only the relative relocations are supported, this allows a rather compact
515c6744caaSJens Wiklander  * represenation of the needed relocation information in this struct.
516c6744caaSJens Wiklander  * r_offset is replaced with the offset into the page that need to be updated,
517c6744caaSJens Wiklander  * this number can never be larger than SMALL_PAGE_SIZE so a uint16_t can be
518c6744caaSJens Wiklander  * used to represent it.
519c6744caaSJens Wiklander  *
520c6744caaSJens Wiklander  * All relocations are converted and stored in @relocs. @page_reloc_idx is
521c6744caaSJens Wiklander  * an array of length @rop.fobj.num_pages with an entry for each page. If
522c6744caaSJens Wiklander  * @page_reloc_idx[page_idx] isn't UINT16_MAX it's an index into @relocs.
523c6744caaSJens Wiklander  */
524c6744caaSJens Wiklander struct fobj_ro_reloc_paged {
525c6744caaSJens Wiklander 	uint16_t *page_reloc_idx;
526c6744caaSJens Wiklander 	uint16_t *relocs;
527c6744caaSJens Wiklander 	unsigned int num_relocs;
528c6744caaSJens Wiklander 	struct fobj_rop rop;
529c6744caaSJens Wiklander };
530c6744caaSJens Wiklander 
53100361c18SJens Wiklander const struct fobj_ops ops_ro_reloc_paged;
532c6744caaSJens Wiklander 
533c6744caaSJens Wiklander static unsigned int get_num_rels(unsigned int num_pages,
534c6744caaSJens Wiklander 				 unsigned int reloc_offs,
535c6744caaSJens Wiklander 				 const uint32_t *reloc, unsigned int num_relocs)
536c6744caaSJens Wiklander {
537c6744caaSJens Wiklander 	const unsigned int align_mask __maybe_unused = sizeof(long) - 1;
538c6744caaSJens Wiklander 	unsigned int nrels = 0;
539c6744caaSJens Wiklander 	unsigned int n = 0;
540c6744caaSJens Wiklander 	vaddr_t offs = 0;
541c6744caaSJens Wiklander 
542c6744caaSJens Wiklander 	/*
543c6744caaSJens Wiklander 	 * Count the number of relocations which are needed for these
544c6744caaSJens Wiklander 	 * pages.  Also check that the data is well formed, only expected
545c6744caaSJens Wiklander 	 * relocations and sorted in order of address which it applies to.
546c6744caaSJens Wiklander 	 */
547c6744caaSJens Wiklander 	for (; n < num_relocs; n++) {
548be501eb1SJorge Ramirez-Ortiz 		assert(IS_ALIGNED_WITH_TYPE(reloc[n], unsigned long));
549c6744caaSJens Wiklander 		assert(offs < reloc[n]);	/* check that it's sorted */
550c6744caaSJens Wiklander 		offs = reloc[n];
551c6744caaSJens Wiklander 		if (offs >= reloc_offs &&
552c6744caaSJens Wiklander 		    offs <= reloc_offs + num_pages * SMALL_PAGE_SIZE)
553c6744caaSJens Wiklander 			nrels++;
554c6744caaSJens Wiklander 	}
555c6744caaSJens Wiklander 
556c6744caaSJens Wiklander 	return nrels;
557c6744caaSJens Wiklander }
558c6744caaSJens Wiklander 
559c6744caaSJens Wiklander static void init_rels(struct fobj_ro_reloc_paged *rrp, unsigned int reloc_offs,
560c6744caaSJens Wiklander 		      const uint32_t *reloc, unsigned int num_relocs)
561c6744caaSJens Wiklander {
562c6744caaSJens Wiklander 	unsigned int npg = rrp->rop.fobj.num_pages;
563c6744caaSJens Wiklander 	unsigned int pg_idx = 0;
564c6744caaSJens Wiklander 	unsigned int reln = 0;
565c6744caaSJens Wiklander 	unsigned int n = 0;
566c6744caaSJens Wiklander 	uint32_t r = 0;
567c6744caaSJens Wiklander 
568c6744caaSJens Wiklander 	for (n = 0; n < npg; n++)
569c6744caaSJens Wiklander 		rrp->page_reloc_idx[n] = UINT16_MAX;
570c6744caaSJens Wiklander 
571c6744caaSJens Wiklander 	for (n = 0; n < num_relocs ; n++) {
572c6744caaSJens Wiklander 		if (reloc[n] < reloc_offs)
573c6744caaSJens Wiklander 			continue;
574c6744caaSJens Wiklander 
575c6744caaSJens Wiklander 		/* r is the offset from beginning of this fobj */
576c6744caaSJens Wiklander 		r = reloc[n] - reloc_offs;
577c6744caaSJens Wiklander 
578c6744caaSJens Wiklander 		pg_idx = r / SMALL_PAGE_SIZE;
579c6744caaSJens Wiklander 		if (pg_idx >= npg)
580c6744caaSJens Wiklander 			break;
581c6744caaSJens Wiklander 
582c6744caaSJens Wiklander 		if (rrp->page_reloc_idx[pg_idx] == UINT16_MAX)
583c6744caaSJens Wiklander 			rrp->page_reloc_idx[pg_idx] = reln;
584c6744caaSJens Wiklander 		rrp->relocs[reln] = r - pg_idx * SMALL_PAGE_SIZE;
585c6744caaSJens Wiklander 		reln++;
586c6744caaSJens Wiklander 	}
587c6744caaSJens Wiklander 
588c6744caaSJens Wiklander 	assert(reln == rrp->num_relocs);
589c6744caaSJens Wiklander }
590c6744caaSJens Wiklander 
591c6744caaSJens Wiklander struct fobj *fobj_ro_reloc_paged_alloc(unsigned int num_pages, void *hashes,
592c6744caaSJens Wiklander 				       unsigned int reloc_offs,
593c6744caaSJens Wiklander 				       const void *reloc,
594c6744caaSJens Wiklander 				       unsigned int reloc_len, void *store)
595c6744caaSJens Wiklander {
596c6744caaSJens Wiklander 	struct fobj_ro_reloc_paged *rrp = NULL;
597c6744caaSJens Wiklander 	const unsigned int num_relocs = reloc_len / sizeof(uint32_t);
598c6744caaSJens Wiklander 	unsigned int nrels = 0;
599c6744caaSJens Wiklander 
600be501eb1SJorge Ramirez-Ortiz 	assert(IS_ALIGNED_WITH_TYPE(reloc, uint32_t));
601be501eb1SJorge Ramirez-Ortiz 	assert(IS_ALIGNED_WITH_TYPE(reloc_len, uint32_t));
602c6744caaSJens Wiklander 	assert(num_pages && hashes && store);
603c6744caaSJens Wiklander 	if (!reloc_len) {
604c6744caaSJens Wiklander 		assert(!reloc);
605c6744caaSJens Wiklander 		return fobj_ro_paged_alloc(num_pages, hashes, store);
606c6744caaSJens Wiklander 	}
607c6744caaSJens Wiklander 	assert(reloc);
608c6744caaSJens Wiklander 
609c6744caaSJens Wiklander 	nrels = get_num_rels(num_pages, reloc_offs, reloc, num_relocs);
610c6744caaSJens Wiklander 	if (!nrels)
611c6744caaSJens Wiklander 		return fobj_ro_paged_alloc(num_pages, hashes, store);
612c6744caaSJens Wiklander 
613c6744caaSJens Wiklander 	rrp = calloc(1, sizeof(*rrp) + num_pages * sizeof(uint16_t) +
614c6744caaSJens Wiklander 			nrels * sizeof(uint16_t));
615c6744caaSJens Wiklander 	if (!rrp)
616c6744caaSJens Wiklander 		return NULL;
617c6744caaSJens Wiklander 	rop_init(&rrp->rop, &ops_ro_reloc_paged, num_pages, hashes, store);
618c6744caaSJens Wiklander 	rrp->page_reloc_idx = (uint16_t *)(rrp + 1);
619c6744caaSJens Wiklander 	rrp->relocs = rrp->page_reloc_idx + num_pages;
620c6744caaSJens Wiklander 	rrp->num_relocs = nrels;
621c6744caaSJens Wiklander 	init_rels(rrp, reloc_offs, reloc, num_relocs);
622c6744caaSJens Wiklander 
623c6744caaSJens Wiklander 	return &rrp->rop.fobj;
624c6744caaSJens Wiklander }
625c6744caaSJens Wiklander 
626c6744caaSJens Wiklander static struct fobj_ro_reloc_paged *to_rrp(struct fobj *fobj)
627c6744caaSJens Wiklander {
628c6744caaSJens Wiklander 	assert(fobj->ops == &ops_ro_reloc_paged);
629c6744caaSJens Wiklander 
630c6744caaSJens Wiklander 	return container_of(fobj, struct fobj_ro_reloc_paged, rop.fobj);
631c6744caaSJens Wiklander }
632c6744caaSJens Wiklander 
633c6744caaSJens Wiklander static void rrp_free(struct fobj *fobj)
634c6744caaSJens Wiklander {
635c6744caaSJens Wiklander 	struct fobj_ro_reloc_paged *rrp = to_rrp(fobj);
636c6744caaSJens Wiklander 
637c6744caaSJens Wiklander 	rop_uninit(&rrp->rop);
638c6744caaSJens Wiklander 	free(rrp);
639c6744caaSJens Wiklander }
640c6744caaSJens Wiklander 
641c6744caaSJens Wiklander static TEE_Result rrp_load_page(struct fobj *fobj, unsigned int page_idx,
642c6744caaSJens Wiklander 				void *va)
643c6744caaSJens Wiklander {
644c6744caaSJens Wiklander 	struct fobj_ro_reloc_paged *rrp = to_rrp(fobj);
645c6744caaSJens Wiklander 	unsigned int end_rel = rrp->num_relocs;
646c6744caaSJens Wiklander 	TEE_Result res = TEE_SUCCESS;
647c6744caaSJens Wiklander 	unsigned long *where = NULL;
648c6744caaSJens Wiklander 	unsigned int n = 0;
649c6744caaSJens Wiklander 
650c6744caaSJens Wiklander 	res = rop_load_page_helper(&rrp->rop, page_idx, va);
651c6744caaSJens Wiklander 	if (res)
652c6744caaSJens Wiklander 		return res;
653c6744caaSJens Wiklander 
654c6744caaSJens Wiklander 	/* Find the reloc index of the next page to tell when we're done */
655c6744caaSJens Wiklander 	for (n = page_idx + 1; n < fobj->num_pages; n++) {
656c6744caaSJens Wiklander 		if (rrp->page_reloc_idx[n] != UINT16_MAX) {
657c6744caaSJens Wiklander 			end_rel = rrp->page_reloc_idx[n];
658c6744caaSJens Wiklander 			break;
659c6744caaSJens Wiklander 		}
660c6744caaSJens Wiklander 	}
661c6744caaSJens Wiklander 
662c6744caaSJens Wiklander 	for (n = rrp->page_reloc_idx[page_idx]; n < end_rel; n++) {
663c6744caaSJens Wiklander 		where = (void *)((vaddr_t)va + rrp->relocs[n]);
664*c79fb6d4SJens Wiklander 		*where += boot_mmu_config.map_offset;
665c6744caaSJens Wiklander 	}
666c6744caaSJens Wiklander 
667c6744caaSJens Wiklander 	return TEE_SUCCESS;
668c6744caaSJens Wiklander }
6693639b55fSJerome Forissier DECLARE_KEEP_PAGER(rrp_load_page);
670c6744caaSJens Wiklander 
67100361c18SJens Wiklander /*
67200361c18SJens Wiklander  * Note: this variable is weak just to ease breaking its dependency chain
67300361c18SJens Wiklander  * when added to the unpaged area.
67400361c18SJens Wiklander  */
67500361c18SJens Wiklander const struct fobj_ops ops_ro_reloc_paged
67639e8c200SJerome Forissier __weak __relrodata_unpaged("ops_ro_reloc_paged") = {
677c6744caaSJens Wiklander 	.free = rrp_free,
678c6744caaSJens Wiklander 	.load_page = rrp_load_page,
679c6744caaSJens Wiklander 	.save_page = rop_save_page, /* Direct reuse */
680c6744caaSJens Wiklander };
681c6744caaSJens Wiklander #endif /*CFG_CORE_ASLR*/
682c6744caaSJens Wiklander 
68300361c18SJens Wiklander const struct fobj_ops ops_locked_paged;
684ee546289SJens Wiklander 
685ee546289SJens Wiklander struct fobj *fobj_locked_paged_alloc(unsigned int num_pages)
686ee546289SJens Wiklander {
687ee546289SJens Wiklander 	struct fobj *f = NULL;
688ee546289SJens Wiklander 
689ee546289SJens Wiklander 	assert(num_pages);
690ee546289SJens Wiklander 
691ee546289SJens Wiklander 	f = calloc(1, sizeof(*f));
692ee546289SJens Wiklander 	if (!f)
693ee546289SJens Wiklander 		return NULL;
694ee546289SJens Wiklander 
695ee546289SJens Wiklander 	fobj_init(f, &ops_locked_paged, num_pages);
696ee546289SJens Wiklander 
697ee546289SJens Wiklander 	return f;
698ee546289SJens Wiklander }
699ee546289SJens Wiklander 
700ee546289SJens Wiklander static void lop_free(struct fobj *fobj)
701ee546289SJens Wiklander {
702ee546289SJens Wiklander 	assert(fobj->ops == &ops_locked_paged);
703ee546289SJens Wiklander 	fobj_uninit(fobj);
704ee546289SJens Wiklander 	free(fobj);
705ee546289SJens Wiklander }
706ee546289SJens Wiklander 
707ee546289SJens Wiklander static TEE_Result lop_load_page(struct fobj *fobj __maybe_unused,
708ee546289SJens Wiklander 				unsigned int page_idx __maybe_unused,
709ee546289SJens Wiklander 				void *va)
710ee546289SJens Wiklander {
711ee546289SJens Wiklander 	assert(fobj->ops == &ops_locked_paged);
712ee546289SJens Wiklander 	assert(refcount_val(&fobj->refc));
713ee546289SJens Wiklander 	assert(page_idx < fobj->num_pages);
714ee546289SJens Wiklander 
715ee546289SJens Wiklander 	memset(va, 0, SMALL_PAGE_SIZE);
716ee546289SJens Wiklander 
717ee546289SJens Wiklander 	return TEE_SUCCESS;
718ee546289SJens Wiklander }
7193639b55fSJerome Forissier DECLARE_KEEP_PAGER(lop_load_page);
720ee546289SJens Wiklander 
721ee546289SJens Wiklander static TEE_Result lop_save_page(struct fobj *fobj __unused,
722ee546289SJens Wiklander 				unsigned int page_idx __unused,
723ee546289SJens Wiklander 				const void *va __unused)
724ee546289SJens Wiklander {
725ee546289SJens Wiklander 	return TEE_ERROR_GENERIC;
726ee546289SJens Wiklander }
7273639b55fSJerome Forissier DECLARE_KEEP_PAGER(lop_save_page);
728ee546289SJens Wiklander 
72900361c18SJens Wiklander /*
73000361c18SJens Wiklander  * Note: this variable is weak just to ease breaking its dependency chain
73100361c18SJens Wiklander  * when added to the unpaged area.
73200361c18SJens Wiklander  */
73300361c18SJens Wiklander const struct fobj_ops ops_locked_paged
73439e8c200SJerome Forissier __weak __relrodata_unpaged("ops_locked_paged") = {
735ee546289SJens Wiklander 	.free = lop_free,
736ee546289SJens Wiklander 	.load_page = lop_load_page,
737ee546289SJens Wiklander 	.save_page = lop_save_page,
738ee546289SJens Wiklander };
739ee546289SJens Wiklander #endif /*CFG_WITH_PAGER*/
740fbcaa411SJens Wiklander 
741fbcaa411SJens Wiklander #ifndef CFG_PAGED_USER_TA
742fbcaa411SJens Wiklander 
743fbcaa411SJens Wiklander struct fobj_sec_mem {
744fbcaa411SJens Wiklander 	tee_mm_entry_t *mm;
745fbcaa411SJens Wiklander 	struct fobj fobj;
746fbcaa411SJens Wiklander };
747fbcaa411SJens Wiklander 
74800361c18SJens Wiklander const struct fobj_ops ops_sec_mem;
749fbcaa411SJens Wiklander 
750fbcaa411SJens Wiklander struct fobj *fobj_sec_mem_alloc(unsigned int num_pages)
751fbcaa411SJens Wiklander {
752fbcaa411SJens Wiklander 	struct fobj_sec_mem *f = calloc(1, sizeof(*f));
753fbcaa411SJens Wiklander 	size_t size = 0;
754fbcaa411SJens Wiklander 	void *va = NULL;
755fbcaa411SJens Wiklander 
756fbcaa411SJens Wiklander 	if (!f)
757fbcaa411SJens Wiklander 		return NULL;
758fbcaa411SJens Wiklander 
759fbcaa411SJens Wiklander 	if (MUL_OVERFLOW(num_pages, SMALL_PAGE_SIZE, &size))
760fbcaa411SJens Wiklander 		goto err;
761fbcaa411SJens Wiklander 
762fbcaa411SJens Wiklander 	f->mm = tee_mm_alloc(&tee_mm_sec_ddr, size);
763fbcaa411SJens Wiklander 	if (!f->mm)
764fbcaa411SJens Wiklander 		goto err;
765fbcaa411SJens Wiklander 
766c2e4eb43SAnton Rybakov 	va = phys_to_virt(tee_mm_get_smem(f->mm), MEM_AREA_TA_RAM, size);
767fbcaa411SJens Wiklander 	if (!va)
768fbcaa411SJens Wiklander 		goto err;
769fbcaa411SJens Wiklander 
770a0e8ffe9SJens Wiklander 	memtag_clear_mem(va, size);
771fbcaa411SJens Wiklander 	f->fobj.ops = &ops_sec_mem;
772fbcaa411SJens Wiklander 	f->fobj.num_pages = num_pages;
773fbcaa411SJens Wiklander 	refcount_set(&f->fobj.refc, 1);
774fbcaa411SJens Wiklander 
775fbcaa411SJens Wiklander 	return &f->fobj;
776fbcaa411SJens Wiklander err:
777fbcaa411SJens Wiklander 	tee_mm_free(f->mm);
778fbcaa411SJens Wiklander 	free(f);
779fbcaa411SJens Wiklander 
780fbcaa411SJens Wiklander 	return NULL;
781fbcaa411SJens Wiklander }
782fbcaa411SJens Wiklander 
783fbcaa411SJens Wiklander static struct fobj_sec_mem *to_sec_mem(struct fobj *fobj)
784fbcaa411SJens Wiklander {
785fbcaa411SJens Wiklander 	assert(fobj->ops == &ops_sec_mem);
786fbcaa411SJens Wiklander 
787fbcaa411SJens Wiklander 	return container_of(fobj, struct fobj_sec_mem, fobj);
788fbcaa411SJens Wiklander }
789fbcaa411SJens Wiklander 
790fbcaa411SJens Wiklander static void sec_mem_free(struct fobj *fobj)
791fbcaa411SJens Wiklander {
792fbcaa411SJens Wiklander 	struct fobj_sec_mem *f = to_sec_mem(fobj);
793fbcaa411SJens Wiklander 
794fbcaa411SJens Wiklander 	assert(!refcount_val(&fobj->refc));
795fbcaa411SJens Wiklander 	tee_mm_free(f->mm);
796fbcaa411SJens Wiklander 	free(f);
797fbcaa411SJens Wiklander }
798fbcaa411SJens Wiklander 
799fbcaa411SJens Wiklander static paddr_t sec_mem_get_pa(struct fobj *fobj, unsigned int page_idx)
800fbcaa411SJens Wiklander {
801fbcaa411SJens Wiklander 	struct fobj_sec_mem *f = to_sec_mem(fobj);
802fbcaa411SJens Wiklander 
803fbcaa411SJens Wiklander 	assert(refcount_val(&fobj->refc));
804fbcaa411SJens Wiklander 	assert(page_idx < fobj->num_pages);
805fbcaa411SJens Wiklander 
806fbcaa411SJens Wiklander 	return tee_mm_get_smem(f->mm) + page_idx * SMALL_PAGE_SIZE;
807fbcaa411SJens Wiklander }
808fbcaa411SJens Wiklander 
80900361c18SJens Wiklander /*
81000361c18SJens Wiklander  * Note: this variable is weak just to ease breaking its dependency chain
81100361c18SJens Wiklander  * when added to the unpaged area.
81200361c18SJens Wiklander  */
81339e8c200SJerome Forissier const struct fobj_ops ops_sec_mem __weak __relrodata_unpaged("ops_sec_mem") = {
814fbcaa411SJens Wiklander 	.free = sec_mem_free,
815fbcaa411SJens Wiklander 	.get_pa = sec_mem_get_pa,
816fbcaa411SJens Wiklander };
817fbcaa411SJens Wiklander 
818fbcaa411SJens Wiklander #endif /*PAGED_USER_TA*/
819