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