1910441c3SYu Chien Peter Lin // SPDX-License-Identifier: BSD-2-Clause 2910441c3SYu Chien Peter Lin /* 3910441c3SYu Chien Peter Lin * Copyright (c) 2015-2023, Linaro Limited 4910441c3SYu Chien Peter Lin * Copyright (c) 2023, Arm Limited 5910441c3SYu Chien Peter Lin */ 6910441c3SYu Chien Peter Lin 7c60785c4SYu-Chien Peter Lin #include <crypto/crypto.h> 8910441c3SYu Chien Peter Lin #include <kernel/boot.h> 9910441c3SYu Chien Peter Lin #include <kernel/dt.h> 10910441c3SYu Chien Peter Lin #include <libfdt.h> 11910441c3SYu Chien Peter Lin #include <mm/core_memprot.h> 12910441c3SYu Chien Peter Lin 13910441c3SYu Chien Peter Lin #ifdef CFG_CORE_DYN_SHM 14910441c3SYu Chien Peter Lin static uint64_t get_dt_val_and_advance(const void *data, size_t *offs, 15910441c3SYu Chien Peter Lin uint32_t cell_size) 16910441c3SYu Chien Peter Lin { 17910441c3SYu Chien Peter Lin uint64_t rv = 0; 18910441c3SYu Chien Peter Lin 19910441c3SYu Chien Peter Lin if (cell_size == 1) { 20910441c3SYu Chien Peter Lin uint32_t v; 21910441c3SYu Chien Peter Lin 22910441c3SYu Chien Peter Lin memcpy(&v, (const uint8_t *)data + *offs, sizeof(v)); 23910441c3SYu Chien Peter Lin *offs += sizeof(v); 24910441c3SYu Chien Peter Lin rv = fdt32_to_cpu(v); 25910441c3SYu Chien Peter Lin } else { 26910441c3SYu Chien Peter Lin uint64_t v; 27910441c3SYu Chien Peter Lin 28910441c3SYu Chien Peter Lin memcpy(&v, (const uint8_t *)data + *offs, sizeof(v)); 29910441c3SYu Chien Peter Lin *offs += sizeof(v); 30910441c3SYu Chien Peter Lin rv = fdt64_to_cpu(v); 31910441c3SYu Chien Peter Lin } 32910441c3SYu Chien Peter Lin 33910441c3SYu Chien Peter Lin return rv; 34910441c3SYu Chien Peter Lin } 35910441c3SYu Chien Peter Lin 36910441c3SYu Chien Peter Lin /* 37910441c3SYu Chien Peter Lin * Find all non-secure memory from DT. Memory marked inaccessible by Secure 38910441c3SYu Chien Peter Lin * World is ignored since it could not be mapped to be used as dynamic shared 39910441c3SYu Chien Peter Lin * memory. 40910441c3SYu Chien Peter Lin */ 41910441c3SYu Chien Peter Lin static int __maybe_unused get_nsec_memory_helper(void *fdt, struct core_mmu_phys_mem *mem) 42910441c3SYu Chien Peter Lin { 43910441c3SYu Chien Peter Lin const uint8_t *prop = NULL; 44910441c3SYu Chien Peter Lin uint64_t a = 0; 45910441c3SYu Chien Peter Lin uint64_t l = 0; 46910441c3SYu Chien Peter Lin size_t prop_offs = 0; 47910441c3SYu Chien Peter Lin size_t prop_len = 0; 48910441c3SYu Chien Peter Lin int elems_total = 0; 49910441c3SYu Chien Peter Lin int addr_size = 0; 50910441c3SYu Chien Peter Lin int len_size = 0; 51910441c3SYu Chien Peter Lin int offs = 0; 52910441c3SYu Chien Peter Lin size_t n = 0; 53910441c3SYu Chien Peter Lin int len = 0; 54910441c3SYu Chien Peter Lin 55910441c3SYu Chien Peter Lin addr_size = fdt_address_cells(fdt, 0); 56910441c3SYu Chien Peter Lin if (addr_size < 0) 57910441c3SYu Chien Peter Lin return 0; 58910441c3SYu Chien Peter Lin 59910441c3SYu Chien Peter Lin len_size = fdt_size_cells(fdt, 0); 60910441c3SYu Chien Peter Lin if (len_size < 0) 61910441c3SYu Chien Peter Lin return 0; 62910441c3SYu Chien Peter Lin 63910441c3SYu Chien Peter Lin while (true) { 64910441c3SYu Chien Peter Lin offs = fdt_node_offset_by_prop_value(fdt, offs, "device_type", 65910441c3SYu Chien Peter Lin "memory", 66910441c3SYu Chien Peter Lin sizeof("memory")); 67910441c3SYu Chien Peter Lin if (offs < 0) 68910441c3SYu Chien Peter Lin break; 69910441c3SYu Chien Peter Lin 70910441c3SYu Chien Peter Lin if (fdt_get_status(fdt, offs) != (DT_STATUS_OK_NSEC | 71910441c3SYu Chien Peter Lin DT_STATUS_OK_SEC)) 72910441c3SYu Chien Peter Lin continue; 73910441c3SYu Chien Peter Lin 74910441c3SYu Chien Peter Lin prop = fdt_getprop(fdt, offs, "reg", &len); 75910441c3SYu Chien Peter Lin if (!prop) 76910441c3SYu Chien Peter Lin continue; 77910441c3SYu Chien Peter Lin 78910441c3SYu Chien Peter Lin prop_len = len; 79910441c3SYu Chien Peter Lin for (n = 0, prop_offs = 0; prop_offs < prop_len; n++) { 80910441c3SYu Chien Peter Lin a = get_dt_val_and_advance(prop, &prop_offs, addr_size); 81910441c3SYu Chien Peter Lin if (prop_offs >= prop_len) { 82910441c3SYu Chien Peter Lin n--; 83910441c3SYu Chien Peter Lin break; 84910441c3SYu Chien Peter Lin } 85910441c3SYu Chien Peter Lin 86910441c3SYu Chien Peter Lin l = get_dt_val_and_advance(prop, &prop_offs, len_size); 87910441c3SYu Chien Peter Lin if (mem) { 88910441c3SYu Chien Peter Lin mem->type = MEM_AREA_DDR_OVERALL; 89910441c3SYu Chien Peter Lin mem->addr = a; 90910441c3SYu Chien Peter Lin mem->size = l; 91910441c3SYu Chien Peter Lin mem++; 92910441c3SYu Chien Peter Lin } 93910441c3SYu Chien Peter Lin } 94910441c3SYu Chien Peter Lin 95910441c3SYu Chien Peter Lin elems_total += n; 96910441c3SYu Chien Peter Lin } 97910441c3SYu Chien Peter Lin 98910441c3SYu Chien Peter Lin return elems_total; 99910441c3SYu Chien Peter Lin } 100910441c3SYu Chien Peter Lin 101910441c3SYu Chien Peter Lin #ifdef CFG_DT 102910441c3SYu Chien Peter Lin static struct core_mmu_phys_mem *get_nsec_memory(void *fdt, size_t *nelems) 103910441c3SYu Chien Peter Lin { 104910441c3SYu Chien Peter Lin struct core_mmu_phys_mem *mem = NULL; 105910441c3SYu Chien Peter Lin int elems_total = 0; 106910441c3SYu Chien Peter Lin 107910441c3SYu Chien Peter Lin elems_total = get_nsec_memory_helper(fdt, NULL); 108910441c3SYu Chien Peter Lin if (elems_total <= 0) 109910441c3SYu Chien Peter Lin return NULL; 110910441c3SYu Chien Peter Lin 111910441c3SYu Chien Peter Lin mem = nex_calloc(elems_total, sizeof(*mem)); 112910441c3SYu Chien Peter Lin if (!mem) 113910441c3SYu Chien Peter Lin panic(); 114910441c3SYu Chien Peter Lin 115910441c3SYu Chien Peter Lin elems_total = get_nsec_memory_helper(fdt, mem); 116910441c3SYu Chien Peter Lin assert(elems_total > 0); 117910441c3SYu Chien Peter Lin 118910441c3SYu Chien Peter Lin *nelems = elems_total; 119910441c3SYu Chien Peter Lin 120910441c3SYu Chien Peter Lin return mem; 121910441c3SYu Chien Peter Lin } 122910441c3SYu Chien Peter Lin #else /*CFG_DT*/ 123910441c3SYu Chien Peter Lin static struct core_mmu_phys_mem *get_nsec_memory(void *fdt __unused, 124910441c3SYu Chien Peter Lin size_t *nelems __unused) 125910441c3SYu Chien Peter Lin { 126910441c3SYu Chien Peter Lin return NULL; 127910441c3SYu Chien Peter Lin } 128910441c3SYu Chien Peter Lin #endif /*!CFG_DT*/ 129910441c3SYu Chien Peter Lin 130910441c3SYu Chien Peter Lin void discover_nsec_memory(void) 131910441c3SYu Chien Peter Lin { 132910441c3SYu Chien Peter Lin struct core_mmu_phys_mem *mem; 133910441c3SYu Chien Peter Lin const struct core_mmu_phys_mem *mem_begin = NULL; 134910441c3SYu Chien Peter Lin const struct core_mmu_phys_mem *mem_end = NULL; 135910441c3SYu Chien Peter Lin size_t nelems; 136910441c3SYu Chien Peter Lin void *fdt = get_external_dt(); 137910441c3SYu Chien Peter Lin 138910441c3SYu Chien Peter Lin if (fdt) { 139910441c3SYu Chien Peter Lin mem = get_nsec_memory(fdt, &nelems); 140910441c3SYu Chien Peter Lin if (mem) { 141910441c3SYu Chien Peter Lin core_mmu_set_discovered_nsec_ddr(mem, nelems); 142910441c3SYu Chien Peter Lin return; 143910441c3SYu Chien Peter Lin } 144910441c3SYu Chien Peter Lin 145*5011b395SEtienne Carriere DMSG("No non-secure memory found in external DT"); 146*5011b395SEtienne Carriere } 147*5011b395SEtienne Carriere 148*5011b395SEtienne Carriere fdt = get_embedded_dt(); 149*5011b395SEtienne Carriere if (fdt) { 150*5011b395SEtienne Carriere mem = get_nsec_memory(fdt, &nelems); 151*5011b395SEtienne Carriere if (mem) { 152*5011b395SEtienne Carriere core_mmu_set_discovered_nsec_ddr(mem, nelems); 153*5011b395SEtienne Carriere return; 154*5011b395SEtienne Carriere } 155*5011b395SEtienne Carriere 156*5011b395SEtienne Carriere DMSG("No non-secure memory found in embedded DT"); 157910441c3SYu Chien Peter Lin } 158910441c3SYu Chien Peter Lin 159910441c3SYu Chien Peter Lin mem_begin = phys_ddr_overall_begin; 160910441c3SYu Chien Peter Lin mem_end = phys_ddr_overall_end; 161910441c3SYu Chien Peter Lin nelems = mem_end - mem_begin; 162910441c3SYu Chien Peter Lin if (nelems) { 163910441c3SYu Chien Peter Lin /* 164910441c3SYu Chien Peter Lin * Platform cannot use both register_ddr() and the now 165910441c3SYu Chien Peter Lin * deprecated register_dynamic_shm(). 166910441c3SYu Chien Peter Lin */ 167910441c3SYu Chien Peter Lin assert(phys_ddr_overall_compat_begin == 168910441c3SYu Chien Peter Lin phys_ddr_overall_compat_end); 169910441c3SYu Chien Peter Lin } else { 170910441c3SYu Chien Peter Lin mem_begin = phys_ddr_overall_compat_begin; 171910441c3SYu Chien Peter Lin mem_end = phys_ddr_overall_compat_end; 172910441c3SYu Chien Peter Lin nelems = mem_end - mem_begin; 173910441c3SYu Chien Peter Lin if (!nelems) 174910441c3SYu Chien Peter Lin return; 175910441c3SYu Chien Peter Lin DMSG("Warning register_dynamic_shm() is deprecated, " 176910441c3SYu Chien Peter Lin "please use register_ddr() instead"); 177910441c3SYu Chien Peter Lin } 178910441c3SYu Chien Peter Lin 179910441c3SYu Chien Peter Lin mem = nex_calloc(nelems, sizeof(*mem)); 180910441c3SYu Chien Peter Lin if (!mem) 181910441c3SYu Chien Peter Lin panic(); 182910441c3SYu Chien Peter Lin 183910441c3SYu Chien Peter Lin memcpy(mem, phys_ddr_overall_begin, sizeof(*mem) * nelems); 184910441c3SYu Chien Peter Lin core_mmu_set_discovered_nsec_ddr(mem, nelems); 185910441c3SYu Chien Peter Lin } 186910441c3SYu Chien Peter Lin #else /*CFG_CORE_DYN_SHM*/ 187910441c3SYu Chien Peter Lin void discover_nsec_memory(void) 188910441c3SYu Chien Peter Lin { 189910441c3SYu Chien Peter Lin } 190910441c3SYu Chien Peter Lin #endif /*!CFG_CORE_DYN_SHM*/ 191910441c3SYu Chien Peter Lin 192910441c3SYu Chien Peter Lin #ifdef CFG_CORE_RESERVED_SHM 193910441c3SYu Chien Peter Lin int mark_static_shm_as_reserved(struct dt_descriptor *dt) 194910441c3SYu Chien Peter Lin { 195910441c3SYu Chien Peter Lin vaddr_t shm_start; 196910441c3SYu Chien Peter Lin vaddr_t shm_end; 197910441c3SYu Chien Peter Lin 198910441c3SYu Chien Peter Lin core_mmu_get_mem_by_type(MEM_AREA_NSEC_SHM, &shm_start, &shm_end); 199910441c3SYu Chien Peter Lin if (shm_start != shm_end) 200910441c3SYu Chien Peter Lin return add_res_mem_dt_node(dt, "optee_shm", 201910441c3SYu Chien Peter Lin virt_to_phys((void *)shm_start), 202910441c3SYu Chien Peter Lin shm_end - shm_start); 203910441c3SYu Chien Peter Lin 204910441c3SYu Chien Peter Lin DMSG("No SHM configured"); 205910441c3SYu Chien Peter Lin return -1; 206910441c3SYu Chien Peter Lin } 207910441c3SYu Chien Peter Lin #endif /*CFG_CORE_RESERVED_SHM*/ 208c60785c4SYu-Chien Peter Lin 209c60785c4SYu-Chien Peter Lin #if defined(_CFG_CORE_STACK_PROTECTOR) || defined(CFG_WITH_STACK_CANARIES) 210c60785c4SYu-Chien Peter Lin /* Generate random stack canary value on boot up */ 211c60785c4SYu-Chien Peter Lin __weak void plat_get_random_stack_canaries(void *buf, size_t ncan, size_t size) 212c60785c4SYu-Chien Peter Lin { 213c60785c4SYu-Chien Peter Lin TEE_Result ret = TEE_ERROR_GENERIC; 214c60785c4SYu-Chien Peter Lin size_t i = 0; 215c60785c4SYu-Chien Peter Lin 216c60785c4SYu-Chien Peter Lin assert(buf && ncan && size); 217c60785c4SYu-Chien Peter Lin 218c60785c4SYu-Chien Peter Lin /* 219c60785c4SYu-Chien Peter Lin * With virtualization the RNG is not initialized in Nexus core. 220c60785c4SYu-Chien Peter Lin * Need to override with platform specific implementation. 221c60785c4SYu-Chien Peter Lin */ 222c60785c4SYu-Chien Peter Lin if (IS_ENABLED(CFG_NS_VIRTUALIZATION)) { 223c60785c4SYu-Chien Peter Lin IMSG("WARNING: Using fixed value for stack canary"); 224c60785c4SYu-Chien Peter Lin memset(buf, 0xab, ncan * size); 225c60785c4SYu-Chien Peter Lin goto out; 226c60785c4SYu-Chien Peter Lin } 227c60785c4SYu-Chien Peter Lin 228c60785c4SYu-Chien Peter Lin ret = crypto_rng_read(buf, ncan * size); 229c60785c4SYu-Chien Peter Lin if (ret != TEE_SUCCESS) 230c60785c4SYu-Chien Peter Lin panic("Failed to generate random stack canary"); 231c60785c4SYu-Chien Peter Lin 232c60785c4SYu-Chien Peter Lin out: 233c60785c4SYu-Chien Peter Lin /* Leave null byte in canary to prevent string base exploit */ 234c60785c4SYu-Chien Peter Lin for (i = 0; i < ncan; i++) 235c60785c4SYu-Chien Peter Lin *((uint8_t *)buf + size * i) = 0; 236c60785c4SYu-Chien Peter Lin } 237c60785c4SYu-Chien Peter Lin #endif /* _CFG_CORE_STACK_PROTECTOR || CFG_WITH_STACK_CANARIES */ 238