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