/******************************************************************************* * Parse the OPTEE image * Return 0 on success or a negative error code otherwise. ******************************************************************************/ static int parse_optee_image(image_info_t *image_info, optee_image_t *optee_image) { uintptr_t init_load_addr, free_end, requested_end; size_t init_size; init_load_addr = ((uint64_t)optee_image->load_addr_hi << 32) | optee_image->load_addr_lo; init_size = optee_image->size; /* * -1 indicates loader decided address; take our pre-mapped area * for current image since arm-tf could not allocate memory dynamically */ if (init_load_addr == -1) init_load_addr = image_info->image_base; /* Check that the default end address doesn't overflow */ if (check_uptr_overflow(image_info->image_base, image_info->image_max_size - 1)) return -1; free_end = image_info->image_base + (image_info->image_max_size - 1); /* Check that the image end address doesn't overflow */ if (check_uptr_overflow(init_load_addr, init_size - 1)) return -1; requested_end = init_load_addr + (init_size - 1); /* * Check that the requested RAM location is within reserved * space for OPTEE. */ if (!((init_load_addr >= image_info->image_base) && (requested_end <= free_end))) { WARN("The load address in optee header %p - %p is not in reserved area: %p - %p.\n", (void *)init_load_addr, (void *)(init_load_addr + init_size), (void *)image_info->image_base, (void *)(image_info->image_base + image_info->image_max_size)); return -1; } /* * Remove the skip attr from image_info, the image will be loaded. * The default attr in image_info is "IMAGE_ATTRIB_SKIP_LOADING", which * mean the image will not be loaded. Here, we parse the header image to * know that the extra image need to be loaded, so remove the skip attr. */ image_info->h.attr &= ~IMAGE_ATTRIB_SKIP_LOADING; /* Update image base and size of image_info */ image_info->image_base = init_load_addr; image_info->image_size = init_size; return 0; }
/****************************************************************************** * Determine whether the memory region delimited by 'addr' and 'size' is free, * given the extents of free memory. * Return 1 if it is free, 0 if it is not free or if the input values are * invalid. *****************************************************************************/ int is_mem_free(uintptr_t free_base, size_t free_size, uintptr_t addr, size_t size) { uintptr_t free_end, requested_end; /* * Handle corner cases first. * * The order of the 2 tests is important, because if there's no space * left (i.e. free_size == 0) but we don't ask for any memory * (i.e. size == 0) then we should report that the memory is free. */ if (size == 0) return 1; /* A zero-byte region is always free */ if (free_size == 0) return 0; /* * Check that the end addresses don't overflow. * If they do, consider that this memory region is not free, as this * is an invalid scenario. */ if (check_uptr_overflow(free_base, free_size - 1)) return 0; free_end = free_base + (free_size - 1); if (check_uptr_overflow(addr, size - 1)) return 0; requested_end = addr + (size - 1); /* * Finally, check that the requested memory region lies within the free * region. */ return (addr >= free_base) && (requested_end <= free_end); }
/* * Write to the field in the structure corresponding to `structure_id`. * `fld_off` is the offset to the field in the structure and `mode` * indicates whether cache maintenance need to performed for the write. * The `data` is the pointer to data of size specified by `size`. * Returns SDS_OK on success or corresponding error codes on failure. */ int sds_struct_write(uint32_t structure_id, unsigned int fld_off, void *data, size_t size, sds_access_mode_t mode) { int status; uintptr_t field_base; struct_header_t *header = NULL; if (!data) return SDS_ERR_INVALID_PARAMS; /* Check if a structure with this ID exists */ status = get_struct_header(structure_id, &header); if (status != SDS_OK) return status; assert(header); if (mode == SDS_ACCESS_MODE_CACHED) inv_dcache_range((uintptr_t)header, SDS_HEADER_SIZE + size); if (!IS_SDS_HEADER_VALID(header)) { WARN("SDS: Writing to un-finalized structure 0x%x\n", structure_id); return SDS_ERR_STRUCT_NOT_FINALIZED; } if ((fld_off + size) > GET_SDS_HEADER_STRUCT_SIZE(header)) return SDS_ERR_FAIL; field_base = (uintptr_t)header + SDS_HEADER_SIZE + fld_off; if (check_uptr_overflow(field_base, size - 1)) return SDS_ERR_FAIL; /* Copy the required field in the struct */ memcpy((void *)field_base, data, size); if (mode == SDS_ACCESS_MODE_CACHED) flush_dcache_range((uintptr_t)field_base, size); return SDS_OK; }
/* * BL2 utility function to initialize dynamic configuration specified by * TB_FW_CONFIG. Populate the bl_mem_params_node_t of other FW_CONFIGs if * specified in TB_FW_CONFIG. */ void arm_bl2_dyn_cfg_init(void) { int err = 0, tb_fw_node; unsigned int i; bl_mem_params_node_t *cfg_mem_params = NULL; uint64_t image_base; uint32_t image_size; const unsigned int config_ids[] = { HW_CONFIG_ID, SOC_FW_CONFIG_ID, NT_FW_CONFIG_ID, #ifdef SPD_tspd /* Currently tos_fw_config is only present for TSP */ TOS_FW_CONFIG_ID #endif }; if (tb_fw_cfg_dtb == NULL) { VERBOSE("No TB_FW_CONFIG specified\n"); return; } err = arm_dyn_tb_fw_cfg_init(tb_fw_cfg_dtb, &tb_fw_node); if (err < 0) { ERROR("Invalid TB_FW_CONFIG passed from BL1\n"); panic(); } /* Iterate through all the fw config IDs */ for (i = 0; i < ARRAY_SIZE(config_ids); i++) { /* Get the config load address and size from TB_FW_CONFIG */ cfg_mem_params = get_bl_mem_params_node(config_ids[i]); if (cfg_mem_params == NULL) { VERBOSE("Couldn't find HW_CONFIG in bl_mem_params_node\n"); continue; } err = arm_dyn_get_config_load_info(tb_fw_cfg_dtb, tb_fw_node, config_ids[i], &image_base, &image_size); if (err < 0) { VERBOSE("Couldn't find config_id %d load info in TB_FW_CONFIG\n", config_ids[i]); continue; } /* * Do some runtime checks on the load addresses of soc_fw_config, * tos_fw_config, nt_fw_config. This is not a comprehensive check * of all invalid addresses but to prevent trivial porting errors. */ if (config_ids[i] != HW_CONFIG_ID) { if (check_uptr_overflow(image_base, image_size)) continue; #ifdef BL31_BASE /* Ensure the configs don't overlap with BL31 */ if ((image_base > BL31_BASE) || ((image_base + image_size) > BL31_BASE)) continue; #endif /* Ensure the configs are loaded in a valid address */ if (image_base < ARM_BL_RAM_BASE) continue; #ifdef BL32_BASE /* * If BL32 is present, ensure that the configs don't * overlap with it. */ if (image_base >= BL32_BASE && image_base <= BL32_LIMIT) continue; #endif } cfg_mem_params->image_info.image_base = (uintptr_t)image_base; cfg_mem_params->image_info.image_max_size = image_size; /* Remove the IMAGE_ATTRIB_SKIP_LOADING attribute from HW_CONFIG node */ cfg_mem_params->image_info.h.attr &= ~IMAGE_ATTRIB_SKIP_LOADING; } #if TRUSTED_BOARD_BOOT && defined(DYN_DISABLE_AUTH) uint32_t disable_auth = 0; err = arm_dyn_get_disable_auth(tb_fw_cfg_dtb, tb_fw_node, &disable_auth); if (err < 0) return; if (disable_auth == 1) dyn_disable_auth(); #endif }