• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <assert.h>
8 
9 #include <common/debug.h>
10 #if MEASURED_BOOT
11 #include <common/desc_image_load.h>
12 #endif
13 #include <common/fdt_wrappers.h>
14 
15 #include <lib/fconf/fconf.h>
16 #include <lib/fconf/fconf_dyn_cfg_getter.h>
17 #include <libfdt.h>
18 
19 #include <plat/arm/common/arm_dyn_cfg_helpers.h>
20 #include <plat/arm/common/plat_arm.h>
21 
22 #define DTB_PROP_MBEDTLS_HEAP_ADDR "mbedtls_heap_addr"
23 #define DTB_PROP_MBEDTLS_HEAP_SIZE "mbedtls_heap_size"
24 
25 #if MEASURED_BOOT
26 #ifdef SPD_opteed
27 /*
28  * Currently OP-TEE does not support reading DTBs from Secure memory
29  * and this property should be removed when this feature is supported.
30  */
31 #define DTB_PROP_HW_SM_LOG_ADDR		"tpm_event_log_sm_addr"
32 #endif /* SPD_opteed */
33 #define DTB_PROP_HW_LOG_ADDR		"tpm_event_log_addr"
34 #define DTB_PROP_HW_LOG_SIZE    	"tpm_event_log_size"
35 #define DTB_PROP_HW_LOG_MAX_SIZE	"tpm_event_log_max_size"
36 #endif /* MEASURED_BOOT */
37 
38 static size_t event_log_max_size __unused;
39 
40 /*******************************************************************************
41  * Validate the tb_fw_config is a valid DTB file and returns the node offset
42  * to "arm,tb_fw" property.
43  * Arguments:
44  *	void *dtb - pointer to the TB_FW_CONFIG in memory
45  *	int *node - Returns the node offset to "arm,tb_fw" property if found.
46  *
47  * Returns 0 on success and -1 on error.
48  ******************************************************************************/
arm_dyn_tb_fw_cfg_init(void * dtb,int * node)49 int arm_dyn_tb_fw_cfg_init(void *dtb, int *node)
50 {
51 	assert(dtb != NULL);
52 	assert(node != NULL);
53 
54 	/* Check if the pointer to DT is correct */
55 	if (fdt_check_header(dtb) != 0) {
56 		WARN("Invalid DTB file passed as%s\n", " TB_FW_CONFIG");
57 		return -1;
58 	}
59 
60 	/* Assert the node offset point to "arm,tb_fw" compatible property */
61 	*node = fdt_node_offset_by_compatible(dtb, -1, "arm,tb_fw");
62 	if (*node < 0) {
63 		WARN("The compatible property '%s' not%s", "arm,tb_fw",
64 			" found in the config\n");
65 		return -1;
66 	}
67 
68 	VERBOSE("Dyn cfg: '%s'%s", "arm,tb_fw", " found in the config\n");
69 	return 0;
70 }
71 
72 /*
73  * This function writes the Mbed TLS heap address and size in the DTB. When it
74  * is called, it is guaranteed that a DTB is available. However it is not
75  * guaranteed that the shared Mbed TLS heap implementation is used. Thus we
76  * return error code from here and it's the responsibility of the caller to
77  * determine the action upon error.
78  *
79  * This function is supposed to be called only by BL1.
80  *
81  * Returns:
82  *	0 = success
83  *     -1 = error
84  */
arm_set_dtb_mbedtls_heap_info(void * dtb,void * heap_addr,size_t heap_size)85 int arm_set_dtb_mbedtls_heap_info(void *dtb, void *heap_addr, size_t heap_size)
86 {
87 	int dtb_root;
88 
89 	/*
90 	 * Verify that the DTB is valid, before attempting to write to it,
91 	 * and get the DTB root node.
92 	 */
93 	int err = arm_dyn_tb_fw_cfg_init(dtb, &dtb_root);
94 	if (err < 0) {
95 		ERROR("Invalid%s loaded. Unable to get root node\n",
96 			" TB_FW_CONFIG");
97 		return -1;
98 	}
99 
100 	/*
101 	 * Write the heap address and size in the DTB.
102 	 *
103 	 * NOTE: The variables heap_addr and heap_size are corrupted
104 	 * by the "fdtw_write_inplace_cells" function. After the
105 	 * function calls they must NOT be reused.
106 	 */
107 	err = fdtw_write_inplace_cells(dtb, dtb_root,
108 		DTB_PROP_MBEDTLS_HEAP_ADDR, 2, &heap_addr);
109 	if (err < 0) {
110 		ERROR("%sDTB property '%s'\n",
111 			"Unable to write ", DTB_PROP_MBEDTLS_HEAP_ADDR);
112 		return -1;
113 	}
114 
115 	err = fdtw_write_inplace_cells(dtb, dtb_root,
116 		DTB_PROP_MBEDTLS_HEAP_SIZE, 1, &heap_size);
117 	if (err < 0) {
118 		ERROR("%sDTB property '%s'\n",
119 			"Unable to write ", DTB_PROP_MBEDTLS_HEAP_SIZE);
120 		return -1;
121 	}
122 
123 	return 0;
124 }
125 
126 #if MEASURED_BOOT
127 #if DICE_PROTECTION_ENVIRONMENT
128 
129 #include <common/desc_image_load.h>
130 
131 #define DTB_PROP_DPE_CTX_HANDLE		"dpe_ctx_handle"
132 
arm_set_dpe_context_handle(uintptr_t config_base,int * ctx_handle)133 static int arm_set_dpe_context_handle(uintptr_t config_base,
134 				      int *ctx_handle)
135 {
136 	/* As libfdt uses void *, we can't avoid this cast */
137 	void *dtb = (void *)config_base;
138 	const char *compatible = "arm,dpe_ctx_handle";
139 	int err, node;
140 
141 	/*
142 	 * Verify that the DTB is valid, before attempting to write to it,
143 	 * and get the DTB root node.
144 	 */
145 
146 	/* Check if the pointer to DT is correct */
147 	err = fdt_check_header(dtb);
148 	if (err < 0) {
149 		WARN("Invalid DTB file passed\n");
150 		return err;
151 	}
152 
153 	/* Assert the node offset point to compatible property */
154 	node = fdt_node_offset_by_compatible(dtb, -1, compatible);
155 	if (node < 0) {
156 		WARN("The compatible property '%s' not%s", compatible,
157 			" found in the config\n");
158 		return node;
159 	}
160 
161 	VERBOSE("Dyn cfg: '%s'%s", compatible, " found in the config\n");
162 
163 	err = fdtw_write_inplace_cells(dtb, node,
164 		DTB_PROP_DPE_CTX_HANDLE, 1, ctx_handle);
165 	if (err < 0) {
166 		ERROR("%sDTB property '%s'\n",
167 			"Unable to write ", DTB_PROP_DPE_CTX_HANDLE);
168 	} else {
169 		/*
170 		 * Ensure that the info written to the DTB is visible
171 		 * to other images.
172 		 */
173 		flush_dcache_range(config_base, fdt_totalsize(dtb));
174 	}
175 
176 	return err;
177 }
178 
179 /*
180  * This function writes the DPE context handle value to the NT_FW_CONFIG DTB.
181  *
182  * This function is supposed to be called only by BL2.
183  *
184  * Returns:
185  *	0 = success
186  *    < 0 = error
187  */
arm_set_nt_fw_info(int * ctx_handle)188 int arm_set_nt_fw_info(int *ctx_handle)
189 {
190 	uintptr_t config_base;
191 	const bl_mem_params_node_t *cfg_mem_params;
192 
193 	/* Get the config load address and size from NT_FW_CONFIG */
194 	cfg_mem_params = get_bl_mem_params_node(NT_FW_CONFIG_ID);
195 	assert(cfg_mem_params != NULL);
196 
197 	config_base = cfg_mem_params->image_info.image_base;
198 
199 	/* Write the context handle value in the DTB */
200 	return arm_set_dpe_context_handle(config_base, ctx_handle);
201 }
202 
203 /*
204  * This function writes the DPE context handle value to the TB_FW_CONFIG DTB.
205  *
206  * This function is supposed to be called only by BL1.
207  *
208  * Returns:
209  *	0 = success
210  *    < 0 = error
211  */
arm_set_tb_fw_info(int * ctx_handle)212 int arm_set_tb_fw_info(int *ctx_handle)
213 {
214 	/*
215 	 * Read tb_fw_config device tree for Event Log properties
216 	 * and write the Event Log address and its size in the DTB
217 	 */
218 	const struct dyn_cfg_dtb_info_t *tb_fw_config_info;
219 	uintptr_t tb_fw_cfg_dtb;
220 
221 	tb_fw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, TB_FW_CONFIG_ID);
222 	assert(tb_fw_config_info != NULL);
223 
224 	tb_fw_cfg_dtb = tb_fw_config_info->config_addr;
225 
226 	/* Write the context handle value in the DTB */
227 	return arm_set_dpe_context_handle(tb_fw_cfg_dtb, ctx_handle);
228 }
229 
230 /*
231  * This function reads the initial DPE context handle from TB_FW_CONFIG DTB.
232  *
233  * This function is supposed to be called only by BL2.
234  *
235  * Returns:
236  *	0 = success
237  *    < 0 = error
238  */
239 
arm_get_tb_fw_info(int * ctx_handle)240 int arm_get_tb_fw_info(int *ctx_handle)
241 {
242 	/* As libfdt uses void *, we can't avoid this cast */
243 	const struct dyn_cfg_dtb_info_t *tb_fw_config_info;
244 	int node, rc;
245 
246 	tb_fw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, TB_FW_CONFIG_ID);
247 	assert(tb_fw_config_info != NULL);
248 
249 	void *dtb = (void *)tb_fw_config_info->config_addr;
250 	const char *compatible = "arm,dpe_ctx_handle";
251 
252 	/* Assert the node offset point to compatible property */
253 	node = fdt_node_offset_by_compatible(dtb, -1, compatible);
254 	if (node < 0) {
255 		WARN("The compatible property '%s'%s", compatible,
256 		     " not specified in TB_FW config.\n");
257 		return node;
258 	}
259 
260 	VERBOSE("Dyn cfg: '%s'%s", compatible, " found in the config\n");
261 
262 	rc = fdt_read_uint32(dtb, node, DTB_PROP_DPE_CTX_HANDLE, (uint32_t *)ctx_handle);
263 	if (rc != 0) {
264 		ERROR("%s%s", DTB_PROP_DPE_CTX_HANDLE,
265 		      " not specified in TB_FW config.\n");
266 	}
267 
268 	return rc;
269 }
270 #else
271 /*
272  * Write the Event Log address and its size in the DTB.
273  *
274  * Returns:
275  *	0 = success
276  *    < 0 = error
277  */
arm_set_event_log_info(uintptr_t config_base,uintptr_t sm_log_addr,uintptr_t log_addr,size_t log_size)278 static int arm_set_event_log_info(uintptr_t config_base,
279 #ifdef SPD_opteed
280 				  uintptr_t sm_log_addr,
281 #endif
282 				  uintptr_t log_addr, size_t log_size)
283 {
284 	/* As libfdt uses void *, we can't avoid this cast */
285 	void *dtb = (void *)config_base;
286 	const char *compatible = "arm,tpm_event_log";
287 	int err, node;
288 
289 	/*
290 	 * Verify that the DTB is valid, before attempting to write to it,
291 	 * and get the DTB root node.
292 	 */
293 
294 	/* Check if the pointer to DT is correct */
295 	err = fdt_check_header(dtb);
296 	if (err < 0) {
297 		WARN("Invalid DTB file passed\n");
298 		return err;
299 	}
300 
301 	/* Assert the node offset point to compatible property */
302 	node = fdt_node_offset_by_compatible(dtb, -1, compatible);
303 	if (node < 0) {
304 		WARN("The compatible property '%s' not%s", compatible,
305 			" found in the config\n");
306 		return node;
307 	}
308 
309 	VERBOSE("Dyn cfg: '%s'%s", compatible, " found in the config\n");
310 
311 #ifdef SPD_opteed
312 	if (sm_log_addr != 0UL) {
313 		err = fdtw_write_inplace_cells(dtb, node,
314 			DTB_PROP_HW_SM_LOG_ADDR, 2, &sm_log_addr);
315 		if (err < 0) {
316 			ERROR("%sDTB property '%s'\n",
317 				"Unable to write ", DTB_PROP_HW_SM_LOG_ADDR);
318 			return err;
319 		}
320 	}
321 #endif
322 	err = fdtw_write_inplace_cells(dtb, node,
323 		DTB_PROP_HW_LOG_ADDR, 2, &log_addr);
324 	if (err < 0) {
325 		ERROR("%sDTB property '%s'\n",
326 			"Unable to write ", DTB_PROP_HW_LOG_ADDR);
327 		return err;
328 	}
329 
330 	assert(event_log_max_size != 0U);
331 	err = fdtw_write_inplace_cells(dtb, node,
332 				       DTB_PROP_HW_LOG_MAX_SIZE, 1,
333 				       &event_log_max_size);
334 	if (err < 0) {
335 		ERROR("%sDTB property '%s'\n",
336 		      "Unable to write ", DTB_PROP_HW_LOG_MAX_SIZE);
337 		return err;
338 	}
339 
340 	err = fdtw_write_inplace_cells(dtb, node,
341 		DTB_PROP_HW_LOG_SIZE, 1, &log_size);
342 	if (err < 0) {
343 		ERROR("%sDTB property '%s'\n",
344 			"Unable to write ", DTB_PROP_HW_LOG_SIZE);
345 	} else {
346 		/*
347 		 * Ensure that the info written to the DTB is visible
348 		 * to other images.
349 		 */
350 		flush_dcache_range(config_base, fdt_totalsize(dtb));
351 	}
352 
353 	return err;
354 }
355 
356 /*
357  * This function writes the Event Log address and its size
358  * in the TOS_FW_CONFIG DTB.
359  *
360  * This function is supposed to be called only by BL2.
361  *
362  * Returns:
363  *	0 = success
364  *    < 0 = error
365  */
arm_set_tos_fw_info(uintptr_t log_addr,size_t log_size)366 int arm_set_tos_fw_info(uintptr_t log_addr, size_t log_size)
367 {
368 	uintptr_t config_base;
369 	const bl_mem_params_node_t *cfg_mem_params;
370 	int err;
371 
372 	assert(log_addr != 0UL);
373 
374 	/* Get the config load address and size of TOS_FW_CONFIG */
375 	cfg_mem_params = get_bl_mem_params_node(TOS_FW_CONFIG_ID);
376 	assert(cfg_mem_params != NULL);
377 
378 	config_base = cfg_mem_params->image_info.image_base;
379 
380 	/* Write the Event Log address and its size in the DTB */
381 	err = arm_set_event_log_info(config_base,
382 #ifdef SPD_opteed
383 					0UL,
384 #endif
385 					log_addr, log_size);
386 	if (err < 0) {
387 		ERROR("%sEvent Log data to TOS_FW_CONFIG\n",
388 					"Unable to write ");
389 	}
390 
391 	return err;
392 }
393 
394 /*
395  * This function writes the Event Log address and its size
396  * in the NT_FW_CONFIG DTB.
397  *
398  * This function is supposed to be called only by BL2.
399  *
400  * Returns:
401  *	0 = success
402  *    < 0 = error
403  */
arm_set_nt_fw_info(uintptr_t log_addr,size_t log_size,uintptr_t * ns_log_addr)404 int arm_set_nt_fw_info(
405 #ifdef SPD_opteed
406 			uintptr_t log_addr,
407 #endif
408 			size_t log_size, uintptr_t *ns_log_addr)
409 {
410 	uintptr_t config_base;
411 	uintptr_t ns_addr;
412 	const bl_mem_params_node_t *cfg_mem_params;
413 	int err;
414 
415 	assert(ns_log_addr != NULL);
416 
417 	/* Get the config load address and size from NT_FW_CONFIG */
418 	cfg_mem_params = get_bl_mem_params_node(NT_FW_CONFIG_ID);
419 	assert(cfg_mem_params != NULL);
420 
421 	config_base = cfg_mem_params->image_info.image_base;
422 
423 	/* Calculate Event Log address in Non-secure memory */
424 	ns_addr = cfg_mem_params->image_info.image_base +
425 			cfg_mem_params->image_info.image_max_size;
426 
427 	/* Check for memory space */
428 	if ((uint64_t)(ns_addr + log_size) > ARM_NS_DRAM1_END) {
429 		return -1;
430 	}
431 
432 	/* Write the Event Log address and its size in the DTB */
433 	err = arm_set_event_log_info(config_base,
434 #ifdef SPD_opteed
435 					log_addr,
436 #endif
437 					ns_addr, log_size);
438 
439 	/* Return Event Log address in Non-secure memory */
440 	*ns_log_addr = (err < 0) ? 0UL : ns_addr;
441 	return err;
442 }
443 
444 /*
445  * This function writes the Event Log address and its size
446  * in the TB_FW_CONFIG DTB.
447  *
448  * This function is supposed to be called only by BL1.
449  *
450  * Returns:
451  *     0 = success
452  *   < 0 = error
453  */
arm_set_tb_fw_info(uintptr_t log_addr,size_t log_size,size_t log_max_size)454 int arm_set_tb_fw_info(uintptr_t log_addr, size_t log_size, size_t log_max_size)
455 {
456 	/*
457 	 * Read tb_fw_config device tree for Event Log properties
458 	 * and write the Event Log address and its size in the DTB
459 	 */
460 	const struct dyn_cfg_dtb_info_t *tb_fw_config_info;
461 	uintptr_t tb_fw_cfg_dtb;
462 	int err;
463 
464 	tb_fw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, TB_FW_CONFIG_ID);
465 	assert(tb_fw_config_info != NULL);
466 
467 	tb_fw_cfg_dtb = tb_fw_config_info->config_addr;
468 
469 	event_log_max_size = log_max_size;
470 
471 	err = arm_set_event_log_info(tb_fw_cfg_dtb,
472 #ifdef SPD_opteed
473 				     0UL,
474 #endif
475 				     log_addr, log_size);
476 	return err;
477 }
478 
479 /*
480  * This function reads the Event Log address and its size
481  * properties present in TB_FW_CONFIG DTB.
482  *
483  * This function is supposed to be called only by BL2.
484  *
485  * Returns:
486  *     0 = success
487  *   < 0 = error
488  * Alongside returns Event Log address and its size.
489  */
490 
arm_get_tb_fw_info(uint64_t * log_addr,size_t * log_size,size_t * log_max_size)491 int arm_get_tb_fw_info(uint64_t *log_addr, size_t *log_size,
492 		       size_t *log_max_size)
493 {
494 	/* As libfdt uses void *, we can't avoid this cast */
495 	const struct dyn_cfg_dtb_info_t *tb_fw_config_info;
496 	int node, rc;
497 
498 	tb_fw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, TB_FW_CONFIG_ID);
499 	assert(tb_fw_config_info != NULL);
500 
501 	void *dtb = (void *)tb_fw_config_info->config_addr;
502 	const char *compatible = "arm,tpm_event_log";
503 
504 	/* Assert the node offset point to compatible property */
505 	node = fdt_node_offset_by_compatible(dtb, -1, compatible);
506 	if (node < 0) {
507 		WARN("The compatible property '%s'%s", compatible,
508 		     " not specified in TB_FW config.\n");
509 		return node;
510 	}
511 
512 	VERBOSE("Dyn cfg: '%s'%s", compatible, " found in the config\n");
513 
514 	rc = fdt_read_uint64(dtb, node, DTB_PROP_HW_LOG_ADDR, log_addr);
515 	if (rc != 0) {
516 		ERROR("%s%s", DTB_PROP_HW_LOG_ADDR,
517 		      " not specified in TB_FW config.\n");
518 		return rc;
519 	}
520 
521 	rc = fdt_read_uint32(dtb, node, DTB_PROP_HW_LOG_SIZE, (uint32_t *)log_size);
522 	if (rc != 0) {
523 		ERROR("%s%s", DTB_PROP_HW_LOG_SIZE,
524 		      " not specified in TB_FW config.\n");
525 		return rc;
526 	}
527 
528 	rc = fdt_read_uint32(dtb, node, DTB_PROP_HW_LOG_MAX_SIZE,
529 			     (uint32_t *)log_max_size);
530 	if (rc != 0) {
531 		ERROR("%s%s", DTB_PROP_HW_LOG_MAX_SIZE,
532 		      " not specified in TB_FW config.\n");
533 		return rc;
534 	} else {
535 		event_log_max_size = *log_max_size;
536 	}
537 
538 	return rc;
539 }
540 #endif /* DICE_PROTECTION_ENVIRONMENT */
541 #endif /* MEASURED_BOOT */
542