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