1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2015-2023, Linaro Limited
4  * Copyright (c) 2023, Arm Limited
5  */
6 
7 #include <kernel/boot.h>
8 #include <kernel/dt.h>
9 #include <libfdt.h>
10 #include <mm/core_memprot.h>
11 
12 #ifdef CFG_CORE_DYN_SHM
get_dt_val_and_advance(const void * data,size_t * offs,uint32_t cell_size)13 static uint64_t get_dt_val_and_advance(const void *data, size_t *offs,
14 				       uint32_t cell_size)
15 {
16 	uint64_t rv = 0;
17 
18 	if (cell_size == 1) {
19 		uint32_t v;
20 
21 		memcpy(&v, (const uint8_t *)data + *offs, sizeof(v));
22 		*offs += sizeof(v);
23 		rv = fdt32_to_cpu(v);
24 	} else {
25 		uint64_t v;
26 
27 		memcpy(&v, (const uint8_t *)data + *offs, sizeof(v));
28 		*offs += sizeof(v);
29 		rv = fdt64_to_cpu(v);
30 	}
31 
32 	return rv;
33 }
34 
35 /*
36  * Find all non-secure memory from DT. Memory marked inaccessible by Secure
37  * World is ignored since it could not be mapped to be used as dynamic shared
38  * memory.
39  */
get_nsec_memory_helper(void * fdt,struct core_mmu_phys_mem * mem)40 static int __maybe_unused get_nsec_memory_helper(void *fdt, struct core_mmu_phys_mem *mem)
41 {
42 	const uint8_t *prop = NULL;
43 	uint64_t a = 0;
44 	uint64_t l = 0;
45 	size_t prop_offs = 0;
46 	size_t prop_len = 0;
47 	int elems_total = 0;
48 	int addr_size = 0;
49 	int len_size = 0;
50 	int offs = 0;
51 	size_t n = 0;
52 	int len = 0;
53 
54 	addr_size = fdt_address_cells(fdt, 0);
55 	if (addr_size < 0)
56 		return 0;
57 
58 	len_size = fdt_size_cells(fdt, 0);
59 	if (len_size < 0)
60 		return 0;
61 
62 	while (true) {
63 		offs = fdt_node_offset_by_prop_value(fdt, offs, "device_type",
64 						     "memory",
65 						     sizeof("memory"));
66 		if (offs < 0)
67 			break;
68 
69 		if (fdt_get_status(fdt, offs) != (DT_STATUS_OK_NSEC |
70 						   DT_STATUS_OK_SEC))
71 			continue;
72 
73 		prop = fdt_getprop(fdt, offs, "reg", &len);
74 		if (!prop)
75 			continue;
76 
77 		prop_len = len;
78 		for (n = 0, prop_offs = 0; prop_offs < prop_len; n++) {
79 			a = get_dt_val_and_advance(prop, &prop_offs, addr_size);
80 			if (prop_offs >= prop_len) {
81 				n--;
82 				break;
83 			}
84 
85 			l = get_dt_val_and_advance(prop, &prop_offs, len_size);
86 			if (mem) {
87 				mem->type = MEM_AREA_DDR_OVERALL;
88 				mem->addr = a;
89 				mem->size = l;
90 				mem++;
91 			}
92 		}
93 
94 		elems_total += n;
95 	}
96 
97 	return elems_total;
98 }
99 
100 #ifdef CFG_DT
get_nsec_memory(void * fdt,size_t * nelems)101 static struct core_mmu_phys_mem *get_nsec_memory(void *fdt, size_t *nelems)
102 {
103 	struct core_mmu_phys_mem *mem = NULL;
104 	int elems_total = 0;
105 
106 	elems_total = get_nsec_memory_helper(fdt, NULL);
107 	if (elems_total <= 0)
108 		return NULL;
109 
110 	mem = nex_calloc(elems_total, sizeof(*mem));
111 	if (!mem)
112 		panic();
113 
114 	elems_total = get_nsec_memory_helper(fdt, mem);
115 	assert(elems_total > 0);
116 
117 	*nelems = elems_total;
118 
119 	return mem;
120 }
121 #else /*CFG_DT*/
get_nsec_memory(void * fdt __unused,size_t * nelems __unused)122 static struct core_mmu_phys_mem *get_nsec_memory(void *fdt __unused,
123 						 size_t *nelems __unused)
124 {
125 	return NULL;
126 }
127 #endif /*!CFG_DT*/
128 
discover_nsec_memory(void)129 void discover_nsec_memory(void)
130 {
131 	struct core_mmu_phys_mem *mem;
132 	const struct core_mmu_phys_mem *mem_begin = NULL;
133 	const struct core_mmu_phys_mem *mem_end = NULL;
134 	size_t nelems;
135 	void *fdt = get_external_dt();
136 
137 	if (fdt) {
138 		mem = get_nsec_memory(fdt, &nelems);
139 		if (mem) {
140 			core_mmu_set_discovered_nsec_ddr(mem, nelems);
141 			return;
142 		}
143 
144 		DMSG("No non-secure memory found in FDT");
145 	}
146 
147 	mem_begin = phys_ddr_overall_begin;
148 	mem_end = phys_ddr_overall_end;
149 	nelems = mem_end - mem_begin;
150 	if (nelems) {
151 		/*
152 		 * Platform cannot use both register_ddr() and the now
153 		 * deprecated register_dynamic_shm().
154 		 */
155 		assert(phys_ddr_overall_compat_begin ==
156 		       phys_ddr_overall_compat_end);
157 	} else {
158 		mem_begin = phys_ddr_overall_compat_begin;
159 		mem_end = phys_ddr_overall_compat_end;
160 		nelems = mem_end - mem_begin;
161 		if (!nelems)
162 			return;
163 		DMSG("Warning register_dynamic_shm() is deprecated, "
164 		     "please use register_ddr() instead");
165 	}
166 
167 	mem = nex_calloc(nelems, sizeof(*mem));
168 	if (!mem)
169 		panic();
170 
171 	memcpy(mem, phys_ddr_overall_begin, sizeof(*mem) * nelems);
172 	core_mmu_set_discovered_nsec_ddr(mem, nelems);
173 }
174 #else /*CFG_CORE_DYN_SHM*/
discover_nsec_memory(void)175 void discover_nsec_memory(void)
176 {
177 }
178 #endif /*!CFG_CORE_DYN_SHM*/
179 
180 #ifdef CFG_CORE_RESERVED_SHM
mark_static_shm_as_reserved(struct dt_descriptor * dt)181 int mark_static_shm_as_reserved(struct dt_descriptor *dt)
182 {
183 	vaddr_t shm_start;
184 	vaddr_t shm_end;
185 
186 	core_mmu_get_mem_by_type(MEM_AREA_NSEC_SHM, &shm_start, &shm_end);
187 	if (shm_start != shm_end)
188 		return add_res_mem_dt_node(dt, "optee_shm",
189 					   virt_to_phys((void *)shm_start),
190 					   shm_end - shm_start);
191 
192 	DMSG("No SHM configured");
193 	return -1;
194 }
195 #endif /*CFG_CORE_RESERVED_SHM*/
196