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