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