1 /*
2 * SPDX-License-Identifier: BSD-3-Clause
3 * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
4 */
5
6 #include <arch_features.h>
7 #include <arch_helpers.h>
8 #include <assert.h>
9 #include <debug.h>
10 #include <rmm_el3_ifc.h>
11 #include <rmm_el3_ifc_priv.h>
12 #include <smc.h>
13 #include <stdint.h>
14 #include <string.h>
15 #include <utils_def.h>
16 #include <xlat_defs.h>
17
18 /*
19 * Local copy of the core boot manifest to be used during runtime
20 */
21 static struct rmm_core_manifest local_core_manifest;
22
23 /*
24 * Manifest status
25 */
26 static bool manifest_processed;
27
rmm_el3_ifc_process_boot_manifest(void)28 void rmm_el3_ifc_process_boot_manifest(void)
29 {
30 assert((manifest_processed == (bool)false) &&
31 (is_mmu_enabled() == (bool)false));
32
33 /*
34 * The boot manifest is expected to be on the shared area.
35 * Make a local copy of it.
36 */
37 (void)memcpy((void *)&local_core_manifest,
38 (void *)rmm_el3_ifc_get_shared_buf_pa(),
39 sizeof(struct rmm_core_manifest));
40
41 inv_dcache_range((uintptr_t)&local_core_manifest,
42 sizeof(local_core_manifest));
43
44 /*
45 * Validate the Boot Manifest Version.
46 */
47 if (!IS_RMM_EL3_MANIFEST_COMPATIBLE(local_core_manifest.version)) {
48 rmm_el3_ifc_report_fail_to_el3(
49 E_RMM_BOOT_MANIFEST_VERSION_NOT_SUPPORTED);
50 }
51
52 manifest_processed = true;
53 inv_dcache_range((uintptr_t)&manifest_processed, sizeof(bool));
54 }
55
56 /* Return the raw value of the received boot manifest */
rmm_el3_ifc_get_manifest_version(void)57 unsigned int rmm_el3_ifc_get_manifest_version(void)
58 {
59 assert(manifest_processed == (bool)true);
60
61 return local_core_manifest.version;
62 }
63
64 /* Return a pointer to the platform manifest */
65 /* coverity[misra_c_2012_rule_8_7_violation:SUPPRESS] */
rmm_el3_ifc_get_plat_manifest_pa(void)66 uintptr_t rmm_el3_ifc_get_plat_manifest_pa(void)
67 {
68 assert((manifest_processed == (bool)true) &&
69 (is_mmu_enabled() == (bool)false));
70
71 return local_core_manifest.plat_data;
72 }
73
74 /*
75 * Calculate checksum of 64-bit words @buffer with @size length
76 */
checksum_calc(uint64_t * buffer,size_t size)77 static uint64_t checksum_calc(uint64_t *buffer, size_t size)
78 {
79 uint64_t sum = 0UL;
80
81 assert(((uintptr_t)buffer & (sizeof(uint64_t) - 1UL)) == 0UL);
82 assert((size & (sizeof(uint64_t) - 1UL)) == 0UL);
83
84 for (unsigned long i = 0UL; i < (size / sizeof(uint64_t)); i++) {
85 sum += buffer[i];
86 }
87
88 return sum;
89 }
90
91 /*
92 * Return validated memory data passed in plat_memory pointer.
93 * If the function returns E_RMM_BOOT_SUCCESS, then it either returns a pointer
94 * to the platform memory info structure setup by EL3 Firmware in *memory_info
95 * or NULL if the number of memory banks specified by EL3 is 0 and the pointer
96 * to memory_bank[] array is NULL. In case of any other error, NULL is returned
97 * in *memory_info.
98 */
get_memory_data_validated_pa(unsigned long max_num_banks,struct memory_info ** memory_info,struct memory_info * plat_memory,unsigned int max_granules)99 static int get_memory_data_validated_pa(unsigned long max_num_banks,
100 struct memory_info **memory_info,
101 struct memory_info *plat_memory,
102 unsigned int max_granules)
103 {
104 uint64_t num_banks, checksum, num_granules = 0UL;
105 uintptr_t end = 0UL;
106 struct memory_bank *bank_ptr;
107
108 assert((memory_info != NULL) && (plat_memory != NULL));
109 assert(manifest_processed && !is_mmu_enabled());
110
111 /* Set pointer to the platform memory info structure to NULL */
112 *memory_info = NULL;
113
114 /* Number of banks */
115 num_banks = plat_memory->num_banks;
116
117 /* Pointer to memory_bank[] array */
118 bank_ptr = plat_memory->banks;
119
120 /*
121 * Return *memory_info set to NULL if number of banks is 0 and all other
122 * fields are valid. This is expected only for device address ranges.
123 */
124 if ((num_banks == 0UL) && (bank_ptr == NULL) &&
125 (plat_memory->checksum == 0UL)) {
126 VERBOSE(" None\n");
127 return E_RMM_BOOT_SUCCESS;
128 }
129
130 /* Validate number of banks and pointer to banks[] */
131 if ((num_banks == 0UL) || (num_banks > max_num_banks) ||
132 (bank_ptr == NULL)) {
133 return E_RMM_BOOT_MANIFEST_DATA_ERROR;
134 }
135
136 /* Calculate checksum of memory_info structure */
137 checksum = num_banks + (uint64_t)bank_ptr + plat_memory->checksum;
138
139 for (unsigned long i = 0UL; i < num_banks; i++) {
140 uint64_t size = bank_ptr->size;
141 uintptr_t start = bank_ptr->base;
142 uintptr_t max_pa_size =
143 (uintptr_t)(1ULL << arch_feat_get_pa_width());
144
145 /* Base address, size of bank and alignments */
146 if ((start == 0UL) || (size == 0UL) ||
147 (((start | size) & PAGE_SIZE_MASK) != 0UL)) {
148 return E_RMM_BOOT_MANIFEST_DATA_ERROR;
149 }
150
151 /*
152 * Check that base addresses of DRAM banks are
153 * passed in ascending order without overlapping.
154 */
155 if (start < end) {
156 return E_RMM_BOOT_MANIFEST_DATA_ERROR;
157 }
158
159 /* Update end address of the bank */
160 end = start + size - 1UL;
161
162 /*
163 * Check that the bank does not exceed the PA range
164 * supported by the platform.
165 */
166 if (end >= max_pa_size) {
167 return E_RMM_BOOT_MANIFEST_DATA_ERROR;
168 }
169
170 /* Total number of granules */
171 num_granules += (size / GRANULE_SIZE);
172
173 VERBOSE(" 0x%lx-0x%lx\n", start, end);
174
175 bank_ptr++;
176 }
177
178 /* Update checksum */
179 assert(plat_memory->banks != NULL);
180 checksum += checksum_calc((uint64_t *)plat_memory->banks,
181 sizeof(struct memory_bank) * num_banks);
182
183 /* Checksum must be 0 */
184 if (checksum != 0UL) {
185 return E_RMM_BOOT_MANIFEST_DATA_ERROR;
186 }
187
188 /* Check for the maximum number of granules supported */
189 if (num_granules > max_granules) {
190 ERROR("Number of granules %lu exceeds maximum of %u\n",
191 num_granules, max_granules);
192 return E_RMM_BOOT_MANIFEST_DATA_ERROR;
193 }
194
195 *memory_info = plat_memory;
196 return E_RMM_BOOT_SUCCESS;
197 }
198
199 /*
200 * Return validated DRAM data passed in plat_dram pointer.
201 * Return a pointer to the platform DRAM info structure setup by EL3 Firmware
202 * or NULL in case of an error.
203 */
rmm_el3_ifc_get_dram_data_validated_pa(unsigned long max_num_banks,struct memory_info ** plat_dram_info)204 int rmm_el3_ifc_get_dram_data_validated_pa(unsigned long max_num_banks,
205 struct memory_info **plat_dram_info)
206 {
207 int ret;
208
209 assert(plat_dram_info != NULL);
210
211 /*
212 * Validate the Boot Manifest Version
213 */
214 if (local_core_manifest.version <
215 RMM_EL3_MANIFEST_MAKE_VERSION(U(0), U(2))) {
216 return E_RMM_BOOT_MANIFEST_VERSION_NOT_SUPPORTED;
217 }
218
219 VERBOSE("DRAM:\n");
220
221 ret = get_memory_data_validated_pa(max_num_banks, plat_dram_info,
222 &local_core_manifest.plat_dram,
223 RMM_MAX_GRANULES);
224 if (ret != E_RMM_BOOT_SUCCESS) {
225 return ret;
226 }
227
228 /* No DRAM data */
229 if (*plat_dram_info == NULL) {
230 return E_RMM_BOOT_MANIFEST_DATA_ERROR;
231 }
232
233 return E_RMM_BOOT_SUCCESS;
234 }
235
236 /*
237 * Return validated device address ranges data passed in plat_dev_range_info
238 * pointer type.
239 * In case of E_RMM_BOOT_SUCCESS, return a pointer to the platform device
240 * address ranges info structure setup by EL3 Firmware or NULL if the number
241 * of memory banks specified by EL3 is 0 and the pointer to memory_bank[] array
242 * is NULL. In case of any other error, return NULL in *plat_dev_range_info.
243 */
rmm_el3_ifc_get_dev_range_validated_pa(unsigned long max_num_banks,struct memory_info ** plat_dev_range_info,enum dev_coh_type type)244 int rmm_el3_ifc_get_dev_range_validated_pa(unsigned long max_num_banks,
245 struct memory_info **plat_dev_range_info,
246 enum dev_coh_type type)
247 {
248 struct memory_info *plat_memory;
249 unsigned int max_granules;
250
251 /*
252 * Validate the Boot Manifest Version
253 */
254 if (local_core_manifest.version <
255 RMM_EL3_MANIFEST_MAKE_VERSION(U(0), U(4))) {
256 *plat_dev_range_info = NULL;
257 return E_RMM_BOOT_MANIFEST_VERSION_NOT_SUPPORTED;
258 }
259
260 assert(type < DEV_MEM_MAX);
261
262 VERBOSE("Device %scoherent address range:\n",
263 (type == DEV_MEM_COHERENT) ? "" : "non-");
264
265 if (type == DEV_MEM_COHERENT) {
266 plat_memory = &local_core_manifest.plat_coh_region;
267 max_granules = RMM_MAX_COH_GRANULES;
268 } else {
269 plat_memory = &local_core_manifest.plat_ncoh_region;
270 max_granules = RMM_MAX_NCOH_GRANULES;
271 }
272
273 return get_memory_data_validated_pa(max_num_banks, plat_dev_range_info,
274 plat_memory,
275 max_granules);
276 }
277
278 /*
279 * Return validated Console list passed in plat_console pointer
280 * from the Boot manifest v0.3 onwards.
281 */
rmm_el3_ifc_get_console_list_pa(struct console_list ** plat_console_list)282 int rmm_el3_ifc_get_console_list_pa(struct console_list **plat_console_list)
283 {
284 uint64_t num_consoles, checksum;
285 struct console_list *csl_list;
286 struct console_info *console_ptr;
287
288 assert((manifest_processed == (bool)true) &&
289 (is_mmu_enabled() == (bool)false));
290
291 *plat_console_list = NULL;
292
293 /*
294 * Validate the Boot Manifest Version
295 */
296 if (local_core_manifest.version <
297 RMM_EL3_MANIFEST_MAKE_VERSION(U(0), U(3))) {
298 return E_RMM_BOOT_MANIFEST_VERSION_NOT_SUPPORTED;
299 }
300
301 csl_list = &local_core_manifest.plat_console;
302
303 /* Number of consoles */
304 num_consoles = csl_list->num_consoles;
305
306 /* Pointer to the consoles array */
307 console_ptr = csl_list->consoles;
308
309 /* Calculate the checksum of the console_list structure */
310 checksum = num_consoles + (uint64_t)console_ptr + csl_list->checksum;
311
312 /* Update checksum */
313 checksum += checksum_calc((uint64_t *)console_ptr,
314 sizeof(struct console_info) * num_consoles);
315
316 /* Verify the checksum is 0 */
317 if (checksum != 0UL) {
318 return E_RMM_BOOT_MANIFEST_DATA_ERROR;
319 }
320
321 *plat_console_list = csl_list;
322
323 return E_RMM_BOOT_SUCCESS;
324 }
325