arm_dyn_cfg_helpers.c 7.77 KB
Newer Older
1
2
3
4
5
6
/*
 * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

Roberto Vargas's avatar
Roberto Vargas committed
7
#include <arm_dyn_cfg_helpers.h>
8
9
10
11
#include <assert.h>
#include <desc_image_load.h>
#include <fdt_wrappers.h>
#include <libfdt.h>
Soby Mathew's avatar
Soby Mathew committed
12
#include <plat_arm.h>
13

14
15
#define DTB_PROP_MBEDTLS_HEAP_ADDR "mbedtls_heap_addr"
#define DTB_PROP_MBEDTLS_HEAP_SIZE "mbedtls_heap_size"
16
17
18
19
20
21
22
23
24
25
26
27
28
29

typedef struct config_load_info_prop {
	unsigned int config_id;
	const char *config_addr;
	const char *config_max_size;
} config_load_info_prop_t;

static const config_load_info_prop_t prop_names[] = {
	{HW_CONFIG_ID, "hw_config_addr", "hw_config_max_size"},
	{SOC_FW_CONFIG_ID, "soc_fw_config_addr", "soc_fw_config_max_size"},
	{TOS_FW_CONFIG_ID, "tos_fw_config_addr", "tos_fw_config_max_size"},
	{NT_FW_CONFIG_ID, "nt_fw_config_addr", "nt_fw_config_max_size"}
};

30
/*******************************************************************************
31
32
33
34
 * Helper to read the load information corresponding to the `config_id` in
 * TB_FW_CONFIG. This function expects the following properties to be defined :
 *	<config>_addr		size : 2 cells
 *	<config>_max_size	size : 1 cell
35
36
37
38
39
 *
 * Arguments:
 *	void *dtb		 - pointer to the TB_FW_CONFIG in memory
 *	int node		 - The node offset to appropriate node in the
 *					 DTB.
40
41
 *	unsigned int config_id	 - The configuration id
 *	uint64_t *config_addr	 - Returns the `config` load address if read
42
 *					 is successful.
43
 *	uint32_t *config_size	 - Returns the `config` size if read is
44
45
46
47
 *					 successful.
 *
 * Returns 0 on success and -1 on error.
 ******************************************************************************/
48
49
int arm_dyn_get_config_load_info(void *dtb, int node, unsigned int config_id,
		uint64_t *config_addr, uint32_t *config_size)
50
51
{
	int err;
52
	unsigned int i;
53

Soby Mathew's avatar
Soby Mathew committed
54
	assert(dtb != NULL);
55
56
57
58
59
60
61
62
63
64
65
66
	assert(config_addr != NULL);
	assert(config_size != NULL);

	for (i = 0; i < ARRAY_SIZE(prop_names); i++) {
		if (prop_names[i].config_id == config_id)
			break;
	}

	if (i == ARRAY_SIZE(prop_names)) {
		WARN("Invalid config id %d\n", config_id);
		return -1;
	}
67
68
69
70
71
72
73

	/* Check if the pointer to DT is correct */
	assert(fdt_check_header(dtb) == 0);

	/* Assert the node offset point to "arm,tb_fw" compatible property */
	assert(node == fdt_node_offset_by_compatible(dtb, -1, "arm,tb_fw"));

74
75
	err = fdtw_read_cells(dtb, node, prop_names[i].config_addr, 2,
				(void *) config_addr);
76
	if (err < 0) {
77
		WARN("Read cell failed for %s\n", prop_names[i].config_addr);
78
79
80
		return -1;
	}

81
82
	err = fdtw_read_cells(dtb, node, prop_names[i].config_max_size, 1,
				(void *) config_size);
83
	if (err < 0) {
84
		WARN("Read cell failed for %s\n", prop_names[i].config_max_size);
85
86
87
		return -1;
	}

88
89
	VERBOSE("Dyn cfg: Read config_id %d load info from TB_FW_CONFIG 0x%llx 0x%x\n",
				config_id, (unsigned long long)*config_addr, *config_size);
90
91

	return 0;
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
}

/*******************************************************************************
 * Helper to read the `disable_auth` property in config DTB. This function
 * expects the following properties to be present in the config DTB.
 *	name : disable_auth		size : 1 cell
 *
 * Arguments:
 *	void *dtb		 - pointer to the TB_FW_CONFIG in memory
 *	int node		 - The node offset to appropriate node in the
 *				   DTB.
 *	uint64_t *disable_auth	 - The value of `disable_auth` property on
 *				   successful read. Must be 0 or 1.
 *
 * Returns 0 on success and -1 on error.
 ******************************************************************************/
int arm_dyn_get_disable_auth(void *dtb, int node, uint32_t *disable_auth)
{
	int err;

	assert(dtb != NULL);
	assert(disable_auth != NULL);

	/* Check if the pointer to DT is correct */
	assert(fdt_check_header(dtb) == 0);

	/* Assert the node offset point to "arm,tb_fw" compatible property */
	assert(node == fdt_node_offset_by_compatible(dtb, -1, "arm,tb_fw"));

	/* Locate the disable_auth cell and read the value */
	err = fdtw_read_cells(dtb, node, "disable_auth", 1, disable_auth);
	if (err < 0) {
		WARN("Read cell failed for `disable_auth`\n");
		return -1;
	}

	/* Check if the value is boolean */
129
	if ((*disable_auth != 0U) && (*disable_auth != 1U)) {
130
131
132
133
134
135
136
		WARN("Invalid value for `disable_auth` cell %d\n", *disable_auth);
		return -1;
	}

	VERBOSE("Dyn cfg: `disable_auth` cell found with value = %d\n",
					*disable_auth);
	return 0;
137
138
139
140
141
142
143
144
145
146
147
148
149
}

/*******************************************************************************
 * 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)
{
Soby Mathew's avatar
Soby Mathew committed
150
151
	assert(dtb != NULL);
	assert(node != NULL);
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168

	/* Check if the pointer to DT is correct */
	if (fdt_check_header(dtb) != 0) {
		WARN("Invalid DTB file passed as TB_FW_CONFIG\n");
		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 `arm,tb_fw` not found in the config\n");
		return -1;
	}

	VERBOSE("Dyn cfg: Found \"arm,tb_fw\" in the config\n");
	return 0;
}
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187

/*
 * Reads and returns the Mbed TLS shared heap information from the DTB.
 * This function is supposed to be called *only* when a DTB is present.
 * This function is supposed to be called only by BL2.
 *
 * Returns:
 *	0 = success
 *	-1 = error. In this case the values of heap_addr, heap_size should be
 *	    considered as garbage by the caller.
 */
int arm_get_dtb_mbedtls_heap_info(void *dtb, void **heap_addr,
	size_t *heap_size)
{
	int err, dtb_root;

	/* Verify the DTB is valid and get the root node */
	err = arm_dyn_tb_fw_cfg_init(dtb, &dtb_root);
	if (err < 0) {
188
		ERROR("Invalid TB_FW_CONFIG. Cannot retrieve Mbed TLS heap information from DTB\n");
189
190
191
192
193
194
195
		return -1;
	}

	/* Retrieve the Mbed TLS heap details from the DTB */
	err = fdtw_read_cells(dtb, dtb_root,
		DTB_PROP_MBEDTLS_HEAP_ADDR, 2, heap_addr);
	if (err < 0) {
196
		ERROR("Error while reading %s from DTB\n",
197
198
199
200
201
202
			DTB_PROP_MBEDTLS_HEAP_ADDR);
		return -1;
	}
	err = fdtw_read_cells(dtb, dtb_root,
		DTB_PROP_MBEDTLS_HEAP_SIZE, 1, heap_size);
	if (err < 0) {
203
		ERROR("Error while reading %s from DTB\n",
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
			DTB_PROP_MBEDTLS_HEAP_SIZE);
		return -1;
	}
	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 err, dtb_root;

	/*
	 * Verify that the DTB is valid, before attempting to write to it,
	 * and get the DTB root node.
	 */
	err = arm_dyn_tb_fw_cfg_init(dtb, &dtb_root);
	if (err < 0) {
234
		ERROR("Invalid TB_FW_CONFIG loaded. Unable to get root node\n");
235
236
237
238
239
240
241
242
243
244
245
246
247
		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) {
248
249
		ERROR("Unable to write DTB property %s\n",
			DTB_PROP_MBEDTLS_HEAP_ADDR);
250
251
252
253
254
255
		return -1;
	}

	err = fdtw_write_inplace_cells(dtb, dtb_root,
		DTB_PROP_MBEDTLS_HEAP_SIZE, 1, &heap_size);
	if (err < 0) {
256
257
		ERROR("Unable to write DTB property %s\n",
			DTB_PROP_MBEDTLS_HEAP_SIZE);
258
259
260
261
262
		return -1;
	}

	return 0;
}