1 /* 2 * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <arm_dyn_cfg_helpers.h> 8 #include <assert.h> 9 #include <debug.h> 10 #include <desc_image_load.h> 11 #if TRUSTED_BOARD_BOOT 12 #include <mbedtls_config.h> 13 #endif 14 #include <plat_arm.h> 15 #include <platform.h> 16 #include <platform_def.h> 17 #include <string.h> 18 #include <tbbr_img_def.h> 19 20 #if LOAD_IMAGE_V2 21 22 /* Variable to store the address of TB_FW_CONFIG file */ 23 static void *tb_fw_cfg_dtb; 24 static size_t tb_fw_cfg_dtb_size; 25 26 27 #if TRUSTED_BOARD_BOOT 28 29 static void *mbedtls_heap_addr; 30 static size_t mbedtls_heap_size; 31 32 /* 33 * This function is the implementation of the shared Mbed TLS heap between 34 * BL1 and BL2 for Arm platforms. The shared heap address is passed from BL1 35 * to BL2 with a pointer. This pointer resides inside the TB_FW_CONFIG file 36 * which is a DTB. 37 * 38 * This function is placed inside an #if directive for the below reasons: 39 * - To allocate space for the Mbed TLS heap --only if-- Trusted Board Boot 40 * is enabled. 41 * - This implementation requires the DTB to be present so that BL1 has a 42 * mechanism to pass the pointer to BL2. If LOAD_IMAGE_V2=0 then 43 * TB_FW_CONFIG is not present, which means that this implementation 44 * cannot be applied. 45 */ 46 int arm_get_mbedtls_heap(void **heap_addr, size_t *heap_size) 47 { 48 assert(heap_addr != NULL); 49 assert(heap_size != NULL); 50 51 #if defined(IMAGE_BL1) || BL2_AT_EL3 52 53 /* If in BL1 or BL2_AT_EL3 define a heap */ 54 static unsigned char heap[TF_MBEDTLS_HEAP_SIZE]; 55 56 *heap_addr = heap; 57 *heap_size = sizeof(heap); 58 mbedtls_heap_addr = heap; 59 mbedtls_heap_size = sizeof(heap); 60 61 #elif defined(IMAGE_BL2) 62 63 int err; 64 65 /* If in BL2, retrieve the already allocated heap's info from DTB */ 66 if (tb_fw_cfg_dtb != NULL) { 67 err = arm_get_dtb_mbedtls_heap_info(tb_fw_cfg_dtb, heap_addr, 68 heap_size); 69 if (err < 0) { 70 ERROR("BL2: unable to retrieve shared Mbed TLS heap information from DTB\n"); 71 panic(); 72 } 73 } else { 74 ERROR("BL2: DTB missing, cannot get Mbed TLS heap\n"); 75 panic(); 76 } 77 #endif 78 79 return 0; 80 } 81 82 /* 83 * Puts the shared Mbed TLS heap information to the DTB. 84 * Executed only from BL1. 85 */ 86 void arm_bl1_set_mbedtls_heap(void) 87 { 88 int err; 89 90 /* 91 * If tb_fw_cfg_dtb==NULL then DTB is not present for the current 92 * platform. As such, we don't attempt to write to the DTB at all. 93 * 94 * If mbedtls_heap_addr==NULL, then it means we are using the default 95 * heap implementation. As such, BL2 will have its own heap for sure 96 * and hence there is no need to pass any information to the DTB. 97 * 98 * In the latter case, if we still wanted to write in the DTB the heap 99 * information, we would need to call plat_get_mbedtls_heap to retrieve 100 * the default heap's address and size. 101 */ 102 if ((tb_fw_cfg_dtb != NULL) && (mbedtls_heap_addr != NULL)) { 103 err = arm_set_dtb_mbedtls_heap_info(tb_fw_cfg_dtb, 104 mbedtls_heap_addr, mbedtls_heap_size); 105 if (err < 0) { 106 ERROR("BL1: unable to write shared Mbed TLS heap information to DTB\n"); 107 panic(); 108 } 109 /* 110 * Ensure that the info written to the DTB is visible to other 111 * images. It's critical because BL2 won't be able to proceed 112 * without the heap info. 113 */ 114 flush_dcache_range((uintptr_t)tb_fw_cfg_dtb, 115 tb_fw_cfg_dtb_size); 116 } 117 } 118 119 #endif /* TRUSTED_BOARD_BOOT */ 120 121 /* 122 * Helper function to load TB_FW_CONFIG and populate the load information to 123 * arg0 of BL2 entrypoint info. 124 */ 125 void arm_load_tb_fw_config(void) 126 { 127 int err; 128 uintptr_t config_base = 0; 129 image_desc_t *image_desc; 130 131 image_desc_t arm_tb_fw_info = { 132 .image_id = TB_FW_CONFIG_ID, 133 SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY, 134 VERSION_2, image_info_t, 0), 135 .image_info.image_base = ARM_TB_FW_CONFIG_BASE, 136 .image_info.image_max_size = 137 ARM_TB_FW_CONFIG_LIMIT - ARM_TB_FW_CONFIG_BASE 138 }; 139 140 VERBOSE("BL1: Loading TB_FW_CONFIG\n"); 141 err = load_auth_image(TB_FW_CONFIG_ID, &arm_tb_fw_info.image_info); 142 if (err != 0) { 143 /* Return if TB_FW_CONFIG is not loaded */ 144 VERBOSE("Failed to load TB_FW_CONFIG\n"); 145 return; 146 } 147 148 /* At this point we know that a DTB is indeed available */ 149 config_base = arm_tb_fw_info.image_info.image_base; 150 tb_fw_cfg_dtb = (void *)config_base; 151 tb_fw_cfg_dtb_size = (size_t)arm_tb_fw_info.image_info.image_max_size; 152 153 /* The BL2 ep_info arg0 is modified to point to TB_FW_CONFIG */ 154 image_desc = bl1_plat_get_image_desc(BL2_IMAGE_ID); 155 assert(image_desc != NULL); 156 image_desc->ep_info.args.arg0 = config_base; 157 158 INFO("BL1: TB_FW_CONFIG loaded at address = %p\n", 159 (void *) config_base); 160 161 #if TRUSTED_BOARD_BOOT && defined(DYN_DISABLE_AUTH) 162 int tb_fw_node; 163 uint32_t disable_auth = 0; 164 165 err = arm_dyn_tb_fw_cfg_init((void *)config_base, &tb_fw_node); 166 if (err < 0) { 167 ERROR("Invalid TB_FW_CONFIG loaded\n"); 168 panic(); 169 } 170 171 err = arm_dyn_get_disable_auth((void *)config_base, tb_fw_node, &disable_auth); 172 if (err < 0) 173 return; 174 175 if (disable_auth == 1) 176 dyn_disable_auth(); 177 #endif 178 } 179 180 /* 181 * BL2 utility function to set the address of TB_FW_CONFIG passed from BL1. 182 */ 183 void arm_bl2_set_tb_cfg_addr(void *dtb) 184 { 185 assert(dtb != NULL); 186 tb_fw_cfg_dtb = dtb; 187 } 188 189 /* 190 * BL2 utility function to initialize dynamic configuration specified by 191 * TB_FW_CONFIG. Populate the bl_mem_params_node_t of other FW_CONFIGs if 192 * specified in TB_FW_CONFIG. 193 */ 194 void arm_bl2_dyn_cfg_init(void) 195 { 196 int err = 0, tb_fw_node; 197 unsigned int i; 198 bl_mem_params_node_t *cfg_mem_params = NULL; 199 uint64_t image_base; 200 uint32_t image_size; 201 const unsigned int config_ids[] = { 202 HW_CONFIG_ID, 203 SOC_FW_CONFIG_ID, 204 NT_FW_CONFIG_ID, 205 #ifdef SPD_tspd 206 /* Currently tos_fw_config is only present for TSP */ 207 TOS_FW_CONFIG_ID 208 #endif 209 }; 210 211 if (tb_fw_cfg_dtb == NULL) { 212 VERBOSE("No TB_FW_CONFIG specified\n"); 213 return; 214 } 215 216 err = arm_dyn_tb_fw_cfg_init(tb_fw_cfg_dtb, &tb_fw_node); 217 if (err < 0) { 218 ERROR("Invalid TB_FW_CONFIG passed from BL1\n"); 219 panic(); 220 } 221 222 /* Iterate through all the fw config IDs */ 223 for (i = 0; i < ARRAY_SIZE(config_ids); i++) { 224 /* Get the config load address and size from TB_FW_CONFIG */ 225 cfg_mem_params = get_bl_mem_params_node(config_ids[i]); 226 if (cfg_mem_params == NULL) { 227 VERBOSE("Couldn't find HW_CONFIG in bl_mem_params_node\n"); 228 continue; 229 } 230 231 err = arm_dyn_get_config_load_info(tb_fw_cfg_dtb, tb_fw_node, 232 config_ids[i], &image_base, &image_size); 233 if (err < 0) { 234 VERBOSE("Couldn't find config_id %d load info in TB_FW_CONFIG\n", 235 config_ids[i]); 236 continue; 237 } 238 239 /* 240 * Do some runtime checks on the load addresses of soc_fw_config, 241 * tos_fw_config, nt_fw_config. This is not a comprehensive check 242 * of all invalid addresses but to prevent trivial porting errors. 243 */ 244 if (config_ids[i] != HW_CONFIG_ID) { 245 246 if (check_uptr_overflow(image_base, image_size) != 0) 247 continue; 248 249 /* Ensure the configs don't overlap with BL31 */ 250 if ((image_base > BL31_BASE) || ((image_base + image_size) > BL31_BASE)) 251 continue; 252 253 /* Ensure the configs are loaded in a valid address */ 254 if (image_base < ARM_BL_RAM_BASE) 255 continue; 256 #ifdef BL32_BASE 257 /* 258 * If BL32 is present, ensure that the configs don't 259 * overlap with it. 260 */ 261 if (image_base >= BL32_BASE && image_base <= BL32_LIMIT) 262 continue; 263 #endif 264 } 265 266 267 cfg_mem_params->image_info.image_base = (uintptr_t)image_base; 268 cfg_mem_params->image_info.image_max_size = image_size; 269 270 /* Remove the IMAGE_ATTRIB_SKIP_LOADING attribute from HW_CONFIG node */ 271 cfg_mem_params->image_info.h.attr &= ~IMAGE_ATTRIB_SKIP_LOADING; 272 } 273 274 #if TRUSTED_BOARD_BOOT && defined(DYN_DISABLE_AUTH) 275 uint32_t disable_auth = 0; 276 277 err = arm_dyn_get_disable_auth(tb_fw_cfg_dtb, tb_fw_node, 278 &disable_auth); 279 if (err < 0) 280 return; 281 282 if (disable_auth == 1) 283 dyn_disable_auth(); 284 #endif 285 } 286 287 #endif /* LOAD_IMAGE_V2 */ 288