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