xref: /optee_os/core/mm/boot_mem.c (revision fe85eae5b0b3ddd2efca12df010d663f0e8c1891)
1*fe85eae5SJens Wiklander // SPDX-License-Identifier: BSD-2-Clause
2*fe85eae5SJens Wiklander /*
3*fe85eae5SJens Wiklander  * Copyright (c) 2024, Linaro Limited
4*fe85eae5SJens Wiklander  */
5*fe85eae5SJens Wiklander 
6*fe85eae5SJens Wiklander #include <assert.h>
7*fe85eae5SJens Wiklander #include <kernel/boot.h>
8*fe85eae5SJens Wiklander #include <mm/core_memprot.h>
9*fe85eae5SJens Wiklander #include <mm/core_mmu.h>
10*fe85eae5SJens Wiklander #include <mm/phys_mem.h>
11*fe85eae5SJens Wiklander #include <mm/tee_mm.h>
12*fe85eae5SJens Wiklander #include <stdalign.h>
13*fe85eae5SJens Wiklander #include <string.h>
14*fe85eae5SJens Wiklander #include <util.h>
15*fe85eae5SJens Wiklander 
16*fe85eae5SJens Wiklander /*
17*fe85eae5SJens Wiklander  * struct boot_mem_reloc - Pointers relocated in memory during boot
18*fe85eae5SJens Wiklander  * @ptrs: Array of relocation
19*fe85eae5SJens Wiklander  * @count: Number of cells used in @ptrs
20*fe85eae5SJens Wiklander  * @next: Next relocation array when @ptrs is fully used
21*fe85eae5SJens Wiklander  */
22*fe85eae5SJens Wiklander struct boot_mem_reloc {
23*fe85eae5SJens Wiklander 	void **ptrs[64];
24*fe85eae5SJens Wiklander 	size_t count;
25*fe85eae5SJens Wiklander 	struct boot_mem_reloc *next;
26*fe85eae5SJens Wiklander };
27*fe85eae5SJens Wiklander 
28*fe85eae5SJens Wiklander /*
29*fe85eae5SJens Wiklander  * struct boot_mem_desc - Stack like boot memory allocation pool
30*fe85eae5SJens Wiklander  * @orig_mem_start: Boot memory stack base address
31*fe85eae5SJens Wiklander  * @orig_mem_end: Boot memory start end address
32*fe85eae5SJens Wiklander  * @mem_start: Boot memory free space start address
33*fe85eae5SJens Wiklander  * @mem_end: Boot memory free space end address
34*fe85eae5SJens Wiklander  * @reloc: Boot memory pointers requiring relocation
35*fe85eae5SJens Wiklander  */
36*fe85eae5SJens Wiklander struct boot_mem_desc {
37*fe85eae5SJens Wiklander 	vaddr_t orig_mem_start;
38*fe85eae5SJens Wiklander 	vaddr_t orig_mem_end;
39*fe85eae5SJens Wiklander 	vaddr_t mem_start;
40*fe85eae5SJens Wiklander 	vaddr_t mem_end;
41*fe85eae5SJens Wiklander 	struct boot_mem_reloc *reloc;
42*fe85eae5SJens Wiklander };
43*fe85eae5SJens Wiklander 
44*fe85eae5SJens Wiklander static struct boot_mem_desc *boot_mem_desc;
45*fe85eae5SJens Wiklander 
46*fe85eae5SJens Wiklander static void *mem_alloc_tmp(struct boot_mem_desc *desc, size_t len, size_t align)
47*fe85eae5SJens Wiklander {
48*fe85eae5SJens Wiklander 	vaddr_t va = 0;
49*fe85eae5SJens Wiklander 
50*fe85eae5SJens Wiklander 	assert(desc && desc->mem_start && desc->mem_end);
51*fe85eae5SJens Wiklander 	assert(IS_POWER_OF_TWO(align) && !(len % align));
52*fe85eae5SJens Wiklander 	if (SUB_OVERFLOW(desc->mem_end, len, &va))
53*fe85eae5SJens Wiklander 		panic();
54*fe85eae5SJens Wiklander 	va = ROUNDDOWN(va, align);
55*fe85eae5SJens Wiklander 	if (va < desc->mem_start)
56*fe85eae5SJens Wiklander 		panic();
57*fe85eae5SJens Wiklander 	desc->mem_end = va;
58*fe85eae5SJens Wiklander 	return (void *)va;
59*fe85eae5SJens Wiklander }
60*fe85eae5SJens Wiklander 
61*fe85eae5SJens Wiklander static void *mem_alloc(struct boot_mem_desc *desc, size_t len, size_t align)
62*fe85eae5SJens Wiklander {
63*fe85eae5SJens Wiklander 	vaddr_t va = 0;
64*fe85eae5SJens Wiklander 	vaddr_t ve = 0;
65*fe85eae5SJens Wiklander 
66*fe85eae5SJens Wiklander 	runtime_assert(!IS_ENABLED(CFG_WITH_PAGER));
67*fe85eae5SJens Wiklander 	assert(desc && desc->mem_start && desc->mem_end);
68*fe85eae5SJens Wiklander 	assert(IS_POWER_OF_TWO(align) && !(len % align));
69*fe85eae5SJens Wiklander 	va = ROUNDUP(desc->mem_start, align);
70*fe85eae5SJens Wiklander 	if (ADD_OVERFLOW(va, len, &ve))
71*fe85eae5SJens Wiklander 		panic();
72*fe85eae5SJens Wiklander 	if (ve > desc->mem_end)
73*fe85eae5SJens Wiklander 		panic();
74*fe85eae5SJens Wiklander 	desc->mem_start = ve;
75*fe85eae5SJens Wiklander 	return (void *)va;
76*fe85eae5SJens Wiklander }
77*fe85eae5SJens Wiklander 
78*fe85eae5SJens Wiklander void boot_mem_init(vaddr_t start, vaddr_t end, vaddr_t orig_end)
79*fe85eae5SJens Wiklander {
80*fe85eae5SJens Wiklander 	struct boot_mem_desc desc = {
81*fe85eae5SJens Wiklander 		.orig_mem_start = start,
82*fe85eae5SJens Wiklander 		.orig_mem_end = orig_end,
83*fe85eae5SJens Wiklander 		.mem_start = start,
84*fe85eae5SJens Wiklander 		.mem_end = end,
85*fe85eae5SJens Wiklander 	};
86*fe85eae5SJens Wiklander 
87*fe85eae5SJens Wiklander 	boot_mem_desc = mem_alloc_tmp(&desc, sizeof(desc), alignof(desc));
88*fe85eae5SJens Wiklander 	*boot_mem_desc = desc;
89*fe85eae5SJens Wiklander 	boot_mem_desc->reloc = mem_alloc_tmp(boot_mem_desc,
90*fe85eae5SJens Wiklander 					     sizeof(*boot_mem_desc->reloc),
91*fe85eae5SJens Wiklander 					     alignof(*boot_mem_desc->reloc));
92*fe85eae5SJens Wiklander 	memset(boot_mem_desc->reloc, 0, sizeof(*boot_mem_desc->reloc));
93*fe85eae5SJens Wiklander }
94*fe85eae5SJens Wiklander 
95*fe85eae5SJens Wiklander void boot_mem_add_reloc(void *ptr)
96*fe85eae5SJens Wiklander {
97*fe85eae5SJens Wiklander 	struct boot_mem_reloc *reloc = NULL;
98*fe85eae5SJens Wiklander 
99*fe85eae5SJens Wiklander 	assert(boot_mem_desc && boot_mem_desc->reloc);
100*fe85eae5SJens Wiklander 	reloc = boot_mem_desc->reloc;
101*fe85eae5SJens Wiklander 
102*fe85eae5SJens Wiklander 	/* If the reloc struct is full, allocate a new and link it first */
103*fe85eae5SJens Wiklander 	if (reloc->count == ARRAY_SIZE(reloc->ptrs)) {
104*fe85eae5SJens Wiklander 		reloc = boot_mem_alloc_tmp(sizeof(*reloc), alignof(*reloc));
105*fe85eae5SJens Wiklander 		reloc->next = boot_mem_desc->reloc;
106*fe85eae5SJens Wiklander 		boot_mem_desc->reloc = reloc;
107*fe85eae5SJens Wiklander 	}
108*fe85eae5SJens Wiklander 
109*fe85eae5SJens Wiklander 	reloc->ptrs[reloc->count] = ptr;
110*fe85eae5SJens Wiklander 	reloc->count++;
111*fe85eae5SJens Wiklander }
112*fe85eae5SJens Wiklander 
113*fe85eae5SJens Wiklander static void *add_offs(void *p, size_t offs)
114*fe85eae5SJens Wiklander {
115*fe85eae5SJens Wiklander 	assert(p);
116*fe85eae5SJens Wiklander 	return (uint8_t *)p + offs;
117*fe85eae5SJens Wiklander }
118*fe85eae5SJens Wiklander 
119*fe85eae5SJens Wiklander void boot_mem_relocate(size_t offs)
120*fe85eae5SJens Wiklander {
121*fe85eae5SJens Wiklander 	struct boot_mem_reloc *reloc = NULL;
122*fe85eae5SJens Wiklander 	size_t n = 0;
123*fe85eae5SJens Wiklander 
124*fe85eae5SJens Wiklander 	boot_mem_desc = add_offs(boot_mem_desc, offs);
125*fe85eae5SJens Wiklander 
126*fe85eae5SJens Wiklander 	boot_mem_desc->orig_mem_start += offs;
127*fe85eae5SJens Wiklander 	boot_mem_desc->orig_mem_end += offs;
128*fe85eae5SJens Wiklander 	boot_mem_desc->mem_start += offs;
129*fe85eae5SJens Wiklander 	boot_mem_desc->mem_end += offs;
130*fe85eae5SJens Wiklander 	boot_mem_desc->reloc = add_offs(boot_mem_desc->reloc, offs);
131*fe85eae5SJens Wiklander 
132*fe85eae5SJens Wiklander 	for (reloc = boot_mem_desc->reloc;; reloc = reloc->next) {
133*fe85eae5SJens Wiklander 		for (n = 0; n < reloc->count; n++) {
134*fe85eae5SJens Wiklander 			reloc->ptrs[n] = add_offs(reloc->ptrs[n], offs);
135*fe85eae5SJens Wiklander 			*reloc->ptrs[n] = add_offs(*reloc->ptrs[n], offs);
136*fe85eae5SJens Wiklander 		}
137*fe85eae5SJens Wiklander 		if (!reloc->next)
138*fe85eae5SJens Wiklander 			break;
139*fe85eae5SJens Wiklander 		reloc->next = add_offs(reloc->next, offs);
140*fe85eae5SJens Wiklander 	}
141*fe85eae5SJens Wiklander }
142*fe85eae5SJens Wiklander 
143*fe85eae5SJens Wiklander void *boot_mem_alloc(size_t len, size_t align)
144*fe85eae5SJens Wiklander {
145*fe85eae5SJens Wiklander 	return mem_alloc(boot_mem_desc, len, align);
146*fe85eae5SJens Wiklander }
147*fe85eae5SJens Wiklander 
148*fe85eae5SJens Wiklander void *boot_mem_alloc_tmp(size_t len, size_t align)
149*fe85eae5SJens Wiklander {
150*fe85eae5SJens Wiklander 	return mem_alloc_tmp(boot_mem_desc, len, align);
151*fe85eae5SJens Wiklander }
152*fe85eae5SJens Wiklander 
153*fe85eae5SJens Wiklander vaddr_t boot_mem_release_unused(void)
154*fe85eae5SJens Wiklander {
155*fe85eae5SJens Wiklander 	tee_mm_entry_t *mm = NULL;
156*fe85eae5SJens Wiklander 	paddr_t pa = 0;
157*fe85eae5SJens Wiklander 	vaddr_t va = 0;
158*fe85eae5SJens Wiklander 	size_t n = 0;
159*fe85eae5SJens Wiklander 	vaddr_t tmp_va = 0;
160*fe85eae5SJens Wiklander 	paddr_t tmp_pa = 0;
161*fe85eae5SJens Wiklander 	size_t tmp_n = 0;
162*fe85eae5SJens Wiklander 
163*fe85eae5SJens Wiklander 	assert(boot_mem_desc);
164*fe85eae5SJens Wiklander 
165*fe85eae5SJens Wiklander 	n = boot_mem_desc->mem_start - boot_mem_desc->orig_mem_start;
166*fe85eae5SJens Wiklander 	DMSG("Allocated %zu bytes at va %#"PRIxVA" pa %#"PRIxPA,
167*fe85eae5SJens Wiklander 	     n, boot_mem_desc->orig_mem_start,
168*fe85eae5SJens Wiklander 	     vaddr_to_phys(boot_mem_desc->orig_mem_start));
169*fe85eae5SJens Wiklander 
170*fe85eae5SJens Wiklander 	DMSG("Tempalloc %zu bytes at va %#"PRIxVA,
171*fe85eae5SJens Wiklander 	     (size_t)(boot_mem_desc->orig_mem_end - boot_mem_desc->mem_end),
172*fe85eae5SJens Wiklander 	     boot_mem_desc->mem_end);
173*fe85eae5SJens Wiklander 
174*fe85eae5SJens Wiklander 	if (IS_ENABLED(CFG_WITH_PAGER))
175*fe85eae5SJens Wiklander 		goto out;
176*fe85eae5SJens Wiklander 
177*fe85eae5SJens Wiklander 	pa = vaddr_to_phys(ROUNDUP(boot_mem_desc->orig_mem_start,
178*fe85eae5SJens Wiklander 				   SMALL_PAGE_SIZE));
179*fe85eae5SJens Wiklander 	mm = nex_phys_mem_mm_find(pa);
180*fe85eae5SJens Wiklander 	if (!mm)
181*fe85eae5SJens Wiklander 		panic();
182*fe85eae5SJens Wiklander 
183*fe85eae5SJens Wiklander 	va = ROUNDUP(boot_mem_desc->mem_start, SMALL_PAGE_SIZE);
184*fe85eae5SJens Wiklander 
185*fe85eae5SJens Wiklander 	tmp_va = ROUNDDOWN(boot_mem_desc->mem_end, SMALL_PAGE_SIZE);
186*fe85eae5SJens Wiklander 	tmp_n = boot_mem_desc->orig_mem_end - tmp_va;
187*fe85eae5SJens Wiklander 	tmp_pa = vaddr_to_phys(tmp_va);
188*fe85eae5SJens Wiklander 
189*fe85eae5SJens Wiklander 	pa = tee_mm_get_smem(mm);
190*fe85eae5SJens Wiklander 	n = vaddr_to_phys(boot_mem_desc->mem_start) - pa;
191*fe85eae5SJens Wiklander 	tee_mm_free(mm);
192*fe85eae5SJens Wiklander 	DMSG("Carving out %#"PRIxPA"..%#"PRIxPA, pa, pa + n - 1);
193*fe85eae5SJens Wiklander 	mm = nex_phys_mem_alloc2(pa, n);
194*fe85eae5SJens Wiklander 	if (!mm)
195*fe85eae5SJens Wiklander 		panic();
196*fe85eae5SJens Wiklander 	mm = nex_phys_mem_alloc2(tmp_pa, tmp_n);
197*fe85eae5SJens Wiklander 	if (!mm)
198*fe85eae5SJens Wiklander 		panic();
199*fe85eae5SJens Wiklander 
200*fe85eae5SJens Wiklander 	n = tmp_va - boot_mem_desc->mem_start;
201*fe85eae5SJens Wiklander 	DMSG("Releasing %zu bytes from va %#"PRIxVA, n, va);
202*fe85eae5SJens Wiklander 
203*fe85eae5SJens Wiklander 	/* Unmap the now unused pages */
204*fe85eae5SJens Wiklander 	core_mmu_unmap_pages(va, n / SMALL_PAGE_SIZE);
205*fe85eae5SJens Wiklander 
206*fe85eae5SJens Wiklander out:
207*fe85eae5SJens Wiklander 	/* Stop further allocations. */
208*fe85eae5SJens Wiklander 	boot_mem_desc->mem_start = boot_mem_desc->mem_end;
209*fe85eae5SJens Wiklander 	return va;
210*fe85eae5SJens Wiklander }
211*fe85eae5SJens Wiklander 
212*fe85eae5SJens Wiklander void boot_mem_release_tmp_alloc(void)
213*fe85eae5SJens Wiklander {
214*fe85eae5SJens Wiklander 	tee_mm_entry_t *mm = NULL;
215*fe85eae5SJens Wiklander 	vaddr_t va = 0;
216*fe85eae5SJens Wiklander 	paddr_t pa = 0;
217*fe85eae5SJens Wiklander 	size_t n = 0;
218*fe85eae5SJens Wiklander 
219*fe85eae5SJens Wiklander 	assert(boot_mem_desc &&
220*fe85eae5SJens Wiklander 	       boot_mem_desc->mem_start == boot_mem_desc->mem_end);
221*fe85eae5SJens Wiklander 
222*fe85eae5SJens Wiklander 	if (IS_ENABLED(CFG_WITH_PAGER)) {
223*fe85eae5SJens Wiklander 		n = boot_mem_desc->orig_mem_end - boot_mem_desc->mem_end;
224*fe85eae5SJens Wiklander 		va = boot_mem_desc->mem_end;
225*fe85eae5SJens Wiklander 		boot_mem_desc = NULL;
226*fe85eae5SJens Wiklander 		DMSG("Releasing %zu bytes from va %#"PRIxVA, n, va);
227*fe85eae5SJens Wiklander 		return;
228*fe85eae5SJens Wiklander 	}
229*fe85eae5SJens Wiklander 
230*fe85eae5SJens Wiklander 	va = ROUNDDOWN(boot_mem_desc->mem_end, SMALL_PAGE_SIZE);
231*fe85eae5SJens Wiklander 	pa = vaddr_to_phys(va);
232*fe85eae5SJens Wiklander 
233*fe85eae5SJens Wiklander 	mm = nex_phys_mem_mm_find(pa);
234*fe85eae5SJens Wiklander 	if (!mm)
235*fe85eae5SJens Wiklander 		panic();
236*fe85eae5SJens Wiklander 	assert(pa == tee_mm_get_smem(mm));
237*fe85eae5SJens Wiklander 	n = tee_mm_get_bytes(mm);
238*fe85eae5SJens Wiklander 
239*fe85eae5SJens Wiklander 	/* Boot memory allocation is now done */
240*fe85eae5SJens Wiklander 	boot_mem_desc = NULL;
241*fe85eae5SJens Wiklander 
242*fe85eae5SJens Wiklander 	DMSG("Releasing %zu bytes from va %#"PRIxVA, n, va);
243*fe85eae5SJens Wiklander 
244*fe85eae5SJens Wiklander 	/* Unmap the now unused pages */
245*fe85eae5SJens Wiklander 	core_mmu_unmap_pages(va, n / SMALL_PAGE_SIZE);
246*fe85eae5SJens Wiklander }
247