xref: /optee_os/core/kernel/boot.c (revision 5011b3951cf7363d78adde6073f1189269236483)
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