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