1 /* 2 * Copyright (c) 2018-2020, 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 #endif /* MEASURED_BOOT */ 36 37 /******************************************************************************* 38 * Validate the tb_fw_config is a valid DTB file and returns the node offset 39 * to "arm,tb_fw" property. 40 * Arguments: 41 * void *dtb - pointer to the TB_FW_CONFIG in memory 42 * int *node - Returns the node offset to "arm,tb_fw" property if found. 43 * 44 * Returns 0 on success and -1 on error. 45 ******************************************************************************/ 46 int arm_dyn_tb_fw_cfg_init(void *dtb, int *node) 47 { 48 assert(dtb != NULL); 49 assert(node != NULL); 50 51 /* Check if the pointer to DT is correct */ 52 if (fdt_check_header(dtb) != 0) { 53 WARN("Invalid DTB file passed as%s\n", " TB_FW_CONFIG"); 54 return -1; 55 } 56 57 /* Assert the node offset point to "arm,tb_fw" compatible property */ 58 *node = fdt_node_offset_by_compatible(dtb, -1, "arm,tb_fw"); 59 if (*node < 0) { 60 WARN("The compatible property '%s' not%s", "arm,tb_fw", 61 " found in the config\n"); 62 return -1; 63 } 64 65 VERBOSE("Dyn cfg: '%s'%s", "arm,tb_fw", " found in the config\n"); 66 return 0; 67 } 68 69 /* 70 * This function writes the Mbed TLS heap address and size in the DTB. When it 71 * is called, it is guaranteed that a DTB is available. However it is not 72 * guaranteed that the shared Mbed TLS heap implementation is used. Thus we 73 * return error code from here and it's the responsibility of the caller to 74 * determine the action upon error. 75 * 76 * This function is supposed to be called only by BL1. 77 * 78 * Returns: 79 * 0 = success 80 * -1 = error 81 */ 82 int arm_set_dtb_mbedtls_heap_info(void *dtb, void *heap_addr, size_t heap_size) 83 { 84 int dtb_root; 85 86 /* 87 * Verify that the DTB is valid, before attempting to write to it, 88 * and get the DTB root node. 89 */ 90 int err = arm_dyn_tb_fw_cfg_init(dtb, &dtb_root); 91 if (err < 0) { 92 ERROR("Invalid%s loaded. Unable to get root node\n", 93 " TB_FW_CONFIG"); 94 return -1; 95 } 96 97 /* 98 * Write the heap address and size in the DTB. 99 * 100 * NOTE: The variables heap_addr and heap_size are corrupted 101 * by the "fdtw_write_inplace_cells" function. After the 102 * function calls they must NOT be reused. 103 */ 104 err = fdtw_write_inplace_cells(dtb, dtb_root, 105 DTB_PROP_MBEDTLS_HEAP_ADDR, 2, &heap_addr); 106 if (err < 0) { 107 ERROR("%sDTB property '%s'\n", 108 "Unable to write ", DTB_PROP_MBEDTLS_HEAP_ADDR); 109 return -1; 110 } 111 112 err = fdtw_write_inplace_cells(dtb, dtb_root, 113 DTB_PROP_MBEDTLS_HEAP_SIZE, 1, &heap_size); 114 if (err < 0) { 115 ERROR("%sDTB property '%s'\n", 116 "Unable to write ", DTB_PROP_MBEDTLS_HEAP_SIZE); 117 return -1; 118 } 119 120 return 0; 121 } 122 123 #if MEASURED_BOOT 124 /* 125 * Write the Event Log address and its size in the DTB. 126 * 127 * Returns: 128 * 0 = success 129 * < 0 = error 130 */ 131 static int arm_set_event_log_info(uintptr_t config_base, 132 #ifdef SPD_opteed 133 uintptr_t sm_log_addr, 134 #endif 135 uintptr_t log_addr, size_t log_size) 136 { 137 /* As libfdt uses void *, we can't avoid this cast */ 138 void *dtb = (void *)config_base; 139 const char *compatible = "arm,tpm_event_log"; 140 int err, node; 141 142 /* 143 * Verify that the DTB is valid, before attempting to write to it, 144 * and get the DTB root node. 145 */ 146 147 /* Check if the pointer to DT is correct */ 148 err = fdt_check_header(dtb); 149 if (err < 0) { 150 WARN("Invalid DTB file passed\n"); 151 return err; 152 } 153 154 /* Assert the node offset point to compatible property */ 155 node = fdt_node_offset_by_compatible(dtb, -1, compatible); 156 if (node < 0) { 157 WARN("The compatible property '%s' not%s", compatible, 158 " found in the config\n"); 159 return node; 160 } 161 162 VERBOSE("Dyn cfg: '%s'%s", compatible, " found in the config\n"); 163 164 #ifdef SPD_opteed 165 if (sm_log_addr != 0UL) { 166 err = fdtw_write_inplace_cells(dtb, node, 167 DTB_PROP_HW_SM_LOG_ADDR, 2, &sm_log_addr); 168 if (err < 0) { 169 ERROR("%sDTB property '%s'\n", 170 "Unable to write ", DTB_PROP_HW_SM_LOG_ADDR); 171 return err; 172 } 173 } 174 #endif 175 err = fdtw_write_inplace_cells(dtb, node, 176 DTB_PROP_HW_LOG_ADDR, 2, &log_addr); 177 if (err < 0) { 178 ERROR("%sDTB property '%s'\n", 179 "Unable to write ", DTB_PROP_HW_LOG_ADDR); 180 return err; 181 } 182 183 err = fdtw_write_inplace_cells(dtb, node, 184 DTB_PROP_HW_LOG_SIZE, 1, &log_size); 185 if (err < 0) { 186 ERROR("%sDTB property '%s'\n", 187 "Unable to write ", DTB_PROP_HW_LOG_SIZE); 188 } else { 189 /* 190 * Ensure that the info written to the DTB is visible 191 * to other images. 192 */ 193 flush_dcache_range(config_base, fdt_totalsize(dtb)); 194 } 195 196 return err; 197 } 198 199 /* 200 * This function writes the Event Log address and its size 201 * in the TOS_FW_CONFIG DTB. 202 * 203 * This function is supposed to be called only by BL2. 204 * 205 * Returns: 206 * 0 = success 207 * < 0 = error 208 */ 209 int arm_set_tos_fw_info(uintptr_t log_addr, size_t log_size) 210 { 211 uintptr_t config_base; 212 const bl_mem_params_node_t *cfg_mem_params; 213 int err; 214 215 assert(log_addr != 0UL); 216 217 /* Get the config load address and size of TOS_FW_CONFIG */ 218 cfg_mem_params = get_bl_mem_params_node(TOS_FW_CONFIG_ID); 219 assert(cfg_mem_params != NULL); 220 221 config_base = cfg_mem_params->image_info.image_base; 222 223 /* Write the Event Log address and its size in the DTB */ 224 err = arm_set_event_log_info(config_base, 225 #ifdef SPD_opteed 226 0UL, 227 #endif 228 log_addr, log_size); 229 if (err < 0) { 230 ERROR("%sEvent Log data to TOS_FW_CONFIG\n", 231 "Unable to write "); 232 } 233 234 return err; 235 } 236 237 /* 238 * This function writes the Event Log address and its size 239 * in the NT_FW_CONFIG DTB. 240 * 241 * This function is supposed to be called only by BL2. 242 * 243 * Returns: 244 * 0 = success 245 * < 0 = error 246 */ 247 int arm_set_nt_fw_info( 248 #ifdef SPD_opteed 249 uintptr_t log_addr, 250 #endif 251 size_t log_size, uintptr_t *ns_log_addr) 252 { 253 uintptr_t config_base; 254 uintptr_t ns_addr; 255 const bl_mem_params_node_t *cfg_mem_params; 256 int err; 257 258 assert(ns_log_addr != NULL); 259 260 /* Get the config load address and size from NT_FW_CONFIG */ 261 cfg_mem_params = get_bl_mem_params_node(NT_FW_CONFIG_ID); 262 assert(cfg_mem_params != NULL); 263 264 config_base = cfg_mem_params->image_info.image_base; 265 266 /* Calculate Event Log address in Non-secure memory */ 267 ns_addr = cfg_mem_params->image_info.image_base + 268 cfg_mem_params->image_info.image_max_size; 269 270 /* Check for memory space */ 271 if ((uint64_t)(ns_addr + log_size) > ARM_NS_DRAM1_END) { 272 return -1; 273 } 274 275 /* Write the Event Log address and its size in the DTB */ 276 err = arm_set_event_log_info(config_base, 277 #ifdef SPD_opteed 278 log_addr, 279 #endif 280 ns_addr, log_size); 281 282 /* Return Event Log address in Non-secure memory */ 283 *ns_log_addr = (err < 0) ? 0UL : ns_addr; 284 return err; 285 } 286 287 /* 288 * This function writes the Event Log address and its size 289 * in the TB_FW_CONFIG DTB. 290 * 291 * This function is supposed to be called only by BL1. 292 * 293 * Returns: 294 * 0 = success 295 * < 0 = error 296 */ 297 int arm_set_tb_fw_info(uintptr_t log_addr, size_t log_size) 298 { 299 /* 300 * Read tb_fw_config device tree for Event Log properties 301 * and write the Event Log address and its size in the DTB 302 */ 303 const struct dyn_cfg_dtb_info_t *tb_fw_config_info; 304 uintptr_t tb_fw_cfg_dtb; 305 int err; 306 307 tb_fw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, TB_FW_CONFIG_ID); 308 assert(tb_fw_config_info != NULL); 309 310 tb_fw_cfg_dtb = tb_fw_config_info->config_addr; 311 312 err = arm_set_event_log_info(tb_fw_cfg_dtb, 313 #ifdef SPD_opteed 314 0UL, 315 #endif 316 log_addr, log_size); 317 return err; 318 } 319 320 /* 321 * This function reads the Event Log address and its size 322 * properties present in TB_FW_CONFIG DTB. 323 * 324 * This function is supposed to be called only by BL2. 325 * 326 * Returns: 327 * 0 = success 328 * < 0 = error 329 * Alongside returns Event Log address and its size. 330 */ 331 332 int arm_get_tb_fw_info(uint64_t *log_addr, size_t *log_size) 333 { 334 /* As libfdt uses void *, we can't avoid this cast */ 335 const struct dyn_cfg_dtb_info_t *tb_fw_config_info; 336 int node, rc; 337 338 tb_fw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, TB_FW_CONFIG_ID); 339 assert(tb_fw_config_info != NULL); 340 341 void *dtb = (void *)tb_fw_config_info->config_addr; 342 const char *compatible = "arm,tpm_event_log"; 343 344 /* Assert the node offset point to compatible property */ 345 node = fdt_node_offset_by_compatible(dtb, -1, compatible); 346 if (node < 0) { 347 WARN("The compatible property '%s'%s", compatible, 348 " not specified in TB_FW config.\n"); 349 return node; 350 } 351 352 VERBOSE("Dyn cfg: '%s'%s", compatible, " found in the config\n"); 353 354 rc = fdt_read_uint64(dtb, node, DTB_PROP_HW_LOG_ADDR, log_addr); 355 if (rc != 0) { 356 ERROR("%s%s", DTB_PROP_HW_LOG_ADDR, 357 " not specified in TB_FW config.\n"); 358 return rc; 359 } 360 361 rc = fdt_read_uint32(dtb, node, DTB_PROP_HW_LOG_SIZE, (uint32_t *)log_size); 362 if (rc != 0) { 363 ERROR("%s%s", DTB_PROP_HW_LOG_SIZE, 364 " not specified in TB_FW config.\n"); 365 } 366 367 return rc; 368 } 369 #endif /* MEASURED_BOOT */ 370