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
get_dt_val_and_advance(const void * data,size_t * offs,uint32_t cell_size)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 */
get_nsec_memory_helper(void * fdt,struct core_mmu_phys_mem * mem,const char * dev_type)41*379ad407SJens Wiklander static int __maybe_unused get_nsec_memory_helper(void *fdt,
42*379ad407SJens Wiklander struct core_mmu_phys_mem *mem,
43*379ad407SJens Wiklander const char *dev_type)
44910441c3SYu Chien Peter Lin {
45*379ad407SJens Wiklander size_t dev_type_size = strlen(dev_type) + 1;
46910441c3SYu Chien Peter Lin const uint8_t *prop = NULL;
47910441c3SYu Chien Peter Lin uint64_t a = 0;
48910441c3SYu Chien Peter Lin uint64_t l = 0;
49910441c3SYu Chien Peter Lin size_t prop_offs = 0;
50910441c3SYu Chien Peter Lin size_t prop_len = 0;
51910441c3SYu Chien Peter Lin int elems_total = 0;
52910441c3SYu Chien Peter Lin int addr_size = 0;
53910441c3SYu Chien Peter Lin int len_size = 0;
54910441c3SYu Chien Peter Lin int offs = 0;
55910441c3SYu Chien Peter Lin size_t n = 0;
56910441c3SYu Chien Peter Lin int len = 0;
57910441c3SYu Chien Peter Lin
58910441c3SYu Chien Peter Lin addr_size = fdt_address_cells(fdt, 0);
59910441c3SYu Chien Peter Lin if (addr_size < 0)
60910441c3SYu Chien Peter Lin return 0;
61910441c3SYu Chien Peter Lin
62910441c3SYu Chien Peter Lin len_size = fdt_size_cells(fdt, 0);
63910441c3SYu Chien Peter Lin if (len_size < 0)
64910441c3SYu Chien Peter Lin return 0;
65910441c3SYu Chien Peter Lin
66910441c3SYu Chien Peter Lin while (true) {
67910441c3SYu Chien Peter Lin offs = fdt_node_offset_by_prop_value(fdt, offs, "device_type",
68*379ad407SJens Wiklander dev_type, dev_type_size);
69910441c3SYu Chien Peter Lin if (offs < 0)
70910441c3SYu Chien Peter Lin break;
71910441c3SYu Chien Peter Lin
72910441c3SYu Chien Peter Lin if (fdt_get_status(fdt, offs) != (DT_STATUS_OK_NSEC |
73910441c3SYu Chien Peter Lin DT_STATUS_OK_SEC))
74910441c3SYu Chien Peter Lin continue;
75910441c3SYu Chien Peter Lin
76910441c3SYu Chien Peter Lin prop = fdt_getprop(fdt, offs, "reg", &len);
77910441c3SYu Chien Peter Lin if (!prop)
78910441c3SYu Chien Peter Lin continue;
79910441c3SYu Chien Peter Lin
80910441c3SYu Chien Peter Lin prop_len = len;
81910441c3SYu Chien Peter Lin for (n = 0, prop_offs = 0; prop_offs < prop_len; n++) {
82910441c3SYu Chien Peter Lin a = get_dt_val_and_advance(prop, &prop_offs, addr_size);
83910441c3SYu Chien Peter Lin if (prop_offs >= prop_len) {
84910441c3SYu Chien Peter Lin n--;
85910441c3SYu Chien Peter Lin break;
86910441c3SYu Chien Peter Lin }
87910441c3SYu Chien Peter Lin
88910441c3SYu Chien Peter Lin l = get_dt_val_and_advance(prop, &prop_offs, len_size);
89910441c3SYu Chien Peter Lin if (mem) {
90910441c3SYu Chien Peter Lin mem->type = MEM_AREA_DDR_OVERALL;
91910441c3SYu Chien Peter Lin mem->addr = a;
92910441c3SYu Chien Peter Lin mem->size = l;
93910441c3SYu Chien Peter Lin mem++;
94910441c3SYu Chien Peter Lin }
95910441c3SYu Chien Peter Lin }
96910441c3SYu Chien Peter Lin
97910441c3SYu Chien Peter Lin elems_total += n;
98910441c3SYu Chien Peter Lin }
99910441c3SYu Chien Peter Lin
100910441c3SYu Chien Peter Lin return elems_total;
101910441c3SYu Chien Peter Lin }
102910441c3SYu Chien Peter Lin
103910441c3SYu Chien Peter Lin #ifdef CFG_DT
get_nsec_memory(void * fdt,size_t * nelems,const char * dev_type)104*379ad407SJens Wiklander static struct core_mmu_phys_mem *get_nsec_memory(void *fdt, size_t *nelems,
105*379ad407SJens Wiklander const char *dev_type)
106910441c3SYu Chien Peter Lin {
107910441c3SYu Chien Peter Lin struct core_mmu_phys_mem *mem = NULL;
108910441c3SYu Chien Peter Lin int elems_total = 0;
109910441c3SYu Chien Peter Lin
110*379ad407SJens Wiklander elems_total = get_nsec_memory_helper(fdt, NULL, dev_type);
111910441c3SYu Chien Peter Lin if (elems_total <= 0)
112910441c3SYu Chien Peter Lin return NULL;
113910441c3SYu Chien Peter Lin
114910441c3SYu Chien Peter Lin mem = nex_calloc(elems_total, sizeof(*mem));
115910441c3SYu Chien Peter Lin if (!mem)
116910441c3SYu Chien Peter Lin panic();
117910441c3SYu Chien Peter Lin
118*379ad407SJens Wiklander elems_total = get_nsec_memory_helper(fdt, mem, dev_type);
119910441c3SYu Chien Peter Lin assert(elems_total > 0);
120910441c3SYu Chien Peter Lin
121910441c3SYu Chien Peter Lin *nelems = elems_total;
122910441c3SYu Chien Peter Lin
123910441c3SYu Chien Peter Lin return mem;
124910441c3SYu Chien Peter Lin }
125910441c3SYu Chien Peter Lin #else /*CFG_DT*/
get_nsec_memory(void * fdt __unused,size_t * nelems __unused,const char * dev_type __unused)126910441c3SYu Chien Peter Lin static struct core_mmu_phys_mem *get_nsec_memory(void *fdt __unused,
127*379ad407SJens Wiklander size_t *nelems __unused,
128*379ad407SJens Wiklander const char *dev_type __unused)
129910441c3SYu Chien Peter Lin {
130910441c3SYu Chien Peter Lin return NULL;
131910441c3SYu Chien Peter Lin }
132910441c3SYu Chien Peter Lin #endif /*!CFG_DT*/
133910441c3SYu Chien Peter Lin
discover_nsec_memory(void)134910441c3SYu Chien Peter Lin void discover_nsec_memory(void)
135910441c3SYu Chien Peter Lin {
136*379ad407SJens Wiklander struct core_mmu_phys_mem *mem = NULL;
137910441c3SYu Chien Peter Lin const struct core_mmu_phys_mem *mem_begin = NULL;
138910441c3SYu Chien Peter Lin const struct core_mmu_phys_mem *mem_end = NULL;
139*379ad407SJens Wiklander size_t nelems = 0;
140*379ad407SJens Wiklander void *fdt = NULL;
141910441c3SYu Chien Peter Lin
142*379ad407SJens Wiklander fdt = get_manifest_dt();
143910441c3SYu Chien Peter Lin if (fdt) {
144*379ad407SJens Wiklander mem = get_nsec_memory(fdt, &nelems, "ns-memory");
145910441c3SYu Chien Peter Lin if (mem) {
146*379ad407SJens Wiklander DMSG("Non-secure memory found in manifest DT");
147*379ad407SJens Wiklander core_mmu_set_discovered_nsec_ddr(mem, nelems);
148*379ad407SJens Wiklander return;
149*379ad407SJens Wiklander }
150*379ad407SJens Wiklander
151*379ad407SJens Wiklander DMSG("No non-secure memory found in manifest DT");
152*379ad407SJens Wiklander }
153*379ad407SJens Wiklander
154*379ad407SJens Wiklander fdt = get_external_dt();
155*379ad407SJens Wiklander if (fdt) {
156*379ad407SJens Wiklander mem = get_nsec_memory(fdt, &nelems, "memory");
157*379ad407SJens Wiklander if (mem) {
158*379ad407SJens Wiklander DMSG("Non-secure memory found in extern DT");
159910441c3SYu Chien Peter Lin core_mmu_set_discovered_nsec_ddr(mem, nelems);
160910441c3SYu Chien Peter Lin return;
161910441c3SYu Chien Peter Lin }
162910441c3SYu Chien Peter Lin
1635011b395SEtienne Carriere DMSG("No non-secure memory found in external DT");
1645011b395SEtienne Carriere }
1655011b395SEtienne Carriere
1665011b395SEtienne Carriere fdt = get_embedded_dt();
1675011b395SEtienne Carriere if (fdt) {
168*379ad407SJens Wiklander mem = get_nsec_memory(fdt, &nelems, "memory");
1695011b395SEtienne Carriere if (mem) {
170*379ad407SJens Wiklander DMSG("Non-secure memory found in embedded DT");
1715011b395SEtienne Carriere core_mmu_set_discovered_nsec_ddr(mem, nelems);
1725011b395SEtienne Carriere return;
1735011b395SEtienne Carriere }
1745011b395SEtienne Carriere
1755011b395SEtienne Carriere DMSG("No non-secure memory found in embedded DT");
176910441c3SYu Chien Peter Lin }
177910441c3SYu Chien Peter Lin
178910441c3SYu Chien Peter Lin mem_begin = phys_ddr_overall_begin;
179910441c3SYu Chien Peter Lin mem_end = phys_ddr_overall_end;
180910441c3SYu Chien Peter Lin nelems = mem_end - mem_begin;
181910441c3SYu Chien Peter Lin if (nelems) {
182910441c3SYu Chien Peter Lin /*
183910441c3SYu Chien Peter Lin * Platform cannot use both register_ddr() and the now
184910441c3SYu Chien Peter Lin * deprecated register_dynamic_shm().
185910441c3SYu Chien Peter Lin */
186910441c3SYu Chien Peter Lin assert(phys_ddr_overall_compat_begin ==
187910441c3SYu Chien Peter Lin phys_ddr_overall_compat_end);
188910441c3SYu Chien Peter Lin } else {
189910441c3SYu Chien Peter Lin mem_begin = phys_ddr_overall_compat_begin;
190910441c3SYu Chien Peter Lin mem_end = phys_ddr_overall_compat_end;
191910441c3SYu Chien Peter Lin nelems = mem_end - mem_begin;
192910441c3SYu Chien Peter Lin if (!nelems)
193910441c3SYu Chien Peter Lin return;
194910441c3SYu Chien Peter Lin DMSG("Warning register_dynamic_shm() is deprecated, "
195910441c3SYu Chien Peter Lin "please use register_ddr() instead");
196910441c3SYu Chien Peter Lin }
197910441c3SYu Chien Peter Lin
198910441c3SYu Chien Peter Lin mem = nex_calloc(nelems, sizeof(*mem));
199910441c3SYu Chien Peter Lin if (!mem)
200910441c3SYu Chien Peter Lin panic();
201910441c3SYu Chien Peter Lin
202910441c3SYu Chien Peter Lin memcpy(mem, phys_ddr_overall_begin, sizeof(*mem) * nelems);
203910441c3SYu Chien Peter Lin core_mmu_set_discovered_nsec_ddr(mem, nelems);
204910441c3SYu Chien Peter Lin }
205910441c3SYu Chien Peter Lin #else /*CFG_CORE_DYN_SHM*/
discover_nsec_memory(void)206910441c3SYu Chien Peter Lin void discover_nsec_memory(void)
207910441c3SYu Chien Peter Lin {
208910441c3SYu Chien Peter Lin }
209910441c3SYu Chien Peter Lin #endif /*!CFG_CORE_DYN_SHM*/
210910441c3SYu Chien Peter Lin
211910441c3SYu Chien Peter Lin #ifdef CFG_CORE_RESERVED_SHM
mark_static_shm_as_reserved(struct dt_descriptor * dt)212910441c3SYu Chien Peter Lin int mark_static_shm_as_reserved(struct dt_descriptor *dt)
213910441c3SYu Chien Peter Lin {
214910441c3SYu Chien Peter Lin vaddr_t shm_start;
215910441c3SYu Chien Peter Lin vaddr_t shm_end;
216910441c3SYu Chien Peter Lin
217910441c3SYu Chien Peter Lin core_mmu_get_mem_by_type(MEM_AREA_NSEC_SHM, &shm_start, &shm_end);
218910441c3SYu Chien Peter Lin if (shm_start != shm_end)
219910441c3SYu Chien Peter Lin return add_res_mem_dt_node(dt, "optee_shm",
220910441c3SYu Chien Peter Lin virt_to_phys((void *)shm_start),
221910441c3SYu Chien Peter Lin shm_end - shm_start);
222910441c3SYu Chien Peter Lin
223910441c3SYu Chien Peter Lin DMSG("No SHM configured");
224910441c3SYu Chien Peter Lin return -1;
225910441c3SYu Chien Peter Lin }
226910441c3SYu Chien Peter Lin #endif /*CFG_CORE_RESERVED_SHM*/
227c60785c4SYu-Chien Peter Lin
228c60785c4SYu-Chien Peter Lin #if defined(_CFG_CORE_STACK_PROTECTOR) || defined(CFG_WITH_STACK_CANARIES)
229c60785c4SYu-Chien Peter Lin /* Generate random stack canary value on boot up */
plat_get_random_stack_canaries(void * buf,size_t ncan,size_t size)230c60785c4SYu-Chien Peter Lin __weak void plat_get_random_stack_canaries(void *buf, size_t ncan, size_t size)
231c60785c4SYu-Chien Peter Lin {
232c60785c4SYu-Chien Peter Lin TEE_Result ret = TEE_ERROR_GENERIC;
233c60785c4SYu-Chien Peter Lin size_t i = 0;
234c60785c4SYu-Chien Peter Lin
235c60785c4SYu-Chien Peter Lin assert(buf && ncan && size);
236c60785c4SYu-Chien Peter Lin
237c60785c4SYu-Chien Peter Lin /*
238c60785c4SYu-Chien Peter Lin * With virtualization the RNG is not initialized in Nexus core.
239c60785c4SYu-Chien Peter Lin * Need to override with platform specific implementation.
240c60785c4SYu-Chien Peter Lin */
241c60785c4SYu-Chien Peter Lin if (IS_ENABLED(CFG_NS_VIRTUALIZATION)) {
242c60785c4SYu-Chien Peter Lin IMSG("WARNING: Using fixed value for stack canary");
243c60785c4SYu-Chien Peter Lin memset(buf, 0xab, ncan * size);
244c60785c4SYu-Chien Peter Lin goto out;
245c60785c4SYu-Chien Peter Lin }
246c60785c4SYu-Chien Peter Lin
247c60785c4SYu-Chien Peter Lin ret = crypto_rng_read(buf, ncan * size);
248c60785c4SYu-Chien Peter Lin if (ret != TEE_SUCCESS)
249c60785c4SYu-Chien Peter Lin panic("Failed to generate random stack canary");
250c60785c4SYu-Chien Peter Lin
251c60785c4SYu-Chien Peter Lin out:
252c60785c4SYu-Chien Peter Lin /* Leave null byte in canary to prevent string base exploit */
253c60785c4SYu-Chien Peter Lin for (i = 0; i < ncan; i++)
254c60785c4SYu-Chien Peter Lin *((uint8_t *)buf + size * i) = 0;
255c60785c4SYu-Chien Peter Lin }
256c60785c4SYu-Chien Peter Lin #endif /* _CFG_CORE_STACK_PROTECTOR || CFG_WITH_STACK_CANARIES */
257