summaryrefslogtreecommitdiffstats
path: root/plat/arm/common/arm_dyn_cfg_helpers.c
blob: 5dc11151d01218c62b2e23c1221fcffe9aeff9dc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
/*
 * Copyright (c) 2018-2023, Arm Limited and Contributors. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <assert.h>

#include <common/debug.h>
#if MEASURED_BOOT
#include <common/desc_image_load.h>
#endif
#include <common/fdt_wrappers.h>

#include <lib/fconf/fconf.h>
#include <lib/fconf/fconf_dyn_cfg_getter.h>
#include <libfdt.h>

#include <plat/arm/common/arm_dyn_cfg_helpers.h>
#include <plat/arm/common/plat_arm.h>

#define DTB_PROP_MBEDTLS_HEAP_ADDR "mbedtls_heap_addr"
#define DTB_PROP_MBEDTLS_HEAP_SIZE "mbedtls_heap_size"

#if MEASURED_BOOT
#ifdef SPD_opteed
/*
 * Currently OP-TEE does not support reading DTBs from Secure memory
 * and this property should be removed when this feature is supported.
 */
#define DTB_PROP_HW_SM_LOG_ADDR		"tpm_event_log_sm_addr"
#endif /* SPD_opteed */
#define DTB_PROP_HW_LOG_ADDR		"tpm_event_log_addr"
#define DTB_PROP_HW_LOG_SIZE    	"tpm_event_log_size"
#define DTB_PROP_HW_LOG_MAX_SIZE	"tpm_event_log_max_size"
#endif /* MEASURED_BOOT */

static size_t event_log_max_size __unused;

/*******************************************************************************
 * Validate the tb_fw_config is a valid DTB file and returns the node offset
 * to "arm,tb_fw" property.
 * Arguments:
 *	void *dtb - pointer to the TB_FW_CONFIG in memory
 *	int *node - Returns the node offset to "arm,tb_fw" property if found.
 *
 * Returns 0 on success and -1 on error.
 ******************************************************************************/
int arm_dyn_tb_fw_cfg_init(void *dtb, int *node)
{
	assert(dtb != NULL);
	assert(node != NULL);

	/* Check if the pointer to DT is correct */
	if (fdt_check_header(dtb) != 0) {
		WARN("Invalid DTB file passed as%s\n", " TB_FW_CONFIG");
		return -1;
	}

	/* Assert the node offset point to "arm,tb_fw" compatible property */
	*node = fdt_node_offset_by_compatible(dtb, -1, "arm,tb_fw");
	if (*node < 0) {
		WARN("The compatible property '%s' not%s", "arm,tb_fw",
			" found in the config\n");
		return -1;
	}

	VERBOSE("Dyn cfg: '%s'%s", "arm,tb_fw", " found in the config\n");
	return 0;
}

/*
 * This function writes the Mbed TLS heap address and size in the DTB. When it
 * is called, it is guaranteed that a DTB is available. However it is not
 * guaranteed that the shared Mbed TLS heap implementation is used. Thus we
 * return error code from here and it's the responsibility of the caller to
 * determine the action upon error.
 *
 * This function is supposed to be called only by BL1.
 *
 * Returns:
 *	0 = success
 *     -1 = error
 */
int arm_set_dtb_mbedtls_heap_info(void *dtb, void *heap_addr, size_t heap_size)
{
	int dtb_root;

	/*
	 * Verify that the DTB is valid, before attempting to write to it,
	 * and get the DTB root node.
	 */
	int err = arm_dyn_tb_fw_cfg_init(dtb, &dtb_root);
	if (err < 0) {
		ERROR("Invalid%s loaded. Unable to get root node\n",
			" TB_FW_CONFIG");
		return -1;
	}

	/*
	 * Write the heap address and size in the DTB.
	 *
	 * NOTE: The variables heap_addr and heap_size are corrupted
	 * by the "fdtw_write_inplace_cells" function. After the
	 * function calls they must NOT be reused.
	 */
	err = fdtw_write_inplace_cells(dtb, dtb_root,
		DTB_PROP_MBEDTLS_HEAP_ADDR, 2, &heap_addr);
	if (err < 0) {
		ERROR("%sDTB property '%s'\n",
			"Unable to write ", DTB_PROP_MBEDTLS_HEAP_ADDR);
		return -1;
	}

	err = fdtw_write_inplace_cells(dtb, dtb_root,
		DTB_PROP_MBEDTLS_HEAP_SIZE, 1, &heap_size);
	if (err < 0) {
		ERROR("%sDTB property '%s'\n",
			"Unable to write ", DTB_PROP_MBEDTLS_HEAP_SIZE);
		return -1;
	}

	return 0;
}

#if MEASURED_BOOT
/*
 * Write the Event Log address and its size in the DTB.
 *
 * Returns:
 *	0 = success
 *    < 0 = error
 */
static int arm_set_event_log_info(uintptr_t config_base,
#ifdef SPD_opteed
				  uintptr_t sm_log_addr,
#endif
				  uintptr_t log_addr, size_t log_size)
{
	/* As libfdt uses void *, we can't avoid this cast */
	void *dtb = (void *)config_base;
	const char *compatible = "arm,tpm_event_log";
	int err, node;

	/*
	 * Verify that the DTB is valid, before attempting to write to it,
	 * and get the DTB root node.
	 */

	/* Check if the pointer to DT is correct */
	err = fdt_check_header(dtb);
	if (err < 0) {
		WARN("Invalid DTB file passed\n");
		return err;
	}

	/* Assert the node offset point to compatible property */
	node = fdt_node_offset_by_compatible(dtb, -1, compatible);
	if (node < 0) {
		WARN("The compatible property '%s' not%s", compatible,
			" found in the config\n");
		return node;
	}

	VERBOSE("Dyn cfg: '%s'%s", compatible, " found in the config\n");

#ifdef SPD_opteed
	if (sm_log_addr != 0UL) {
		err = fdtw_write_inplace_cells(dtb, node,
			DTB_PROP_HW_SM_LOG_ADDR, 2, &sm_log_addr);
		if (err < 0) {
			ERROR("%sDTB property '%s'\n",
				"Unable to write ", DTB_PROP_HW_SM_LOG_ADDR);
			return err;
		}
	}
#endif
	err = fdtw_write_inplace_cells(dtb, node,
		DTB_PROP_HW_LOG_ADDR, 2, &log_addr);
	if (err < 0) {
		ERROR("%sDTB property '%s'\n",
			"Unable to write ", DTB_PROP_HW_LOG_ADDR);
		return err;
	}

	assert(event_log_max_size != 0U);
	err = fdtw_write_inplace_cells(dtb, node,
				       DTB_PROP_HW_LOG_MAX_SIZE, 1,
				       &event_log_max_size);
	if (err < 0) {
		ERROR("%sDTB property '%s'\n",
		      "Unable to write ", DTB_PROP_HW_LOG_MAX_SIZE);
		return err;
	}

	err = fdtw_write_inplace_cells(dtb, node,
		DTB_PROP_HW_LOG_SIZE, 1, &log_size);
	if (err < 0) {
		ERROR("%sDTB property '%s'\n",
			"Unable to write ", DTB_PROP_HW_LOG_SIZE);
	} else {
		/*
		 * Ensure that the info written to the DTB is visible
		 * to other images.
		 */
		flush_dcache_range(config_base, fdt_totalsize(dtb));
	}

	return err;
}

/*
 * This function writes the Event Log address and its size
 * in the TOS_FW_CONFIG DTB.
 *
 * This function is supposed to be called only by BL2.
 *
 * Returns:
 *	0 = success
 *    < 0 = error
 */
int arm_set_tos_fw_info(uintptr_t log_addr, size_t log_size)
{
	uintptr_t config_base;
	const bl_mem_params_node_t *cfg_mem_params;
	int err;

	assert(log_addr != 0UL);

	/* Get the config load address and size of TOS_FW_CONFIG */
	cfg_mem_params = get_bl_mem_params_node(TOS_FW_CONFIG_ID);
	assert(cfg_mem_params != NULL);

	config_base = cfg_mem_params->image_info.image_base;

	/* Write the Event Log address and its size in the DTB */
	err = arm_set_event_log_info(config_base,
#ifdef SPD_opteed
					0UL,
#endif
					log_addr, log_size);
	if (err < 0) {
		ERROR("%sEvent Log data to TOS_FW_CONFIG\n",
					"Unable to write ");
	}

	return err;
}

/*
 * This function writes the Event Log address and its size
 * in the NT_FW_CONFIG DTB.
 *
 * This function is supposed to be called only by BL2.
 *
 * Returns:
 *	0 = success
 *    < 0 = error
 */
int arm_set_nt_fw_info(
#ifdef SPD_opteed
			uintptr_t log_addr,
#endif
			size_t log_size, uintptr_t *ns_log_addr)
{
	uintptr_t config_base;
	uintptr_t ns_addr;
	const bl_mem_params_node_t *cfg_mem_params;
	int err;

	assert(ns_log_addr != NULL);

	/* Get the config load address and size from NT_FW_CONFIG */
	cfg_mem_params = get_bl_mem_params_node(NT_FW_CONFIG_ID);
	assert(cfg_mem_params != NULL);

	config_base = cfg_mem_params->image_info.image_base;

	/* Calculate Event Log address in Non-secure memory */
	ns_addr = cfg_mem_params->image_info.image_base +
			cfg_mem_params->image_info.image_max_size;

	/* Check for memory space */
	if ((uint64_t)(ns_addr + log_size) > ARM_NS_DRAM1_END) {
		return -1;
	}

	/* Write the Event Log address and its size in the DTB */
	err = arm_set_event_log_info(config_base,
#ifdef SPD_opteed
					log_addr,
#endif
					ns_addr, log_size);

	/* Return Event Log address in Non-secure memory */
	*ns_log_addr = (err < 0) ? 0UL : ns_addr;
	return err;
}

/*
 * This function writes the Event Log address and its size
 * in the TB_FW_CONFIG DTB.
 *
 * This function is supposed to be called only by BL1.
 *
 * Returns:
 *     0 = success
 *   < 0 = error
 */
int arm_set_tb_fw_info(uintptr_t log_addr, size_t log_size, size_t log_max_size)
{
	/*
	 * Read tb_fw_config device tree for Event Log properties
	 * and write the Event Log address and its size in the DTB
	 */
	const struct dyn_cfg_dtb_info_t *tb_fw_config_info;
	uintptr_t tb_fw_cfg_dtb;
	int err;

	tb_fw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, TB_FW_CONFIG_ID);
	assert(tb_fw_config_info != NULL);

	tb_fw_cfg_dtb = tb_fw_config_info->config_addr;

	event_log_max_size = log_max_size;

	err = arm_set_event_log_info(tb_fw_cfg_dtb,
#ifdef SPD_opteed
				     0UL,
#endif
				     log_addr, log_size);
	return err;
}

/*
 * This function reads the Event Log address and its size
 * properties present in TB_FW_CONFIG DTB.
 *
 * This function is supposed to be called only by BL2.
 *
 * Returns:
 *     0 = success
 *   < 0 = error
 * Alongside returns Event Log address and its size.
 */

int arm_get_tb_fw_info(uint64_t *log_addr, size_t *log_size,
		       size_t *log_max_size)
{
	/* As libfdt uses void *, we can't avoid this cast */
	const struct dyn_cfg_dtb_info_t *tb_fw_config_info;
	int node, rc;

	tb_fw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, TB_FW_CONFIG_ID);
	assert(tb_fw_config_info != NULL);

	void *dtb = (void *)tb_fw_config_info->config_addr;
	const char *compatible = "arm,tpm_event_log";

	/* Assert the node offset point to compatible property */
	node = fdt_node_offset_by_compatible(dtb, -1, compatible);
	if (node < 0) {
		WARN("The compatible property '%s'%s", compatible,
		     " not specified in TB_FW config.\n");
		return node;
	}

	VERBOSE("Dyn cfg: '%s'%s", compatible, " found in the config\n");

	rc = fdt_read_uint64(dtb, node, DTB_PROP_HW_LOG_ADDR, log_addr);
	if (rc != 0) {
		ERROR("%s%s", DTB_PROP_HW_LOG_ADDR,
		      " not specified in TB_FW config.\n");
		return rc;
	}

	rc = fdt_read_uint32(dtb, node, DTB_PROP_HW_LOG_SIZE, (uint32_t *)log_size);
	if (rc != 0) {
		ERROR("%s%s", DTB_PROP_HW_LOG_SIZE,
		      " not specified in TB_FW config.\n");
		return rc;
	}

	rc = fdt_read_uint32(dtb, node, DTB_PROP_HW_LOG_MAX_SIZE,
			     (uint32_t *)log_max_size);
	if (rc != 0) {
		ERROR("%s%s", DTB_PROP_HW_LOG_MAX_SIZE,
		      " not specified in TB_FW config.\n");
		return rc;
	} else {
		event_log_max_size = *log_max_size;
	}

	return rc;
}
#endif /* MEASURED_BOOT */