xref: /optee_os/core/arch/riscv/kernel/boot.c (revision 19bcbfd13462f5506018dffb5fc4416ab8ba31d1)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2023 Andes Technology Corporation
4  * Copyright 2022-2023 NXP
5  */
6 
7 #include <assert.h>
8 #include <compiler.h>
9 #include <config.h>
10 #include <console.h>
11 #include <keep.h>
12 #include <kernel/boot.h>
13 #include <kernel/dt.h>
14 #include <kernel/linker.h>
15 #include <kernel/misc.h>
16 #include <kernel/panic.h>
17 #include <kernel/thread.h>
18 #include <libfdt.h>
19 #include <mm/core_memprot.h>
20 #include <mm/core_mmu.h>
21 #include <mm/page_alloc.h>
22 #include <mm/tee_mm.h>
23 #include <mm/tee_pager.h>
24 #include <platform_config.h>
25 #include <riscv.h>
26 #include <sbi.h>
27 #include <stdalign.h>
28 #include <stdio.h>
29 #include <trace.h>
30 #include <util.h>
31 
32 #define PADDR_INVALID               ULONG_MAX
33 
34 paddr_t start_addr;
35 
36 uint32_t sem_cpu_sync[CFG_TEE_CORE_NB_CORE];
37 uint32_t hartids[CFG_TEE_CORE_NB_CORE];
38 
39 #if defined(CFG_DT)
40 static int mark_tddram_as_reserved(struct dt_descriptor *dt)
41 {
42 	return add_res_mem_dt_node(dt, "optee_core", CFG_TDDRAM_START,
43 				   CFG_TDDRAM_SIZE);
44 }
45 
46 static void update_external_dt(void)
47 {
48 	struct dt_descriptor *dt = get_external_dt_desc();
49 
50 	if (!dt || !dt->blob)
51 		return;
52 
53 #ifdef CFG_CORE_RESERVED_SHM
54 	if (mark_static_shm_as_reserved(dt))
55 		panic("Failed to config non-secure memory");
56 #endif
57 
58 	if (mark_tddram_as_reserved(dt))
59 		panic("Failed to config secure memory");
60 }
61 #else /*CFG_DT*/
62 static void update_external_dt(void)
63 {
64 }
65 #endif /*!CFG_DT*/
66 
67 #ifdef CFG_RISCV_S_MODE
68 static void start_secondary_cores(void)
69 {
70 	uint32_t curr_hartid = thread_get_core_local()->hart_id;
71 	enum sbi_hsm_hart_state status = 0;
72 	uint32_t hartid = 0;
73 	int rc = 0;
74 	int i = 0;
75 
76 	/* The primary CPU is always indexed by 0 */
77 	assert(get_core_pos() == 0);
78 
79 	for (i = 0; i < CFG_TEE_CORE_NB_CORE; i++) {
80 		hartid = hartids[i];
81 
82 		if (hartid == curr_hartid)
83 			continue;
84 
85 		rc = sbi_hsm_hart_get_status(hartid, &status);
86 		/*
87 		 * Skip if the hartid is not an assigned hart
88 		 * of the trusted domain, or its HSM state is
89 		 * not stopped.
90 		 */
91 		if (rc || status != SBI_HSM_STATE_STOPPED)
92 			continue;
93 
94 		DMSG("Bringing up secondary hart%"PRIu32, hartid);
95 
96 		rc = sbi_hsm_hart_start(hartid, start_addr, 0 /* unused */);
97 		if (rc) {
98 			EMSG("Error starting secondary hart%"PRIu32, hartid);
99 			panic();
100 		}
101 	}
102 }
103 #endif
104 
105 void init_tee_runtime(void)
106 {
107 	call_preinitcalls();
108 	call_early_initcalls();
109 	call_service_initcalls();
110 
111 	/* Reinitialize canaries around the stacks with crypto_rng_read(). */
112 	thread_update_canaries();
113 }
114 
115 static bool add_padding_to_pool(vaddr_t va, size_t len, void *ptr __unused)
116 {
117 	malloc_add_pool((void *)va, len);
118 	return true;
119 }
120 
121 static void init_primary(void)
122 {
123 	vaddr_t va __maybe_unused = 0;
124 
125 	/*
126 	 * Mask asynchronous exceptions before switch to the thread vector
127 	 * as the thread handler requires those to be masked while
128 	 * executing with the temporary stack. The thread subsystem also
129 	 * asserts that the foreign interrupts are blocked when using most of
130 	 * its functions.
131 	 */
132 	thread_set_exceptions(THREAD_EXCP_ALL);
133 
134 	malloc_add_pool(__heap1_start, __heap1_end - __heap1_start);
135 	IMSG_RAW("\n");
136 	if (IS_ENABLED(CFG_DYN_CONFIG)) {
137 		size_t sz = sizeof(struct thread_core_local) *
138 			    CFG_TEE_CORE_NB_CORE;
139 		void *p = boot_mem_alloc(sz, 2 * alignof(void *));
140 
141 		malloc_add_pool(p, sz);
142 	}
143 
144 	core_mmu_save_mem_map();
145 	core_mmu_init_phys_mem();
146 	boot_mem_foreach_padding(add_padding_to_pool, NULL);
147 	va = boot_mem_release_unused();
148 	if (IS_ENABLED(CFG_DYN_CONFIG))
149 		page_alloc_init();
150 
151 	/* Initialize canaries around the stacks */
152 	thread_init_canaries();
153 	thread_init_per_cpu();
154 }
155 
156 /* May be overridden in plat-$(PLATFORM)/main.c */
157 __weak void plat_primary_init_early(void)
158 {
159 }
160 
161 /* May be overridden in plat-$(PLATFORM)/main.c */
162 __weak void boot_primary_init_intc(void)
163 {
164 }
165 
166 /* May be overridden in plat-$(PLATFORM)/main.c */
167 __weak void boot_primary_init_core_ids(void)
168 {
169 #ifdef CFG_DT
170 	const void *fdt = get_external_dt();
171 	const fdt32_t *reg = NULL;
172 	int cpu_offset = 0;
173 	int offset = 0;
174 	int len = 0;
175 	int i = 0;
176 
177 	offset = fdt_path_offset(fdt, "/cpus");
178 	if (offset < 0)
179 		panic("Failed to find /cpus node in the device tree");
180 
181 	fdt_for_each_subnode(cpu_offset, fdt, offset) {
182 		/*
183 		 * Assume all TEE cores are enabled. The "reg"
184 		 * property in the CPU node indicates the hart ID.
185 		 */
186 		if (fdt_get_status(fdt, cpu_offset) == DT_STATUS_DISABLED)
187 			continue;
188 
189 		reg = fdt_getprop(fdt, cpu_offset, "reg", &len);
190 		if (!reg) {
191 			EMSG("CPU node does not have 'reg' property");
192 			continue;
193 		}
194 
195 		assert(i < CFG_TEE_CORE_NB_CORE);
196 		hartids[i++] = fdt32_to_cpu(*reg);
197 	}
198 
199 	assert(i == CFG_TEE_CORE_NB_CORE);
200 #endif
201 }
202 
203 /* May be overridden in plat-$(PLATFORM)/main.c */
204 __weak void boot_secondary_init_intc(void)
205 {
206 }
207 
208 void boot_init_primary_early(void)
209 {
210 	init_primary();
211 }
212 
213 void boot_init_primary_late(unsigned long fdt,
214 			    unsigned long tos_fw_config __unused)
215 {
216 	init_external_dt(fdt, CFG_DTB_MAX_SIZE);
217 	discover_nsec_memory();
218 	update_external_dt();
219 	thread_init_threads(CFG_NUM_THREADS);
220 	thread_init_boot_thread();
221 	thread_init_thread_core_local(CFG_TEE_CORE_NB_CORE);
222 }
223 
224 void __weak boot_init_primary_runtime(void)
225 {
226 	size_t pos = get_core_pos();
227 
228 	/* The primary CPU is always indexed by 0 */
229 	assert(pos == 0);
230 
231 	thread_init_primary();
232 	IMSG("OP-TEE version: %s", core_v_str);
233 	if (IS_ENABLED(CFG_INSECURE)) {
234 		IMSG("WARNING: This OP-TEE configuration might be insecure!");
235 		IMSG("WARNING: Please check https://optee.readthedocs.io/en/latest/architecture/porting_guidelines.html");
236 	}
237 	IMSG("Primary CPU0 (hart%"PRIu32") initializing",
238 	     thread_get_hartid_by_hartindex(pos));
239 	boot_primary_init_intc();
240 	boot_primary_init_core_ids();
241 	init_tee_runtime();
242 	boot_mem_release_tmp_alloc();
243 }
244 
245 void __weak boot_init_primary_final(void)
246 {
247 	size_t pos = get_core_pos();
248 
249 	call_driver_initcalls();
250 	call_finalcalls();
251 	IMSG("Primary CPU0 (hart%"PRIu32") initialized",
252 	     thread_get_hartid_by_hartindex(pos));
253 
254 #ifdef CFG_RISCV_S_MODE
255 	start_secondary_cores();
256 #endif
257 }
258 
259 static void init_secondary_helper(void)
260 {
261 	size_t pos = get_core_pos();
262 
263 	IMSG("Secondary CPU%zu (hart%"PRIu32") initializing",
264 	     pos, thread_get_hartid_by_hartindex(pos));
265 
266 	/*
267 	 * Mask asynchronous exceptions before switch to the thread vector
268 	 * as the thread handler requires those to be masked while
269 	 * executing with the temporary stack. The thread subsystem also
270 	 * asserts that the foreign interrupts are blocked when using most of
271 	 * its functions.
272 	 */
273 	thread_set_exceptions(THREAD_EXCP_ALL);
274 
275 	thread_init_per_cpu();
276 	boot_secondary_init_intc();
277 
278 	IMSG("Secondary CPU%zu (hart%"PRIu32") initialized",
279 	     pos, thread_get_hartid_by_hartindex(pos));
280 }
281 
282 void boot_init_secondary(unsigned long nsec_entry __unused)
283 {
284 	init_secondary_helper();
285 }
286