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