| /* |
| * This file is part of the coreboot project. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; version 2 of the License. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| */ |
| |
| #include <arch/cache.h> |
| #include <arch/lib_helpers.h> |
| #include <arch/mmu.h> |
| #include <arch/transition.h> |
| #include <bl31.h> |
| #include <bootmem.h> |
| #include <cbfs.h> |
| #include <cbmem.h> |
| #include <console/console.h> |
| #include <program_loading.h> |
| |
| #include <arm-trusted-firmware/include/export/common/bl_common_exp.h> |
| |
| static entry_point_info_t bl32_ep_info = { |
| .h = { |
| .type = PARAM_EP, |
| .version = PARAM_VERSION_1, |
| .size = sizeof(bl32_ep_info), |
| .attr = EP_SECURE, |
| }, |
| }; |
| static entry_point_info_t bl33_ep_info = { |
| .h = { |
| .type = PARAM_EP, |
| .version = PARAM_VERSION_1, |
| .size = sizeof(bl33_ep_info), |
| .attr = EP_NON_SECURE, |
| }, |
| }; |
| |
| static bl_params_node_t bl32_params_node = { |
| .image_id = BL32_IMAGE_ID, |
| .ep_info = &bl32_ep_info, |
| }; |
| static bl_params_node_t bl33_params_node = { |
| .image_id = BL33_IMAGE_ID, |
| .ep_info = &bl33_ep_info, |
| }; |
| |
| static bl_params_t bl_params = { |
| .h = { |
| .type = PARAM_BL_PARAMS, |
| .version = PARAM_VERSION_2, |
| .size = sizeof(bl_params), |
| .attr = 0, |
| }, |
| .head = &bl33_params_node, |
| }; |
| |
| static struct bl_aux_param_header *bl_aux_params; |
| |
| /* Only works when using the default soc_get_bl31_plat_params() below. */ |
| void register_bl31_aux_param(struct bl_aux_param_header *param) |
| { |
| param->next = (uintptr_t)bl_aux_params; |
| bl_aux_params = param; |
| } |
| |
| /* Default implementation. All newly added SoCs should use this if possible! */ |
| __weak void *soc_get_bl31_plat_params(void) |
| { |
| static struct bl_aux_param_uint64 cbtable_param = { |
| .h = { .type = BL_AUX_PARAM_COREBOOT_TABLE, }, |
| }; |
| if (!cbtable_param.value) { |
| cbtable_param.value = (uint64_t)cbmem_find(CBMEM_ID_CBTABLE); |
| if (cbtable_param.value) |
| register_bl31_aux_param(&cbtable_param.h); |
| } |
| return bl_aux_params; |
| } |
| |
| void run_bl31(u64 payload_entry, u64 payload_arg0, u64 payload_spsr) |
| { |
| struct prog bl31 = PROG_INIT(PROG_BL31, CONFIG_CBFS_PREFIX"/bl31"); |
| void (*bl31_entry)(bl_params_t *params, void *plat_params) = NULL; |
| |
| if (prog_locate(&bl31)) |
| die("BL31 not found"); |
| |
| if (!selfload_check(&bl31, BM_MEM_BL31)) |
| die("BL31 load failed"); |
| bl31_entry = prog_entry(&bl31); |
| |
| if (CONFIG(ARM64_USE_SECURE_OS)) { |
| struct prog bl32 = PROG_INIT(PROG_BL32, |
| CONFIG_CBFS_PREFIX"/secure_os"); |
| |
| if (prog_locate(&bl32)) |
| die("BL32 not found"); |
| |
| if (cbfs_prog_stage_load(&bl32)) |
| die("BL32 load failed"); |
| |
| bl32_ep_info.pc = (uintptr_t)prog_entry(&bl32); |
| bl32_ep_info.spsr = SPSR_EXCEPTION_MASK | |
| get_eret_el(EL1, SPSR_USE_L); |
| bl33_params_node.next_params_info = &bl32_params_node; |
| } |
| |
| bl33_ep_info.pc = payload_entry; |
| bl33_ep_info.spsr = payload_spsr; |
| bl33_ep_info.args.arg0 = payload_arg0; |
| |
| void *bl31_plat_params = soc_get_bl31_plat_params(); |
| |
| /* MMU disable will flush cache, so passed params land in memory. */ |
| raw_write_daif(SPSR_EXCEPTION_MASK); |
| mmu_disable(); |
| bl31_entry(&bl_params, bl31_plat_params); |
| die("BL31 returned!"); |
| } |