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