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