1 /* 2 * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 9 #include <libfdt.h> 10 11 #include <common/desc_image_load.h> 12 #include <common/fdt_wrappers.h> 13 14 #include <arm_dyn_cfg_helpers.h> 15 #include <plat_arm.h> 16 17 #define DTB_PROP_MBEDTLS_HEAP_ADDR "mbedtls_heap_addr" 18 #define DTB_PROP_MBEDTLS_HEAP_SIZE "mbedtls_heap_size" 19 20 typedef struct config_load_info_prop { 21 unsigned int config_id; 22 const char *config_addr; 23 const char *config_max_size; 24 } config_load_info_prop_t; 25 26 static const config_load_info_prop_t prop_names[] = { 27 {HW_CONFIG_ID, "hw_config_addr", "hw_config_max_size"}, 28 {SOC_FW_CONFIG_ID, "soc_fw_config_addr", "soc_fw_config_max_size"}, 29 {TOS_FW_CONFIG_ID, "tos_fw_config_addr", "tos_fw_config_max_size"}, 30 {NT_FW_CONFIG_ID, "nt_fw_config_addr", "nt_fw_config_max_size"} 31 }; 32 33 /******************************************************************************* 34 * Helper to read the load information corresponding to the `config_id` in 35 * TB_FW_CONFIG. This function expects the following properties to be defined : 36 * <config>_addr size : 2 cells 37 * <config>_max_size size : 1 cell 38 * 39 * Arguments: 40 * void *dtb - pointer to the TB_FW_CONFIG in memory 41 * int node - The node offset to appropriate node in the 42 * DTB. 43 * unsigned int config_id - The configuration id 44 * uint64_t *config_addr - Returns the `config` load address if read 45 * is successful. 46 * uint32_t *config_size - Returns the `config` size if read is 47 * successful. 48 * 49 * Returns 0 on success and -1 on error. 50 ******************************************************************************/ 51 int arm_dyn_get_config_load_info(void *dtb, int node, unsigned int config_id, 52 uint64_t *config_addr, uint32_t *config_size) 53 { 54 int err; 55 unsigned int i; 56 57 assert(dtb != NULL); 58 assert(config_addr != NULL); 59 assert(config_size != NULL); 60 61 for (i = 0; i < ARRAY_SIZE(prop_names); i++) { 62 if (prop_names[i].config_id == config_id) 63 break; 64 } 65 66 if (i == ARRAY_SIZE(prop_names)) { 67 WARN("Invalid config id %d\n", config_id); 68 return -1; 69 } 70 71 /* Check if the pointer to DT is correct */ 72 assert(fdt_check_header(dtb) == 0); 73 74 /* Assert the node offset point to "arm,tb_fw" compatible property */ 75 assert(node == fdt_node_offset_by_compatible(dtb, -1, "arm,tb_fw")); 76 77 err = fdtw_read_cells(dtb, node, prop_names[i].config_addr, 2, 78 (void *) config_addr); 79 if (err < 0) { 80 WARN("Read cell failed for %s\n", prop_names[i].config_addr); 81 return -1; 82 } 83 84 err = fdtw_read_cells(dtb, node, prop_names[i].config_max_size, 1, 85 (void *) config_size); 86 if (err < 0) { 87 WARN("Read cell failed for %s\n", prop_names[i].config_max_size); 88 return -1; 89 } 90 91 VERBOSE("Dyn cfg: Read config_id %d load info from TB_FW_CONFIG 0x%llx 0x%x\n", 92 config_id, (unsigned long long)*config_addr, *config_size); 93 94 return 0; 95 } 96 97 /******************************************************************************* 98 * Helper to read the `disable_auth` property in config DTB. This function 99 * expects the following properties to be present in the config DTB. 100 * name : disable_auth size : 1 cell 101 * 102 * Arguments: 103 * void *dtb - pointer to the TB_FW_CONFIG in memory 104 * int node - The node offset to appropriate node in the 105 * DTB. 106 * uint64_t *disable_auth - The value of `disable_auth` property on 107 * successful read. Must be 0 or 1. 108 * 109 * Returns 0 on success and -1 on error. 110 ******************************************************************************/ 111 int arm_dyn_get_disable_auth(void *dtb, int node, uint32_t *disable_auth) 112 { 113 int err; 114 115 assert(dtb != NULL); 116 assert(disable_auth != NULL); 117 118 /* Check if the pointer to DT is correct */ 119 assert(fdt_check_header(dtb) == 0); 120 121 /* Assert the node offset point to "arm,tb_fw" compatible property */ 122 assert(node == fdt_node_offset_by_compatible(dtb, -1, "arm,tb_fw")); 123 124 /* Locate the disable_auth cell and read the value */ 125 err = fdtw_read_cells(dtb, node, "disable_auth", 1, disable_auth); 126 if (err < 0) { 127 WARN("Read cell failed for `disable_auth`\n"); 128 return -1; 129 } 130 131 /* Check if the value is boolean */ 132 if ((*disable_auth != 0U) && (*disable_auth != 1U)) { 133 WARN("Invalid value for `disable_auth` cell %d\n", *disable_auth); 134 return -1; 135 } 136 137 VERBOSE("Dyn cfg: `disable_auth` cell found with value = %d\n", 138 *disable_auth); 139 return 0; 140 } 141 142 /******************************************************************************* 143 * Validate the tb_fw_config is a valid DTB file and returns the node offset 144 * to "arm,tb_fw" property. 145 * Arguments: 146 * void *dtb - pointer to the TB_FW_CONFIG in memory 147 * int *node - Returns the node offset to "arm,tb_fw" property if found. 148 * 149 * Returns 0 on success and -1 on error. 150 ******************************************************************************/ 151 int arm_dyn_tb_fw_cfg_init(void *dtb, int *node) 152 { 153 assert(dtb != NULL); 154 assert(node != NULL); 155 156 /* Check if the pointer to DT is correct */ 157 if (fdt_check_header(dtb) != 0) { 158 WARN("Invalid DTB file passed as TB_FW_CONFIG\n"); 159 return -1; 160 } 161 162 /* Assert the node offset point to "arm,tb_fw" compatible property */ 163 *node = fdt_node_offset_by_compatible(dtb, -1, "arm,tb_fw"); 164 if (*node < 0) { 165 WARN("The compatible property `arm,tb_fw` not found in the config\n"); 166 return -1; 167 } 168 169 VERBOSE("Dyn cfg: Found \"arm,tb_fw\" in the config\n"); 170 return 0; 171 } 172 173 /* 174 * Reads and returns the Mbed TLS shared heap information from the DTB. 175 * This function is supposed to be called *only* when a DTB is present. 176 * This function is supposed to be called only by BL2. 177 * 178 * Returns: 179 * 0 = success 180 * -1 = error. In this case the values of heap_addr, heap_size should be 181 * considered as garbage by the caller. 182 */ 183 int arm_get_dtb_mbedtls_heap_info(void *dtb, void **heap_addr, 184 size_t *heap_size) 185 { 186 int err, dtb_root; 187 188 /* Verify the DTB is valid and get the root node */ 189 err = arm_dyn_tb_fw_cfg_init(dtb, &dtb_root); 190 if (err < 0) { 191 ERROR("Invalid TB_FW_CONFIG. Cannot retrieve Mbed TLS heap information from DTB\n"); 192 return -1; 193 } 194 195 /* Retrieve the Mbed TLS heap details from the DTB */ 196 err = fdtw_read_cells(dtb, dtb_root, 197 DTB_PROP_MBEDTLS_HEAP_ADDR, 2, heap_addr); 198 if (err < 0) { 199 ERROR("Error while reading %s from DTB\n", 200 DTB_PROP_MBEDTLS_HEAP_ADDR); 201 return -1; 202 } 203 err = fdtw_read_cells(dtb, dtb_root, 204 DTB_PROP_MBEDTLS_HEAP_SIZE, 1, heap_size); 205 if (err < 0) { 206 ERROR("Error while reading %s from DTB\n", 207 DTB_PROP_MBEDTLS_HEAP_SIZE); 208 return -1; 209 } 210 return 0; 211 } 212 213 214 /* 215 * This function writes the Mbed TLS heap address and size in the DTB. When it 216 * is called, it is guaranteed that a DTB is available. However it is not 217 * guaranteed that the shared Mbed TLS heap implementation is used. Thus we 218 * return error code from here and it's the responsibility of the caller to 219 * determine the action upon error. 220 * 221 * This function is supposed to be called only by BL1. 222 * 223 * Returns: 224 * 0 = success 225 * 1 = error 226 */ 227 int arm_set_dtb_mbedtls_heap_info(void *dtb, void *heap_addr, size_t heap_size) 228 { 229 int err, dtb_root; 230 231 /* 232 * Verify that the DTB is valid, before attempting to write to it, 233 * and get the DTB root node. 234 */ 235 err = arm_dyn_tb_fw_cfg_init(dtb, &dtb_root); 236 if (err < 0) { 237 ERROR("Invalid TB_FW_CONFIG loaded. Unable to get root node\n"); 238 return -1; 239 } 240 241 /* 242 * Write the heap address and size in the DTB. 243 * 244 * NOTE: The variables heap_addr and heap_size are corrupted 245 * by the "fdtw_write_inplace_cells" function. After the 246 * function calls they must NOT be reused. 247 */ 248 err = fdtw_write_inplace_cells(dtb, dtb_root, 249 DTB_PROP_MBEDTLS_HEAP_ADDR, 2, &heap_addr); 250 if (err < 0) { 251 ERROR("Unable to write DTB property %s\n", 252 DTB_PROP_MBEDTLS_HEAP_ADDR); 253 return -1; 254 } 255 256 err = fdtw_write_inplace_cells(dtb, dtb_root, 257 DTB_PROP_MBEDTLS_HEAP_SIZE, 1, &heap_size); 258 if (err < 0) { 259 ERROR("Unable to write DTB property %s\n", 260 DTB_PROP_MBEDTLS_HEAP_SIZE); 261 return -1; 262 } 263 264 return 0; 265 } 266