diff options
127 files changed, 4736 insertions, 1265 deletions
@@ -76,6 +76,8 @@ USE_COHERENT_MEM := 1 PSCI_EXTENDED_STATE_ID := 0 # Default FIP file name FIP_NAME := fip.bin +# Default FWU_FIP file name +FWU_FIP_NAME := fwu_fip.bin # By default, use the -pedantic option in the gcc command line DISABLE_PEDANTIC := 0 # Flags to generate the Chain of Trust @@ -152,6 +154,7 @@ VERSION_STRING := v${VERSION_MAJOR}.${VERSION_MINOR}(${BUILD_TYPE}):${BUILD_STR # target 'certificates' to create them all ifneq (${GENERATE_COT},0) FIP_DEPS += certificates + FWU_FIP_DEPS += fwu_certificates endif @@ -197,7 +200,8 @@ BL_COMMON_SOURCES += common/bl_common.c \ lib/stdlib/std.c \ plat/common/aarch64/platform_helpers.S -INCLUDES += -Iinclude/bl31 \ +INCLUDES += -Iinclude/bl1 \ + -Iinclude/bl31 \ -Iinclude/bl31/services \ -Iinclude/common \ -Iinclude/drivers \ @@ -322,8 +326,10 @@ ifneq (${GENERATE_COT},0) # Common cert_create options ifneq (${CREATE_KEYS},0) $(eval CRT_ARGS += -n) + $(eval FWU_CRT_ARGS += -n) ifneq (${SAVE_KEYS},0) $(eval CRT_ARGS += -k) + $(eval FWU_CRT_ARGS += -k) endif endif # Include TBBR makefile (unless the platform indicates otherwise) @@ -413,6 +419,11 @@ NEED_BL2 := yes include bl2/bl2.mk endif +ifdef BL2U_SOURCES +NEED_BL2U := yes +include bl2u/bl2u.mk +endif + ifdef BL31_SOURCES # When booting an EL3 payload, there is no need to compile the BL31 image nor # put it in the FIP. @@ -427,7 +438,7 @@ endif # Build targets ################################################################################ -.PHONY: all msg_start clean realclean distclean cscope locate-checkpatch checkcodebase checkpatch fiptool fip certtool +.PHONY: all msg_start clean realclean distclean cscope locate-checkpatch checkcodebase checkpatch fiptool fip fwu_fip certtool .SUFFIXES: all: msg_start @@ -470,6 +481,12 @@ ifeq (${NEED_BL33},yes) $(eval $(call FIP_ADD_IMG,BL33,--bl33)) endif +ifeq (${NEED_BL2U},yes) +BL2U_PATH := $(if ${BL2U},${BL2U},$(call IMG_BIN,2u)) +$(if ${BL2U}, ,$(eval $(call MAKE_BL,2u))) +$(eval $(call FWU_FIP_ADD_PAYLOAD,${BL2U_PATH},--bl2u)) +endif + locate-checkpatch: ifndef CHECKPATCH $(error "Please set CHECKPATCH to point to the Linux checkpatch.pl file, eg: CHECKPATCH=../linux/script/checkpatch.pl") @@ -528,8 +545,24 @@ ${BUILD_PLAT}/${FIP_NAME}: ${FIP_DEPS} ${FIPTOOL} @echo "Built $@ successfully" @echo +ifneq (${GENERATE_COT},0) +fwu_certificates: ${FWU_CRT_DEPS} ${CRTTOOL} + ${Q}${CRTTOOL} ${FWU_CRT_ARGS} + @echo + @echo "Built $@ successfully" + @echo "FWU certificates can be found in ${BUILD_PLAT}" + @echo +endif + +${BUILD_PLAT}/${FWU_FIP_NAME}: ${FWU_FIP_DEPS} ${FIPTOOL} + ${Q}${FIPTOOL} --dump ${FWU_FIP_ARGS} $@ + @echo + @echo "Built $@ successfully" + @echo + fiptool: ${FIPTOOL} fip: ${BUILD_PLAT}/${FIP_NAME} +fwu_fip: ${BUILD_PLAT}/${FWU_FIP_NAME} .PHONY: ${FIPTOOL} ${FIPTOOL}: @@ -555,10 +588,12 @@ help: @echo " all Build all individual bootloader binaries" @echo " bl1 Build the BL1 binary" @echo " bl2 Build the BL2 binary" + @echo " bl2u Build the BL2U binary" @echo " bl31 Build the BL3-1 binary" @echo " bl32 Build the BL3-2 binary" @echo " certificates Build the certificates (requires 'GENERATE_COT=1')" @echo " fip Build the Firmware Image Package (FIP)" + @echo " fwu_fip Build the FWU Firmware Image Package (FIP)" @echo " checkcodebase Check the coding style of the entire source tree" @echo " checkpatch Check the coding style on changes in the current" @echo " branch against BASE_COMMIT (default origin/master)" diff --git a/bl1/aarch64/bl1_entrypoint.S b/bl1/aarch64/bl1_entrypoint.S index 83594f21..ce277524 100644 --- a/bl1/aarch64/bl1_entrypoint.S +++ b/bl1/aarch64/bl1_entrypoint.S @@ -69,10 +69,14 @@ func bl1_entrypoint /* -------------------------------------------------- * Initialize platform and jump to our c-entry point - * for this type of reset. Panic if it returns + * for this type of reset. * -------------------------------------------------- */ bl bl1_main -panic: - b panic + + /* -------------------------------------------------- + * Do the transition to next boot image. + * -------------------------------------------------- + */ + b el3_exit endfunc bl1_entrypoint diff --git a/bl1/aarch64/bl1_exceptions.S b/bl1/aarch64/bl1_exceptions.S index 5415d395..9ff6a57b 100644 --- a/bl1/aarch64/bl1_exceptions.S +++ b/bl1/aarch64/bl1_exceptions.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -31,7 +31,8 @@ #include <arch.h> #include <asm_macros.S> #include <bl_common.h> -#include <runtime_svc.h> +#include <bl1.h> +#include <context.h> .globl bl1_exceptions @@ -115,10 +116,12 @@ SynchronousExceptionA64: /* Enable the SError interrupt */ msr daifclr, #DAIF_ABT_BIT + str x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR] + /* Expect only SMC exceptions */ - mrs x19, esr_el3 - ubfx x20, x19, #ESR_EC_SHIFT, #ESR_EC_LENGTH - cmp x20, #EC_AARCH64_SMC + mrs x30, esr_el3 + ubfx x30, x30, #ESR_EC_SHIFT, #ESR_EC_LENGTH + cmp x30, #EC_AARCH64_SMC b.ne unexpected_sync_exception b smc_handler64 @@ -179,21 +182,40 @@ SErrorA32: func smc_handler64 + + /* ---------------------------------------------- + * Detect if this is a RUN_IMAGE or other SMC. + * ---------------------------------------------- + */ + mov x30, #BL1_SMC_RUN_IMAGE + cmp x30, x0 + b.ne smc_handler + + /* ------------------------------------------------ + * Make sure only Secure world reaches here. + * ------------------------------------------------ + */ + mrs x30, scr_el3 + tst x30, #SCR_NS_BIT + b.ne unexpected_sync_exception + + /* ---------------------------------------------- + * Handling RUN_IMAGE SMC. First switch back to + * SP_EL0 for the C runtime stack. + * ---------------------------------------------- + */ + ldr x30, [sp, #CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP] + msr spsel, #0 + mov sp, x30 + /* --------------------------------------------------------------------- - * Only a single SMC exception from BL2 to ask BL1 to pass EL3 control - * to BL31 is expected here. It expects: - * - X0 with RUN_IMAGE SMC function ID; - * - X1 with the address of a entry_point_info_t structure describing - * the BL31 entrypoint. + * Pass EL3 control to BL31. + * Here it expects X1 with the address of a entry_point_info_t + * structure describing the BL31 entrypoint. * --------------------------------------------------------------------- */ - mov x19, x0 mov x20, x1 - mov x0, #RUN_IMAGE - cmp x19, x0 - b.ne unexpected_sync_exception - mov x0, x20 bl bl1_print_bl31_ep_info @@ -228,3 +250,69 @@ unexpected_sync_exception: bl plat_report_exception wfi b unexpected_sync_exception + + /* ----------------------------------------------------- + * Save Secure/Normal world context and jump to + * BL1 SMC handler. + * ----------------------------------------------------- + */ +smc_handler: + /* ----------------------------------------------------- + * Save the GP registers x0-x29. + * TODO: Revisit to store only SMCC specified registers. + * ----------------------------------------------------- + */ + bl save_gp_registers + + /* ----------------------------------------------------- + * Populate the parameters for the SMC handler. We + * already have x0-x4 in place. x5 will point to a + * cookie (not used now). x6 will point to the context + * structure (SP_EL3) and x7 will contain flags we need + * to pass to the handler. + * ----------------------------------------------------- + */ + mov x5, xzr + mov x6, sp + + /* ----------------------------------------------------- + * Restore the saved C runtime stack value which will + * become the new SP_EL0 i.e. EL3 runtime stack. It was + * saved in the 'cpu_context' structure prior to the last + * ERET from EL3. + * ----------------------------------------------------- + */ + ldr x12, [x6, #CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP] + + /* --------------------------------------------- + * Switch back to SP_EL0 for the C runtime stack. + * --------------------------------------------- + */ + msr spsel, #0 + mov sp, x12 + + /* ----------------------------------------------------- + * Save the SPSR_EL3, ELR_EL3, & SCR_EL3 in case there + * is a world switch during SMC handling. + * ----------------------------------------------------- + */ + mrs x16, spsr_el3 + mrs x17, elr_el3 + mrs x18, scr_el3 + stp x16, x17, [x6, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3] + str x18, [x6, #CTX_EL3STATE_OFFSET + CTX_SCR_EL3] + + /* Copy SCR_EL3.NS bit to the flag to indicate caller's security */ + bfi x7, x18, #0, #1 + + /* ----------------------------------------------------- + * Go to BL1 SMC handler. + * ----------------------------------------------------- + */ + bl bl1_smc_handler + + /* ----------------------------------------------------- + * Do the transition to next BL image. + * ----------------------------------------------------- + */ + b el3_exit @@ -1,5 +1,5 @@ # -# Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. +# Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: @@ -32,6 +32,14 @@ BL1_SOURCES += bl1/bl1_main.c \ bl1/aarch64/bl1_arch_setup.c \ bl1/aarch64/bl1_entrypoint.S \ bl1/aarch64/bl1_exceptions.S \ - lib/cpus/aarch64/cpu_helpers.S + bl1/bl1_context_mgmt.c \ + common/aarch64/context.S \ + common/context_mgmt.c \ + lib/cpus/aarch64/cpu_helpers.S \ + plat/common/plat_bl1_common.c + +ifeq (${TRUSTED_BOARD_BOOT},1) +BL1_SOURCES += bl1/bl1_fwu.c +endif BL1_LINKERFILE := bl1/bl1.ld.S diff --git a/bl1/bl1_context_mgmt.c b/bl1/bl1_context_mgmt.c new file mode 100644 index 00000000..6355190e --- /dev/null +++ b/bl1/bl1_context_mgmt.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arch_helpers.h> +#include <assert.h> +#include <context.h> +#include <context_mgmt.h> +#include <platform.h> + +/* + * Following array will be used for context management. + * There are 2 instances, for the Secure and Non-Secure contexts. + */ +static cpu_context_t bl1_cpu_context[2]; + +/* Following contains the cpu context pointers. */ +static void *bl1_cpu_context_ptr[2]; + + +void *cm_get_context(uint32_t security_state) +{ + assert(sec_state_is_valid(security_state)); + return bl1_cpu_context_ptr[security_state]; +} + +void cm_set_context(void *context, uint32_t security_state) +{ + assert(sec_state_is_valid(security_state)); + bl1_cpu_context_ptr[security_state] = context; +} + +/******************************************************************************* + * This function prepares the context for Secure/Normal world images. + * Normal world images are transitioned to EL2(if supported) else EL1. + ******************************************************************************/ +void bl1_prepare_next_image(unsigned int image_id) +{ + unsigned int security_state; + image_desc_t *image_desc; + entry_point_info_t *next_bl_ep; + + /* Get the image descriptor. */ + image_desc = bl1_plat_get_image_desc(image_id); + assert(image_desc); + + /* Get the entry point info. */ + next_bl_ep = &image_desc->ep_info; + + /* Get the image security state. */ + security_state = GET_SEC_STATE(next_bl_ep->h.attr); + + /* Setup the Secure/Non-Secure context if not done already. */ + if (!cm_get_context(security_state)) + cm_set_context(&bl1_cpu_context[security_state], security_state); + + /* Prepare the SPSR for the next BL image. */ + if (security_state == SECURE) { + next_bl_ep->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX, + DISABLE_ALL_EXCEPTIONS); + } else { + /* Use EL2 if supported else use EL1. */ + if (read_id_aa64pfr0_el1() & + (ID_AA64PFR0_ELX_MASK << ID_AA64PFR0_EL2_SHIFT)) { + next_bl_ep->spsr = SPSR_64(MODE_EL2, MODE_SP_ELX, + DISABLE_ALL_EXCEPTIONS); + } else { + next_bl_ep->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX, + DISABLE_ALL_EXCEPTIONS); + } + } + + /* Allow platform to make change */ + bl1_plat_set_ep_info(image_id, next_bl_ep); + + /* Prepare the context for the next BL image. */ + cm_init_my_context(next_bl_ep); + cm_prepare_el3_exit(security_state); + + /* Indicate that image is in execution state. */ + image_desc->state = IMAGE_STATE_EXECUTED; + + print_entry_point_info(next_bl_ep); +} diff --git a/bl1/bl1_fwu.c b/bl1/bl1_fwu.c new file mode 100644 index 00000000..f8b414e3 --- /dev/null +++ b/bl1/bl1_fwu.c @@ -0,0 +1,503 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <assert.h> +#include <arch_helpers.h> +#include <auth_mod.h> +#include <bl1.h> +#include <bl_common.h> +#include <context.h> +#include <context_mgmt.h> +#include <debug.h> +#include <errno.h> +#include <platform.h> +#include <platform_def.h> +#include <smcc_helpers.h> +#include <string.h> +#include "bl1_private.h" + +/* + * Function declarations. + */ +static int bl1_fwu_image_copy(unsigned int image_id, + uintptr_t image_addr, + unsigned int block_size, + unsigned int image_size, + unsigned int flags); +static int bl1_fwu_image_auth(unsigned int image_id, + uintptr_t image_addr, + unsigned int image_size, + unsigned int flags); +static int bl1_fwu_image_execute(unsigned int image_id, + void **handle, + unsigned int flags); +static register_t bl1_fwu_image_resume(unsigned int image_id, + register_t image_param, + void **handle, + unsigned int flags); +static int bl1_fwu_sec_image_done(void **handle, + unsigned int flags); +__dead2 static void bl1_fwu_done(void *cookie, void *reserved); + +/* + * This keeps track of last executed secure image id. + */ +static unsigned int sec_exec_image_id = INVALID_IMAGE_ID; + +/******************************************************************************* + * Top level handler for servicing FWU SMCs. + ******************************************************************************/ +register_t bl1_fwu_smc_handler(unsigned int smc_fid, + register_t x1, + register_t x2, + register_t x3, + register_t x4, + void *cookie, + void *handle, + unsigned int flags) +{ + + switch (smc_fid) { + case FWU_SMC_IMAGE_COPY: + SMC_RET1(handle, bl1_fwu_image_copy(x1, x2, x3, x4, flags)); + + case FWU_SMC_IMAGE_AUTH: + SMC_RET1(handle, bl1_fwu_image_auth(x1, x2, x3, flags)); + + case FWU_SMC_IMAGE_EXECUTE: + SMC_RET1(handle, bl1_fwu_image_execute(x1, &handle, flags)); + + case FWU_SMC_IMAGE_RESUME: + SMC_RET1(handle, bl1_fwu_image_resume(x1, x2, &handle, flags)); + + case FWU_SMC_SEC_IMAGE_DONE: + SMC_RET1(handle, bl1_fwu_sec_image_done(&handle, flags)); + + case FWU_SMC_UPDATE_DONE: + bl1_fwu_done(cookie, NULL); + /* We should never return from bl1_fwu_done() */ + + default: + assert(0); + break; + } + + SMC_RET0(handle); +} + +/******************************************************************************* + * This function is responsible for copying secure images in AP Secure RAM. + ******************************************************************************/ +static int bl1_fwu_image_copy(unsigned int image_id, + uintptr_t image_src, + unsigned int block_size, + unsigned int image_size, + unsigned int flags) +{ + uintptr_t base_addr; + meminfo_t *mem_layout; + + /* Get the image descriptor. */ + image_desc_t *image_desc = bl1_plat_get_image_desc(image_id); + + /* Check if we are in correct state. */ + if ((!image_desc) || + ((image_desc->state != IMAGE_STATE_RESET) && + (image_desc->state != IMAGE_STATE_COPYING))) { + WARN("BL1-FWU: Copy not allowed due to invalid state\n"); + return -EPERM; + } + + /* Only Normal world is allowed to copy a Secure image. */ + if ((GET_SEC_STATE(flags) == SECURE) || + (GET_SEC_STATE(image_desc->ep_info.h.attr) == NON_SECURE)) { + WARN("BL1-FWU: Copy not allowed for Non-Secure " + "image from Secure-world\n"); + return -EPERM; + } + + if ((!image_src) || (!block_size)) { + WARN("BL1-FWU: Copy not allowed due to invalid image source" + " or block size\n"); + return -ENOMEM; + } + + /* Get the image base address. */ + base_addr = image_desc->image_info.image_base; + + if (image_desc->state == IMAGE_STATE_COPYING) { + /* + * If last block is more than expected then + * clip the block to the required image size. + */ + if (image_desc->image_info.copied_size + block_size > + image_desc->image_info.image_size) { + block_size = image_desc->image_info.image_size - + image_desc->image_info.copied_size; + WARN("BL1-FWU: Copy argument block_size > remaining image size." + " Clipping block_size\n"); + } + + /* Make sure the image src/size is mapped. */ + if (bl1_plat_mem_check(image_src, block_size, flags)) { + WARN("BL1-FWU: Copy arguments source/size not mapped\n"); + return -ENOMEM; + } + + INFO("BL1-FWU: Continuing image copy in blocks\n"); + + /* Copy image for given block size. */ + base_addr += image_desc->image_info.copied_size; + image_desc->image_info.copied_size += block_size; + memcpy((void *)base_addr, (const void *)image_src, block_size); + flush_dcache_range(base_addr, block_size); + + /* Update the state if last block. */ + if (image_desc->image_info.copied_size == + image_desc->image_info.image_size) { + image_desc->state = IMAGE_STATE_COPIED; + INFO("BL1-FWU: Image copy in blocks completed\n"); + } + } else { + /* This means image is in RESET state and ready to be copied. */ + INFO("BL1-FWU: Fresh call to copy an image\n"); + + if (!image_size) { + WARN("BL1-FWU: Copy not allowed due to invalid image size\n"); + return -ENOMEM; + } + + /* + * If block size is more than total size then + * assume block size as the total image size. + */ + if (block_size > image_size) { + block_size = image_size; + WARN("BL1-FWU: Copy argument block_size > image size." + " Clipping block_size\n"); + } + + /* Make sure the image src/size is mapped. */ + if (bl1_plat_mem_check(image_src, block_size, flags)) { + WARN("BL1-FWU: Copy arguments source/size not mapped\n"); + return -ENOMEM; + } + + /* Find out how much free trusted ram remains after BL1 load */ + mem_layout = bl1_plat_sec_mem_layout(); + if ((image_desc->image_info.image_base < mem_layout->free_base) || + (image_desc->image_info.image_base + image_size > + mem_layout->free_base + mem_layout->free_size)) { + WARN("BL1-FWU: Memory not available to copy\n"); + return -ENOMEM; + } + + /* Update the image size. */ + image_desc->image_info.image_size = image_size; + + /* Copy image for given size. */ + memcpy((void *)base_addr, (const void *)image_src, block_size); + flush_dcache_range(base_addr, block_size); + + /* Update the state. */ + if (block_size == image_size) { + image_desc->state = IMAGE_STATE_COPIED; + INFO("BL1-FWU: Image is copied successfully\n"); + } else { + image_desc->state = IMAGE_STATE_COPYING; + INFO("BL1-FWU: Started image copy in blocks\n"); + } + + image_desc->image_info.copied_size = block_size; + } + + return 0; +} + +/******************************************************************************* + * This function is responsible for authenticating Normal/Secure images. + ******************************************************************************/ +static int bl1_fwu_image_auth(unsigned int image_id, + uintptr_t image_src, + unsigned int image_size, + unsigned int flags) +{ + int result; + uintptr_t base_addr; + unsigned int total_size; + + /* Get the image descriptor. */ + image_desc_t *image_desc = bl1_plat_get_image_desc(image_id); + if (!image_desc) + return -EPERM; + + if (GET_SEC_STATE(flags) == SECURE) { + if (image_desc->state != IMAGE_STATE_RESET) { + WARN("BL1-FWU: Authentication from secure world " + "while in invalid state\n"); + return -EPERM; + } + } else { + if (GET_SEC_STATE(image_desc->ep_info.h.attr) == SECURE) { + if (image_desc->state != IMAGE_STATE_COPIED) { + WARN("BL1-FWU: Authentication of secure image " + "from non-secure world while not in copied state\n"); + return -EPERM; + } + } else { + if (image_desc->state != IMAGE_STATE_RESET) { + WARN("BL1-FWU: Authentication of non-secure image " + "from non-secure world while in invalid state\n"); + return -EPERM; + } + } + } + + if (image_desc->state == IMAGE_STATE_COPIED) { + /* + * Image is in COPIED state. + * Use the stored address and size. + */ + base_addr = image_desc->image_info.image_base; + total_size = image_desc->image_info.image_size; + } else { + if ((!image_src) || (!image_size)) { + WARN("BL1-FWU: Auth not allowed due to invalid" + " image source/size\n"); + return -ENOMEM; + } + + /* + * Image is in RESET state. + * Check the parameters and authenticate the source image in place. + */ + if (bl1_plat_mem_check(image_src, image_size, flags)) { + WARN("BL1-FWU: Authentication arguments source/size not mapped\n"); + return -ENOMEM; + } + + base_addr = image_src; + total_size = image_size; + + /* Update the image size in the descriptor. */ + image_desc->image_info.image_size = total_size; + } + + /* + * Authenticate the image. + */ + INFO("BL1-FWU: Authenticating image_id:%d\n", image_id); + result = auth_mod_verify_img(image_id, (void *)base_addr, total_size); + if (result != 0) { + WARN("BL1-FWU: Authentication Failed err=%d\n", result); + + /* + * Authentication has failed. + * Clear the memory if the image was copied. + * This is to prevent an attack where this contains + * some malicious code that can somehow be executed later. + */ + if (image_desc->state == IMAGE_STATE_COPIED) { + /* Clear the memory.*/ + memset((void *)base_addr, 0, total_size); + flush_dcache_range(base_addr, total_size); + + /* Indicate that image can be copied again*/ + image_desc->state = IMAGE_STATE_RESET; + } + return -EAUTH; + } + + /* Indicate that image is in authenticated state. */ + image_desc->state = IMAGE_STATE_AUTHENTICATED; + + /* + * Flush image_info to memory so that other + * secure world images can see changes. + */ + flush_dcache_range((unsigned long)&image_desc->image_info, + sizeof(image_info_t)); + + INFO("BL1-FWU: Authentication was successful\n"); + + return 0; +} + +/******************************************************************************* + * This function is responsible for executing Secure images. + ******************************************************************************/ +static int bl1_fwu_image_execute(unsigned int image_id, + void **handle, + unsigned int flags) +{ + /* Get the image descriptor. */ + image_desc_t *image_desc = bl1_plat_get_image_desc(image_id); + + /* + * Execution is NOT allowed if: + * Caller is from Secure world OR + * Image is Non-Secure OR + * Image is Non-Executable OR + * Image is NOT in AUTHENTICATED state. + */ + if ((!image_desc) || + (GET_SEC_STATE(flags) == SECURE) || + (GET_SEC_STATE(image_desc->ep_info.h.attr) == NON_SECURE) || + (GET_EXEC_STATE(image_desc->image_info.h.attr) == NON_EXECUTABLE) || + (image_desc->state != IMAGE_STATE_AUTHENTICATED)) { + WARN("BL1-FWU: Execution not allowed due to invalid state/args\n"); + return -EPERM; + } + + INFO("BL1-FWU: Executing Secure image\n"); + + /* Save NS-EL1 system registers. */ + cm_el1_sysregs_context_save(NON_SECURE); + + /* Prepare the image for execution. */ + bl1_prepare_next_image(image_id); + + /* Update the secure image id. */ + sec_exec_image_id = image_id; + + *handle = cm_get_context(SECURE); + return 0; +} + +/******************************************************************************* + * This function is responsible for resuming Secure/Non-Secure images. + ******************************************************************************/ +static register_t bl1_fwu_image_resume(unsigned int image_id, + register_t image_param, + void **handle, + unsigned int flags) +{ + image_desc_t *image_desc; + unsigned int resume_sec_state; + + if (GET_SEC_STATE(flags) == SECURE) { + /* Get the image descriptor for last executed secure image id. */ + image_desc = bl1_plat_get_image_desc(sec_exec_image_id); + + if ((!image_desc) || (image_desc->state != IMAGE_STATE_EXECUTED)) { + WARN("BL1-FWU: Resume not allowed for secure image " + "due to invalid state\n"); + return -EPERM; + } + + /* Update the flags. */ + image_desc->state = IMAGE_STATE_INTERRUPTED; + resume_sec_state = NON_SECURE; + } else { + /* Get the image descriptor for image id to be resumed. */ + image_desc = bl1_plat_get_image_desc(image_id); + + /* Make sure image is secure and was interrupted. */ + if ((!image_desc) || + (GET_SEC_STATE(image_desc->ep_info.h.attr) == NON_SECURE) || + (image_desc->state != IMAGE_STATE_INTERRUPTED)) { + WARN("BL1-FWU: Resume not allowed for NS image/ invalid state\n"); + return -EPERM; + } + + /* Update the flags. */ + image_desc->state = IMAGE_STATE_EXECUTED; + resume_sec_state = SECURE; + } + + /* Save the EL1 system registers of calling world. */ + cm_el1_sysregs_context_save(GET_SEC_STATE(flags)); + + /* Restore the EL1 system registers of resuming world. */ + cm_el1_sysregs_context_restore(resume_sec_state); + + /* Update the next context. */ + cm_set_next_eret_context(resume_sec_state); + + INFO("BL1-FWU: Resuming %s world context\n", + (resume_sec_state == SECURE) ? "Secure" : "Normal"); + + *handle = cm_get_context(resume_sec_state); + return image_param; +} + +/******************************************************************************* + * This function is responsible for resuming normal world context. + ******************************************************************************/ +static int bl1_fwu_sec_image_done(void **handle, unsigned int flags) +{ + + /* Get the image descriptor for last executed secure image id. */ + image_desc_t *image_desc = bl1_plat_get_image_desc(sec_exec_image_id); + + /* + * Make sure caller is from secure world + * and the image is in EXECUTED state. + */ + if ((!image_desc) || + (GET_SEC_STATE(flags) == NON_SECURE) || + (image_desc->state != IMAGE_STATE_EXECUTED)) { + WARN("BL1-FWU: Done not allowed for NS caller/ invalid state\n"); + return -EPERM; + } + + /* Update the flags. */ + image_desc->state = IMAGE_STATE_RESET; + sec_exec_image_id = INVALID_IMAGE_ID; + + /* + * Secure world is done so no need to save the context. + * Just restore the Non-Secure context. + */ + cm_el1_sysregs_context_restore(NON_SECURE); + + /* Update the next context. */ + cm_set_next_eret_context(NON_SECURE); + + INFO("BL1-FWU: Resuming Normal world context\n"); + + *handle = cm_get_context(NON_SECURE); + return 0; +} + +/******************************************************************************* + * This function provides the opportunity for users to perform any + * platform specific handling after the Firmware update is done. + ******************************************************************************/ +__dead2 static void bl1_fwu_done(void *cookie, void *reserved) +{ + NOTICE("BL1-FWU: *******FWU Process Completed*******\n"); + + /* + * Call platform done function. + */ + bl1_plat_fwu_done(cookie, reserved); + assert(0); +} diff --git a/bl1/bl1_main.c b/bl1/bl1_main.c index 73f023ab..84d56110 100644 --- a/bl1/bl1_main.c +++ b/bl1/bl1_main.c @@ -32,43 +32,22 @@ #include <arch_helpers.h> #include <assert.h> #include <auth_mod.h> +#include <bl1.h> #include <bl_common.h> #include <debug.h> #include <platform.h> #include <platform_def.h> +#include <smcc_helpers.h> #include "bl1_private.h" +#include <uuid.h> -/******************************************************************************* - * Runs BL2 from the given entry point. It results in dropping the - * exception level - ******************************************************************************/ -static void __dead2 bl1_run_bl2(entry_point_info_t *bl2_ep) -{ - /* Check bl2 security state is expected as secure */ - assert(GET_SECURITY_STATE(bl2_ep->h.attr) == SECURE); - /* Check NS Bit is also set as secure */ - assert(!(read_scr_el3() & SCR_NS_BIT)); - - bl1_arch_next_el_setup(); +/* BL1 Service UUID */ +DEFINE_SVC_UUID(bl1_svc_uid, + 0xfd3967d4, 0x72cb, 0x4d9a, 0xb5, 0x75, + 0x67, 0x15, 0xd6, 0xf4, 0xbb, 0x4a); - /* Tell next EL what we want done */ - bl2_ep->args.arg0 = RUN_IMAGE; - write_spsr_el3(bl2_ep->spsr); - write_elr_el3(bl2_ep->pc); - - NOTICE("BL1: Booting BL2\n"); - print_entry_point_info(bl2_ep); - - eret(bl2_ep->args.arg0, - bl2_ep->args.arg1, - bl2_ep->args.arg2, - bl2_ep->args.arg3, - bl2_ep->args.arg4, - bl2_ep->args.arg5, - bl2_ep->args.arg6, - bl2_ep->args.arg7); -} +static void bl1_load_bl2(void); /******************************************************************************* * The next function has a weak definition. Platform specific code can override @@ -91,7 +70,8 @@ void bl1_init_bl2_mem_layout(const meminfo_t *bl1_mem_layout, /* Check that BL1's memory is lying outside of the free memory */ assert((BL1_RAM_LIMIT <= bl1_mem_layout->free_base) || - (BL1_RAM_BASE >= bl1_mem_layout->free_base + bl1_mem_layout->free_size)); + (BL1_RAM_BASE >= bl1_mem_layout->free_base + + bl1_mem_layout->free_size)); /* Remove BL1 RW data from the scope of memory visible to BL2 */ *bl2_mem_layout = *bl1_mem_layout; @@ -105,13 +85,13 @@ void bl1_init_bl2_mem_layout(const meminfo_t *bl1_mem_layout, /******************************************************************************* * Function to perform late architectural and platform specific initialization. - * It also locates and loads the BL2 raw binary image in the trusted DRAM. Only - * called by the primary cpu after a cold boot. - * TODO: Add support for alternative image load mechanism e.g using virtio/elf - * loader etc. - ******************************************************************************/ + * It also queries the platform to load and run next BL image. Only called + * by the primary cpu after a cold boot. + ******************************************************************************/ void bl1_main(void) { + unsigned int image_id; + /* Announce our arrival */ NOTICE(FIRMWARE_WELCOME_STR); NOTICE("BL1: %s\n", version_string); @@ -119,11 +99,6 @@ void bl1_main(void) INFO("BL1: RAM 0x%lx - 0x%lx\n", BL1_RAM_BASE, BL1_RAM_LIMIT); - image_info_t bl2_image_info = { {0} }; - entry_point_info_t bl2_ep = { {0} }; - meminfo_t *bl1_tzram_layout; - meminfo_t *bl2_tzram_layout = 0x0; - int err; #if DEBUG unsigned long val; @@ -153,28 +128,65 @@ void bl1_main(void) /* Perform remaining generic architectural setup from EL3 */ bl1_arch_setup(); +#if TRUSTED_BOARD_BOOT + /* Initialize authentication module */ + auth_mod_init(); +#endif /* TRUSTED_BOARD_BOOT */ + /* Perform platform setup in BL1. */ bl1_platform_setup(); - SET_PARAM_HEAD(&bl2_image_info, PARAM_IMAGE_BINARY, VERSION_1, 0); - SET_PARAM_HEAD(&bl2_ep, PARAM_EP, VERSION_1, 0); + /* Get the image id of next image to load and run. */ + image_id = bl1_plat_get_next_image_id(); + + /* + * We currently interpret any image id other than + * BL2_IMAGE_ID as the start of firmware update. + */ + if (image_id == BL2_IMAGE_ID) + bl1_load_bl2(); + else + NOTICE("BL1-FWU: *******FWU Process Started*******\n"); + + bl1_prepare_next_image(image_id); +} + +/******************************************************************************* + * This function locates and loads the BL2 raw binary image in the trusted SRAM. + * Called by the primary cpu after a cold boot. + * TODO: Add support for alternative image load mechanism e.g using virtio/elf + * loader etc. + ******************************************************************************/ +void bl1_load_bl2(void) +{ + image_desc_t *image_desc; + image_info_t *image_info; + entry_point_info_t *ep_info; + meminfo_t *bl1_tzram_layout; + meminfo_t *bl2_tzram_layout; + int err; + + /* Get the image descriptor */ + image_desc = bl1_plat_get_image_desc(BL2_IMAGE_ID); + assert(image_desc); + + /* Get the image info */ + image_info = &image_desc->image_info; + + /* Get the entry point info */ + ep_info = &image_desc->ep_info; /* Find out how much free trusted ram remains after BL1 load */ bl1_tzram_layout = bl1_plat_sec_mem_layout(); INFO("BL1: Loading BL2\n"); -#if TRUSTED_BOARD_BOOT - /* Initialize authentication module */ - auth_mod_init(); -#endif /* TRUSTED_BOARD_BOOT */ - /* Load the BL2 image */ err = load_auth_image(bl1_tzram_layout, BL2_IMAGE_ID, - BL2_BASE, - &bl2_image_info, - &bl2_ep); + image_info->image_base, + image_info, + ep_info); if (err) { ERROR("Failed to load BL2 firmware.\n"); @@ -191,11 +203,10 @@ void bl1_main(void) bl2_tzram_layout = (meminfo_t *) bl1_tzram_layout->free_base; bl1_init_bl2_mem_layout(bl1_tzram_layout, bl2_tzram_layout); - bl1_plat_set_bl2_ep_info(&bl2_image_info, &bl2_ep); - bl2_ep.args.arg1 = (unsigned long)bl2_tzram_layout; - bl1_run_bl2(&bl2_ep); - - return; + ep_info->args.arg1 = (unsigned long)bl2_tzram_layout; + NOTICE("BL1: Booting BL2\n"); + VERBOSE("BL1: BL2 memory layout address = 0x%llx\n", + (unsigned long long) bl2_tzram_layout); } /******************************************************************************* @@ -216,3 +227,45 @@ void print_debug_loop_message(void) NOTICE("BL1: Please connect the debugger to continue\n"); } #endif + +/******************************************************************************* + * Top level handler for servicing BL1 SMCs. + ******************************************************************************/ +register_t bl1_smc_handler(unsigned int smc_fid, + register_t x1, + register_t x2, + register_t x3, + register_t x4, + void *cookie, + void *handle, + unsigned int flags) +{ + +#if TRUSTED_BOARD_BOOT + /* + * Dispatch FWU calls to FWU SMC handler and return its return + * value + */ + if (is_fwu_fid(smc_fid)) { + return bl1_fwu_smc_handler(smc_fid, x1, x2, x3, x4, cookie, + handle, flags); + } +#endif + + switch (smc_fid) { + case BL1_SMC_CALL_COUNT: + SMC_RET1(handle, BL1_NUM_SMC_CALLS); + + case BL1_SMC_UID: + SMC_UUID_RET(handle, bl1_svc_uid); + + case BL1_SMC_VERSION: + SMC_RET1(handle, BL1_SMC_MAJOR_VER | BL1_SMC_MINOR_VER); + + default: + break; + } + + WARN("Unimplemented BL1 SMC Call: 0x%x \n", smc_fid); + SMC_RET1(handle, SMC_UNK); +} diff --git a/bl1/bl1_private.h b/bl1/bl1_private.h index 0a8fc45c..283bbb97 100644 --- a/bl1/bl1_private.h +++ b/bl1/bl1_private.h @@ -31,6 +31,8 @@ #ifndef __BL1_PRIVATE_H__ #define __BL1_PRIVATE_H__ +#include <types.h> + /******************************************************************************* * Declarations of linker defined symbols which will tell us where BL1 lives * in Trusted RAM @@ -46,4 +48,14 @@ extern uint64_t __BL1_RAM_END__; void bl1_arch_setup(void); void bl1_arch_next_el_setup(void); +void bl1_prepare_next_image(unsigned int image_id); + +register_t bl1_fwu_smc_handler(unsigned int smc_fid, + register_t x1, + register_t x2, + register_t x3, + register_t x4, + void *cookie, + void *handle, + unsigned int flags); #endif /* __BL1_PRIVATE_H__ */ diff --git a/bl1/tbbr/tbbr_img_desc.c b/bl1/tbbr/tbbr_img_desc.c new file mode 100644 index 00000000..42de8517 --- /dev/null +++ b/bl1/tbbr/tbbr_img_desc.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <bl1.h> +#include <bl_common.h> +#include <platform_def.h> + +image_desc_t bl1_tbbr_image_descs[] = { + { + .image_id = FWU_CERT_ID, + .image_info.h.attr = SET_EXEC_STATE(NON_EXECUTABLE), + .image_info.image_base = BL2_BASE, + .ep_info.h.attr = SET_SEC_STATE(SECURE), + }, +#if NS_BL1U_BASE + { + .image_id = NS_BL1U_IMAGE_ID, + .image_info.h.attr = SET_EXEC_STATE(EXECUTABLE), + .image_info.image_base = NS_BL1U_BASE, + .ep_info.h.attr = SET_SEC_STATE(NON_SECURE), + .ep_info.pc = NS_BL1U_BASE, + }, +#endif +#if SCP_BL2U_BASE + { + .image_id = SCP_BL2U_IMAGE_ID, + .image_info.h.attr = SET_EXEC_STATE(NON_EXECUTABLE), + .image_info.image_base = SCP_BL2U_BASE, + .ep_info.h.attr = SET_SEC_STATE(SECURE), + }, +#endif +#if BL2U_BASE + { + .image_id = BL2U_IMAGE_ID, + .image_info.h.attr = SET_EXEC_STATE(EXECUTABLE), + .image_info.image_base = BL2U_BASE, + .ep_info.h.attr = SET_SEC_STATE(SECURE), + .ep_info.pc = BL2U_BASE, + }, +#endif +#if NS_BL2U_BASE + { + .image_id = NS_BL2U_IMAGE_ID, + .image_info.h.attr = SET_EXEC_STATE(NON_EXECUTABLE), + .image_info.image_base = NS_BL2U_BASE, + .ep_info.h.attr = SET_SEC_STATE(NON_SECURE), + }, +#endif + BL2_IMAGE_DESC, + + { + .image_id = INVALID_IMAGE_ID, + } +}; diff --git a/bl2/aarch64/bl2_entrypoint.S b/bl2/aarch64/bl2_entrypoint.S index 1d262297..75eb02a9 100644 --- a/bl2/aarch64/bl2_entrypoint.S +++ b/bl2/aarch64/bl2_entrypoint.S @@ -39,13 +39,12 @@ func bl2_entrypoint /*--------------------------------------------- - * Store the extents of the tzram available to - * BL2 for future use. Use the opcode param to - * allow implement other functions if needed. + * Save from x1 the extents of the tzram + * available to BL2 for future use. + * x0 is not currently used. * --------------------------------------------- - */ - mov x20, x0 - mov x21, x1 + */ + mov x20, x1 /* --------------------------------------------- * Set the exception vector to something sane. @@ -74,14 +73,6 @@ func bl2_entrypoint isb /* --------------------------------------------- - * Check the opcodes out of paranoia. - * --------------------------------------------- - */ - mov x0, #RUN_IMAGE - cmp x0, x20 - b.ne _panic - - /* --------------------------------------------- * Invalidate the RW memory used by the BL2 * image. This includes the data and NOBITS * sections. This is done to safeguard against @@ -126,7 +117,7 @@ func bl2_entrypoint * specific early arch. setup e.g. mmu setup * --------------------------------------------- */ - mov x0, x21 + mov x0, x20 bl bl2_early_platform_setup bl bl2_plat_arch_setup diff --git a/bl2/bl2_main.c b/bl2/bl2_main.c index a3f016f9..f4756405 100644 --- a/bl2/bl2_main.c +++ b/bl2/bl2_main.c @@ -32,6 +32,7 @@ #include <arch_helpers.h> #include <assert.h> #include <auth_mod.h> +#include <bl1.h> #include <bl_common.h> #include <debug.h> #include <errno.h> @@ -281,5 +282,5 @@ void bl2_main(void) * the BL3-2 (if present) and BL3-3 software images will be passed to * BL3-1 as an argument. */ - smc(RUN_IMAGE, (unsigned long)bl31_ep_info, 0, 0, 0, 0, 0, 0); + smc(BL1_SMC_RUN_IMAGE, (unsigned long)bl31_ep_info, 0, 0, 0, 0, 0, 0); } diff --git a/bl2u/aarch64/bl2u_entrypoint.S b/bl2u/aarch64/bl2u_entrypoint.S new file mode 100644 index 00000000..c9aad81f --- /dev/null +++ b/bl2u/aarch64/bl2u_entrypoint.S @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arch.h> +#include <asm_macros.S> +#include <bl_common.h> + + + .globl bl2u_entrypoint + + +func bl2u_entrypoint + /*--------------------------------------------- + * Store the extents of the tzram available to + * BL2U and other platform specific information + * for future use. x0 is currently not used. + * --------------------------------------------- + */ + mov x20, x1 + mov x21, x2 + + /* --------------------------------------------- + * Set the exception vector to something sane. + * --------------------------------------------- + */ + adr x0, early_exceptions + msr vbar_el1, x0 + isb + + /* --------------------------------------------- + * Enable the SError interrupt now that the + * exception vectors have been setup. + * --------------------------------------------- + */ + msr daifclr, #DAIF_ABT_BIT + + /* --------------------------------------------- + * Enable the instruction cache, stack pointer + * and data access alignment checks + * --------------------------------------------- + */ + mov x1, #(SCTLR_I_BIT | SCTLR_A_BIT | SCTLR_SA_BIT) + mrs x0, sctlr_el1 + orr x0, x0, x1 + msr sctlr_el1, x0 + isb + + /* --------------------------------------------- + * Invalidate the RW memory used by the BL2U + * image. This includes the data and NOBITS + * sections. This is done to safeguard against + * possible corruption of this memory by dirty + * cache lines in a system cache as a result of + * use by an earlier boot loader stage. + * --------------------------------------------- + */ + adr x0, __RW_START__ + adr x1, __RW_END__ + sub x1, x1, x0 + bl inv_dcache_range + + /* --------------------------------------------- + * Zero out NOBITS sections. There are 2 of them: + * - the .bss section; + * - the coherent memory section. + * --------------------------------------------- + */ + ldr x0, =__BSS_START__ + ldr x1, =__BSS_SIZE__ + bl zeromem16 + + /* -------------------------------------------- + * Allocate a stack whose memory will be marked + * as Normal-IS-WBWA when the MMU is enabled. + * There is no risk of reading stale stack + * memory after enabling the MMU as only the + * primary cpu is running at the moment. + * -------------------------------------------- + */ + bl plat_set_my_stack + + /* --------------------------------------------- + * Perform early platform setup & platform + * specific early arch. setup e.g. mmu setup + * --------------------------------------------- + */ + mov x0, x20 + mov x1, x21 + bl bl2u_early_platform_setup + bl bl2u_plat_arch_setup + + /* --------------------------------------------- + * Jump to bl2u_main function. + * --------------------------------------------- + */ + bl bl2u_main + +_panic: + b _panic +endfunc bl2u_entrypoint diff --git a/bl2u/bl2u.ld.S b/bl2u/bl2u.ld.S new file mode 100644 index 00000000..ec120779 --- /dev/null +++ b/bl2u/bl2u.ld.S @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <platform_def.h> + +OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT) +OUTPUT_ARCH(PLATFORM_LINKER_ARCH) +ENTRY(bl2u_entrypoint) + +MEMORY { + RAM (rwx): ORIGIN = BL2U_BASE, LENGTH = BL2U_LIMIT - BL2U_BASE +} + + +SECTIONS +{ + . = BL2U_BASE; + ASSERT(. == ALIGN(4096), + "BL2U_BASE address is not aligned on a page boundary.") + + ro . : { + __RO_START__ = .; + *bl2u_entrypoint.o(.text*) + *(.text*) + *(.rodata*) + + *(.vectors) + __RO_END_UNALIGNED__ = .; + /* + * Memory page(s) mapped to this section will be marked as + * read-only, executable. No RW data from the next section must + * creep in. Ensure the rest of the current memory page is unused. + */ + . = NEXT(4096); + __RO_END__ = .; + } >RAM + + /* + * Define a linker symbol to mark start of the RW memory area for this + * image. + */ + __RW_START__ = . ; + + .data . : { + __DATA_START__ = .; + *(.data*) + __DATA_END__ = .; + } >RAM + + stacks (NOLOAD) : { + __STACKS_START__ = .; + *(tzfw_normal_stacks) + __STACKS_END__ = .; + } >RAM + + /* + * The .bss section gets initialised to 0 at runtime. + * Its base address must be 16-byte aligned. + */ + .bss : ALIGN(16) { + __BSS_START__ = .; + *(SORT_BY_ALIGNMENT(.bss*)) + *(COMMON) + __BSS_END__ = .; + } >RAM + + /* + * The xlat_table section is for full, aligned page tables (4K). + * Removing them from .bss avoids forcing 4K alignment on + * the .bss section and eliminates the unecessary zero init + */ + xlat_table (NOLOAD) : { + *(xlat_table) + } >RAM + +#if USE_COHERENT_MEM + /* + * The base address of the coherent memory section must be page-aligned (4K) + * to guarantee that the coherent data are stored on their own pages and + * are not mixed with normal data. This is required to set up the correct + * memory attributes for the coherent data page tables. + */ + coherent_ram (NOLOAD) : ALIGN(4096) { + __COHERENT_RAM_START__ = .; + *(tzfw_coherent_mem) + __COHERENT_RAM_END_UNALIGNED__ = .; + /* + * Memory page(s) mapped to this section will be marked + * as device memory. No other unexpected data must creep in. + * Ensure the rest of the current memory page is unused. + */ + . = NEXT(4096); + __COHERENT_RAM_END__ = .; + } >RAM +#endif + + /* + * Define a linker symbol to mark end of the RW memory area for this + * image. + */ + __RW_END__ = .; + __BL2U_END__ = .; + + __BSS_SIZE__ = SIZEOF(.bss); + + ASSERT(. <= BL2U_LIMIT, "BL2U image has exceeded its limit.") +} diff --git a/bl2u/bl2u.mk b/bl2u/bl2u.mk new file mode 100644 index 00000000..aa9de544 --- /dev/null +++ b/bl2u/bl2u.mk @@ -0,0 +1,35 @@ +# +# Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# Neither the name of ARM nor the names of its contributors may be used +# to endorse or promote products derived from this software without specific +# prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +BL2U_SOURCES += bl2u/bl2u_main.c \ + bl2u/aarch64/bl2u_entrypoint.S \ + common/aarch64/early_exceptions.S + +BL2U_LINKERFILE := bl2u/bl2u.ld.S diff --git a/bl2u/bl2u_main.c b/bl2u/bl2u_main.c new file mode 100644 index 00000000..515ddfb7 --- /dev/null +++ b/bl2u/bl2u_main.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arch.h> +#include <arch_helpers.h> +#include <assert.h> +#include <auth_mod.h> +#include <bl_common.h> +#include <bl1.h> +#include <debug.h> +#include <platform.h> +#include <platform_def.h> +#include <stdint.h> + +/******************************************************************************* + * This function is responsible to: + * Load SCP_BL2U if platform has defined SCP_BL2U_BASE + * Perform platform setup. + * Go back to EL3. + ******************************************************************************/ +void bl2u_main(void) +{ + NOTICE("BL2U: %s\n", version_string); + NOTICE("BL2U: %s\n", build_message); + +#if SCP_BL2U_BASE + int rc; + /* Load the subsequent bootloader images */ + rc = bl2u_plat_handle_scp_bl2u(); + if (rc) { + ERROR("Failed to load SCP_BL2U (%i)\n", rc); + panic(); + } +#endif + + /* Perform platform setup in BL2U after loading SCP_BL2U */ + bl2u_platform_setup(); + + /* + * Indicate that BL2U is done and resume back to + * normal world via an SMC to BL1. + * x1 could be passed to Normal world, + * so DO NOT pass any secret information. + */ + smc(FWU_SMC_SEC_IMAGE_DONE, 0, 0, 0, 0, 0, 0, 0); + wfi(); +} diff --git a/bl31/aarch64/runtime_exceptions.S b/bl31/aarch64/runtime_exceptions.S index 28353202..dc11e0a7 100644 --- a/bl31/aarch64/runtime_exceptions.S +++ b/bl31/aarch64/runtime_exceptions.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -36,7 +36,6 @@ #include <runtime_svc.h> .globl runtime_exceptions - .globl el3_exit /* ----------------------------------------------------- * Handle SMC exceptions separately from other sync. @@ -426,38 +425,7 @@ smc_handler64: #endif blr x15 - /* ----------------------------------------------------- - * This routine assumes that the SP_EL3 is pointing to - * a valid context structure from where the gp regs and - * other special registers can be retrieved. - * - * Keep it in the same section as smc_handler as this - * function uses a fall-through to el3_exit - * ----------------------------------------------------- - */ -el3_exit: ; .type el3_exit, %function - /* ----------------------------------------------------- - * Save the current SP_EL0 i.e. the EL3 runtime stack - * which will be used for handling the next SMC. Then - * switch to SP_EL3 - * ----------------------------------------------------- - */ - mov x17, sp - msr spsel, #1 - str x17, [sp, #CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP] - - /* ----------------------------------------------------- - * Restore SPSR_EL3, ELR_EL3 and SCR_EL3 prior to ERET - * ----------------------------------------------------- - */ - ldr x18, [sp, #CTX_EL3STATE_OFFSET + CTX_SCR_EL3] - ldp x16, x17, [sp, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3] - msr scr_el3, x18 - msr spsr_el3, x16 - msr elr_el3, x17 - - /* Restore saved general purpose registers and return */ - b restore_gp_registers_eret + b el3_exit smc_unknown: /* @@ -479,51 +447,3 @@ rt_svc_fw_critical_error: msr spsel, #1 /* Switch to SP_ELx */ bl report_unhandled_exception endfunc smc_handler - - /* ----------------------------------------------------- - * The following functions are used to saved and restore - * all the general pupose registers. Ideally we would - * only save and restore the callee saved registers when - * a world switch occurs but that type of implementation - * is more complex. So currently we will always save and - * restore these registers on entry and exit of EL3. - * These are not macros to ensure their invocation fits - * within the 32 instructions per exception vector. - * ----------------------------------------------------- - */ -func save_gp_registers - stp x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0] - stp x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2] - stp x4, x5, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X4] - stp x6, x7, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X6] - stp x8, x9, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X8] - stp x10, x11, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X10] - stp x12, x13, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X12] - stp x14, x15, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X14] - stp x16, x17, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X16] - save_x18_to_x29_sp_el0 - ret -endfunc save_gp_registers - -func restore_gp_registers_eret - ldp x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0] - ldp x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2] - -restore_gp_registers_callee_eret: - ldp x4, x5, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X4] - ldp x6, x7, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X6] - ldp x8, x9, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X8] - ldp x10, x11, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X10] - ldp x12, x13, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X12] - ldp x14, x15, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X14] - ldp x18, x19, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X18] - ldp x20, x21, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X20] - ldp x22, x23, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X22] - ldp x24, x25, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X24] - ldp x26, x27, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X26] - ldp x28, x29, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X28] - ldp x30, x17, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR] - msr sp_el0, x17 - ldp x16, x17, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X16] - eret -endfunc restore_gp_registers_eret diff --git a/bl31/bl31.mk b/bl31/bl31.mk index a31c1f47..0c2b631a 100644 --- a/bl31/bl31.mk +++ b/bl31/bl31.mk @@ -29,16 +29,17 @@ # BL31_SOURCES += bl31/bl31_main.c \ - bl31/context_mgmt.c \ bl31/cpu_data_array.c \ bl31/runtime_svc.c \ bl31/interrupt_mgmt.c \ bl31/aarch64/bl31_arch_setup.c \ bl31/aarch64/bl31_entrypoint.S \ - bl31/aarch64/context.S \ bl31/aarch64/cpu_data.S \ bl31/aarch64/runtime_exceptions.S \ bl31/aarch64/crash_reporting.S \ + bl31/bl31_context_mgmt.c \ + common/aarch64/context.S \ + common/context_mgmt.c \ lib/cpus/aarch64/cpu_helpers.S \ lib/locks/exclusive/spinlock.S \ services/std_svc/std_svc_setup.c \ diff --git a/bl31/bl31_context_mgmt.c b/bl31/bl31_context_mgmt.c new file mode 100644 index 00000000..ae244247 --- /dev/null +++ b/bl31/bl31_context_mgmt.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <assert.h> +#include <bl31.h> +#include <context.h> +#include <context_mgmt.h> +#include <cpu_data.h> +#include <platform.h> + + +/******************************************************************************* + * This function returns a pointer to the most recent 'cpu_context' structure + * for the calling CPU that was set as the context for the specified security + * state. NULL is returned if no such structure has been specified. + ******************************************************************************/ +void *cm_get_context(uint32_t security_state) +{ + assert(security_state <= NON_SECURE); + + return get_cpu_data(cpu_context[security_state]); +} + +/******************************************************************************* + * This function sets the pointer to the current 'cpu_context' structure for the + * specified security state for the calling CPU + ******************************************************************************/ +void cm_set_context(void *context, uint32_t security_state) +{ + assert(security_state <= NON_SECURE); + + set_cpu_data(cpu_context[security_state], context); +} + +/******************************************************************************* + * This function returns a pointer to the most recent 'cpu_context' structure + * for the CPU identified by `cpu_idx` that was set as the context for the + * specified security state. NULL is returned if no such structure has been + * specified. + ******************************************************************************/ +void *cm_get_context_by_index(unsigned int cpu_idx, + unsigned int security_state) +{ + assert(sec_state_is_valid(security_state)); + + return get_cpu_data_by_index(cpu_idx, cpu_context[security_state]); +} + +/******************************************************************************* + * This function sets the pointer to the current 'cpu_context' structure for the + * specified security state for the CPU identified by CPU index. + ******************************************************************************/ +void cm_set_context_by_index(unsigned int cpu_idx, void *context, + unsigned int security_state) +{ + assert(sec_state_is_valid(security_state)); + + set_cpu_data_by_index(cpu_idx, cpu_context[security_state], context); +} + +#if !ERROR_DEPRECATED +/* + * These context management helpers are deprecated but are maintained for use + * by SPDs which have not migrated to the new API. If ERROR_DEPRECATED + * is enabled, these are excluded from the build so as to force users to + * migrate to the new API. + */ + +/******************************************************************************* + * This function returns a pointer to the most recent 'cpu_context' structure + * for the CPU identified by MPIDR that was set as the context for the specified + * security state. NULL is returned if no such structure has been specified. + ******************************************************************************/ +void *cm_get_context_by_mpidr(uint64_t mpidr, uint32_t security_state) +{ + assert(sec_state_is_valid(security_state)); + + return cm_get_context_by_index(platform_get_core_pos(mpidr), security_state); +} + +/******************************************************************************* + * This function sets the pointer to the current 'cpu_context' structure for the + * specified security state for the CPU identified by MPIDR + ******************************************************************************/ +void cm_set_context_by_mpidr(uint64_t mpidr, void *context, uint32_t security_state) +{ + assert(sec_state_is_valid(security_state)); + + cm_set_context_by_index(platform_get_core_pos(mpidr), + context, security_state); +} + +/******************************************************************************* + * The following function provides a compatibility function for SPDs using the + * existing cm library routines. This function is expected to be invoked for + * initializing the cpu_context for the CPU specified by MPIDR for first use. + ******************************************************************************/ +void cm_init_context(unsigned long mpidr, const entry_point_info_t *ep) +{ + if ((mpidr & MPIDR_AFFINITY_MASK) == + (read_mpidr_el1() & MPIDR_AFFINITY_MASK)) + cm_init_my_context(ep); + else + cm_init_context_by_index(platform_get_core_pos(mpidr), ep); +} +#endif
\ No newline at end of file diff --git a/bl31/bl31_main.c b/bl31/bl31_main.c index 9abc395b..f22e6121 100644 --- a/bl31/bl31_main.c +++ b/bl31/bl31_main.c @@ -77,7 +77,7 @@ void bl31_main(void) /* Perform remaining generic architectural setup from EL3 */ bl31_arch_setup(); - /* Perform platform setup in BL1 */ + /* Perform platform setup in BL31 */ bl31_platform_setup(); /* Initialise helper libraries */ @@ -109,6 +109,12 @@ void bl31_main(void) * corresponding to the desired security state after the next ERET. */ bl31_prepare_next_image_entry(); + + /* + * Perform any platform specific runtime setup prior to cold boot exit + * from BL31 + */ + bl31_plat_runtime_setup(); } /******************************************************************************* diff --git a/bl31/interrupt_mgmt.c b/bl31/interrupt_mgmt.c index 206578b4..e9918515 100644 --- a/bl31/interrupt_mgmt.c +++ b/bl31/interrupt_mgmt.c @@ -67,18 +67,15 @@ typedef struct intr_type_desc { static intr_type_desc_t intr_type_descs[MAX_INTR_TYPES]; /******************************************************************************* - * This function validates the interrupt type. EL3 interrupts are currently not - * supported. + * This function validates the interrupt type. ******************************************************************************/ static int32_t validate_interrupt_type(uint32_t type) { - if (type == INTR_TYPE_EL3) - return -ENOTSUP; - - if (type != INTR_TYPE_S_EL1 && type != INTR_TYPE_NS) - return -EINVAL; + if (type == INTR_TYPE_S_EL1 || type == INTR_TYPE_NS || + type == INTR_TYPE_EL3) + return 0; - return 0; + return -EINVAL; } /******************************************************************************* @@ -95,6 +92,9 @@ static int32_t validate_routing_model(uint32_t type, uint32_t flags) if (type == INTR_TYPE_NS) return validate_ns_interrupt_rm(flags); + if (type == INTR_TYPE_EL3) + return validate_el3_interrupt_rm(flags); + return -EINVAL; } diff --git a/bl32/tsp/aarch64/tsp_entrypoint.S b/bl32/tsp/aarch64/tsp_entrypoint.S index 9732ff2c..531ab9bf 100644 --- a/bl32/tsp/aarch64/tsp_entrypoint.S +++ b/bl32/tsp/aarch64/tsp_entrypoint.S @@ -177,7 +177,7 @@ func tsp_vector_table b tsp_cpu_off_entry b tsp_cpu_resume_entry b tsp_cpu_suspend_entry - b tsp_fiq_entry + b tsp_sel1_intr_entry b tsp_system_off_entry b tsp_system_reset_entry endfunc tsp_vector_table @@ -325,13 +325,15 @@ func tsp_cpu_suspend_entry restore_args_call_smc endfunc tsp_cpu_suspend_entry - /*--------------------------------------------- + /*------------------------------------------------- * This entrypoint is used by the TSPD to pass - * control for handling a pending S-EL1 FIQ. - * 'x0' contains a magic number which indicates - * this. TSPD expects control to be handed back - * at the end of FIQ processing. This is done - * through an SMC. The handover agreement is: + * control for `synchronously` handling a S-EL1 + * Interrupt which was triggered while executing + * in normal world. 'x0' contains a magic number + * which indicates this. TSPD expects control to + * be handed back at the end of interrupt + * processing. This is done through an SMC. + * The handover agreement is: * * 1. PSTATE.DAIF are set upon entry. 'x1' has * the ELR_EL3 from the non-secure state. @@ -343,40 +345,54 @@ endfunc tsp_cpu_suspend_entry * 4. TSP can use 'x0-x18' to enable its C * runtime. * 5. TSP returns to TSPD using an SMC with - * 'x0' = TSP_HANDLED_S_EL1_FIQ - * --------------------------------------------- + * 'x0' = TSP_HANDLED_S_EL1_INTR + * ------------------------------------------------ */ -func tsp_fiq_entry +func tsp_sel1_intr_entry #if DEBUG - mov x2, #(TSP_HANDLE_FIQ_AND_RETURN & ~0xffff) - movk x2, #(TSP_HANDLE_FIQ_AND_RETURN & 0xffff) + mov_imm x2, TSP_HANDLE_SEL1_INTR_AND_RETURN cmp x0, x2 - b.ne tsp_fiq_entry_panic + b.ne tsp_sel1_int_entry_panic #endif - /*--------------------------------------------- + /*------------------------------------------------- * Save any previous context needed to perform * an exception return from S-EL1 e.g. context - * from a previous IRQ. Update statistics and - * handle the FIQ before returning to the TSPD. + * from a previous Non secure Interrupt. + * Update statistics and handle the S-EL1 + * interrupt before returning to the TSPD. * IRQ/FIQs are not enabled since that will * complicate the implementation. Execution * will be transferred back to the normal world - * in any case. A non-zero return value from the - * fiq handler is an error. - * --------------------------------------------- + * in any case. The handler can return 0 + * if the interrupt was handled or TSP_PREEMPTED + * if the expected interrupt was preempted + * by an interrupt that should be handled in EL3 + * e.g. Group 0 interrupt in GICv3. In both + * the cases switch to EL3 using SMC with id + * TSP_HANDLED_S_EL1_INTR. Any other return value + * from the handler will result in panic. + * ------------------------------------------------ */ save_eret_context x2 x3 - bl tsp_update_sync_fiq_stats - bl tsp_fiq_handler - cbnz x0, tsp_fiq_entry_panic + bl tsp_update_sync_sel1_intr_stats + bl tsp_common_int_handler + /* Check if the S-EL1 interrupt has been handled */ + cbnz x0, tsp_sel1_intr_check_preemption + b tsp_sel1_intr_return +tsp_sel1_intr_check_preemption: + /* Check if the S-EL1 interrupt has been preempted */ + mov_imm x1, TSP_PREEMPTED + cmp x0, x1 + b.ne tsp_sel1_int_entry_panic +tsp_sel1_intr_return: + mov_imm x0, TSP_HANDLED_S_EL1_INTR restore_eret_context x2 x3 - mov x0, #(TSP_HANDLED_S_EL1_FIQ & ~0xffff) - movk x0, #(TSP_HANDLED_S_EL1_FIQ & 0xffff) smc #0 -tsp_fiq_entry_panic: - b tsp_fiq_entry_panic -endfunc tsp_fiq_entry + /* Should never reach here */ +tsp_sel1_int_entry_panic: + b tsp_sel1_int_entry_panic +endfunc tsp_sel1_intr_entry /*--------------------------------------------- * This entrypoint is used by the TSPD when this diff --git a/bl32/tsp/aarch64/tsp_exceptions.S b/bl32/tsp/aarch64/tsp_exceptions.S index 4c0d4361..d5e089f6 100644 --- a/bl32/tsp/aarch64/tsp_exceptions.S +++ b/bl32/tsp/aarch64/tsp_exceptions.S @@ -70,6 +70,28 @@ add sp, sp, SCRATCH_REG_SIZE .endm + /* ---------------------------------------------------- + * Common TSP interrupt handling routine + * ---------------------------------------------------- + */ + .macro handle_tsp_interrupt label + /* Enable the SError interrupt */ + msr daifclr, #DAIF_ABT_BIT + + save_caller_regs_and_lr + bl tsp_common_int_handler + cbz x0, interrupt_exit_\label + + /* + * This interrupt was not targetted to S-EL1 so send it to + * the monitor and wait for execution to resume. + */ + smc #0 +interrupt_exit_\label: + restore_caller_regs_and_lr + eret + .endm + .globl tsp_exceptions /* ----------------------------------------------------- @@ -120,36 +142,12 @@ sync_exception_sp_elx: .align 7 irq_sp_elx: - /* Enable the SError interrupt */ - msr daifclr, #DAIF_ABT_BIT - - save_caller_regs_and_lr - /* We just update some statistics in the handler */ - bl tsp_irq_received - /* Hand over control to the normal world to handle the IRQ */ - smc #0 - /* The resume std smc starts from here */ - restore_caller_regs_and_lr - eret + handle_tsp_interrupt irq_sp_elx check_vector_size irq_sp_elx .align 7 fiq_sp_elx: - /* Enable the SError interrupt */ - msr daifclr, #DAIF_ABT_BIT - - save_caller_regs_and_lr - bl tsp_fiq_handler - cbz x0, fiq_sp_elx_done - - /* - * This FIQ was not targetted to S-EL1 so send it to - * the monitor and wait for execution to resume. - */ - smc #0 -fiq_sp_elx_done: - restore_caller_regs_and_lr - eret + handle_tsp_interrupt fiq_sp_elx check_vector_size fiq_sp_elx .align 7 diff --git a/bl32/tsp/tsp_interrupt.c b/bl32/tsp/tsp_interrupt.c index 139642d0..7654d2e8 100644 --- a/bl32/tsp/tsp_interrupt.c +++ b/bl32/tsp/tsp_interrupt.c @@ -31,50 +31,70 @@ #include <arch_helpers.h> #include <assert.h> #include <debug.h> -#include <gic_v2.h> #include <platform.h> #include <platform_def.h> #include <tsp.h> #include "tsp_private.h" /******************************************************************************* - * This function updates the TSP statistics for FIQs handled synchronously i.e - * the ones that have been handed over by the TSPD. It also keeps count of the - * number of times control was passed back to the TSPD after handling an FIQ. - * In the future it will be possible that the TSPD hands over an FIQ to the TSP - * but does not expect it to return execution. This statistic will be useful to - * distinguish between these two models of synchronous FIQ handling. - * The 'elr_el3' parameter contains the address of the instruction in normal - * world where this FIQ was generated. + * This function updates the TSP statistics for S-EL1 interrupts handled + * synchronously i.e the ones that have been handed over by the TSPD. It also + * keeps count of the number of times control was passed back to the TSPD + * after handling the interrupt. In the future it will be possible that the + * TSPD hands over an S-EL1 interrupt to the TSP but does not expect it to + * return execution. This statistic will be useful to distinguish between these + * two models of synchronous S-EL1 interrupt handling. The 'elr_el3' parameter + * contains the address of the instruction in normal world where this S-EL1 + * interrupt was generated. ******************************************************************************/ -void tsp_update_sync_fiq_stats(uint32_t type, uint64_t elr_el3) +void tsp_update_sync_sel1_intr_stats(uint32_t type, uint64_t elr_el3) { uint32_t linear_id = plat_my_core_pos(); - tsp_stats[linear_id].sync_fiq_count++; - if (type == TSP_HANDLE_FIQ_AND_RETURN) - tsp_stats[linear_id].sync_fiq_ret_count++; + tsp_stats[linear_id].sync_sel1_intr_count++; + if (type == TSP_HANDLE_SEL1_INTR_AND_RETURN) + tsp_stats[linear_id].sync_sel1_intr_ret_count++; #if LOG_LEVEL >= LOG_LEVEL_VERBOSE spin_lock(&console_lock); - VERBOSE("TSP: cpu 0x%lx sync fiq request from 0x%lx\n", + VERBOSE("TSP: cpu 0x%lx sync s-el1 interrupt request from 0x%lx\n", read_mpidr(), elr_el3); - VERBOSE("TSP: cpu 0x%lx: %d sync fiq requests, %d sync fiq returns\n", + VERBOSE("TSP: cpu 0x%lx: %d sync s-el1 interrupt requests," + " %d sync s-el1 interrupt returns\n", read_mpidr(), - tsp_stats[linear_id].sync_fiq_count, - tsp_stats[linear_id].sync_fiq_ret_count); + tsp_stats[linear_id].sync_sel1_intr_count, + tsp_stats[linear_id].sync_sel1_intr_ret_count); spin_unlock(&console_lock); #endif } +/****************************************************************************** + * This function is invoked when a non S-EL1 interrupt is received and causes + * the preemption of TSP. This function returns TSP_PREEMPTED and results + * in the control being handed over to EL3 for handling the interrupt. + *****************************************************************************/ +int32_t tsp_handle_preemption(void) +{ + uint32_t linear_id = plat_my_core_pos(); + + tsp_stats[linear_id].preempt_intr_count++; +#if LOG_LEVEL >= LOG_LEVEL_VERBOSE + spin_lock(&console_lock); + VERBOSE("TSP: cpu 0x%lx: %d preempt interrupt requests\n", + read_mpidr(), tsp_stats[linear_id].preempt_intr_count); + spin_unlock(&console_lock); +#endif + return TSP_PREEMPTED; +} + /******************************************************************************* - * TSP FIQ handler called as a part of both synchronous and asynchronous - * handling of FIQ interrupts. It returns 0 upon successfully handling a S-EL1 - * FIQ and treats all other FIQs as EL3 interrupts. It assumes that the GIC - * architecture version in v2.0 and the secure physical timer interrupt is the - * only S-EL1 interrupt that it needs to handle. + * TSP interrupt handler is called as a part of both synchronous and + * asynchronous handling of TSP interrupts. Currently the physical timer + * interrupt is the only S-EL1 interrupt that this handler expects. It returns + * 0 upon successfully handling the expected interrupt and all other + * interrupts are treated as normal world or EL3 interrupts. ******************************************************************************/ -int32_t tsp_fiq_handler(void) +int32_t tsp_common_int_handler(void) { uint32_t linear_id = plat_my_core_pos(), id; @@ -82,16 +102,21 @@ int32_t tsp_fiq_handler(void) * Get the highest priority pending interrupt id and see if it is the * secure physical generic timer interrupt in which case, handle it. * Otherwise throw this interrupt at the EL3 firmware. + * + * There is a small time window between reading the highest priority + * pending interrupt and acknowledging it during which another + * interrupt of higher priority could become the highest pending + * interrupt. This is not expected to happen currently for TSP. */ id = plat_ic_get_pending_interrupt_id(); /* TSP can only handle the secure physical timer interrupt */ if (id != TSP_IRQ_SEC_PHY_TIMER) - return TSP_EL3_FIQ; + return tsp_handle_preemption(); /* - * Handle the interrupt. Also sanity check if it has been preempted by - * another secure interrupt through an assertion. + * Acknowledge and handle the secure timer interrupt. Also sanity check + * if it has been preempted by another interrupt through an assertion. */ id = plat_ic_acknowledge_interrupt(); assert(id == TSP_IRQ_SEC_PHY_TIMER); @@ -99,29 +124,14 @@ int32_t tsp_fiq_handler(void) plat_ic_end_of_interrupt(id); /* Update the statistics and print some messages */ - tsp_stats[linear_id].fiq_count++; + tsp_stats[linear_id].sel1_intr_count++; #if LOG_LEVEL >= LOG_LEVEL_VERBOSE spin_lock(&console_lock); - VERBOSE("TSP: cpu 0x%lx handled fiq %d\n", + VERBOSE("TSP: cpu 0x%lx handled S-EL1 interrupt %d\n", read_mpidr(), id); - VERBOSE("TSP: cpu 0x%lx: %d fiq requests\n", - read_mpidr(), tsp_stats[linear_id].fiq_count); + VERBOSE("TSP: cpu 0x%lx: %d S-EL1 requests\n", + read_mpidr(), tsp_stats[linear_id].sel1_intr_count); spin_unlock(&console_lock); #endif return 0; } - -int32_t tsp_irq_received(void) -{ - uint32_t linear_id = plat_my_core_pos(); - - tsp_stats[linear_id].irq_count++; -#if LOG_LEVEL >= LOG_LEVEL_VERBOSE - spin_lock(&console_lock); - VERBOSE("TSP: cpu 0x%lx received irq\n", read_mpidr()); - VERBOSE("TSP: cpu 0x%lx: %d irq requests\n", - read_mpidr(), tsp_stats[linear_id].irq_count); - spin_unlock(&console_lock); -#endif - return TSP_PREEMPTED; -} diff --git a/bl32/tsp/tsp_private.h b/bl32/tsp/tsp_private.h index 39fb5f66..e341cfd7 100644 --- a/bl32/tsp/tsp_private.h +++ b/bl32/tsp/tsp_private.h @@ -54,10 +54,14 @@ typedef struct work_statistics { - uint32_t fiq_count; /* Number of FIQs on this cpu */ - uint32_t irq_count; /* Number of IRQs on this cpu */ - uint32_t sync_fiq_count; /* Number of sync. fiqs on this cpu */ - uint32_t sync_fiq_ret_count; /* Number of fiq returns on this cpu */ + /* Number of s-el1 interrupts on this cpu */ + uint32_t sel1_intr_count; + /* Number of non s-el1 interrupts on this cpu which preempted TSP */ + uint32_t preempt_intr_count; + /* Number of sync s-el1 interrupts on this cpu */ + uint32_t sync_sel1_intr_count; + /* Number of s-el1 interrupts returns on this cpu */ + uint32_t sync_sel1_intr_ret_count; uint32_t smc_count; /* Number of returns on this cpu */ uint32_t eret_count; /* Number of entries on this cpu */ uint32_t cpu_on_count; /* Number of cpu on requests */ @@ -115,8 +119,8 @@ void tsp_generic_timer_stop(void); void tsp_generic_timer_save(void); void tsp_generic_timer_restore(void); -/* FIQ management functions */ -void tsp_update_sync_fiq_stats(uint32_t type, uint64_t elr_el3); +/* S-EL1 interrupt management functions */ +void tsp_update_sync_sel1_intr_stats(uint32_t type, uint64_t elr_el3); /* Data structure to keep track of TSP statistics */ diff --git a/bl31/aarch64/context.S b/common/aarch64/context.S index 70a1e5d6..3d13a802 100644 --- a/bl31/aarch64/context.S +++ b/common/aarch64/context.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -32,6 +32,17 @@ #include <asm_macros.S> #include <context.h> + .global el1_sysregs_context_save + .global el1_sysregs_context_restore +#if CTX_INCLUDE_FPREGS + .global fpregs_context_save + .global fpregs_context_restore +#endif + .global save_gp_registers + .global restore_gp_registers_eret + .global restore_gp_registers_callee_eret + .global el3_exit + /* ----------------------------------------------------- * The following function strictly follows the AArch64 * PCS to use x9-x17 (temporary caller-saved registers) @@ -40,7 +51,6 @@ * the register context will be saved. * ----------------------------------------------------- */ - .global el1_sysregs_context_save func el1_sysregs_context_save mrs x9, spsr_el1 @@ -127,7 +137,6 @@ endfunc el1_sysregs_context_save * from where the register context will be restored * ----------------------------------------------------- */ - .global el1_sysregs_context_restore func el1_sysregs_context_restore ldp x9, x10, [x0, #CTX_SPSR_EL1] @@ -225,7 +234,6 @@ endfunc el1_sysregs_context_restore * ----------------------------------------------------- */ #if CTX_INCLUDE_FPREGS - .global fpregs_context_save func fpregs_context_save stp q0, q1, [x0, #CTX_FP_Q0] stp q2, q3, [x0, #CTX_FP_Q2] @@ -269,7 +277,6 @@ endfunc fpregs_context_save * TODO: Revisit when VFP is used in secure world * ----------------------------------------------------- */ - .global fpregs_context_restore func fpregs_context_restore ldp q0, q1, [x0, #CTX_FP_Q0] ldp q2, q3, [x0, #CTX_FP_Q2] @@ -291,7 +298,7 @@ func fpregs_context_restore ldr x9, [x0, #CTX_FP_FPSR] msr fpsr, x9 - str x10, [x0, #CTX_FP_FPCR] + ldr x10, [x0, #CTX_FP_FPCR] msr fpcr, x10 /* @@ -303,3 +310,92 @@ func fpregs_context_restore ret endfunc fpregs_context_restore #endif /* CTX_INCLUDE_FPREGS */ + +/* ----------------------------------------------------- + * The following functions are used to save and restore + * all the general purpose registers. Ideally we would + * only save and restore the callee saved registers when + * a world switch occurs but that type of implementation + * is more complex. So currently we will always save and + * restore these registers on entry and exit of EL3. + * These are not macros to ensure their invocation fits + * within the 32 instructions per exception vector. + * clobbers: x18 + * ----------------------------------------------------- + */ +func save_gp_registers + stp x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0] + stp x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2] + stp x4, x5, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X4] + stp x6, x7, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X6] + stp x8, x9, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X8] + stp x10, x11, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X10] + stp x12, x13, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X12] + stp x14, x15, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X14] + stp x16, x17, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X16] + stp x18, x19, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X18] + stp x20, x21, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X20] + stp x22, x23, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X22] + stp x24, x25, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X24] + stp x26, x27, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X26] + stp x28, x29, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X28] + mrs x18, sp_el0 + str x18, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_SP_EL0] + ret +endfunc save_gp_registers + +func restore_gp_registers_eret + ldp x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0] + ldp x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2] + b restore_gp_registers_callee_eret +endfunc restore_gp_registers_eret + +func restore_gp_registers_callee_eret + ldp x4, x5, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X4] + ldp x6, x7, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X6] + ldp x8, x9, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X8] + ldp x10, x11, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X10] + ldp x12, x13, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X12] + ldp x14, x15, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X14] + ldp x18, x19, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X18] + ldp x20, x21, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X20] + ldp x22, x23, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X22] + ldp x24, x25, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X24] + ldp x26, x27, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X26] + ldp x28, x29, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X28] + ldp x30, x17, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR] + msr sp_el0, x17 + ldp x16, x17, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X16] + eret +endfunc restore_gp_registers_callee_eret + + /* ----------------------------------------------------- + * This routine assumes that the SP_EL3 is pointing to + * a valid context structure from where the gp regs and + * other special registers can be retrieved. + * ----------------------------------------------------- + */ +func el3_exit + /* ----------------------------------------------------- + * Save the current SP_EL0 i.e. the EL3 runtime stack + * which will be used for handling the next SMC. Then + * switch to SP_EL3 + * ----------------------------------------------------- + */ + mov x17, sp + msr spsel, #1 + str x17, [sp, #CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP] + + /* ----------------------------------------------------- + * Restore SPSR_EL3, ELR_EL3 and SCR_EL3 prior to ERET + * ----------------------------------------------------- + */ + ldr x18, [sp, #CTX_EL3STATE_OFFSET + CTX_SCR_EL3] + ldp x16, x17, [sp, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3] + msr scr_el3, x18 + msr spsr_el3, x16 + msr elr_el3, x17 + + /* Restore saved general purpose registers and return */ + b restore_gp_registers_eret +endfunc el3_exit diff --git a/common/aarch64/early_exceptions.S b/common/aarch64/early_exceptions.S index 90f5421b..780a38f6 100644 --- a/common/aarch64/early_exceptions.S +++ b/common/aarch64/early_exceptions.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -29,7 +29,7 @@ */ #include <asm_macros.S> -#include <runtime_svc.h> +#include <bl_common.h> .globl early_exceptions diff --git a/bl31/context_mgmt.c b/common/context_mgmt.c index 6d405343..68ec8945 100644 --- a/bl31/context_mgmt.c +++ b/common/context_mgmt.c @@ -32,14 +32,12 @@ #include <arch_helpers.h> #include <assert.h> #include <bl_common.h> -#include <bl31.h> #include <context.h> #include <context_mgmt.h> -#include <cpu_data.h> #include <interrupt_mgmt.h> #include <platform.h> #include <platform_def.h> -#include <runtime_svc.h> +#include <smcc_helpers.h> #include <string.h> @@ -65,105 +63,6 @@ void cm_init(void) } /******************************************************************************* - * This function returns a pointer to the most recent 'cpu_context' structure - * for the CPU identified by `cpu_idx` that was set as the context for the - * specified security state. NULL is returned if no such structure has been - * specified. - ******************************************************************************/ -void *cm_get_context_by_index(unsigned int cpu_idx, - unsigned int security_state) -{ - assert(sec_state_is_valid(security_state)); - - return get_cpu_data_by_index(cpu_idx, cpu_context[security_state]); -} - -/******************************************************************************* - * This function sets the pointer to the current 'cpu_context' structure for the - * specified security state for the CPU identified by CPU index. - ******************************************************************************/ -void cm_set_context_by_index(unsigned int cpu_idx, void *context, - unsigned int security_state) -{ - assert(sec_state_is_valid(security_state)); - - set_cpu_data_by_index(cpu_idx, cpu_context[security_state], context); -} - -#if !ERROR_DEPRECATED -/* - * These context management helpers are deprecated but are maintained for use - * by SPDs which have not migrated to the new API. If ERROR_DEPRECATED - * is enabled, these are excluded from the build so as to force users to - * migrate to the new API. - */ - -/******************************************************************************* - * This function returns a pointer to the most recent 'cpu_context' structure - * for the CPU identified by MPIDR that was set as the context for the specified - * security state. NULL is returned if no such structure has been specified. - ******************************************************************************/ -void *cm_get_context_by_mpidr(uint64_t mpidr, uint32_t security_state) -{ - assert(sec_state_is_valid(security_state)); - - return cm_get_context_by_index(platform_get_core_pos(mpidr), security_state); -} - -/******************************************************************************* - * This function sets the pointer to the current 'cpu_context' structure for the - * specified security state for the CPU identified by MPIDR - ******************************************************************************/ -void cm_set_context_by_mpidr(uint64_t mpidr, void *context, uint32_t security_state) -{ - assert(sec_state_is_valid(security_state)); - - cm_set_context_by_index(platform_get_core_pos(mpidr), - context, security_state); -} - -/******************************************************************************* - * The following function provides a compatibility function for SPDs using the - * existing cm library routines. This function is expected to be invoked for - * initializing the cpu_context for the CPU specified by MPIDR for first use. - ******************************************************************************/ -void cm_init_context(unsigned long mpidr, const entry_point_info_t *ep) -{ - if ((mpidr & MPIDR_AFFINITY_MASK) == - (read_mpidr_el1() & MPIDR_AFFINITY_MASK)) - cm_init_my_context(ep); - else - cm_init_context_by_index(platform_get_core_pos(mpidr), ep); -} -#endif - -/******************************************************************************* - * This function is used to program the context that's used for exception - * return. This initializes the SP_EL3 to a pointer to a 'cpu_context' set for - * the required security state - ******************************************************************************/ -static inline void cm_set_next_context(void *context) -{ -#if DEBUG - uint64_t sp_mode; - - /* - * Check that this function is called with SP_EL0 as the stack - * pointer - */ - __asm__ volatile("mrs %0, SPSel\n" - : "=r" (sp_mode)); - - assert(sp_mode == MODE_SP_EL0); -#endif - - __asm__ volatile("msr spsel, #1\n" - "mov sp, %0\n" - "msr spsel, #0\n" - : : "r" (context)); -} - -/******************************************************************************* * The following function initializes the cpu_context 'ctx' for * first use, and sets the initial entrypoint state as specified by the * entry_point_info structure. @@ -212,7 +111,13 @@ static void cm_init_context_common(cpu_context_t *ctx, const entry_point_info_t if (EP_GET_ST(ep->h.attr)) scr_el3 |= SCR_ST_BIT; +#if IMAGE_BL31 + /* + * IRQ/FIQ bits only need setting if interrupt routing + * model has been set up for BL31. + */ scr_el3 |= get_scr_el3_from_routing_model(security_state); +#endif /* * Set up SCTLR_ELx for the target exception level: @@ -330,6 +235,14 @@ void cm_prepare_el3_exit(uint32_t security_state) /* Set VPIDR, VMPIDR to match MIDR, MPIDR */ write_vpidr_el2(read_midr_el1()); write_vmpidr_el2(read_mpidr_el1()); + + /* + * Reset VTTBR_EL2. + * Needed because cache maintenance operations depend on + * the VMID even when non-secure EL1&0 stage 2 address + * translation are disabled. + */ + write_vttbr_el2(0); } } diff --git a/docs/interrupt-framework-design.md b/docs/interrupt-framework-design.md index 53707ae9..271cd921 100644 --- a/docs/interrupt-framework-design.md +++ b/docs/interrupt-framework-design.md @@ -399,12 +399,12 @@ requirements mentioned earlier. 1. It passes control to the Test Secure Payload to perform its initialisation. The TSP provides the address of the vector table `tsp_vectors` in the SP which also includes the handler for Secure-EL1 - interrupts in the `fiq_entry` field. The TSPD passes control to the TSP at + interrupts in the `sel1_intr_entry` field. The TSPD passes control to the TSP at this address when it receives a Secure-EL1 interrupt. The handover agreement between the TSP and the TSPD requires that the TSPD masks all interrupts (`PSTATE.DAIF` bits) when it calls - `tsp_fiq_entry()`. The TSP has to preserve the callee saved general + `tsp_sel1_intr_entry()`. The TSP has to preserve the callee saved general purpose, SP_EL1/Secure-EL0, LR, VFP and system registers. It can use `x0-x18` to enable its C runtime. @@ -514,7 +514,7 @@ runtime firmware is not aware of through its platform port. The routing model for Secure-EL1 and non-secure interrupts chosen by the TSP is described in Section 2.2.2. It is known to the TSPD service at build time. -The TSP implements an entrypoint (`tsp_fiq_entry()`) for handling Secure-EL1 +The TSP implements an entrypoint (`tsp_sel1_intr_entry()`) for handling Secure-EL1 interrupts taken in non-secure state and routed through the TSPD service (synchronous handling model). It passes the reference to this entrypoint via `tsp_vectors` to the TSPD service. @@ -700,9 +700,9 @@ takes the following actions upon being invoked. 3. It saves the system register context for the non-secure state by calling `cm_el1_sysregs_context_save(NON_SECURE);`. -4. It sets the `ELR_EL3` system register to `tsp_fiq_entry` and sets the +4. It sets the `ELR_EL3` system register to `tsp_sel1_intr_entry` and sets the `SPSR_EL3.DAIF` bits in the secure CPU context. It sets `x0` to - `TSP_HANDLE_FIQ_AND_RETURN`. If the TSP was in the middle of handling a + `TSP_HANDLE_SEL1_INTR_AND_RETURN`. If the TSP was in the middle of handling a standard SMC, then the `ELR_EL3` and `SPSR_EL3` registers in the secure CPU context are saved first. @@ -723,20 +723,20 @@ state.  -The TSP issues an SMC with `TSP_HANDLED_S_EL1_FIQ` as the function identifier to +The TSP issues an SMC with `TSP_HANDLED_S_EL1_INTR` as the function identifier to signal completion of interrupt handling. The TSP issues an SMC with `TSP_PREEMPTED` as the function identifier to signal generation of a non-secure interrupt in Secure-EL1. The TSPD service takes the following actions in `tspd_smc_handler()` function -upon receiving an SMC with `TSP_HANDLED_S_EL1_FIQ` and `TSP_PREEMPTED` as the +upon receiving an SMC with `TSP_HANDLED_S_EL1_INTR` and `TSP_PREEMPTED` as the function identifiers: 1. It ensures that the call originated from the secure state otherwise execution returns to the non-secure state with `SMC_UNK` in `x0`. -2. If the function identifier is `TSP_HANDLED_S_EL1_FIQ`, it restores the +2. If the function identifier is `TSP_HANDLED_S_EL1_INTR`, it restores the saved `ELR_EL3` and `SPSR_EL3` system registers back to the secure CPU context (see step 4 above) in case the TSP had been preempted by a non secure interrupt earlier. It does not save the secure context since the @@ -811,7 +811,7 @@ state. ##### 2.3.3.1 Test secure payload behavior The TSPD hands control of a Secure-EL1 interrupt to the TSP at the -`tsp_fiq_entry()`. The TSP handles the interrupt while ensuring that the +`tsp_sel1_intr_entry()`. The TSP handles the interrupt while ensuring that the handover agreement described in Section 2.2.2.1 is maintained. It updates some statistics by calling `tsp_update_sync_fiq_stats()`. It then calls `tsp_fiq_handler()` which. @@ -827,7 +827,7 @@ statistics by calling `tsp_update_sync_fiq_stats()`. It then calls end of interrupt processing. The TSP passes control back to the TSPD by issuing an SMC64 with -`TSP_HANDLED_S_EL1_FIQ` as the function identifier. +`TSP_HANDLED_S_EL1_INTR` as the function identifier. The TSP handles interrupts under the asynchronous model as follows. diff --git a/docs/porting-guide.md b/docs/porting-guide.md index e5b4a9c7..ba550f04 100644 --- a/docs/porting-guide.md +++ b/docs/porting-guide.md @@ -1172,6 +1172,21 @@ In ARM standard platforms, this function does the following: * Detects the system topology. +### Function : bl31_plat_runtime_setup() [optional] + + Argument : void + Return : void + +The purpose of this function is allow the platform to perform any BL31 runtime +setup just prior to BL31 exit during cold boot. The default weak +implementation of this function will invoke `console_uninit()` which will +suppress any BL31 runtime logs. + +In ARM Standard platforms, this function will initialize the BL31 runtime +console which will cause all further BL31 logs to be output to the +runtime console. + + ### Function : bl31_get_next_image_info() [mandatory] Argument : unsigned int diff --git a/docs/user-guide.md b/docs/user-guide.md index 70dbddd3..18f22042 100644 --- a/docs/user-guide.md +++ b/docs/user-guide.md @@ -278,10 +278,13 @@ performed. (Coherent memory region is included) or 0 (Coherent memory region is excluded). Default is 1. -* `TSPD_ROUTE_IRQ_TO_EL3`: A non zero value enables the routing model - for non-secure interrupts in which they are routed to EL3 (TSPD). The - default model (when the value is 0) is to route non-secure interrupts - to S-EL1 (TSP). +* `TSP_NS_INTR_ASYNC_PREEMPT`: A non zero value enables the interrupt + routing model which routes non-secure interrupts asynchronously from TSP + to EL3 causing immediate preemption of TSP. The EL3 is responsible + for saving and restoring the TSP context in this routing model. The + default routing model (when the value is 0) is to route non-secure + interrupts to TSP allowing it to save its context and hand over + synchronously to EL3 via an SMC. * `TRUSTED_BOARD_BOOT`: Boolean flag to include support for the Trusted Board Boot feature. When set to '1', BL1 and BL2 images include support to load diff --git a/drivers/arm/gic/v3/gicv3_helpers.c b/drivers/arm/gic/v3/gicv3_helpers.c index 6e8251d5..2fb98cbb 100644 --- a/drivers/arm/gic/v3/gicv3_helpers.c +++ b/drivers/arm/gic/v3/gicv3_helpers.c @@ -312,7 +312,7 @@ void gicv3_secure_spis_configure(uintptr_t gicd_base, unsigned int index, irq_num; uint64_t gic_affinity_val; - assert((int_grp == INT_TYPE_G1S) || (int_grp == INT_TYPE_G0)); + assert((int_grp == INTR_GROUP1S) || (int_grp == INTR_GROUP0)); /* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */ assert(num_ints ? (uintptr_t)sec_intr_list : 1); @@ -324,7 +324,7 @@ void gicv3_secure_spis_configure(uintptr_t gicd_base, gicd_clr_igroupr(gicd_base, irq_num); /* Configure this interrupt as G0 or a G1S interrupt */ - if (int_grp == INT_TYPE_G1S) + if (int_grp == INTR_GROUP1S) gicd_set_igrpmodr(gicd_base, irq_num); else gicd_clr_igrpmodr(gicd_base, irq_num); @@ -386,7 +386,7 @@ void gicv3_secure_ppi_sgi_configure(uintptr_t gicr_base, { unsigned int index, irq_num; - assert((int_grp == INT_TYPE_G1S) || (int_grp == INT_TYPE_G0)); + assert((int_grp == INTR_GROUP1S) || (int_grp == INTR_GROUP0)); /* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */ assert(num_ints ? (uintptr_t)sec_intr_list : 1); @@ -398,7 +398,7 @@ void gicv3_secure_ppi_sgi_configure(uintptr_t gicr_base, gicr_clr_igroupr0(gicr_base, irq_num); /* Configure this interrupt as G0 or a G1S interrupt */ - if (int_grp == INT_TYPE_G1S) + if (int_grp == INTR_GROUP1S) gicr_set_igrpmodr0(gicr_base, irq_num); else gicr_clr_igrpmodr0(gicr_base, irq_num); diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c index 06311e3a..d5cd0ed9 100644 --- a/drivers/arm/gic/v3/gicv3_main.c +++ b/drivers/arm/gic/v3/gicv3_main.c @@ -144,13 +144,13 @@ void gicv3_distif_init(void) gicv3_secure_spis_configure(driver_data->gicd_base, driver_data->g1s_interrupt_num, driver_data->g1s_interrupt_array, - INT_TYPE_G1S); + INTR_GROUP1S); /* Configure the G0 SPIs */ gicv3_secure_spis_configure(driver_data->gicd_base, driver_data->g0_interrupt_num, driver_data->g0_interrupt_array, - INT_TYPE_G0); + INTR_GROUP0); /* Enable the secure SPIs now that they have been configured */ gicd_set_ctlr(driver_data->gicd_base, @@ -186,13 +186,13 @@ void gicv3_rdistif_init(unsigned int proc_num) gicv3_secure_ppi_sgi_configure(gicr_base, driver_data->g1s_interrupt_num, driver_data->g1s_interrupt_array, - INT_TYPE_G1S); + INTR_GROUP1S); /* Configure the G0 SGIs/PPIs */ gicv3_secure_ppi_sgi_configure(gicr_base, driver_data->g0_interrupt_num, driver_data->g0_interrupt_array, - INT_TYPE_G0); + INTR_GROUP0); } /******************************************************************************* @@ -332,9 +332,9 @@ unsigned int gicv3_get_pending_interrupt_type(void) * this interrupt has been configured under by the interrupt controller i.e. * group0 or group1 Secure / Non Secure. The return value can be one of the * following : - * INT_TYPE_G0 : The interrupt type is a Secure Group 0 interrupt - * INT_TYPE_G1S : The interrupt type is a Secure Group 1 secure interrupt - * INT_TYPE_G1NS: The interrupt type is a Secure Group 1 non secure + * INTR_GROUP0 : The interrupt type is a Secure Group 0 interrupt + * INTR_GROUP1S : The interrupt type is a Secure Group 1 secure interrupt + * INTR_GROUP1NS: The interrupt type is a Secure Group 1 non secure * interrupt. ******************************************************************************/ unsigned int gicv3_get_interrupt_type(unsigned int id, @@ -352,7 +352,7 @@ unsigned int gicv3_get_interrupt_type(unsigned int id, /* All LPI interrupts are Group 1 non secure */ if (id >= MIN_LPI_ID) - return INT_TYPE_G1NS; + return INTR_GROUP1NS; if (id < MIN_SPI_ID) { assert(driver_data->rdistif_base_addrs); @@ -370,12 +370,12 @@ unsigned int gicv3_get_interrupt_type(unsigned int id, * interrupt */ if (igroup) - return INT_TYPE_G1NS; + return INTR_GROUP1NS; /* If the GRPMOD bit is set, then it is a Group 1 Secure interrupt */ if (grpmodr) - return INT_TYPE_G1S; + return INTR_GROUP1S; /* Else it is a Group 0 Secure interrupt */ - return INT_TYPE_G0; + return INTR_GROUP0; } diff --git a/drivers/arm/tzc400/tzc400.c b/drivers/arm/tzc400/tzc400.c index 940e00e0..7194443e 100644 --- a/drivers/arm/tzc400/tzc400.c +++ b/drivers/arm/tzc400/tzc400.c @@ -170,9 +170,6 @@ void tzc_init(uintptr_t base) assert(base); - /* Assert if already initialised */ - assert(!tzc.base); - tzc.base = base; /* diff --git a/drivers/auth/tbbr/tbbr_cot.c b/drivers/auth/tbbr/tbbr_cot.c index 79a89651..71634a19 100644 --- a/drivers/auth/tbbr/tbbr_cot.c +++ b/drivers/auth/tbbr/tbbr_cot.c @@ -89,6 +89,12 @@ static auth_param_type_desc_t bl32_hash = AUTH_PARAM_TYPE_DESC( AUTH_PARAM_HASH, BL32_HASH_OID); static auth_param_type_desc_t bl33_hash = AUTH_PARAM_TYPE_DESC( AUTH_PARAM_HASH, BL33_HASH_OID); +static auth_param_type_desc_t scp_bl2u_hash = AUTH_PARAM_TYPE_DESC( + AUTH_PARAM_HASH, SCP_BL2U_HASH_OID); +static auth_param_type_desc_t bl2u_hash = AUTH_PARAM_TYPE_DESC( + AUTH_PARAM_HASH, BL2U_HASH_OID); +static auth_param_type_desc_t ns_bl2u_hash = AUTH_PARAM_TYPE_DESC( + AUTH_PARAM_HASH, NS_BL2U_HASH_OID); /* * TBBR Chain of trust definition @@ -438,6 +444,99 @@ static const auth_img_desc_t cot_desc[] = { } } } + }, + /* + * FWU auth descriptor. + */ + [FWU_CERT_ID] = { + .img_id = FWU_CERT_ID, + .img_type = IMG_CERT, + .parent = NULL, + .img_auth_methods = { + [0] = { + .type = AUTH_METHOD_SIG, + .param.sig = { + .pk = &subject_pk, + .sig = &sig, + .alg = &sig_alg, + .data = &raw_data, + } + } + }, + .authenticated_data = { + [0] = { + .type_desc = &scp_bl2u_hash, + .data = { + .ptr = (void *)plat_bl30_hash_buf, + .len = (unsigned int)HASH_DER_LEN + } + }, + [1] = { + .type_desc = &bl2u_hash, + .data = { + .ptr = (void *)plat_bl2_hash_buf, + .len = (unsigned int)HASH_DER_LEN + } + }, + [2] = { + .type_desc = &ns_bl2u_hash, + .data = { + .ptr = (void *)plat_bl33_hash_buf, + .len = (unsigned int)HASH_DER_LEN + } + } + } + }, + /* + * SCP_BL2U + */ + [SCP_BL2U_IMAGE_ID] = { + .img_id = SCP_BL2U_IMAGE_ID, + .img_type = IMG_RAW, + .parent = &cot_desc[FWU_CERT_ID], + .img_auth_methods = { + [0] = { + .type = AUTH_METHOD_HASH, + .param.hash = { + .data = &raw_data, + .hash = &scp_bl2u_hash, + } + } + } + }, + /* + * BL2U + */ + [BL2U_IMAGE_ID] = { + .img_id = BL2U_IMAGE_ID, + .img_type = IMG_RAW, + .parent = &cot_desc[FWU_CERT_ID], + .img_auth_methods = { + [0] = { + .type = AUTH_METHOD_HASH, + .param.hash = { + .data = &raw_data, + .hash = &bl2u_hash, + } + } + } + }, + /* + * NS_BL2U + */ + [NS_BL2U_IMAGE_ID] = { + .img_id = NS_BL2U_IMAGE_ID, + .img_type = IMG_RAW, + .parent = &cot_desc[FWU_CERT_ID], + .img_auth_methods = { + [0] = { + .type = AUTH_METHOD_HASH, + .param.hash = { + .data = &raw_data, + .hash = &ns_bl2u_hash, + } + } + } } }; diff --git a/drivers/console/console.S b/drivers/console/console.S index d966f0d3..40a6db9f 100644 --- a/drivers/console/console.S +++ b/drivers/console/console.S @@ -30,6 +30,7 @@ #include <asm_macros.S> .globl console_init + .globl console_uninit .globl console_putc .globl console_getc @@ -66,6 +67,20 @@ init_fail: ret endfunc console_init + /* ----------------------------------------------- + * void console_uninit(void) + * Function to finish the use of console driver. + * It sets the console_base as NULL so that any + * further invocation of `console_putc` or + * `console_getc` APIs would return error. + * ----------------------------------------------- + */ +func console_uninit + mov x0, #0 + adrp x3, console_base + str x0, [x3, :lo12:console_base] +endfunc console_uninit + /* --------------------------------------------- * int console_putc(int c) * Function to output a character over the diff --git a/include/bl1/bl1.h b/include/bl1/bl1.h new file mode 100644 index 00000000..9fb3cb28 --- /dev/null +++ b/include/bl1/bl1.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __BL1_FWU_H__ +#define __BL1_FWU_H__ + +#include <bl_common.h> + +/* + * Defines for BL1 SMC function ids. + */ +#define BL1_SMC_CALL_COUNT 0x0 +#define BL1_SMC_UID 0x1 +/* SMC #0x2 reserved */ +#define BL1_SMC_VERSION 0x3 + +/* + * Corresponds to the function ID of the SMC that + * the BL1 exception handler service to execute BL31. + */ +#define BL1_SMC_RUN_IMAGE 0x4 + +/* + * BL1 SMC version + */ +#define BL1_SMC_MAJOR_VER 0x0 +#define BL1_SMC_MINOR_VER 0x1 + +/* + * Defines for FWU SMC function ids. + */ + +#define FWU_SMC_IMAGE_COPY 0x10 +#define FWU_SMC_IMAGE_AUTH 0x11 +#define FWU_SMC_IMAGE_EXECUTE 0x12 +#define FWU_SMC_IMAGE_RESUME 0x13 +#define FWU_SMC_SEC_IMAGE_DONE 0x14 +#define FWU_SMC_UPDATE_DONE 0x15 + +/* + * Number of FWU calls (above) implemented + */ +#define FWU_NUM_SMC_CALLS 6 + +#if TRUSTED_BOARD_BOOT +# define BL1_NUM_SMC_CALLS (FWU_NUM_SMC_CALLS + 4) +#else +# define BL1_NUM_SMC_CALLS 4 +#endif + +/* + * The macros below are used to identify FWU + * calls from the SMC function ID + */ +#define FWU_SMC_FID_START FWU_SMC_IMAGE_COPY +#define FWU_SMC_FID_END FWU_SMC_UPDATE_DONE +#define is_fwu_fid(_fid) \ + ((_fid >= FWU_SMC_FID_START) && (_fid <= FWU_SMC_FID_END)) + +#ifndef __ASSEMBLY__ +#include <cassert.h> + +/* + * Check if the total number of FWU SMC calls are as expected. + */ +CASSERT(FWU_NUM_SMC_CALLS == \ + (FWU_SMC_FID_END - FWU_SMC_FID_START + 1),\ + assert_FWU_NUM_SMC_CALLS_mismatch); + +#endif /* __ASSEMBLY__ */ +#endif /* __BL1_FWU_H__ */ diff --git a/include/bl1/tbbr/tbbr_img_desc.h b/include/bl1/tbbr/tbbr_img_desc.h new file mode 100644 index 00000000..56f35075 --- /dev/null +++ b/include/bl1/tbbr/tbbr_img_desc.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __TBBR_IMG_DESC_H__ +#define __TBBR_IMG_DESC_H__ + +#include <bl_common.h> + +extern image_desc_t bl1_tbbr_image_descs[]; + +#endif /* __TBBR_IMG_DESC_H__ */ diff --git a/include/bl31/interrupt_mgmt.h b/include/bl31/interrupt_mgmt.h index e07ddf83..0172b607 100644 --- a/include/bl31/interrupt_mgmt.h +++ b/include/bl31/interrupt_mgmt.h @@ -63,6 +63,10 @@ #define INTR_NS_VALID_RM0 0x0 /* Routed to EL1/EL2 from NS and to EL3 from Secure */ #define INTR_NS_VALID_RM1 0x1 +/* Routed to EL3 from NS. Taken to S-EL1 from Secure and handed over to EL3 */ +#define INTR_EL3_VALID_RM0 0x2 +/* Routed to EL3 from NS and Secure */ +#define INTR_EL3_VALID_RM1 0x3 /* This is the default routing model */ #define INTR_DEFAULT_RM 0x0 @@ -87,12 +91,16 @@ * of interrupt. If the model does not match one of the valid masks * -EINVAL is returned. ******************************************************************************/ -#define validate_sel1_interrupt_rm(x) (x == INTR_SEL1_VALID_RM0 ? 0 : \ - (x == INTR_SEL1_VALID_RM1 ? 0 :\ +#define validate_sel1_interrupt_rm(x) ((x) == INTR_SEL1_VALID_RM0 ? 0 : \ + ((x) == INTR_SEL1_VALID_RM1 ? 0 :\ + -EINVAL)) + +#define validate_ns_interrupt_rm(x) ((x) == INTR_NS_VALID_RM0 ? 0 : \ + ((x) == INTR_NS_VALID_RM1 ? 0 :\ -EINVAL)) -#define validate_ns_interrupt_rm(x) (x == INTR_NS_VALID_RM0 ? 0 : \ - (x == INTR_NS_VALID_RM1 ? 0 :\ +#define validate_el3_interrupt_rm(x) ((x) == INTR_EL3_VALID_RM0 ? 0 : \ + ((x) == INTR_EL3_VALID_RM1 ? 0 :\ -EINVAL)) /******************************************************************************* diff --git a/include/bl31/runtime_svc.h b/include/bl31/runtime_svc.h index f1124183..30ba29f0 100644 --- a/include/bl31/runtime_svc.h +++ b/include/bl31/runtime_svc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -31,74 +31,9 @@ #ifndef __RUNTIME_SVC_H__ #define __RUNTIME_SVC_H__ -/******************************************************************************* - * Bit definitions inside the function id as per the SMC calling convention - ******************************************************************************/ -#define FUNCID_TYPE_SHIFT 31 -#define FUNCID_CC_SHIFT 30 -#define FUNCID_OEN_SHIFT 24 -#define FUNCID_NUM_SHIFT 0 - -#define FUNCID_TYPE_MASK 0x1 -#define FUNCID_CC_MASK 0x1 -#define FUNCID_OEN_MASK 0x3f -#define FUNCID_NUM_MASK 0xffff - -#define FUNCID_TYPE_WIDTH 1 -#define FUNCID_CC_WIDTH 1 -#define FUNCID_OEN_WIDTH 6 -#define FUNCID_NUM_WIDTH 16 - -#define GET_SMC_CC(id) ((id >> FUNCID_CC_SHIFT) & \ - FUNCID_CC_MASK) -#define GET_SMC_TYPE(id) ((id >> FUNCID_TYPE_SHIFT) & \ - FUNCID_TYPE_MASK) - -#define SMC_64 1 -#define SMC_32 0 -#define SMC_UNK 0xffffffff -#define SMC_TYPE_FAST 1 -#define SMC_TYPE_STD 0 -#define SMC_PREEMPTED 0xfffffffe -/******************************************************************************* - * Owning entity number definitions inside the function id as per the SMC - * calling convention - ******************************************************************************/ -#define OEN_ARM_START 0 -#define OEN_ARM_END 0 -#define OEN_CPU_START 1 -#define OEN_CPU_END 1 -#define OEN_SIP_START 2 -#define OEN_SIP_END 2 -#define OEN_OEM_START 3 -#define OEN_OEM_END 3 -#define OEN_STD_START 4 /* Standard Calls */ -#define OEN_STD_END 4 -#define OEN_TAP_START 48 /* Trusted Applications */ -#define OEN_TAP_END 49 -#define OEN_TOS_START 50 /* Trusted OS */ -#define OEN_TOS_END 63 -#define OEN_LIMIT 64 +#include <bl_common.h> /* to include exception types */ +#include <smcc_helpers.h> /* to include SMCC definitions */ -/******************************************************************************* - * Constants to indicate type of exception to the common exception handler. - ******************************************************************************/ -#define SYNC_EXCEPTION_SP_EL0 0x0 -#define IRQ_SP_EL0 0x1 -#define FIQ_SP_EL0 0x2 -#define SERROR_SP_EL0 0x3 -#define SYNC_EXCEPTION_SP_ELX 0x4 -#define IRQ_SP_ELX 0x5 -#define FIQ_SP_ELX 0x6 -#define SERROR_SP_ELX 0x7 -#define SYNC_EXCEPTION_AARCH64 0x8 -#define IRQ_AARCH64 0x9 -#define FIQ_AARCH64 0xa -#define SERROR_AARCH64 0xb -#define SYNC_EXCEPTION_AARCH32 0xc -#define IRQ_AARCH32 0xd -#define FIQ_AARCH32 0xe -#define SERROR_AARCH32 0xf /******************************************************************************* * Structure definition, typedefs & constants for the runtime service framework @@ -122,68 +57,9 @@ #ifndef __ASSEMBLY__ -#include <cassert.h> -#include <context.h> -#include <stdint.h> - -/* Various flags passed to SMC handlers */ -#define SMC_FROM_SECURE (0 << 0) -#define SMC_FROM_NON_SECURE (1 << 0) - -#define is_caller_non_secure(_f) (!!(_f & SMC_FROM_NON_SECURE)) -#define is_caller_secure(_f) (!(is_caller_non_secure(_f))) - /* Prototype for runtime service initializing function */ typedef int32_t (*rt_svc_init_t)(void); -/* Convenience macros to return from SMC handler */ -#define SMC_RET0(_h) { \ - return (uint64_t) (_h); \ -} -#define SMC_RET1(_h, _x0) { \ - write_ctx_reg(get_gpregs_ctx(_h), CTX_GPREG_X0, (_x0)); \ - SMC_RET0(_h); \ -} -#define SMC_RET2(_h, _x0, _x1) { \ - write_ctx_reg(get_gpregs_ctx(_h), CTX_GPREG_X1, (_x1)); \ - SMC_RET1(_h, (_x0)); \ -} -#define SMC_RET3(_h, _x0, _x1, _x2) { \ - write_ctx_reg(get_gpregs_ctx(_h), CTX_GPREG_X2, (_x2)); \ - SMC_RET2(_h, (_x0), (_x1)); \ -} -#define SMC_RET4(_h, _x0, _x1, _x2, _x3) { \ - write_ctx_reg(get_gpregs_ctx(_h), CTX_GPREG_X3, (_x3)); \ - SMC_RET3(_h, (_x0), (_x1), (_x2)); \ -} - - -/* - * Convenience macros to access general purpose registers using handle provided - * to SMC handler. These takes the offset values defined in context.h - */ -#define SMC_GET_GP(_h, _g) \ - read_ctx_reg(get_gpregs_ctx(_h), (_g)); -#define SMC_SET_GP(_h, _g, _v) \ - write_ctx_reg(get_gpregs_ctx(_h), (_g), (_v)); - -/* - * Convenience macros to access EL3 context registers using handle provided to - * SMC handler. These takes the offset values defined in context.h - */ -#define SMC_GET_EL3(_h, _e) \ - read_ctx_reg(get_el3state_ctx(_h), (_e)); -#define SMC_SET_EL3(_h, _e, _v) \ - write_ctx_reg(get_el3state_ctx(_h), (_e), (_v)); - -/* The macro below is used to identify a Standard Service SMC call */ -#define is_std_svc_call(_fid) ((((_fid) >> FUNCID_OEN_SHIFT) & \ - FUNCID_OEN_MASK) == OEN_STD_START) - -/* The macro below is used to identify a valid Fast SMC call */ -#define is_valid_fast_smc(_fid) ((!(((_fid) >> 16) & 0xff)) && \ - (GET_SMC_TYPE(_fid) == SMC_TYPE_FAST)) - /* * Prototype for runtime service SMC handler function. x0 (SMC Function ID) to * x4 are as passed by the caller. Rest of the arguments to SMC and the context @@ -247,28 +123,6 @@ CASSERT(RT_SVC_DESC_HANDLE == __builtin_offsetof(rt_svc_desc_t, handle), \ ((call_type & FUNCID_TYPE_MASK) \ << FUNCID_OEN_WIDTH)) - -/* - * Macro to define UUID for services. Apart from defining and initializing a - * uuid_t structure, this macro verifies that the first word of the defined UUID - * does not equal SMC_UNK. This is to ensure that the caller won't mistake the - * returned UUID in x0 for an invalid SMC error return - */ -#define DEFINE_SVC_UUID(_name, _tl, _tm, _th, _cl, _ch, \ - _n0, _n1, _n2, _n3, _n4, _n5) \ - CASSERT(_tl != SMC_UNK, invalid_svc_uuid);\ - static const uuid_t _name = { \ - _tl, _tm, _th, _cl, _ch, \ - { _n0, _n1, _n2, _n3, _n4, _n5 } \ - } - -/* Return a UUID in the SMC return registers */ -#define SMC_UUID_RET(_h, _uuid) \ - SMC_RET4(handle, ((const uint32_t *) &(_uuid))[0], \ - ((const uint32_t *) &(_uuid))[1], \ - ((const uint32_t *) &(_uuid))[2], \ - ((const uint32_t *) &(_uuid))[3]) - /******************************************************************************* * Function & variable prototypes ******************************************************************************/ diff --git a/include/bl32/tsp/tsp.h b/include/bl32/tsp/tsp.h index c6578b78..fd43fd3b 100644 --- a/include/bl32/tsp/tsp.h +++ b/include/bl32/tsp/tsp.h @@ -45,12 +45,12 @@ #define TSP_SYSTEM_RESET_DONE 0xf2000009 /* - * Function identifiers to handle FIQs through the synchronous handling model. - * If the TSP was previously interrupted then control has to be returned to - * the TSPD after handling the interrupt else execution can remain in the TSP. + * Function identifiers to handle S-El1 interrupt through the synchronous + * handling model. If the TSP was previously interrupted then control has to + * be returned to the TSPD after handling the interrupt else execution can + * remain in the TSP. */ -#define TSP_HANDLED_S_EL1_FIQ 0xf2000006 -#define TSP_EL3_FIQ 0xf2000007 +#define TSP_HANDLED_S_EL1_INTR 0xf2000006 /* SMC function ID that TSP uses to request service from secure monitor */ #define TSP_GET_ARGS 0xf2001000 @@ -63,7 +63,7 @@ #define TSP_SUB 0x2001 #define TSP_MUL 0x2002 #define TSP_DIV 0x2003 -#define TSP_HANDLE_FIQ_AND_RETURN 0x2004 +#define TSP_HANDLE_SEL1_INTR_AND_RETURN 0x2004 /* * Generate function IDs for TSP services to be used in SMC calls, by @@ -115,7 +115,7 @@ typedef struct tsp_vectors { tsp_vector_isn_t cpu_off_entry; tsp_vector_isn_t cpu_resume_entry; tsp_vector_isn_t cpu_suspend_entry; - tsp_vector_isn_t fiq_entry; + tsp_vector_isn_t sel1_intr_entry; tsp_vector_isn_t system_off_entry; tsp_vector_isn_t system_reset_entry; } tsp_vectors_t; diff --git a/include/common/bl_common.h b/include/common/bl_common.h index c9a7a3da..b7cb95aa 100644 --- a/include/common/bl_common.h +++ b/include/common/bl_common.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -45,14 +45,6 @@ #define TOP 0x1 #define BOTTOM !TOP -/****************************************************************************** - * Opcode passed in x0 to tell next EL that we want to run an image. - * Corresponds to the function ID of the only SMC that the BL1 exception - * handlers service. That's why the chosen value is the first function ID of - * the ARM SMC64 range. - *****************************************************************************/ -#define RUN_IMAGE 0xC0000000 - /******************************************************************************* * Constants that allow assembler code to access members of and the * 'entry_point_info' structure at their correct offsets. @@ -60,11 +52,41 @@ #define ENTRY_POINT_INFO_PC_OFFSET 0x08 #define ENTRY_POINT_INFO_ARGS_OFFSET 0x18 -#define PARAM_EP_SECURITY_MASK 0x1 +/* The following are used to set/get image attributes. */ +#define EXECUTABLE (0x1) +#define NON_EXECUTABLE (0x0) +#define PARAM_EP_EXECUTE_MASK (0x1) +#define PARAM_EP_EXECUTE_SHIFT (0x1) +#define PARAM_EP_SECURITY_MASK (0x1) +#define PARAM_EP_SECURITY_SHIFT (0x0) + #define GET_SECURITY_STATE(x) (x & PARAM_EP_SECURITY_MASK) #define SET_SECURITY_STATE(x, security) \ ((x) = ((x) & ~PARAM_EP_SECURITY_MASK) | (security)) +#define GET_EXEC_STATE(x) \ + (((x) >> PARAM_EP_EXECUTE_SHIFT) & PARAM_EP_EXECUTE_MASK) + +#define SET_EXEC_STATE(x) \ + (((x) & PARAM_EP_EXECUTE_MASK) << PARAM_EP_EXECUTE_SHIFT) + +#define GET_SEC_STATE(x) \ + (((x) >> PARAM_EP_SECURITY_SHIFT) & PARAM_EP_SECURITY_MASK) + +#define SET_SEC_STATE(x) \ + (((x) & PARAM_EP_SECURITY_MASK) << PARAM_EP_SECURITY_SHIFT) + +/* + * The following are used for image state attributes. + * Image can only be in one of the following state. + */ +#define IMAGE_STATE_RESET 0 +#define IMAGE_STATE_COPIED 1 +#define IMAGE_STATE_COPYING 2 +#define IMAGE_STATE_AUTHENTICATED 3 +#define IMAGE_STATE_EXECUTED 4 +#define IMAGE_STATE_INTERRUPTED 5 + #define EP_EE_MASK 0x2 #define EP_EE_LITTLE 0x0 #define EP_EE_BIG 0x2 @@ -83,6 +105,8 @@ #define VERSION_1 0x01 +#define INVALID_IMAGE_ID (0xFFFFFFFF) + #define SET_PARAM_HEAD(_p, _type, _ver, _attr) do { \ (_p)->h.type = (uint8_t)(_type); \ (_p)->h.version = (uint8_t)(_ver); \ @@ -90,6 +114,26 @@ (_p)->h.attr = (uint32_t)(_attr) ; \ } while (0) +/******************************************************************************* + * Constants to indicate type of exception to the common exception handler. + ******************************************************************************/ +#define SYNC_EXCEPTION_SP_EL0 0x0 +#define IRQ_SP_EL0 0x1 +#define FIQ_SP_EL0 0x2 +#define SERROR_SP_EL0 0x3 +#define SYNC_EXCEPTION_SP_ELX 0x4 +#define IRQ_SP_ELX 0x5 +#define FIQ_SP_ELX 0x6 +#define SERROR_SP_ELX 0x7 +#define SYNC_EXCEPTION_AARCH64 0x8 +#define IRQ_AARCH64 0x9 +#define FIQ_AARCH64 0xa +#define SERROR_AARCH64 0xb +#define SYNC_EXCEPTION_AARCH32 0xc +#define IRQ_AARCH32 0xd +#define FIQ_AARCH32 0xe +#define SERROR_AARCH32 0xf + #ifndef __ASSEMBLY__ #include <cdefs.h> /* For __dead2 */ #include <cassert.h> @@ -106,6 +150,8 @@ extern unsigned long __RO_START__; extern unsigned long __RO_END__; #if IMAGE_BL2 extern unsigned long __BL2_END__; +#elif IMAGE_BL2U +extern unsigned long __BL2U_END__; #elif IMAGE_BL31 extern unsigned long __BL31_END__; #elif IMAGE_BL32 @@ -177,8 +223,24 @@ typedef struct image_info { param_header_t h; uintptr_t image_base; /* physical address of base of image */ uint32_t image_size; /* bytes read from image file */ + uint32_t copied_size; /* image size copied in blocks */ } image_info_t; +/***************************************************************************** + * The image descriptor struct definition. + *****************************************************************************/ +typedef struct image_desc { + /* Contains unique image id for the image. */ + unsigned int image_id; + image_info_t image_info; + entry_point_info_t ep_info; + /* + * This member contains Image state information. + * Refer IMAGE_STATE_XXX defined above. + */ + unsigned int state; +} image_desc_t; + /******************************************************************************* * This structure represents the superset of information that can be passed to * BL31 e.g. while passing control to it from BL2. The BL32 parameters will be diff --git a/include/bl31/context.h b/include/common/context.h index 0dfebe0b..0dfebe0b 100644 --- a/include/bl31/context.h +++ b/include/common/context.h diff --git a/include/bl31/context_mgmt.h b/include/common/context_mgmt.h index 1ef40766..141b3481 100644 --- a/include/bl31/context_mgmt.h +++ b/include/common/context_mgmt.h @@ -31,9 +31,9 @@ #ifndef __CM_H__ #define __CM_H__ +#include <arch.h> +#include <bl_common.h> #include <common_def.h> -#include <cpu_data.h> -#include <stdint.h> /******************************************************************************* * Forward declarations @@ -46,7 +46,6 @@ struct entry_point_info; void cm_init(void); void *cm_get_context_by_mpidr(uint64_t mpidr, uint32_t security_state) __warn_deprecated; -static inline void *cm_get_context(uint32_t security_state); void cm_set_context_by_mpidr(uint64_t mpidr, void *context, uint32_t security_state) __warn_deprecated; @@ -55,7 +54,9 @@ void *cm_get_context_by_index(unsigned int cpu_idx, void cm_set_context_by_index(unsigned int cpu_idx, void *context, unsigned int security_state); -static inline void cm_set_context(void *context, uint32_t security_state); +void *cm_get_context(uint32_t security_state); +void cm_set_context(void *context, uint32_t security_state); +inline void cm_set_next_context(void *context); void cm_init_context(uint64_t mpidr, const struct entry_point_info *ep) __warn_deprecated; void cm_init_my_context(const struct entry_point_info *ep); @@ -76,27 +77,28 @@ uint32_t cm_get_scr_el3(uint32_t security_state); /* Inline definitions */ /******************************************************************************* - * This function returns a pointer to the most recent 'cpu_context' structure - * for the calling CPU that was set as the context for the specified security - * state. NULL is returned if no such structure has been specified. + * This function is used to program the context that's used for exception + * return. This initializes the SP_EL3 to a pointer to a 'cpu_context' set for + * the required security state ******************************************************************************/ -void *cm_get_context(uint32_t security_state) +inline void cm_set_next_context(void *context) { - assert(security_state <= NON_SECURE); +#if DEBUG + uint64_t sp_mode; - return get_cpu_data(cpu_context[security_state]); -} + /* + * Check that this function is called with SP_EL0 as the stack + * pointer + */ + __asm__ volatile("mrs %0, SPSel\n" + : "=r" (sp_mode)); -/******************************************************************************* - * This function sets the pointer to the current 'cpu_context' structure for the - * specified security state for the calling CPU - ******************************************************************************/ -void cm_set_context(void *context, uint32_t security_state) -{ - assert(security_state <= NON_SECURE); + assert(sp_mode == MODE_SP_EL0); +#endif - set_cpu_data(cpu_context[security_state], context); + __asm__ volatile("msr spsel, #1\n" + "mov sp, %0\n" + "msr spsel, #0\n" + : : "r" (context)); } - - #endif /* __CM_H__ */ diff --git a/include/common/el3_common_macros.S b/include/common/el3_common_macros.S index 87e172e8..0514e2a2 100644 --- a/include/common/el3_common_macros.S +++ b/include/common/el3_common_macros.S @@ -247,13 +247,11 @@ #endif .endif /* _init_c_runtime */ -#if IMAGE_BL31 /* --------------------------------------------------------------------- * Use SP_EL0 for the C runtime stack. * --------------------------------------------------------------------- */ msr spsel, #0 -#endif /* IMAGE_BL31 */ /* --------------------------------------------------------------------- * Allocate a stack whose memory will be marked as Normal-IS-WBWA when diff --git a/include/common/firmware_image_package.h b/include/common/firmware_image_package.h index 8fb669e3..daa043a8 100644 --- a/include/common/firmware_image_package.h +++ b/include/common/firmware_image_package.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2014-2015, ARM Limited and Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -39,6 +39,14 @@ /* ToC Entry UUIDs */ +#define UUID_TRUSTED_UPDATE_FIRMWARE_SCP_BL2U \ + {0x03279265, 0x742f, 0x44e6, 0x8d, 0xff, {0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10} } +#define UUID_TRUSTED_UPDATE_FIRMWARE_BL2U \ + {0x37ebb360, 0xe5c1, 0x41ea, 0x9d, 0xf3, {0x19, 0xed, 0xa1, 0x1f, 0x68, 0x01} } +#define UUID_TRUSTED_UPDATE_FIRMWARE_NS_BL2U \ + {0x111d514f, 0xe52b, 0x494e, 0xb4, 0xc5, {0x83, 0xc2, 0xf7, 0x15, 0x84, 0x0a} } +#define UUID_TRUSTED_FWU_CERT \ + {0xb28a4071, 0xd618, 0x4c87, 0x8b, 0x2e, {0xc6, 0xdc, 0xcd, 0x50, 0xf0, 0x96} } #define UUID_TRUSTED_BOOT_FIRMWARE_BL2 \ {0x0becf95f, 0x224d, 0x4d3e, 0xa5, 0x44, {0xc3, 0x9d, 0x81, 0xc7, 0x3f, 0x0a} } #define UUID_SCP_FIRMWARE_BL30 \ diff --git a/include/common/smcc_helpers.h b/include/common/smcc_helpers.h new file mode 100644 index 00000000..6a07b013 --- /dev/null +++ b/include/common/smcc_helpers.h @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __SMCC_HELPERS_H__ +#define __SMCC_HELPERS_H__ + +/******************************************************************************* + * Bit definitions inside the function id as per the SMC calling convention + ******************************************************************************/ +#define FUNCID_TYPE_SHIFT 31 +#define FUNCID_CC_SHIFT 30 +#define FUNCID_OEN_SHIFT 24 +#define FUNCID_NUM_SHIFT 0 + +#define FUNCID_TYPE_MASK 0x1 +#define FUNCID_CC_MASK 0x1 +#define FUNCID_OEN_MASK 0x3f +#define FUNCID_NUM_MASK 0xffff + +#define FUNCID_TYPE_WIDTH 1 +#define FUNCID_CC_WIDTH 1 +#define FUNCID_OEN_WIDTH 6 +#define FUNCID_NUM_WIDTH 16 + +#define GET_SMC_CC(id) ((id >> FUNCID_CC_SHIFT) & \ + FUNCID_CC_MASK) +#define GET_SMC_TYPE(id) ((id >> FUNCID_TYPE_SHIFT) & \ + FUNCID_TYPE_MASK) + +#define SMC_64 1 +#define SMC_32 0 +#define SMC_UNK 0xffffffff +#define SMC_TYPE_FAST 1 +#define SMC_TYPE_STD 0 +#define SMC_PREEMPTED 0xfffffffe +/******************************************************************************* + * Owning entity number definitions inside the function id as per the SMC + * calling convention + ******************************************************************************/ +#define OEN_ARM_START 0 +#define OEN_ARM_END 0 +#define OEN_CPU_START 1 +#define OEN_CPU_END 1 +#define OEN_SIP_START 2 +#define OEN_SIP_END 2 +#define OEN_OEM_START 3 +#define OEN_OEM_END 3 +#define OEN_STD_START 4 /* Standard Calls */ +#define OEN_STD_END 4 +#define OEN_TAP_START 48 /* Trusted Applications */ +#define OEN_TAP_END 49 +#define OEN_TOS_START 50 /* Trusted OS */ +#define OEN_TOS_END 63 +#define OEN_LIMIT 64 + +#ifndef __ASSEMBLY__ + +#include <cassert.h> +#include <context.h> +#include <stdint.h> + +/* Various flags passed to SMC handlers */ +#define SMC_FROM_SECURE (0 << 0) +#define SMC_FROM_NON_SECURE (1 << 0) + +#define is_caller_non_secure(_f) (!!(_f & SMC_FROM_NON_SECURE)) +#define is_caller_secure(_f) (!(is_caller_non_secure(_f))) + +/* Convenience macros to return from SMC handler */ +#define SMC_RET0(_h) { \ + return (uint64_t) (_h); \ +} +#define SMC_RET1(_h, _x0) { \ + write_ctx_reg(get_gpregs_ctx(_h), CTX_GPREG_X0, (_x0)); \ + SMC_RET0(_h); \ +} +#define SMC_RET2(_h, _x0, _x1) { \ + write_ctx_reg(get_gpregs_ctx(_h), CTX_GPREG_X1, (_x1)); \ + SMC_RET1(_h, (_x0)); \ +} +#define SMC_RET3(_h, _x0, _x1, _x2) { \ + write_ctx_reg(get_gpregs_ctx(_h), CTX_GPREG_X2, (_x2)); \ + SMC_RET2(_h, (_x0), (_x1)); \ +} +#define SMC_RET4(_h, _x0, _x1, _x2, _x3) { \ + write_ctx_reg(get_gpregs_ctx(_h), CTX_GPREG_X3, (_x3)); \ + SMC_RET3(_h, (_x0), (_x1), (_x2)); \ +} + +/* + * Convenience macros to access general purpose registers using handle provided + * to SMC handler. These takes the offset values defined in context.h + */ +#define SMC_GET_GP(_h, _g) \ + read_ctx_reg(get_gpregs_ctx(_h), (_g)); +#define SMC_SET_GP(_h, _g, _v) \ + write_ctx_reg(get_gpregs_ctx(_h), (_g), (_v)); + +/* + * Convenience macros to access EL3 context registers using handle provided to + * SMC handler. These takes the offset values defined in context.h + */ +#define SMC_GET_EL3(_h, _e) \ + read_ctx_reg(get_el3state_ctx(_h), (_e)); +#define SMC_SET_EL3(_h, _e, _v) \ + write_ctx_reg(get_el3state_ctx(_h), (_e), (_v)); + +/* The macro below is used to identify a Standard Service SMC call */ +#define is_std_svc_call(_fid) ((((_fid) >> FUNCID_OEN_SHIFT) & \ + FUNCID_OEN_MASK) == OEN_STD_START) + +/* The macro below is used to identify a valid Fast SMC call */ +#define is_valid_fast_smc(_fid) ((!(((_fid) >> 16) & 0xff)) && \ + (GET_SMC_TYPE(_fid) == SMC_TYPE_FAST)) + +/* + * Macro to define UUID for services. Apart from defining and initializing a + * uuid_t structure, this macro verifies that the first word of the defined UUID + * does not equal SMC_UNK. This is to ensure that the caller won't mistake the + * returned UUID in x0 for an invalid SMC error return + */ +#define DEFINE_SVC_UUID(_name, _tl, _tm, _th, _cl, _ch, \ + _n0, _n1, _n2, _n3, _n4, _n5) \ + CASSERT(_tl != SMC_UNK, invalid_svc_uuid);\ + static const uuid_t _name = { \ + _tl, _tm, _th, _cl, _ch, \ + { _n0, _n1, _n2, _n3, _n4, _n5 } \ + } + +/* Return a UUID in the SMC return registers */ +#define SMC_UUID_RET(_h, _uuid) \ + SMC_RET4(handle, ((const uint32_t *) &(_uuid))[0], \ + ((const uint32_t *) &(_uuid))[1], \ + ((const uint32_t *) &(_uuid))[2], \ + ((const uint32_t *) &(_uuid))[3]) + +#endif /*__ASSEMBLY__*/ +#endif /* __SMCC_HELPERS_H__ */ diff --git a/include/common/tbbr/tbbr_img_def.h b/include/common/tbbr/tbbr_img_def.h index c43c3954..fabe0b94 100644 --- a/include/common/tbbr/tbbr_img_def.h +++ b/include/common/tbbr/tbbr_img_def.h @@ -63,4 +63,19 @@ #define BL32_CERT_ID 14 #define BL33_CERT_ID 15 +/* Non-Trusted ROM Firmware NS_BL1U */ +#define NS_BL1U_IMAGE_ID 16 + +/* Trusted FWU Certificate */ +#define FWU_CERT_ID 17 + +/* Trusted FWU SCP Firmware SCP_BL2U */ +#define SCP_BL2U_IMAGE_ID 18 + +/* Trusted FWU Boot Firmware BL2U */ +#define BL2U_IMAGE_ID 19 + +/* Non-Trusted FWU Firmware NS_BL2U */ +#define NS_BL2U_IMAGE_ID 20 + #endif /* __TBBR_IMG_DEF_H__ */ diff --git a/include/drivers/arm/cci400.h b/include/drivers/arm/cci400.h index 620221a6..a5dc9a03 100644 --- a/include/drivers/arm/cci400.h +++ b/include/drivers/arm/cci400.h @@ -31,6 +31,14 @@ #ifndef __CCI_400_H__ #define __CCI_400_H__ +/************************************************************** + * THIS DRIVER IS DEPRECATED. Please use the driver in cci.h + **************************************************************/ +#if ERROR_DEPRECATED +#error " The CCI-400 specific driver is deprecated." +#endif + + /* Slave interface offsets from PERIPHBASE */ #define SLAVE_IFACE4_OFFSET 0x5000 #define SLAVE_IFACE3_OFFSET 0x4000 @@ -68,6 +76,7 @@ #ifndef __ASSEMBLY__ +#include <common_def.h> #include <stdint.h> /* Function declarations */ @@ -83,10 +92,10 @@ */ void cci_init(uintptr_t cci_base, int slave_iface3_cluster_ix, - int slave_iface4_cluster_ix); + int slave_iface4_cluster_ix) __warn_deprecated; -void cci_enable_cluster_coherency(unsigned long mpidr); -void cci_disable_cluster_coherency(unsigned long mpidr); +void cci_enable_cluster_coherency(unsigned long mpidr) __warn_deprecated; +void cci_disable_cluster_coherency(unsigned long mpidr) __warn_deprecated; #endif /* __ASSEMBLY__ */ #endif /* __CCI_400_H__ */ diff --git a/include/drivers/arm/gicv3.h b/include/drivers/arm/gicv3.h index e874f5cd..ae6fd917 100644 --- a/include/drivers/arm/gicv3.h +++ b/include/drivers/arm/gicv3.h @@ -35,9 +35,9 @@ * GICv3 miscellaneous definitions ******************************************************************************/ /* Interrupt group definitions */ -#define INT_TYPE_G1S 0 -#define INT_TYPE_G0 1 -#define INT_TYPE_G1NS 2 +#define INTR_GROUP1S 0 +#define INTR_GROUP0 1 +#define INTR_GROUP1NS 2 /* Interrupt IDs reported by the HPPIR and IAR registers */ #define PENDING_G1S_INTID 1020 diff --git a/include/drivers/console.h b/include/drivers/console.h index d374157b..69ad0bd7 100644 --- a/include/drivers/console.h +++ b/include/drivers/console.h @@ -35,6 +35,7 @@ int console_init(uintptr_t base_addr, unsigned int uart_clk, unsigned int baud_rate); +void console_uninit(void); int console_putc(int c); int console_getc(void); diff --git a/include/drivers/delay_timer.h b/include/drivers/delay_timer.h index 4f3bdc88..0dec626c 100644 --- a/include/drivers/delay_timer.h +++ b/include/drivers/delay_timer.h @@ -38,7 +38,7 @@ * The driver must be initialized with a structure that provides a * function pointer to return the timer value and a clock * multiplier/divider. The ratio of the multiplier and the divider is - * the clock frequency in MHz. + * the clock period in microseconds. ********************************************************************/ typedef struct timer_ops { diff --git a/include/lib/aarch64/arch_helpers.h b/include/lib/aarch64/arch_helpers.h index 43c6917e..067b8302 100644 --- a/include/lib/aarch64/arch_helpers.h +++ b/include/lib/aarch64/arch_helpers.h @@ -270,6 +270,8 @@ DEFINE_SYSREG_RW_FUNCS(ttbr0_el3) DEFINE_SYSREG_RW_FUNCS(ttbr1_el1) +DEFINE_SYSREG_RW_FUNCS(vttbr_el2) + DEFINE_SYSREG_RW_FUNCS(cptr_el2) DEFINE_SYSREG_RW_FUNCS(cptr_el3) diff --git a/include/plat/arm/board/common/board_arm_def.h b/include/plat/arm/board/common/board_arm_def.h index 3abf235e..b4e43134 100644 --- a/include/plat/arm/board/common/board_arm_def.h +++ b/include/plat/arm/board/common/board_arm_def.h @@ -53,6 +53,8 @@ # else # define PLATFORM_STACK_SIZE 0x400 # endif +#elif IMAGE_BL2U +# define PLATFORM_STACK_SIZE 0x200 #elif IMAGE_BL31 # define PLATFORM_STACK_SIZE 0x400 #elif IMAGE_BL32 @@ -65,10 +67,18 @@ */ #if IMAGE_BL1 # if PLAT_fvp -# define PLAT_ARM_MMAP_ENTRIES 7 +# if TRUSTED_BOARD_BOOT +# define PLAT_ARM_MMAP_ENTRIES 8 +# else +# define PLAT_ARM_MMAP_ENTRIES 7 +# endif /* TRUSTED_BOARD_BOOT */ # else -# define PLAT_ARM_MMAP_ENTRIES 6 -# endif +# if TRUSTED_BOARD_BOOT +# define PLAT_ARM_MMAP_ENTRIES 7 +# else +# define PLAT_ARM_MMAP_ENTRIES 6 +# endif /* TRUSTED_BOARD_BOOT */ +# endif /* PLAT_ */ #endif #if IMAGE_BL2 # if PLAT_fvp @@ -77,6 +87,13 @@ # define PLAT_ARM_MMAP_ENTRIES 8 # endif #endif +#if IMAGE_BL2U +# if PLAT_fvp +# define PLAT_ARM_MMAP_ENTRIES 3 +# else +# define PLAT_ARM_MMAP_ENTRIES 4 +#endif +#endif #if IMAGE_BL31 #define PLAT_ARM_MMAP_ENTRIES 5 #endif @@ -88,12 +105,22 @@ * Platform specific page table and MMU setup constants */ #if IMAGE_BL1 -# if PLAT_juno -# define MAX_XLAT_TABLES 2 +# if TRUSTED_BOARD_BOOT +# define MAX_XLAT_TABLES 4 # else +# if PLAT_juno +# define MAX_XLAT_TABLES 2 +# else +# define MAX_XLAT_TABLES 3 +# endif /* PLAT_ */ +# endif /* TRUSTED_BOARD_BOOT */ +#elif IMAGE_BL2 +# if PLAT_juno # define MAX_XLAT_TABLES 3 +# else +# define MAX_XLAT_TABLES 4 # endif /* PLAT_ */ -#elif IMAGE_BL2 +#elif IMAGE_BL2U # if PLAT_juno # define MAX_XLAT_TABLES 3 # else diff --git a/include/plat/arm/board/common/board_css_def.h b/include/plat/arm/board/common/board_css_def.h index 2e32b41c..975f1fc5 100644 --- a/include/plat/arm/board/common/board_css_def.h +++ b/include/plat/arm/board/common/board_css_def.h @@ -74,8 +74,11 @@ #define PLAT_ARM_BOOT_UART_BASE SOC_CSS_UART0_BASE #define PLAT_ARM_BOOT_UART_CLK_IN_HZ SOC_CSS_UART0_CLK_IN_HZ -#define PLAT_ARM_CRASH_UART_BASE SOC_CSS_UART1_BASE -#define PLAT_ARM_CRASH_UART_CLK_IN_HZ SOC_CSS_UART1_CLK_IN_HZ +#define PLAT_ARM_BL31_RUN_UART_BASE SOC_CSS_UART1_BASE +#define PLAT_ARM_BL31_RUN_UART_CLK_IN_HZ SOC_CSS_UART1_CLK_IN_HZ + +#define PLAT_ARM_CRASH_UART_BASE PLAT_ARM_BL31_RUN_UART_BASE +#define PLAT_ARM_CRASH_UART_CLK_IN_HZ PLAT_ARM_BL31_RUN_UART_CLK_IN_HZ #define PLAT_ARM_TSP_UART_BASE V2M_IOFPGA_UART0_BASE #define PLAT_ARM_TSP_UART_CLK_IN_HZ V2M_IOFPGA_UART0_CLK_IN_HZ diff --git a/include/plat/arm/board/common/v2m_def.h b/include/plat/arm/board/common/v2m_def.h index 7ed0af6c..888792ed 100644 --- a/include/plat/arm/board/common/v2m_def.h +++ b/include/plat/arm/board/common/v2m_def.h @@ -112,6 +112,13 @@ #define V2M_SP804_TIMER0_BASE 0x1C110000 #define V2M_SP804_TIMER1_BASE 0x1C120000 +/* SP810 controller */ +#define V2M_SP810_BASE 0x1c020000 +#define V2M_SP810_CTRL_TIM0_SEL (1 << 15) +#define V2M_SP810_CTRL_TIM1_SEL (1 << 17) +#define V2M_SP810_CTRL_TIM2_SEL (1 << 19) +#define V2M_SP810_CTRL_TIM3_SEL (1 << 21) + #define V2M_MAP_FLASH0_RW MAP_REGION_FLAT(V2M_FLASH0_BASE,\ V2M_FLASH0_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) diff --git a/include/plat/arm/common/aarch64/arm_macros.S b/include/plat/arm/common/aarch64/arm_macros.S index 594b0965..eaaa62fe 100644 --- a/include/plat/arm/common/aarch64/arm_macros.S +++ b/include/plat/arm/common/aarch64/arm_macros.S @@ -31,12 +31,21 @@ #define __ARM_MACROS_S__ #include <cci.h> -#include <gic_v2.h> +#include <gic_common.h> +#include <gicv2.h> +#include <gicv3.h> #include <platform_def.h> .section .rodata.gic_reg_name, "aS" +/* Applicable only to GICv2 and GICv3 with SRE disabled (legacy mode) */ gicc_regs: .asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", "" + +/* Applicable only to GICv3 with SRE enabled */ +icc_regs: + .asciz "icc_hppir0_el1", "icc_hppir1_el1", "icc_ctlr_el3", "" + +/* Registers common to both GICv2 and GICv3 */ gicd_pend_reg: .asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n" \ " Offset:\t\t\tvalue\n" @@ -54,6 +63,28 @@ spacer: * --------------------------------------------- */ .macro arm_print_gic_regs + /* Check for GICv3 system register access */ + mrs x7, id_aa64pfr0_el1 + ubfx x7, x7, #ID_AA64PFR0_GIC_SHIFT, #ID_AA64PFR0_GIC_WIDTH + cmp x7, #1 + b.ne print_gicv2 + + /* Check for SRE enable */ + mrs x8, ICC_SRE_EL3 + tst x8, #ICC_SRE_SRE_BIT + b.eq print_gicv2 + + /* Load the icc reg list to x6 */ + adr x6, icc_regs + /* Load the icc regs to gp regs used by str_in_crash_buf_print */ + mrs x8, ICC_HPPIR0_EL1 + mrs x9, ICC_HPPIR1_EL1 + mrs x10, ICC_CTLR_EL3 + /* Store to the crash buf and print to console */ + bl str_in_crash_buf_print + b print_gic_common + +print_gicv2: /* Load the gicc reg list to x6 */ adr x6, gicc_regs /* Load the gicc regs to gp regs used by str_in_crash_buf_print */ @@ -63,6 +94,7 @@ spacer: /* Store to the crash buf and print to console */ bl str_in_crash_buf_print +print_gic_common: /* Print the GICD_ISPENDR regs */ add x7, x16, #GICD_ISPENDR adr x4, gicd_pend_reg diff --git a/include/plat/arm/common/arm_config.h b/include/plat/arm/common/arm_config.h index 0b161276..24c1f0a1 100644 --- a/include/plat/arm/common/arm_config.h +++ b/include/plat/arm/common/arm_config.h @@ -42,12 +42,6 @@ enum arm_config_flags { }; typedef struct arm_config { - uintptr_t gicd_base; - uintptr_t gicc_base; - uintptr_t gich_base; - uintptr_t gicv_base; - unsigned int max_aff0; - unsigned int max_aff1; unsigned long flags; } arm_config_t; diff --git a/include/plat/arm/common/arm_def.h b/include/plat/arm/common/arm_def.h index 4726d5e5..4a50c1c8 100644 --- a/include/plat/arm/common/arm_def.h +++ b/include/plat/arm/common/arm_def.h @@ -135,6 +135,22 @@ #define ARM_IRQ_SEC_SGI_6 14 #define ARM_IRQ_SEC_SGI_7 15 +/* + * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3 + * terminology. On a GICv2 system or mode, the lists will be merged and treated + * as Group 0 interrupts. + */ +#define ARM_G1S_IRQS ARM_IRQ_SEC_PHY_TIMER, \ + ARM_IRQ_SEC_SGI_1, \ + ARM_IRQ_SEC_SGI_2, \ + ARM_IRQ_SEC_SGI_3, \ + ARM_IRQ_SEC_SGI_4, \ + ARM_IRQ_SEC_SGI_5, \ + ARM_IRQ_SEC_SGI_7 + +#define ARM_G0_IRQS ARM_IRQ_SEC_SGI_0, \ + ARM_IRQ_SEC_SGI_6 + #define ARM_SHARED_RAM_ATTR ((PLAT_ARM_SHARED_RAM_CACHED ? \ MT_MEMORY : MT_DEVICE) \ | MT_RW | MT_SECURE) @@ -294,6 +310,14 @@ # error "Unsupported ARM_TSP_RAM_LOCATION_ID value" #endif +/******************************************************************************* + * FWU Images: NS_BL1U, BL2U & NS_BL2U defines. + ******************************************************************************/ +#define BL2U_BASE BL2_BASE +#define BL2U_LIMIT BL31_BASE +#define NS_BL2U_BASE ARM_NS_DRAM1_BASE +#define NS_BL1U_BASE (V2M_FLASH0_BASE + 0x03EB8000) + /* * ID of the secure physical generic timer interrupt used by the TSP. */ diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h index aadf58d8..32c062d1 100644 --- a/include/plat/arm/common/plat_arm.h +++ b/include/plat/arm/common/plat_arm.h @@ -37,7 +37,6 @@ #include <stdint.h> #include <xlat_tables.h> - /* * Extern declarations common to ARM standard platforms */ @@ -166,20 +165,33 @@ void arm_bl2_plat_arch_setup(void); uint32_t arm_get_spsr_for_bl32_entry(void); uint32_t arm_get_spsr_for_bl33_entry(void); +/* BL2U utility functions */ +void arm_bl2u_early_platform_setup(struct meminfo *mem_layout, + void *plat_info); +void arm_bl2u_platform_setup(void); +void arm_bl2u_plat_arch_setup(void); + /* BL3-1 utility functions */ void arm_bl31_early_platform_setup(bl31_params_t *from_bl2, void *plat_params_from_bl2); void arm_bl31_platform_setup(void); +void arm_bl31_plat_runtime_setup(void); void arm_bl31_plat_arch_setup(void); /* TSP utility functions */ void arm_tsp_early_platform_setup(void); +/* FIP TOC validity check */ +int arm_io_is_toc_valid(void); /* * Mandatory functions required in ARM standard platforms */ +void plat_arm_gic_driver_init(void); void plat_arm_gic_init(void); +void plat_arm_gic_cpuif_enable(void); +void plat_arm_gic_cpuif_disable(void); +void plat_arm_gic_pcpu_init(void); void plat_arm_security_setup(void); void plat_arm_pwrc_setup(void); diff --git a/include/plat/arm/css/common/aarch64/css_macros.S b/include/plat/arm/css/common/aarch64/css_macros.S index 2a26eb70..9f18e09c 100644 --- a/include/plat/arm/css/common/aarch64/css_macros.S +++ b/include/plat/arm/css/common/aarch64/css_macros.S @@ -41,8 +41,8 @@ * --------------------------------------------- */ .macro plat_print_gic_regs - mov_imm x16, PLAT_CSS_GICD_BASE - mov_imm x17, PLAT_CSS_GICC_BASE + mov_imm x16, PLAT_ARM_GICD_BASE + mov_imm x17, PLAT_ARM_GICC_BASE arm_print_gic_regs .endm diff --git a/include/plat/arm/css/common/css_def.h b/include/plat/arm/css/common/css_def.h index 98b69cb3..3fa4c153 100644 --- a/include/plat/arm/css/common/css_def.h +++ b/include/plat/arm/css/common/css_def.h @@ -50,6 +50,10 @@ #define NSRAM_BASE 0x2e000000 #define NSRAM_SIZE 0x00008000 +/* System Security Control Registers */ +#define SSC_REG_BASE 0x2a420000 +#define SSC_GPRETN (SSC_REG_BASE + 0x030) + /* The slave_bootsecure controls access to GPU, DMC and CS. */ #define CSS_NIC400_SLAVE_BOOTSECURE 8 @@ -61,6 +65,16 @@ #define CSS_IRQ_SEC_SYS_TIMER 91 /* + * Define a list of Group 1 Secure interrupts as per GICv3 terminology. On a + * GICv2 system or mode, the interrupts will be treated as Group 0 interrupts. + */ +#define CSS_G1S_IRQS CSS_IRQ_MHU, \ + CSS_IRQ_GPU_SMMU_0, \ + CSS_IRQ_TZC, \ + CSS_IRQ_TZ_WDOG, \ + CSS_IRQ_SEC_SYS_TIMER + +/* * SCP <=> AP boot configuration * * The SCP/AP boot configuration is a 32-bit word located at a known offset from @@ -102,6 +116,8 @@ */ #define BL30_BASE BL31_BASE +#define SCP_BL2U_BASE BL31_BASE + #define PLAT_ARM_SHARED_RAM_CACHED MHU_PAYLOAD_CACHED /* Load address of Non-Secure Image for CSS platform ports */ diff --git a/include/plat/common/common_def.h b/include/plat/common/common_def.h index 43c69cc8..4175b145 100644 --- a/include/plat/common/common_def.h +++ b/include/plat/common/common_def.h @@ -30,6 +30,9 @@ #ifndef __COMMON_DEF_H__ #define __COMMON_DEF_H__ +#include <bl_common.h> +#include <platform_def.h> + /****************************************************************************** * Required platform porting definitions that are expected to be common to * all platforms @@ -74,5 +77,14 @@ */ #define __warn_deprecated __attribute__ ((deprecated)) +#define BL2_IMAGE_DESC { \ + .image_id = BL2_IMAGE_ID, \ + .image_info.h.version = VERSION_1, \ + .image_info.h.attr = SET_EXEC_STATE(EXECUTABLE),\ + .image_info.image_base = BL2_BASE, \ + .ep_info.h.attr = SET_SEC_STATE(SECURE), \ + .ep_info.pc = BL2_BASE \ +} + #endif /* __COMMON_DEF_H__ */ diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h index de9848b7..b3213b8f 100644 --- a/include/plat/common/platform.h +++ b/include/plat/common/platform.h @@ -43,6 +43,7 @@ struct meminfo; struct image_info; struct entry_point_info; struct bl31_params; +struct image_desc; /******************************************************************************* * plat_get_rotpk_info() flags @@ -92,11 +93,11 @@ void bl1_platform_setup(void); struct meminfo *bl1_plat_sec_mem_layout(void); /* - * This function allows the platform to change the entrypoint information for - * BL2, after BL1 has loaded BL2 into memory but before BL2 is executed. + * The following function is mandatory when the + * firmware update feature is used. */ -void bl1_plat_set_bl2_ep_info(struct image_info *image, - struct entry_point_info *ep); +int bl1_plat_mem_check(uintptr_t mem_base, unsigned int mem_size, + unsigned int flags); /******************************************************************************* * Optional BL1 functions (may be overridden) @@ -104,6 +105,25 @@ void bl1_plat_set_bl2_ep_info(struct image_info *image, void bl1_init_bl2_mem_layout(const struct meminfo *bl1_mem_layout, struct meminfo *bl2_mem_layout); +/* + * The following functions are used for image loading process in BL1. + */ +void bl1_plat_set_ep_info(unsigned int image_id, + struct entry_point_info *ep_info); +/* + * The following functions are mandatory when firmware update + * feature is used and optional otherwise. + */ +unsigned int bl1_plat_get_next_image_id(void); +struct image_desc *bl1_plat_get_image_desc(unsigned int image_id); + +/* + * The following functions are used by firmware update + * feature and may optionally be overridden. + */ +__dead2 void bl1_plat_fwu_done(void *cookie, void *reserved); + + /******************************************************************************* * Mandatory BL2 functions ******************************************************************************/ @@ -173,12 +193,30 @@ void bl2_plat_get_bl32_meminfo(struct meminfo *mem_info); ******************************************************************************/ /******************************************************************************* + * Mandatory BL2U functions. + ******************************************************************************/ +void bl2u_early_platform_setup(struct meminfo *mem_layout, + void *plat_info); +void bl2u_plat_arch_setup(void); +void bl2u_platform_setup(void); + +/******************************************************************************* + * Conditionally mandatory BL2U functions for CSS platforms. + ******************************************************************************/ +/* + * This function is used to perform any platform-specific actions required to + * handle the BL2U_SCP firmware. + */ +int bl2u_plat_handle_scp_bl2u(void); + +/******************************************************************************* * Mandatory BL3-1 functions ******************************************************************************/ void bl31_early_platform_setup(struct bl31_params *from_bl2, void *plat_params_from_bl2); void bl31_plat_arch_setup(void); void bl31_platform_setup(void); +void bl31_plat_runtime_setup(void); struct entry_point_info *bl31_plat_get_next_image_ep_info(uint32_t type); /******************************************************************************* diff --git a/make_helpers/build_macros.mk b/make_helpers/build_macros.mk index 9ab6e648..08cb4b12 100644 --- a/make_helpers/build_macros.mk +++ b/make_helpers/build_macros.mk @@ -28,6 +28,22 @@ # POSSIBILITY OF SUCH DAMAGE. # +# This table is used in converting lower case to upper case. +uppercase_table:=a,A b,B c,C d,D e,E f,F g,G h,H i,I j,J k,K l,L m,M n,N o,O p,P q,Q r,R s,S t,T u,U v,V w,W x,X y,Y z,Z + +# Internal macro used for converting lower case to upper case. +# $(1) = upper case table +# $(2) = String to convert +define uppercase_internal +$(if $(1),$$(subst $(firstword $(1)),$(call uppercase_internal,$(wordlist 2,$(words $(1)),$(1)),$(2))),$(2)) +endef + +# A macro for converting a string to upper case +# $(1) = String to convert +define uppercase +$(eval uppercase_result:=$(call uppercase_internal,$(uppercase_table),$(1)))$(uppercase_result) +endef + # Convenience function for adding build definitions # $(eval $(call add_define,FOO)) will have: # -DFOO if $(FOO) is empty; -DFOO=$(FOO) otherwise @@ -82,7 +98,7 @@ define FIP_ADD_PAYLOAD $(eval $(if $(3),FIP_DEPS += $(3))) endef -# CERT_ADD_CMD_OPT adds a new command line option to the cert_create invokation +# CERT_ADD_CMD_OPT adds a new command line option to the cert_create invocation # $(1) = parameter filename # $(2) = cert_create command line option for the specified parameter # $(3) = input parameter (false if empty) @@ -107,6 +123,38 @@ check_$(1): $$(if $(value $(1)),,$$(error "Platform '${PLAT}' requires $(1). Please set $(1) to point to the right file")) endef +# FWU_FIP_ADD_PAYLOAD appends the command line arguments required by the FIP tool +# to package a new FWU payload. Optionally, it adds the dependency on this payload +# $(1) = payload filename (e.g. ns_bl2u.bin) +# $(2) = command line option for the specified payload (e.g. --ns_bl2u) +# $(3) = fip target dependency (optional) (e.g. ns_bl2u) +define FWU_FIP_ADD_PAYLOAD + $(eval $(if $(3),FWU_FIP_DEPS += $(3))) + $(eval FWU_FIP_ARGS += $(2) $(1)) +endef + +# FWU_CERT_ADD_CMD_OPT adds a new command line option to the cert_create invocation +# $(1) = parameter filename +# $(2) = cert_create command line option for the specified parameter +# $(3) = input parameter (false if empty) +define FWU_CERT_ADD_CMD_OPT + $(eval $(if $(3),FWU_CRT_DEPS += $(1))) + $(eval FWU_CRT_ARGS += $(2) $(1)) +endef + +# FWU_FIP_ADD_IMG allows the platform to pack a binary image in the FWU FIP +# $(1) build option to specify the image filename (BL2U, NS_BL2U, etc) +# $(2) command line option for the fip_create tool (bl2u, ns_bl2u, etc) +# Example: +# $(eval $(call FWU_FIP_ADD_IMG,BL2U,--bl2u)) +define FWU_FIP_ADD_IMG + FWU_CRT_DEPS += check_$(1) + FWU_FIP_DEPS += check_$(1) + $(call FWU_FIP_ADD_PAYLOAD,$(value $(1)),$(2)) + +check_$(1): + $$(if $(value $(1)),,$$(error "Platform '${PLAT}' requires $(1). Please set $(1) to point to the right file")) +endef ################################################################################ # Auxiliary macros to build TF images from sources @@ -123,7 +171,7 @@ $(strip $(foreach goal,$(1),$(filter $(goal),$(MAKECMDGOALS)))) endef # List of rules that involve building things -BUILD_TARGETS := all bl1 bl2 bl31 bl32 certificates fip +BUILD_TARGETS := all bl1 bl2 bl2u bl31 bl32 certificates fip # Does the list of goals specified on the command line include a build target? ifneq ($(call match_goals,${BUILD_TARGETS}),) @@ -134,15 +182,16 @@ endif # MAKE_C builds a C source file and generates the dependency file # $(1) = output directory # $(2) = source file (%.c) -# $(3) = BL stage (2, 30, 31, 32, 33) +# $(3) = BL stage (2, 2u, 30, 31, 32, 33) define MAKE_C $(eval OBJ := $(1)/$(patsubst %.c,%.o,$(notdir $(2)))) $(eval PREREQUISITES := $(patsubst %.o,%.d,$(OBJ))) +$(eval IMAGE := IMAGE_BL$(call uppercase,$(3))) $(OBJ): $(2) @echo " CC $$<" - $$(Q)$$(CC) $$(CFLAGS) -DIMAGE_BL$(3) -c $$< -o $$@ + $$(Q)$$(CC) $$(CFLAGS) -D$(IMAGE) -c $$< -o $$@ $(PREREQUISITES): $(2) @@ -160,15 +209,16 @@ endef # MAKE_S builds an assembly source file and generates the dependency file # $(1) = output directory # $(2) = assembly file (%.S) -# $(3) = BL stage (2, 30, 31, 32, 33) +# $(3) = BL stage (2, 2u, 30, 31, 32, 33) define MAKE_S $(eval OBJ := $(1)/$(patsubst %.S,%.o,$(notdir $(2)))) $(eval PREREQUISITES := $(patsubst %.o,%.d,$(OBJ))) +$(eval IMAGE := IMAGE_BL$(call uppercase,$(3))) $(OBJ): $(2) @echo " AS $$<" - $$(Q)$$(AS) $$(ASFLAGS) -DIMAGE_BL$(3) -c $$< -o $$@ + $$(Q)$$(AS) $$(ASFLAGS) -D$(IMAGE) -c $$< -o $$@ $(PREREQUISITES): $(2) @echo " DEPS $$@" @@ -243,20 +293,22 @@ endef # MAKE_BL macro defines the targets and options to build each BL image. # Arguments: -# $(1) = BL stage (2, 30, 31, 32, 33) +# $(1) = BL stage (2, 2u, 30, 31, 32, 33) # $(2) = In FIP (false if empty) define MAKE_BL $(eval BUILD_DIR := ${BUILD_PLAT}/bl$(1)) - $(eval SOURCES := $(BL$(1)_SOURCES) $(BL_COMMON_SOURCES) $(PLAT_BL_COMMON_SOURCES)) + $(eval BL_SOURCES := $(BL$(call uppercase,$(1))_SOURCES)) + $(eval SOURCES := $(BL_SOURCES) $(BL_COMMON_SOURCES) $(PLAT_BL_COMMON_SOURCES)) $(eval OBJS := $(addprefix $(BUILD_DIR)/,$(call SOURCES_TO_OBJS,$(SOURCES)))) $(eval LINKERFILE := $(call IMG_LINKERFILE,$(1))) $(eval MAPFILE := $(call IMG_MAPFILE,$(1))) $(eval ELF := $(call IMG_ELF,$(1))) $(eval DUMP := $(call IMG_DUMP,$(1))) $(eval BIN := $(call IMG_BIN,$(1))) + $(eval BL_LINKERFILE := $(BL$(call uppercase,$(1))_LINKERFILE)) $(eval $(call MAKE_OBJS,$(BUILD_DIR),$(SOURCES),$(1))) - $(eval $(call MAKE_LD,$(LINKERFILE),$(BL$(1)_LINKERFILE))) + $(eval $(call MAKE_LD,$(LINKERFILE),$(BL_LINKERFILE))) $(BUILD_DIR): $$(Q)mkdir -p "$$@" diff --git a/make_helpers/tbbr/tbbr_tools.mk b/make_helpers/tbbr/tbbr_tools.mk index 2ec72b90..bf0d2967 100644 --- a/make_helpers/tbbr/tbbr_tools.mk +++ b/make_helpers/tbbr/tbbr_tools.mk @@ -56,16 +56,22 @@ # Certificate generation tool default parameters TRUSTED_KEY_CERT := ${BUILD_PLAT}/trusted_key.crt +FWU_CERT := ${BUILD_PLAT}/fwu_cert.crt # Add Trusted Key certificate to the fip_create and cert_create command line options $(eval $(call FIP_ADD_PAYLOAD,${TRUSTED_KEY_CERT},--trusted-key-cert)) $(eval $(call CERT_ADD_CMD_OPT,${TRUSTED_KEY_CERT},--trusted-key-cert)) +# Add fwu certificate to the fip_create and cert_create command line options +$(eval $(call FWU_FIP_ADD_PAYLOAD,${FWU_CERT},--fwu-cert)) +$(eval $(call FWU_CERT_ADD_CMD_OPT,${FWU_CERT},--fwu-cert)) + # Add the keys to the cert_create command line options (private keys are NOT # packed in the FIP). Developers can use their own keys by specifying the proper # build option in the command line when building the Trusted Firmware $(if ${KEY_ALG},$(eval $(call CERT_ADD_CMD_OPT,${KEY_ALG},--key-alg))) $(if ${ROT_KEY},$(eval $(call CERT_ADD_CMD_OPT,${ROT_KEY},--rot-key))) +$(if ${ROT_KEY},$(eval $(call FWU_CERT_ADD_CMD_OPT,${ROT_KEY},--rot-key))) $(if ${TRUSTED_WORLD_KEY},$(eval $(call CERT_ADD_CMD_OPT,${TRUSTED_WORLD_KEY},--trusted-world-key))) $(if ${NON_TRUSTED_WORLD_KEY},$(eval $(call CERT_ADD_CMD_OPT,${NON_TRUSTED_WORLD_KEY},--non-trusted-world-key))) @@ -114,3 +120,17 @@ ifneq (${BL33},) $(eval $(call FIP_ADD_PAYLOAD,${BUILD_PLAT}/bl33.crt,--bl33-cert)) $(eval $(call FIP_ADD_PAYLOAD,${BUILD_PLAT}/bl33_key.crt,--bl33-key-cert)) endif + +# Add the BL2U image +$(if ${BL2U},$(eval $(call FWU_CERT_ADD_CMD_OPT,${BL2U},--bl2u,true)),\ + $(eval $(call FWU_CERT_ADD_CMD_OPT,$(call IMG_BIN,2u),--bl2u,true))) + +# Add the SCP_BL2U image +ifneq (${SCP_BL2U},) + $(eval $(call FWU_CERT_ADD_CMD_OPT,${SCP_BL2U},--scp_bl2u,true)) +endif + +# Add the NS_BL2U image +ifneq (${NS_BL2U},) + $(eval $(call FWU_CERT_ADD_CMD_OPT,${NS_BL2U},--ns_bl2u,true)) +endif diff --git a/plat/arm/board/common/board_css_common.c b/plat/arm/board/common/board_css_common.c index 7bf0273d..62253f8c 100644 --- a/plat/arm/board/common/board_css_common.c +++ b/plat/arm/board/common/board_css_common.c @@ -42,6 +42,9 @@ const mmap_region_t plat_arm_mmap[] = { V2M_MAP_IOFPGA, CSS_MAP_DEVICE, SOC_CSS_MAP_DEVICE, +#if TRUSTED_BOARD_BOOT + ARM_MAP_NS_DRAM1, +#endif {0} }; #endif @@ -57,6 +60,14 @@ const mmap_region_t plat_arm_mmap[] = { {0} }; #endif +#if IMAGE_BL2U +const mmap_region_t plat_arm_mmap[] = { + ARM_MAP_SHARED_RAM, + CSS_MAP_DEVICE, + SOC_CSS_MAP_DEVICE, + {0} +}; +#endif #if IMAGE_BL31 const mmap_region_t plat_arm_mmap[] = { ARM_MAP_SHARED_RAM, diff --git a/plat/arm/board/fvp/aarch64/fvp_common.c b/plat/arm/board/fvp/aarch64/fvp_common.c index 8771e5b4..305505d3 100644 --- a/plat/arm/board/fvp/aarch64/fvp_common.c +++ b/plat/arm/board/fvp/aarch64/fvp_common.c @@ -30,14 +30,23 @@ #include <arm_config.h> #include <arm_def.h> -#include <arm_gic.h> #include <cci.h> #include <debug.h> +#include <gicv2.h> #include <mmio.h> #include <plat_arm.h> #include <v2m_def.h> #include "../fvp_def.h" +#if (FVP_USE_GIC_DRIVER == FVP_GICV2) +extern gicv2_driver_data_t arm_gic_data; +#endif + +/* Defines for GIC Driver build time selection */ +#define FVP_GICV2 1 +#define FVP_GICV3 2 +#define FVP_GICV3_LEGACY 3 + /******************************************************************************* * arm_config holds the characteristics of the differences between the three FVP * platforms (Base, A53_A57 & Foundation). It will be populated during cold boot @@ -73,6 +82,9 @@ const mmap_region_t plat_arm_mmap[] = { MAP_DEVICE0, MAP_DEVICE1, MAP_DEVICE2, +#if TRUSTED_BOARD_BOOT + ARM_MAP_NS_DRAM1, +#endif {0} }; #endif @@ -89,6 +101,13 @@ const mmap_region_t plat_arm_mmap[] = { {0} }; #endif +#if IMAGE_BL2U +const mmap_region_t plat_arm_mmap[] = { + MAP_DEVICE0, + V2M_MAP_IOFPGA, + {0} +}; +#endif #if IMAGE_BL31 const mmap_region_t plat_arm_mmap[] = { ARM_MAP_SHARED_RAM, @@ -110,33 +129,6 @@ const mmap_region_t plat_arm_mmap[] = { ARM_CASSERT_MMAP -#if IMAGE_BL31 || IMAGE_BL32 -/* Array of secure interrupts to be configured by the gic driver */ -const unsigned int irq_sec_array[] = { - ARM_IRQ_SEC_PHY_TIMER, - ARM_IRQ_SEC_SGI_0, - ARM_IRQ_SEC_SGI_1, - ARM_IRQ_SEC_SGI_2, - ARM_IRQ_SEC_SGI_3, - ARM_IRQ_SEC_SGI_4, - ARM_IRQ_SEC_SGI_5, - ARM_IRQ_SEC_SGI_6, - ARM_IRQ_SEC_SGI_7, - FVP_IRQ_TZ_WDOG, - FVP_IRQ_SEC_SYS_TIMER -}; - -void plat_arm_gic_init(void) -{ - arm_gic_init(arm_config.gicc_base, - arm_config.gicd_base, - BASE_GICR_BASE, - irq_sec_array, - ARRAY_SIZE(irq_sec_array)); -} - -#endif - /******************************************************************************* * A single boot loader stack is expected to work on both the Foundation FVP * models and the two flavours of the Base FVP models (AEMv8 & Cortex). The @@ -165,16 +157,28 @@ void fvp_config_setup(void) */ switch (bld) { case BLD_GIC_VE_MMAP: - arm_config.gicd_base = VE_GICD_BASE; - arm_config.gicc_base = VE_GICC_BASE; - arm_config.gich_base = VE_GICH_BASE; - arm_config.gicv_base = VE_GICV_BASE; +#if IMAGE_BL31 || IMAGE_BL32 +#if FVP_USE_GIC_DRIVER == FVP_GICV2 + /* + * If the FVP implements the VE compatible memory map, then the + * GICv2 driver must be included in the build. Update the platform + * data with the correct GICv2 base addresses before it is used + * to initialise the driver. + * + * This update of platform data is temporary and will be removed + * once VE memory map for FVP is no longer supported by Trusted + * Firmware. + */ + arm_gic_data.gicd_base = VE_GICD_BASE; + arm_gic_data.gicc_base = VE_GICC_BASE; + +#else + ERROR("Only GICv2 driver supported for VE memory map\n"); + panic(); +#endif /* __FVP_USE_GIC_DRIVER == FVP_GICV2__ */ +#endif /* __IMAGE_BL31 || IMAGE_BL32__ */ break; case BLD_GIC_A53A57_MMAP: - arm_config.gicd_base = BASE_GICD_BASE; - arm_config.gicc_base = BASE_GICC_BASE; - arm_config.gich_base = BASE_GICH_BASE; - arm_config.gicv_base = BASE_GICV_BASE; break; default: ERROR("Unsupported board build %x\n", bld); @@ -187,8 +191,6 @@ void fvp_config_setup(void) */ switch (hbi) { case HBI_FOUNDATION_FVP: - arm_config.max_aff0 = 4; - arm_config.max_aff1 = 1; arm_config.flags = 0; /* @@ -206,8 +208,6 @@ void fvp_config_setup(void) } break; case HBI_BASE_FVP: - arm_config.max_aff0 = 4; - arm_config.max_aff1 = 2; arm_config.flags |= ARM_CONFIG_BASE_MMAP | ARM_CONFIG_HAS_CCI | ARM_CONFIG_HAS_TZC; diff --git a/plat/arm/board/fvp/aarch64/fvp_helpers.S b/plat/arm/board/fvp/aarch64/fvp_helpers.S index 2c24e61f..338d1581 100644 --- a/plat/arm/board/fvp/aarch64/fvp_helpers.S +++ b/plat/arm/board/fvp/aarch64/fvp_helpers.S @@ -30,7 +30,8 @@ #include <arch.h> #include <asm_macros.S> -#include <gic_v2.h> +#include <gicv2.h> +#include <gicv3.h> #include <platform_def.h> #include <v2m_def.h> #include "../drivers/pwrc/fvp_pwrc.h" @@ -74,9 +75,26 @@ func plat_secondary_cold_boot_setup str w0, [x1, #PPOFFR_OFF] /* --------------------------------------------- - * Deactivate the gic cpu interface as well + * Disable GIC bypass as well * --------------------------------------------- */ + /* Check for GICv3 system register access */ + mrs x0, id_aa64pfr0_el1 + ubfx x0, x0, #ID_AA64PFR0_GIC_SHIFT, #ID_AA64PFR0_GIC_WIDTH + cmp x0, #1 + b.ne gicv2_bypass_disable + + /* Check for SRE enable */ + mrs x1, ICC_SRE_EL3 + tst x1, #ICC_SRE_SRE_BIT + b.eq gicv2_bypass_disable + + mrs x2, ICC_SRE_EL3 + orr x2, x2, #(ICC_SRE_DIB_BIT | ICC_SRE_DFB_BIT) + msr ICC_SRE_EL3, x2 + b secondary_cold_boot_wait + +gicv2_bypass_disable: ldr x0, =VE_GICC_BASE ldr x1, =BASE_GICC_BASE fvp_choose_gicmmap x0, x1, x2, w2, x1 @@ -84,6 +102,7 @@ func plat_secondary_cold_boot_setup orr w0, w0, #(IRQ_BYP_DIS_GRP0 | FIQ_BYP_DIS_GRP0) str w0, [x1, #GICC_CTLR] +secondary_cold_boot_wait: /* --------------------------------------------- * There is no sane reason to come out of this * wfi so panic if we do. This cpu will be pow- diff --git a/plat/arm/board/fvp/fvp_bl1_setup.c b/plat/arm/board/fvp/fvp_bl1_setup.c index 33712d1e..91bc9c4e 100644 --- a/plat/arm/board/fvp/fvp_bl1_setup.c +++ b/plat/arm/board/fvp/fvp_bl1_setup.c @@ -29,6 +29,7 @@ */ #include <plat_arm.h> +#include <tbbr_img_def.h> #include "fvp_private.h" @@ -52,3 +53,16 @@ void bl1_early_platform_setup(void) */ fvp_cci_enable(); } + +/******************************************************************************* + * The following function checks if Firmware update is needed, + * by checking if TOC in FIP image is valid or not. + ******************************************************************************/ +unsigned int bl1_plat_get_next_image_id(void) +{ + if (!arm_io_is_toc_valid()) + return NS_BL1U_IMAGE_ID; + + return BL2_IMAGE_ID; +} + diff --git a/plat/arm/board/fvp/fvp_bl2_setup.c b/plat/arm/board/fvp/fvp_bl2_setup.c index b1cdef48..305309ab 100644 --- a/plat/arm/board/fvp/fvp_bl2_setup.c +++ b/plat/arm/board/fvp/fvp_bl2_setup.c @@ -28,6 +28,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include <mmio.h> #include <plat_arm.h> #include <sp804_delay_timer.h> #include <v2m_def.h> @@ -47,6 +48,10 @@ void bl2_platform_setup(void) { arm_bl2_platform_setup(); + /* Enable the clock override for SP804 timer 0, which means that no + * clock dividers are applied and the raw (35 MHz) clock will be used */ + mmio_write_32(V2M_SP810_BASE, FVP_SP810_CTRL_TIM0_OV); + /* Initialize delay timer driver using SP804 dual timer 0 */ sp804_timer_init(V2M_SP804_TIMER0_BASE, SP804_TIMER_CLKMULT, SP804_TIMER_CLKDIV); diff --git a/plat/arm/board/fvp/fvp_bl2u_setup.c b/plat/arm/board/fvp/fvp_bl2u_setup.c new file mode 100644 index 00000000..b26f0e04 --- /dev/null +++ b/plat/arm/board/fvp/fvp_bl2u_setup.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <plat_arm.h> +#include "fvp_def.h" +#include "fvp_private.h" + +void bl2u_early_platform_setup(meminfo_t *mem_layout, void *plat_info) +{ + arm_bl2u_early_platform_setup(mem_layout, plat_info); + + /* Initialize the platform config for future decision making */ + fvp_config_setup(); +} diff --git a/plat/arm/board/fvp/fvp_def.h b/plat/arm/board/fvp/fvp_def.h index 3af4db68..41b872af 100644 --- a/plat/arm/board/fvp/fvp_def.h +++ b/plat/arm/board/fvp/fvp_def.h @@ -96,8 +96,14 @@ #define PWRC_BASE 0x1c100000 /* FVP SP804 timer frequency is 35 MHz*/ -#define SP804_TIMER_CLKMULT 35 -#define SP804_TIMER_CLKDIV 1 +#define SP804_TIMER_CLKMULT 1 +#define SP804_TIMER_CLKDIV 35 + +/* SP810 controller. FVP specific flags */ +#define FVP_SP810_CTRL_TIM0_OV (1 << 16) +#define FVP_SP810_CTRL_TIM1_OV (1 << 18) +#define FVP_SP810_CTRL_TIM2_OV (1 << 20) +#define FVP_SP810_CTRL_TIM3_OV (1 << 22) /******************************************************************************* * GIC-400 & interrupt handling related constants diff --git a/plat/arm/board/fvp/fvp_pm.c b/plat/arm/board/fvp/fvp_pm.c index 21ad14fa..c5129a60 100644 --- a/plat/arm/board/fvp/fvp_pm.c +++ b/plat/arm/board/fvp/fvp_pm.c @@ -30,7 +30,6 @@ #include <arch_helpers.h> #include <arm_config.h> -#include <arm_gic.h> #include <assert.h> #include <debug.h> #include <errno.h> @@ -72,7 +71,7 @@ const unsigned int arm_pm_idle_states[] = { static void fvp_cpu_pwrdwn_common(void) { /* Prevent interrupts from spuriously waking up this cpu */ - arm_gic_cpuif_deactivate(); + plat_arm_gic_cpuif_disable(); /* Program the power controller to power off this cpu. */ fvp_pwrc_write_ppoffr(read_mpidr_el1()); @@ -93,6 +92,42 @@ static void fvp_cluster_pwrdwn_common(void) fvp_pwrc_write_pcoffr(mpidr); } +static void fvp_power_domain_on_finish_common(const psci_power_state_t *target_state) +{ + unsigned long mpidr; + + assert(target_state->pwr_domain_state[ARM_PWR_LVL0] == + ARM_LOCAL_STATE_OFF); + + /* Get the mpidr for this cpu */ + mpidr = read_mpidr_el1(); + + /* Perform the common cluster specific operations */ + if (target_state->pwr_domain_state[ARM_PWR_LVL1] == + ARM_LOCAL_STATE_OFF) { + /* + * This CPU might have woken up whilst the cluster was + * attempting to power down. In this case the FVP power + * controller will have a pending cluster power off request + * which needs to be cleared by writing to the PPONR register. + * This prevents the power controller from interpreting a + * subsequent entry of this cpu into a simple wfi as a power + * down request. + */ + fvp_pwrc_write_pponr(mpidr); + + /* Enable coherency if this cluster was off */ + fvp_cci_enable(); + } + + /* + * Clear PWKUPR.WEN bit to ensure interrupts do not interfere + * with a cpu power down unless the bit is set again + */ + fvp_pwrc_clr_wen(mpidr); +} + + /******************************************************************************* * FVP handler called when a CPU is about to enter standby. ******************************************************************************/ @@ -196,43 +231,13 @@ void fvp_pwr_domain_suspend(const psci_power_state_t *target_state) ******************************************************************************/ void fvp_pwr_domain_on_finish(const psci_power_state_t *target_state) { - unsigned long mpidr; - - assert(target_state->pwr_domain_state[ARM_PWR_LVL0] == - ARM_LOCAL_STATE_OFF); - - /* Get the mpidr for this cpu */ - mpidr = read_mpidr_el1(); - - /* Perform the common cluster specific operations */ - if (target_state->pwr_domain_state[ARM_PWR_LVL1] == - ARM_LOCAL_STATE_OFF) { - /* - * This CPU might have woken up whilst the cluster was - * attempting to power down. In this case the FVP power - * controller will have a pending cluster power off request - * which needs to be cleared by writing to the PPONR register. - * This prevents the power controller from interpreting a - * subsequent entry of this cpu into a simple wfi as a power - * down request. - */ - fvp_pwrc_write_pponr(mpidr); - - /* Enable coherency if this cluster was off */ - fvp_cci_enable(); - } - - /* - * Clear PWKUPR.WEN bit to ensure interrupts do not interfere - * with a cpu power down unless the bit is set again - */ - fvp_pwrc_clr_wen(mpidr); + fvp_power_domain_on_finish_common(target_state); /* Enable the gic cpu interface */ - arm_gic_cpuif_setup(); + plat_arm_gic_pcpu_init(); - /* TODO: This setup is needed only after a cold boot */ - arm_gic_pcpu_distif_setup(); + /* Program the gic per-cpu distributor or re-distributor interface */ + plat_arm_gic_cpuif_enable(); } /******************************************************************************* @@ -251,7 +256,10 @@ void fvp_pwr_domain_suspend_finish(const psci_power_state_t *target_state) ARM_LOCAL_STATE_RET) return; - fvp_pwr_domain_on_finish(target_state); + fvp_power_domain_on_finish_common(target_state); + + /* Enable the gic cpu interface */ + plat_arm_gic_cpuif_enable(); } /******************************************************************************* diff --git a/plat/arm/board/fvp/include/plat_macros.S b/plat/arm/board/fvp/include/plat_macros.S index 2feffbe5..2ed0d85e 100644 --- a/plat/arm/board/fvp/include/plat_macros.S +++ b/plat/arm/board/fvp/include/plat_macros.S @@ -53,16 +53,14 @@ /* Check if VE mmap */ cmp w16, #BLD_GIC_VE_MMAP b.eq use_ve_mmap - /* Check if Cortex-A53/A57 mmap */ - cmp w16, #BLD_GIC_A53A57_MMAP - b.ne exit_print_gic_regs + /* Assume Base Cortex mmap */ mov_imm x17, BASE_GICC_BASE mov_imm x16, BASE_GICD_BASE - b print_gicc_regs + b print_gic_regs use_ve_mmap: mov_imm x17, VE_GICC_BASE mov_imm x16, VE_GICD_BASE -print_gicc_regs: +print_gic_regs: arm_print_gic_regs .endm diff --git a/plat/arm/board/fvp/include/platform_def.h b/plat/arm/board/fvp/include/platform_def.h index 9ada6b2a..e93418dc 100644 --- a/plat/arm/board/fvp/include/platform_def.h +++ b/plat/arm/board/fvp/include/platform_def.h @@ -78,8 +78,11 @@ #define PLAT_ARM_BOOT_UART_BASE V2M_IOFPGA_UART0_BASE #define PLAT_ARM_BOOT_UART_CLK_IN_HZ V2M_IOFPGA_UART0_CLK_IN_HZ -#define PLAT_ARM_CRASH_UART_BASE V2M_IOFPGA_UART1_BASE -#define PLAT_ARM_CRASH_UART_CLK_IN_HZ V2M_IOFPGA_UART1_CLK_IN_HZ +#define PLAT_ARM_BL31_RUN_UART_BASE V2M_IOFPGA_UART1_BASE +#define PLAT_ARM_BL31_RUN_UART_CLK_IN_HZ V2M_IOFPGA_UART1_CLK_IN_HZ + +#define PLAT_ARM_CRASH_UART_BASE PLAT_ARM_BL31_RUN_UART_BASE +#define PLAT_ARM_CRASH_UART_CLK_IN_HZ PLAT_ARM_BL31_RUN_UART_CLK_IN_HZ #define PLAT_ARM_TSP_UART_BASE V2M_IOFPGA_UART2_BASE #define PLAT_ARM_TSP_UART_CLK_IN_HZ V2M_IOFPGA_UART2_CLK_IN_HZ @@ -121,5 +124,24 @@ TZC_REGION_ACCESS_RDWR(FVP_NSAID_VIRTIO) | \ TZC_REGION_ACCESS_RDWR(FVP_NSAID_VIRTIO_OLD)) +/* + * GIC related constants to cater for both GICv2 and GICv3 instances of an + * FVP. They could be overriden at runtime in case the FVP implements the legacy + * VE memory map. + */ +#define PLAT_ARM_GICD_BASE BASE_GICD_BASE +#define PLAT_ARM_GICR_BASE BASE_GICR_BASE +#define PLAT_ARM_GICC_BASE BASE_GICC_BASE + +/* + * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3 + * terminology. On a GICv2 system or mode, the lists will be merged and treated + * as Group 0 interrupts. + */ +#define PLAT_ARM_G1S_IRQS ARM_G1S_IRQS, \ + FVP_IRQ_TZ_WDOG, \ + FVP_IRQ_SEC_SYS_TIMER + +#define PLAT_ARM_G0_IRQS ARM_G0_IRQS #endif /* __PLATFORM_DEF_H__ */ diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk index c46d3b71..cb5f5d7e 100644 --- a/plat/arm/board/fvp/platform.mk +++ b/plat/arm/board/fvp/platform.mk @@ -28,6 +28,35 @@ # POSSIBILITY OF SUCH DAMAGE. # +# Use the Legacy GICv3 driver on the FVP by default to maintain compatibility. +FVP_USE_GIC_DRIVER := FVP_GICV3_LEGACY + +# The FVP platform depends on this macro to build with correct GIC driver. +$(eval $(call add_define,FVP_USE_GIC_DRIVER)) + +# Choose the GIC sources depending upon the how the FVP will be invoked +ifeq (${FVP_USE_GIC_DRIVER}, FVP_GICV3) +FVP_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \ + drivers/arm/gic/v3/gicv3_main.c \ + drivers/arm/gic/v3/gicv3_helpers.c \ + plat/common/plat_gicv3.c \ + plat/arm/common/arm_gicv3.c +else ifeq (${FVP_USE_GIC_DRIVER}, FVP_GICV2) +FVP_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \ + drivers/arm/gic/v2/gicv2_main.c \ + drivers/arm/gic/v2/gicv2_helpers.c \ + plat/common/plat_gicv2.c \ + plat/arm/common/arm_gicv2.c +else ifeq (${FVP_USE_GIC_DRIVER}, FVP_GICV3_LEGACY) +FVP_GIC_SOURCES := drivers/arm/gic/arm_gic.c \ + drivers/arm/gic/gic_v2.c \ + drivers/arm/gic/gic_v3.c \ + plat/common/plat_gic.c \ + plat/arm/common/arm_gicv3_legacy.c +else +$(error "Incorrect GIC driver chosen on FVP port") +endif + PLAT_INCLUDES := -Iplat/arm/board/fvp/include @@ -54,6 +83,9 @@ BL2_SOURCES += drivers/arm/sp804/sp804_delay_timer.c \ plat/arm/board/fvp/fvp_io_storage.c \ plat/arm/board/fvp/fvp_security.c +BL2U_SOURCES += plat/arm/board/fvp/fvp_bl2u_setup.c \ + plat/arm/board/fvp/fvp_security.c + BL31_SOURCES += lib/cpus/aarch64/aem_generic.S \ lib/cpus/aarch64/cortex_a53.S \ lib/cpus/aarch64/cortex_a57.S \ @@ -62,7 +94,8 @@ BL31_SOURCES += lib/cpus/aarch64/aem_generic.S \ plat/arm/board/fvp/fvp_security.c \ plat/arm/board/fvp/fvp_topology.c \ plat/arm/board/fvp/aarch64/fvp_helpers.S \ - plat/arm/board/fvp/drivers/pwrc/fvp_pwrc.c + plat/arm/board/fvp/drivers/pwrc/fvp_pwrc.c \ + ${FVP_GIC_SOURCES} # Disable the PSCI platform compatibility layer ENABLE_PLAT_COMPAT := 0 diff --git a/plat/arm/board/fvp/tsp/tsp-fvp.mk b/plat/arm/board/fvp/tsp/tsp-fvp.mk index 99db2f49..54a76fde 100644 --- a/plat/arm/board/fvp/tsp/tsp-fvp.mk +++ b/plat/arm/board/fvp/tsp/tsp-fvp.mk @@ -31,6 +31,7 @@ # TSP source files specific to FVP platform BL32_SOURCES += plat/arm/board/fvp/fvp_topology.c \ plat/arm/board/fvp/drivers/pwrc/fvp_pwrc.c \ - plat/arm/board/fvp/tsp/fvp_tsp_setup.c + plat/arm/board/fvp/tsp/fvp_tsp_setup.c \ + ${FVP_GIC_SOURCES} include plat/arm/common/tsp/arm_tsp.mk diff --git a/plat/arm/board/juno/include/platform_def.h b/plat/arm/board/juno/include/platform_def.h index 39283c56..924eb0ab 100644 --- a/plat/arm/board/juno/include/platform_def.h +++ b/plat/arm/board/juno/include/platform_def.h @@ -94,17 +94,18 @@ */ /* GIC related constants (no GICR in GIC-400) */ -#define PLAT_CSS_GICD_BASE 0x2c010000 -#define PLAT_CSS_GICR_BASE 0x0 -#define PLAT_CSS_GICC_BASE 0x2c02f000 -#define PLAT_CSS_GICH_BASE 0x2c04f000 -#define PLAT_CSS_GICV_BASE 0x2c06f000 - -#define PLAT_CSS_IRQ_SEC_LIST CSS_IRQ_MHU, \ - CSS_IRQ_GPU_SMMU_0, \ - CSS_IRQ_TZC, \ - CSS_IRQ_TZ_WDOG, \ - CSS_IRQ_SEC_SYS_TIMER, \ +#define PLAT_ARM_GICD_BASE 0x2c010000 +#define PLAT_ARM_GICC_BASE 0x2c02f000 +#define PLAT_ARM_GICH_BASE 0x2c04f000 +#define PLAT_ARM_GICV_BASE 0x2c06f000 + +/* + * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3 + * terminology. On a GICv2 system or mode, the lists will be merged and treated + * as Group 0 interrupts. + */ +#define PLAT_ARM_G1S_IRQS CSS_G1S_IRQS, \ + ARM_G1S_IRQS, \ JUNO_IRQ_DMA_SMMU, \ JUNO_IRQ_HDLCD0_SMMU, \ JUNO_IRQ_HDLCD1_SMMU, \ @@ -114,6 +115,8 @@ JUNO_IRQ_GPU_SMMU_1, \ JUNO_IRQ_ETR_SMMU +#define PLAT_ARM_G0_IRQS ARM_G0_IRQS + /* * Required ARM CSS SoC based platform porting definitions */ diff --git a/plat/arm/board/juno/juno_bl1_setup.c b/plat/arm/board/juno/juno_bl1_setup.c new file mode 100644 index 00000000..61a57381 --- /dev/null +++ b/plat/arm/board/juno/juno_bl1_setup.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <bl_common.h> +#include <errno.h> +#include <platform.h> +#include <plat_arm.h> +#include <tbbr_img_def.h> +#include <v2m_def.h> + +#define RESET_REASON_WDOG_RESET (0x2) + +/******************************************************************************* + * The following function checks if Firmware update is needed, + * by checking if TOC in FIP image is valid or watchdog reset happened. + ******************************************************************************/ +unsigned int bl1_plat_get_next_image_id(void) +{ + unsigned int *reset_flags_ptr = (unsigned int *)SSC_GPRETN; + unsigned int *nv_flags_ptr = (unsigned int *) + (V2M_SYSREGS_BASE + V2M_SYS_NVFLAGS); + /* + * Check if TOC is invalid or watchdog reset happened. + */ + if ((arm_io_is_toc_valid() != 1) || + ((*reset_flags_ptr & RESET_REASON_WDOG_RESET) && + ((*nv_flags_ptr == -EAUTH) || (*nv_flags_ptr == -ENOENT)))) + return NS_BL1U_IMAGE_ID; + + return BL2_IMAGE_ID; +} + +/******************************************************************************* + * On JUNO update the arg2 with address of SCP_BL2U image info. + ******************************************************************************/ +void bl1_plat_set_ep_info(unsigned int image_id, + entry_point_info_t *ep_info) +{ + if (image_id == BL2U_IMAGE_ID) { + image_desc_t *image_desc = bl1_plat_get_image_desc(SCP_BL2U_IMAGE_ID); + ep_info->args.arg2 = (unsigned long)&image_desc->image_info; + } +} + +/******************************************************************************* + * On Juno clear SYS_NVFLAGS and wait for watchdog reset. + ******************************************************************************/ +__dead2 void bl1_plat_fwu_done(void *cookie, void *rsvd_ptr) +{ + unsigned int *nv_flags_clr = (unsigned int *) + (V2M_SYSREGS_BASE + V2M_SYS_NVFLAGSCLR); + unsigned int *nv_flags_ptr = (unsigned int *) + (V2M_SYSREGS_BASE + V2M_SYS_NVFLAGS); + + /* Clear the NV flags register. */ + *nv_flags_clr = *nv_flags_ptr; + + while (1) + wfi(); +} diff --git a/plat/arm/board/juno/platform.mk b/plat/arm/board/juno/platform.mk index 127dcbea..fae30e7e 100644 --- a/plat/arm/board/juno/platform.mk +++ b/plat/arm/board/juno/platform.mk @@ -28,6 +28,12 @@ # POSSIBILITY OF SUCH DAMAGE. # +JUNO_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \ + drivers/arm/gic/v2/gicv2_main.c \ + drivers/arm/gic/v2/gicv2_helpers.c \ + plat/common/plat_gicv2.c \ + plat/arm/common/arm_gicv2.c + PLAT_INCLUDES := -Iplat/arm/board/juno/include PLAT_BL_COMMON_SOURCES := plat/arm/board/juno/aarch64/juno_helpers.S @@ -35,16 +41,20 @@ PLAT_BL_COMMON_SOURCES := plat/arm/board/juno/aarch64/juno_helpers.S BL1_SOURCES += lib/cpus/aarch64/cortex_a53.S \ lib/cpus/aarch64/cortex_a57.S \ lib/cpus/aarch64/cortex_a72.S \ + plat/arm/board/juno/juno_bl1_setup.c \ plat/arm/board/juno/juno_err.c BL2_SOURCES += plat/arm/board/juno/juno_security.c \ plat/arm/board/juno/juno_err.c +BL2U_SOURCES += plat/arm/board/juno/juno_security.c + BL31_SOURCES += lib/cpus/aarch64/cortex_a53.S \ lib/cpus/aarch64/cortex_a57.S \ lib/cpus/aarch64/cortex_a72.S \ plat/arm/board/juno/juno_pm.c \ - plat/arm/board/juno/juno_security.c + plat/arm/board/juno/juno_security.c \ + ${JUNO_GIC_SOURCES} # Enable workarounds for selected Cortex-A57 erratas. ERRATA_A57_806969 := 0 diff --git a/plat/arm/board/juno/tsp/tsp-juno.mk b/plat/arm/board/juno/tsp/tsp-juno.mk index bb67012f..2ef964e8 100644 --- a/plat/arm/board/juno/tsp/tsp-juno.mk +++ b/plat/arm/board/juno/tsp/tsp-juno.mk @@ -28,6 +28,7 @@ # POSSIBILITY OF SUCH DAMAGE. # -BL32_SOURCES += plat/arm/css/common/css_topology.c +BL32_SOURCES += plat/arm/css/common/css_topology.c \ + ${JUNO_GIC_SOURCES} include plat/arm/common/tsp/arm_tsp.mk diff --git a/plat/arm/common/arm_bl1_fwu.c b/plat/arm/common/arm_bl1_fwu.c new file mode 100644 index 00000000..9a0d93ad --- /dev/null +++ b/plat/arm/common/arm_bl1_fwu.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <assert.h> +#include <bl_common.h> +#include <debug.h> +#include <errno.h> +#include <plat_arm.h> +#include <tbbr_img_desc.h> + + +/* Struct to keep track of usable memory */ +typedef struct bl1_mem_info{ + uintptr_t mem_base; + unsigned int mem_size; +} bl1_mem_info_t; + +bl1_mem_info_t fwu_addr_map_secure[] = { + { + .mem_base = ARM_SHARED_RAM_BASE, + .mem_size = ARM_SHARED_RAM_SIZE + }, + { + .mem_size = 0 + } +}; + +bl1_mem_info_t fwu_addr_map_non_secure[] = { + { + .mem_base = ARM_NS_DRAM1_BASE, + .mem_size = ARM_NS_DRAM1_SIZE + }, + { + .mem_base = V2M_FLASH0_BASE, + .mem_size = V2M_FLASH0_SIZE + }, + { + .mem_size = 0 + } +}; + +int bl1_plat_mem_check(uintptr_t mem_base, + unsigned int mem_size, + unsigned int flags) +{ + unsigned int index = 0; + bl1_mem_info_t *mmap; + + assert(mem_base); + assert(mem_size); + + /* + * Check the given image source and size. + */ + if (GET_SEC_STATE(flags) == SECURE) + mmap = fwu_addr_map_secure; + else + mmap = fwu_addr_map_non_secure; + + while (mmap[index].mem_size) { + if ((mem_base >= mmap[index].mem_base) && + ((mem_base + mem_size) + <= (mmap[index].mem_base + + mmap[index].mem_size))) + return 0; + + index++; + } + + return -ENOMEM; +} + +/******************************************************************************* + * This function does linear search for image_id and returns image_desc. + ******************************************************************************/ +image_desc_t *bl1_plat_get_image_desc(unsigned int image_id) +{ + unsigned int index = 0; + + while (bl1_tbbr_image_descs[index].image_id != INVALID_IMAGE_ID) { + if (bl1_tbbr_image_descs[index].image_id == image_id) + return &bl1_tbbr_image_descs[index]; + index++; + } + + return NULL; +} diff --git a/plat/arm/common/arm_bl1_setup.c b/plat/arm/common/arm_bl1_setup.c index 79c7d944..d0a4c0b2 100644 --- a/plat/arm/common/arm_bl1_setup.c +++ b/plat/arm/common/arm_bl1_setup.c @@ -57,7 +57,6 @@ #pragma weak bl1_plat_arch_setup #pragma weak bl1_platform_setup #pragma weak bl1_plat_sec_mem_layout -#pragma weak bl1_plat_set_bl2_ep_info /* Data structure which holds the extents of the trusted SRAM for BL1*/ @@ -169,16 +168,3 @@ void bl1_plat_prepare_exit(entry_point_info_t *ep_info) sev(); #endif } - -/******************************************************************************* - * Before calling this function BL2 is loaded in memory and its entrypoint - * is set by load_image. This is a placeholder for the platform to change - * the entrypoint of BL2 and set SPSR and security state. - * On ARM standard platforms we only set the security state of the entrypoint - ******************************************************************************/ -void bl1_plat_set_bl2_ep_info(image_info_t *bl2_image, - entry_point_info_t *bl2_ep) -{ - SET_SECURITY_STATE(bl2_ep->h.attr, SECURE); - bl2_ep->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); -} diff --git a/plat/arm/common/arm_bl2u_setup.c b/plat/arm/common/arm_bl2u_setup.c new file mode 100644 index 00000000..5b7354b3 --- /dev/null +++ b/plat/arm/common/arm_bl2u_setup.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arch_helpers.h> +#include <arm_def.h> +#include <bl_common.h> +#include <console.h> +#include <platform_def.h> +#include <plat_arm.h> +#include <string.h> + + +/* + * The next 2 constants identify the extents of the code & RO data region. + * These addresses are used by the MMU setup code and therefore they must be + * page-aligned. It is the responsibility of the linker script to ensure that + * __RO_START__ and __RO_END__ linker symbols refer to page-aligned addresses. + */ +#define BL2U_RO_BASE (unsigned long)(&__RO_START__) +#define BL2U_RO_LIMIT (unsigned long)(&__RO_END__) + +#if USE_COHERENT_MEM +/* + * The next 2 constants identify the extents of the coherent memory region. + * These addresses are used by the MMU setup code and therefore they must be + * page-aligned. It is the responsibility of the linker script to ensure that + * __COHERENT_RAM_START__ and __COHERENT_RAM_END__ linker symbols refer to + * page-aligned addresses. + */ +#define BL2U_COHERENT_RAM_BASE (unsigned long)(&__COHERENT_RAM_START__) +#define BL2U_COHERENT_RAM_LIMIT (unsigned long)(&__COHERENT_RAM_END__) +#endif + +/* Weak definitions may be overridden in specific ARM standard platform */ +#pragma weak bl2u_platform_setup +#pragma weak bl2u_early_platform_setup +#pragma weak bl2u_plat_arch_setup + +/* + * Perform ARM standard platform setup for BL2U + */ +void arm_bl2u_platform_setup(void) +{ + /* Initialize the secure environment */ + plat_arm_security_setup(); +} + +void bl2u_platform_setup(void) +{ + arm_bl2u_platform_setup(); +} + +void arm_bl2u_early_platform_setup(meminfo_t *mem_layout, void *plat_info) +{ + /* Initialize the console to provide early debug support */ + console_init(PLAT_ARM_BOOT_UART_BASE, PLAT_ARM_BOOT_UART_CLK_IN_HZ, + ARM_CONSOLE_BAUDRATE); +} + +/******************************************************************************* + * BL1 can pass platform dependent information to BL2U in x1. + * In case of ARM CSS platforms x1 contains SCP_BL2U image info. + * In case of ARM FVP platforms x1 is not used. + * In both cases, x0 contains the extents of the memory available to BL2U + ******************************************************************************/ +void bl2u_early_platform_setup(meminfo_t *mem_layout, void *plat_info) +{ + arm_bl2u_early_platform_setup(mem_layout, plat_info); +} + +/******************************************************************************* + * Perform the very early platform specific architectural setup here. At the + * moment this is only initializes the mmu in a quick and dirty way. + * The memory that is used by BL2U is only mapped. + ******************************************************************************/ +void arm_bl2u_plat_arch_setup(void) +{ + arm_configure_mmu_el1(BL2U_RO_LIMIT, + BL31_LIMIT, + BL2U_RO_BASE, + BL2U_RO_LIMIT +#if USE_COHERENT_MEM + , + BL2U_COHERENT_RAM_BASE, + BL2U_COHERENT_RAM_LIMIT +#endif + ); +} + +void bl2u_plat_arch_setup(void) +{ + arm_bl2u_plat_arch_setup(); +} diff --git a/plat/arm/common/arm_bl31_setup.c b/plat/arm/common/arm_bl31_setup.c index 8682fd19..a7c2f7df 100644 --- a/plat/arm/common/arm_bl31_setup.c +++ b/plat/arm/common/arm_bl31_setup.c @@ -31,7 +31,6 @@ #include <arch.h> #include <arch_helpers.h> #include <arm_def.h> -#include <arm_gic.h> #include <assert.h> #include <bl_common.h> #include <cci.h> @@ -200,9 +199,9 @@ void bl31_early_platform_setup(bl31_params_t *from_bl2, ******************************************************************************/ void arm_bl31_platform_setup(void) { - /* Initialize the gic cpu and distributor interfaces */ + /* Initialize the GIC driver, cpu and distributor interfaces */ + plat_arm_gic_driver_init(); plat_arm_gic_init(); - arm_gic_setup(); #if RESET_TO_BL31 /* @@ -224,11 +223,27 @@ void arm_bl31_platform_setup(void) plat_arm_pwrc_setup(); } +/******************************************************************************* + * Perform any BL3-1 platform runtime setup prior to BL3-1 exit common to ARM + * standard platforms + ******************************************************************************/ +void arm_bl31_plat_runtime_setup(void) +{ + /* Initialize the runtime console */ + console_init(PLAT_ARM_BL31_RUN_UART_BASE, PLAT_ARM_BL31_RUN_UART_CLK_IN_HZ, + ARM_CONSOLE_BAUDRATE); +} + void bl31_platform_setup(void) { arm_bl31_platform_setup(); } +void bl31_plat_runtime_setup(void) +{ + arm_bl31_plat_runtime_setup(); +} + /******************************************************************************* * Perform the very early platform specific architectural setup here. At the * moment this is only intializes the mmu in a quick and dirty way. diff --git a/plat/arm/common/arm_common.mk b/plat/arm/common/arm_common.mk index 1290cef3..4ac12d9b 100644 --- a/plat/arm/common/arm_common.mk +++ b/plat/arm/common/arm_common.mk @@ -106,17 +106,18 @@ BL2_SOURCES += drivers/arm/tzc400/tzc400.c \ plat/arm/common/arm_security.c \ plat/common/aarch64/platform_up_stack.S +BL2U_SOURCES += drivers/arm/tzc400/tzc400.c \ + plat/arm/common/arm_bl2u_setup.c \ + plat/arm/common/arm_security.c \ + plat/common/aarch64/platform_up_stack.S + BL31_SOURCES += drivers/arm/cci/cci.c \ drivers/arm/ccn/ccn.c \ - drivers/arm/gic/arm_gic.c \ - drivers/arm/gic/gic_v2.c \ - drivers/arm/gic/gic_v3.c \ drivers/arm/tzc400/tzc400.c \ plat/arm/common/arm_bl31_setup.c \ plat/arm/common/arm_pm.c \ plat/arm/common/arm_security.c \ plat/arm/common/arm_topology.c \ - plat/common/plat_gic.c \ plat/common/aarch64/platform_mp_stack.S \ plat/common/aarch64/plat_psci_common.c @@ -127,13 +128,20 @@ ifneq (${TRUSTED_BOARD_BOOT},0) # Include common TBB sources AUTH_SOURCES := drivers/auth/auth_mod.c \ - drivers/auth/crypto_mod.c \ - drivers/auth/img_parser_mod.c \ - drivers/auth/tbbr/tbbr_cot.c \ + drivers/auth/crypto_mod.c \ + drivers/auth/img_parser_mod.c \ + drivers/auth/tbbr/tbbr_cot.c \ + + PLAT_INCLUDES += -Iinclude/bl1/tbbr + + BL1_SOURCES += ${AUTH_SOURCES} \ + bl1/tbbr/tbbr_img_desc.c \ + plat/arm/common/arm_bl1_fwu.c - BL1_SOURCES += ${AUTH_SOURCES} BL2_SOURCES += ${AUTH_SOURCES} + $(eval $(call FWU_FIP_ADD_IMG,NS_BL2U,--ns_bl2u)) + MBEDTLS_KEY_ALG := ${KEY_ALG} # We expect to locate the *.mk files under the directories specified below diff --git a/plat/arm/common/arm_gicv2.c b/plat/arm/common/arm_gicv2.c new file mode 100644 index 00000000..76f04cd0 --- /dev/null +++ b/plat/arm/common/arm_gicv2.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <gicv2.h> +#include <plat_arm.h> +#include <platform.h> +#include <platform_def.h> + +/****************************************************************************** + * The following functions are defined as weak to allow a platform to override + * the way the GICv2 driver is initialised and used. + *****************************************************************************/ +#pragma weak plat_arm_gic_driver_init +#pragma weak plat_arm_gic_init +#pragma weak plat_arm_gic_cpuif_enable +#pragma weak plat_arm_gic_cpuif_disable +#pragma weak plat_arm_gic_pcpu_init + +/****************************************************************************** + * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0 + * interrupts. + *****************************************************************************/ +const unsigned int g0_interrupt_array[] = { + PLAT_ARM_G1S_IRQS, + PLAT_ARM_G0_IRQS +}; + +/* + * Ideally `arm_gic_data` structure definition should be a `const` but it is + * kept as modifiable for overwriting with different GICD and GICC base when + * running on FVP with VE memory map. + */ +gicv2_driver_data_t arm_gic_data = { + .gicd_base = PLAT_ARM_GICD_BASE, + .gicc_base = PLAT_ARM_GICC_BASE, + .g0_interrupt_num = ARRAY_SIZE(g0_interrupt_array), + .g0_interrupt_array = g0_interrupt_array, +}; + +/****************************************************************************** + * ARM common helper to initialize the GICv2 only driver. + *****************************************************************************/ +void plat_arm_gic_driver_init(void) +{ + gicv2_driver_init(&arm_gic_data); +} + +void plat_arm_gic_init(void) +{ + gicv2_distif_init(); + gicv2_pcpu_distif_init(); + gicv2_cpuif_enable(); +} + +/****************************************************************************** + * ARM common helper to enable the GICv2 CPU interface + *****************************************************************************/ +void plat_arm_gic_cpuif_enable(void) +{ + gicv2_cpuif_enable(); +} + +/****************************************************************************** + * ARM common helper to disable the GICv2 CPU interface + *****************************************************************************/ +void plat_arm_gic_cpuif_disable(void) +{ + gicv2_cpuif_disable(); +} + +/****************************************************************************** + * ARM common helper to initialize the per cpu distributor interface in GICv2 + *****************************************************************************/ +void plat_arm_gic_pcpu_init(void) +{ + gicv2_pcpu_distif_init(); +} diff --git a/plat/arm/common/arm_gicv3.c b/plat/arm/common/arm_gicv3.c new file mode 100644 index 00000000..33f80183 --- /dev/null +++ b/plat/arm/common/arm_gicv3.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arm_def.h> +#include <gicv3.h> +#include <plat_arm.h> +#include <platform.h> +#include <platform_def.h> + +/****************************************************************************** + * The following functions are defined as weak to allow a platform to override + * the way the GICv3 driver is initialised and used. + *****************************************************************************/ +#pragma weak plat_arm_gic_driver_init +#pragma weak plat_arm_gic_init +#pragma weak plat_arm_gic_cpuif_enable +#pragma weak plat_arm_gic_cpuif_disable +#pragma weak plat_arm_gic_pcpu_init + +/* The GICv3 driver only needs to be initialized in EL3 */ +uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT]; + +/* Array of Group1 secure interrupts to be configured by the gic driver */ +const unsigned int g1s_interrupt_array[] = { + PLAT_ARM_G1S_IRQS +}; + +/* Array of Group0 interrupts to be configured by the gic driver */ +const unsigned int g0_interrupt_array[] = { + PLAT_ARM_G0_IRQS +}; + +const gicv3_driver_data_t arm_gic_data = { + .gicd_base = PLAT_ARM_GICD_BASE, + .gicr_base = PLAT_ARM_GICR_BASE, + .g0_interrupt_num = ARRAY_SIZE(g0_interrupt_array), + .g1s_interrupt_num = ARRAY_SIZE(g1s_interrupt_array), + .g0_interrupt_array = g0_interrupt_array, + .g1s_interrupt_array = g1s_interrupt_array, + .rdistif_num = PLATFORM_CORE_COUNT, + .rdistif_base_addrs = rdistif_base_addrs, + .mpidr_to_core_pos = plat_arm_calc_core_pos +}; + +void plat_arm_gic_driver_init(void) +{ + /* + * The GICv3 driver is initialized in EL3 and does not need + * to be initialized again in SEL1. This is because the S-EL1 + * can use GIC system registers to manage interrupts and does + * not need GIC interface base addresses to be configured. + */ +#if IMAGE_BL31 + gicv3_driver_init(&arm_gic_data); +#endif +} + +/****************************************************************************** + * ARM common helper to initialize the GIC. Only invoked by BL31 + *****************************************************************************/ +void plat_arm_gic_init(void) +{ + gicv3_distif_init(); + gicv3_rdistif_init(plat_my_core_pos()); + gicv3_cpuif_enable(plat_my_core_pos()); +} + +/****************************************************************************** + * ARM common helper to enable the GIC CPU interface + *****************************************************************************/ +void plat_arm_gic_cpuif_enable(void) +{ + gicv3_cpuif_enable(plat_my_core_pos()); +} + +/****************************************************************************** + * ARM common helper to disable the GIC CPU interface + *****************************************************************************/ +void plat_arm_gic_cpuif_disable(void) +{ + gicv3_cpuif_disable(plat_my_core_pos()); +} + +/****************************************************************************** + * ARM common helper to initialize the per-cpu redistributor interface in GICv3 + *****************************************************************************/ +void plat_arm_gic_pcpu_init(void) +{ + gicv3_rdistif_init(plat_my_core_pos()); +} diff --git a/plat/arm/common/arm_gicv3_legacy.c b/plat/arm/common/arm_gicv3_legacy.c new file mode 100644 index 00000000..61709334 --- /dev/null +++ b/plat/arm/common/arm_gicv3_legacy.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arm_def.h> +#include <arm_gic.h> +#include <plat_arm.h> +#include <platform.h> +#include <platform_def.h> + +/****************************************************************************** + * The following function is defined as weak to allow a platform to override + * the way the Legacy GICv3 driver is initialised and used. + *****************************************************************************/ +#pragma weak plat_arm_gic_driver_init +#pragma weak plat_arm_gic_init +#pragma weak plat_arm_gic_cpuif_enable +#pragma weak plat_arm_gic_cpuif_disable +#pragma weak plat_arm_gic_pcpu_init + +/* + * In the GICv3 Legacy mode, the Group 1 secure interrupts are treated as Group + * 0 interrupts. + */ +const unsigned int irq_sec_array[] = { + PLAT_ARM_G0_IRQS, + PLAT_ARM_G1S_IRQS +}; + +void plat_arm_gic_driver_init(void) +{ + arm_gic_init(PLAT_ARM_GICC_BASE, + PLAT_ARM_GICD_BASE, + PLAT_ARM_GICR_BASE, + irq_sec_array, + ARRAY_SIZE(irq_sec_array)); +} + +/****************************************************************************** + * ARM common helper to initialize the GIC. + *****************************************************************************/ +void plat_arm_gic_init(void) +{ + arm_gic_setup(); +} + +/****************************************************************************** + * ARM common helper to enable the GIC CPU interface + *****************************************************************************/ +void plat_arm_gic_cpuif_enable(void) +{ + arm_gic_cpuif_setup(); +} + +/****************************************************************************** + * ARM common helper to disable the GIC CPU interface + *****************************************************************************/ +void plat_arm_gic_cpuif_disable(void) +{ + arm_gic_cpuif_deactivate(); +} + +/****************************************************************************** + * ARM common helper to initialize the per-cpu distributor in GICv2 or + * redistributor interface in GICv3. + *****************************************************************************/ +void plat_arm_gic_pcpu_init(void) +{ + arm_gic_pcpu_distif_setup(); +} diff --git a/plat/arm/common/arm_io_storage.c b/plat/arm/common/arm_io_storage.c index ae67cde0..f7e99e9c 100644 --- a/plat/arm/common/arm_io_storage.c +++ b/plat/arm/common/arm_io_storage.c @@ -308,3 +308,17 @@ int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle, return result; } + +/* + * See if a Firmware Image Package is available, + * by checking if TOC is valid or not. + */ +int arm_io_is_toc_valid(void) +{ + int result; + + result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID); + + return (result == 0); +} + diff --git a/plat/arm/common/arm_pm.c b/plat/arm/common/arm_pm.c index cae65970..2ddc5833 100644 --- a/plat/arm/common/arm_pm.c +++ b/plat/arm/common/arm_pm.c @@ -158,15 +158,19 @@ int arm_validate_ns_entrypoint(uintptr_t entrypoint) *****************************************************************************/ void arm_system_pwr_domain_resume(void) { - console_init(PLAT_ARM_BOOT_UART_BASE, PLAT_ARM_BOOT_UART_CLK_IN_HZ, + console_init(PLAT_ARM_BL31_RUN_UART_BASE, PLAT_ARM_BL31_RUN_UART_CLK_IN_HZ, ARM_CONSOLE_BAUDRATE); /* Assert system power domain is available on the platform */ assert(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL2); - arm_gic_setup(); + /* + * TODO: On GICv3 systems, figure out whether the core that wakes up + * first from system suspend need to initialize the re-distributor + * interface of all the other suspended cores. + */ + plat_arm_gic_init(); plat_arm_security_setup(); - arm_configure_sys_timer(); } diff --git a/plat/arm/common/tsp/arm_tsp.mk b/plat/arm/common/tsp/arm_tsp.mk index f285f585..691a2ab6 100644 --- a/plat/arm/common/tsp/arm_tsp.mk +++ b/plat/arm/common/tsp/arm_tsp.mk @@ -29,9 +29,6 @@ # # TSP source files common to ARM standard platforms -BL32_SOURCES += drivers/arm/gic/arm_gic.c \ - drivers/arm/gic/gic_v2.c \ - plat/arm/common/arm_topology.c \ +BL32_SOURCES += plat/arm/common/arm_topology.c \ plat/arm/common/tsp/arm_tsp_setup.c \ - plat/common/aarch64/platform_mp_stack.S \ - plat/common/plat_gic.c + plat/common/aarch64/platform_mp_stack.S diff --git a/plat/arm/common/tsp/arm_tsp_setup.c b/plat/arm/common/tsp/arm_tsp_setup.c index 78db1605..3631c033 100644 --- a/plat/arm/common/tsp/arm_tsp_setup.c +++ b/plat/arm/common/tsp/arm_tsp_setup.c @@ -89,7 +89,7 @@ void tsp_early_platform_setup(void) ******************************************************************************/ void tsp_platform_setup(void) { - plat_arm_gic_init(); + plat_arm_gic_driver_init(); } /******************************************************************************* diff --git a/plat/arm/css/common/css_common.c b/plat/arm/css/common/css_bl1_setup.c index 91813f2c..2abed3b9 100644 --- a/plat/arm/css/common/css_common.c +++ b/plat/arm/css/common/css_bl1_setup.c @@ -28,37 +28,18 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include <arm_gic.h> #include <bl_common.h> -#include <platform_def.h> +#include <debug.h> +#include <plat_arm.h> +#include <soc_css.h> - -#if IMAGE_BL31 || IMAGE_BL32 - -const unsigned int irq_sec_array[] = { - PLAT_CSS_IRQ_SEC_LIST, - ARM_IRQ_SEC_PHY_TIMER, - ARM_IRQ_SEC_SGI_0, - ARM_IRQ_SEC_SGI_1, - ARM_IRQ_SEC_SGI_2, - ARM_IRQ_SEC_SGI_3, - ARM_IRQ_SEC_SGI_4, - ARM_IRQ_SEC_SGI_5, - ARM_IRQ_SEC_SGI_6, - ARM_IRQ_SEC_SGI_7 -}; - - -/* Weak definitions may be overridden in specific CSS based platform */ -#pragma weak plat_arm_gic_init - -void plat_arm_gic_init(void) +void bl1_platform_setup(void) { - arm_gic_init(PLAT_CSS_GICC_BASE, - PLAT_CSS_GICD_BASE, - PLAT_CSS_GICR_BASE, - irq_sec_array, - ARRAY_SIZE(irq_sec_array)); + arm_bl1_platform_setup(); + /* + * Do ARM CSS SoC security setup. + * BL1 needs to enable normal world access to memory. + */ + soc_css_security_setup(); } -#endif /* IMAGE_BL31 || IMAGE_BL32 */ diff --git a/plat/arm/css/common/css_bl2u_setup.c b/plat/arm/css/common/css_bl2u_setup.c new file mode 100644 index 00000000..878b6faf --- /dev/null +++ b/plat/arm/css/common/css_bl2u_setup.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <bl_common.h> +#include <debug.h> +#include <plat_arm.h> +#include "css_scp_bootloader.h" + +/* Weak definition may be overridden in specific CSS based platform */ +#pragma weak bl2u_plat_handle_scp_bl2u + +/* Data structure which holds the SCP_BL2U image info for BL2U */ +static image_info_t scp_bl2u_image_info; + +/******************************************************************************* + * BL1 can pass platform dependent information to BL2U in x1. + * In case of ARM CSS platforms x1 contains SCP_BL2U image info. + * In case of ARM FVP platforms x1 is not used. + * In both cases, x0 contains the extents of the memory available to BL2U + ******************************************************************************/ +void bl2u_early_platform_setup(meminfo_t *mem_layout, void *plat_info) +{ + if (!plat_info) + panic(); + + arm_bl2u_early_platform_setup(mem_layout, plat_info); + + scp_bl2u_image_info = *(image_info_t *)plat_info; +} + +/******************************************************************************* + * Transfer SCP_BL2U from Trusted RAM using the SCP Download protocol. + ******************************************************************************/ +int bl2u_plat_handle_scp_bl2u(void) +{ + int ret; + + INFO("BL2U: Initiating SCP_BL2U transfer to SCP\n"); + + ret = scp_bootloader_transfer((void *)scp_bl2u_image_info.image_base, + scp_bl2u_image_info.image_size); + + if (ret == 0) + INFO("BL2U: SCP_BL2U transferred to SCP\n"); + else + ERROR("BL2U: SCP_BL2U transfer failure\n"); + + return ret; +} diff --git a/plat/arm/css/common/css_common.mk b/plat/arm/css/common/css_common.mk index 6b05869e..49fedc3a 100644 --- a/plat/arm/css/common/css_common.mk +++ b/plat/arm/css/common/css_common.mk @@ -32,21 +32,28 @@ PLAT_INCLUDES += -Iinclude/plat/arm/css/common \ -Iinclude/plat/arm/css/common/aarch64 -PLAT_BL_COMMON_SOURCES += plat/arm/css/common/aarch64/css_helpers.S \ - plat/arm/css/common/css_common.c +PLAT_BL_COMMON_SOURCES += plat/arm/css/common/aarch64/css_helpers.S -#BL1_SOURCES += +BL1_SOURCES += plat/arm/css/common/css_bl1_setup.c BL2_SOURCES += plat/arm/css/common/css_bl2_setup.c \ plat/arm/css/common/css_mhu.c \ plat/arm/css/common/css_scp_bootloader.c \ plat/arm/css/common/css_scpi.c +BL2U_SOURCES += plat/arm/css/common/css_bl2u_setup.c \ + plat/arm/css/common/css_mhu.c \ + plat/arm/css/common/css_scp_bootloader.c \ + plat/arm/css/common/css_scpi.c + BL31_SOURCES += plat/arm/css/common/css_mhu.c \ plat/arm/css/common/css_pm.c \ plat/arm/css/common/css_scpi.c \ plat/arm/css/common/css_topology.c +ifneq (${TRUSTED_BOARD_BOOT},0) +$(eval $(call FWU_FIP_ADD_IMG,SCP_BL2U,--scp_bl2u)) +endif ifneq (${RESET_TO_BL31},0) $(error "Using BL3-1 as the reset vector is not supported on CSS platforms. \ diff --git a/plat/arm/css/common/css_pm.c b/plat/arm/css/common/css_pm.c index 3f468570..6d6646e0 100644 --- a/plat/arm/css/common/css_pm.c +++ b/plat/arm/css/common/css_pm.c @@ -30,7 +30,6 @@ #include <arch_helpers.h> #include <assert.h> -#include <arm_gic.h> #include <cassert.h> #include <cci.h> #include <css_pm.h> @@ -41,6 +40,12 @@ #include <platform_def.h> #include "css_scpi.h" +/* Macros to read the CSS power domain state */ +#define CSS_CORE_PWR_STATE(state) (state)->pwr_domain_state[ARM_PWR_LVL0] +#define CSS_CLUSTER_PWR_STATE(state) (state)->pwr_domain_state[ARM_PWR_LVL1] +#define CSS_SYSTEM_PWR_STATE(state) ((PLAT_MAX_PWR_LVL > ARM_PWR_LVL1) ?\ + (state)->pwr_domain_state[ARM_PWR_LVL2] : 0) + /* Allow CSS platforms to override `plat_arm_psci_pm_ops` */ #pragma weak plat_arm_psci_pm_ops @@ -93,51 +98,39 @@ int css_pwr_domain_on(u_register_t mpidr) return PSCI_E_SUCCESS; } -/******************************************************************************* - * Handler called when a power level has just been powered on after - * being turned off earlier. The target_state encodes the low power state that - * each level has woken up from. - ******************************************************************************/ -void css_pwr_domain_on_finish(const psci_power_state_t *target_state) +static void css_pwr_domain_on_finisher_common( + const psci_power_state_t *target_state) { - assert(target_state->pwr_domain_state[ARM_PWR_LVL0] == - ARM_LOCAL_STATE_OFF); - - if (PLAT_MAX_PWR_LVL > ARM_PWR_LVL1) { - /* - * Perform system initialization if woken up from system - * suspend. - */ - if (target_state->pwr_domain_state[ARM_PWR_LVL2] == - ARM_LOCAL_STATE_OFF) - arm_system_pwr_domain_resume(); - } + assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF); /* * Perform the common cluster specific operations i.e enable coherency * if this cluster was off. */ - if (target_state->pwr_domain_state[ARM_PWR_LVL1] == - ARM_LOCAL_STATE_OFF) + if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF) cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1())); +} + +/******************************************************************************* + * Handler called when a power level has just been powered on after + * being turned off earlier. The target_state encodes the low power state that + * each level has woken up from. This handler would never be invoked with + * the system power domain uninitialized as either the primary would have taken + * care of it as part of cold boot or the first core awakened from system + * suspend would have already initialized it. + ******************************************************************************/ +void css_pwr_domain_on_finish(const psci_power_state_t *target_state) +{ + /* Assert that the system power domain need not be initialized */ + assert(CSS_SYSTEM_PWR_STATE(target_state) == ARM_LOCAL_STATE_RUN); + css_pwr_domain_on_finisher_common(target_state); - if (PLAT_MAX_PWR_LVL > ARM_PWR_LVL1) { - /* - * Skip GIC CPU interface and per-CPU Distributor interface - * setups if woken up from system suspend as it is done as - * part of css_system_pwr_domain_resume(). - */ - if (target_state->pwr_domain_state[ARM_PWR_LVL2] == - ARM_LOCAL_STATE_OFF) - return; - } + /* Program the gic per-cpu distributor or re-distributor interface */ + plat_arm_gic_pcpu_init(); /* Enable the gic cpu interface */ - arm_gic_cpuif_setup(); - - /* todo: Is this setup only needed after a cold boot? */ - arm_gic_pcpu_distif_setup(); + plat_arm_gic_cpuif_enable(); } /******************************************************************************* @@ -152,21 +145,14 @@ static void css_power_down_common(const psci_power_state_t *target_state) uint32_t system_state = scpi_power_on; /* Prevent interrupts from spuriously waking up this cpu */ - arm_gic_cpuif_deactivate(); - - if (PLAT_MAX_PWR_LVL > ARM_PWR_LVL1) { - /* - * Check if power down at system power domain level is - * requested. - */ - if (target_state->pwr_domain_state[ARM_PWR_LVL2] == - ARM_LOCAL_STATE_OFF) + plat_arm_gic_cpuif_disable(); + + /* Check if power down at system power domain level is requested */ + if (CSS_SYSTEM_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF) system_state = scpi_power_retention; - } /* Cluster is to be turned off, so disable coherency */ - if (target_state->pwr_domain_state[ARM_PWR_LVL1] == - ARM_LOCAL_STATE_OFF) { + if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF) { cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr())); cluster_state = scpi_power_off; } @@ -187,9 +173,7 @@ static void css_power_down_common(const psci_power_state_t *target_state) ******************************************************************************/ void css_pwr_domain_off(const psci_power_state_t *target_state) { - assert(target_state->pwr_domain_state[ARM_PWR_LVL0] == - ARM_LOCAL_STATE_OFF); - + assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF); css_power_down_common(target_state); } @@ -200,16 +184,13 @@ void css_pwr_domain_off(const psci_power_state_t *target_state) void css_pwr_domain_suspend(const psci_power_state_t *target_state) { /* - * Juno has retention only at cpu level. Just return + * CSS currently supports retention only at cpu level. Just return * as nothing is to be done for retention. */ - if (target_state->pwr_domain_state[ARM_PWR_LVL0] == - ARM_LOCAL_STATE_RET) + if (CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_RET) return; - assert(target_state->pwr_domain_state[ARM_PWR_LVL0] == - ARM_LOCAL_STATE_OFF); - + assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF); css_power_down_common(target_state); } @@ -223,14 +204,18 @@ void css_pwr_domain_suspend(const psci_power_state_t *target_state) void css_pwr_domain_suspend_finish( const psci_power_state_t *target_state) { - /* - * Return as nothing is to be done on waking up from retention. - */ - if (target_state->pwr_domain_state[ARM_PWR_LVL0] == - ARM_LOCAL_STATE_RET) + /* Return as nothing is to be done on waking up from retention. */ + if (CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_RET) return; - css_pwr_domain_on_finish(target_state); + /* Perform system domain restore if woken up from system suspend */ + if (CSS_SYSTEM_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF) + arm_system_pwr_domain_resume(); + else + /* Enable the gic cpu interface */ + plat_arm_gic_cpuif_enable(); + + css_pwr_domain_on_finisher_common(target_state); } /******************************************************************************* diff --git a/plat/arm/soc/common/soc_css.mk b/plat/arm/soc/common/soc_css.mk index d8a99a8c..7ae8fdb7 100644 --- a/plat/arm/soc/common/soc_css.mk +++ b/plat/arm/soc/common/soc_css.mk @@ -32,9 +32,10 @@ PLAT_INCLUDES += -Iinclude/plat/arm/soc/common/ #PLAT_BL_COMMON_SOURCES += - -#BL1_SOURCES += +BL1_SOURCES += plat/arm/soc/common/soc_css_security.c BL2_SOURCES += plat/arm/soc/common/soc_css_security.c +BL2U_SOURCES += plat/arm/soc/common/soc_css_security.c + BL31_SOURCES += plat/arm/soc/common/soc_css_security.c diff --git a/plat/common/aarch64/plat_common.c b/plat/common/aarch64/plat_common.c index a6a84765..9070c613 100644 --- a/plat/common/aarch64/plat_common.c +++ b/plat/common/aarch64/plat_common.c @@ -28,16 +28,18 @@ * POSSIBILITY OF SUCH DAMAGE. */ #include <assert.h> +#include <console.h> #include <platform.h> #include <xlat_tables.h> /* - * The following 2 platform setup functions are weakly defined. They + * The following platform setup functions are weakly defined. They * provide typical implementations that may be re-used by multiple * platforms but may also be overridden by a platform if required. */ #pragma weak bl31_plat_enable_mmu #pragma weak bl32_plat_enable_mmu +#pragma weak bl31_plat_runtime_setup void bl31_plat_enable_mmu(uint32_t flags) { @@ -49,6 +51,15 @@ void bl32_plat_enable_mmu(uint32_t flags) enable_mmu_el1(flags); } +void bl31_plat_runtime_setup(void) +{ + /* + * Finish the use of console driver in BL31 so that any runtime logs + * from BL31 will be suppressed. + */ + console_uninit(); +} + #if !ENABLE_PLAT_COMPAT /* * Helper function for platform_get_pos() when platform compatibility is diff --git a/plat/common/plat_bl1_common.c b/plat/common/plat_bl1_common.c new file mode 100644 index 00000000..aee9440a --- /dev/null +++ b/plat/common/plat_bl1_common.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arch_helpers.h> +#include <assert.h> +#include <bl_common.h> +#include <debug.h> +#include <errno.h> +#include <platform_def.h> + +/* + * The following platform functions are weakly defined. They + * are default implementations that allow BL1 to compile in + * absence of real definitions. The Platforms may override + * with more complex definitions. + */ +#pragma weak bl1_plat_get_next_image_id +#pragma weak bl1_plat_set_ep_info +#pragma weak bl1_plat_get_image_desc +#pragma weak bl1_plat_fwu_done + + +unsigned int bl1_plat_get_next_image_id(void) +{ + /* BL2 load will be done by default. */ + return BL2_IMAGE_ID; +} + +void bl1_plat_set_ep_info(unsigned int image_id, + entry_point_info_t *ep_info) +{ + +} + +/* + * Following is the default definition that always + * returns BL2 image details. + */ +image_desc_t *bl1_plat_get_image_desc(unsigned int image_id) +{ + static image_desc_t bl2_img_desc = BL2_IMAGE_DESC; + return &bl2_img_desc; +} + +__dead2 void bl1_plat_fwu_done(void *cookie, void *rsvd_ptr) +{ + while (1) + wfi(); +} + +/* + * The Platforms must override with real definition. + */ +#pragma weak bl1_plat_mem_check + +int bl1_plat_mem_check(uintptr_t mem_base, unsigned int mem_size, + unsigned int flags) +{ + assert(0); + return -ENOMEM; +} diff --git a/plat/common/plat_gicv2.c b/plat/common/plat_gicv2.c new file mode 100644 index 00000000..65f89dc6 --- /dev/null +++ b/plat/common/plat_gicv2.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include <assert.h> +#include <gic_common.h> +#include <gicv2.h> +#include <interrupt_mgmt.h> + +/* + * The following platform GIC functions are weakly defined. They + * provide typical implementations that may be re-used by multiple + * platforms but may also be overridden by a platform if required. + */ +#pragma weak plat_ic_get_pending_interrupt_id +#pragma weak plat_ic_get_pending_interrupt_type +#pragma weak plat_ic_acknowledge_interrupt +#pragma weak plat_ic_get_interrupt_type +#pragma weak plat_ic_end_of_interrupt +#pragma weak plat_interrupt_type_to_line + +/* + * This function returns the highest priority pending interrupt at + * the Interrupt controller + */ +uint32_t plat_ic_get_pending_interrupt_id(void) +{ + unsigned int id; + + id = gicv2_get_pending_interrupt_id(); + if (id == GIC_SPURIOUS_INTERRUPT) + return INTR_ID_UNAVAILABLE; + + return id; +} + +/* + * This function returns the type of the highest priority pending interrupt + * at the Interrupt controller. In the case of GICv2, the Highest Priority + * Pending interrupt register (`GICC_HPPIR`) is read to determine the id of + * the pending interrupt. The type of interrupt depends upon the id value + * as follows. + * 1. id < PENDING_G1_INTID (1022) is reported as a S-EL1 interrupt + * 2. id = PENDING_G1_INTID (1022) is reported as a Non-secure interrupt. + * 3. id = GIC_SPURIOUS_INTERRUPT (1023) is reported as an invalid interrupt + * type. + */ +uint32_t plat_ic_get_pending_interrupt_type(void) +{ + unsigned int id; + + id = gicv2_get_pending_interrupt_type(); + + /* Assume that all secure interrupts are S-EL1 interrupts */ + if (id < PENDING_G1_INTID) + return INTR_TYPE_S_EL1; + + if (id == GIC_SPURIOUS_INTERRUPT) + return INTR_TYPE_INVAL; + + return INTR_TYPE_NS; +} + +/* + * This function returns the highest priority pending interrupt at + * the Interrupt controller and indicates to the Interrupt controller + * that the interrupt processing has started. + */ +uint32_t plat_ic_acknowledge_interrupt(void) +{ + return gicv2_acknowledge_interrupt(); +} + +/* + * This function returns the type of the interrupt `id`, depending on how + * the interrupt has been configured in the interrupt controller + */ +uint32_t plat_ic_get_interrupt_type(uint32_t id) +{ + unsigned int type; + + type = gicv2_get_interrupt_group(id); + + /* Assume that all secure interrupts are S-EL1 interrupts */ + return (type) ? INTR_TYPE_NS : INTR_TYPE_S_EL1; +} + +/* + * This functions is used to indicate to the interrupt controller that + * the processing of the interrupt corresponding to the `id` has + * finished. + */ +void plat_ic_end_of_interrupt(uint32_t id) +{ + gicv2_end_of_interrupt(id); +} + +/* + * An ARM processor signals interrupt exceptions through the IRQ and FIQ pins. + * The interrupt controller knows which pin/line it uses to signal a type of + * interrupt. It lets the interrupt management framework determine + * for a type of interrupt and security state, which line should be used in the + * SCR_EL3 to control its routing to EL3. The interrupt line is represented + * as the bit position of the IRQ or FIQ bit in the SCR_EL3. + */ +uint32_t plat_interrupt_type_to_line(uint32_t type, + uint32_t security_state) +{ + assert(type == INTR_TYPE_S_EL1 || + type == INTR_TYPE_EL3 || + type == INTR_TYPE_NS); + + /* Non-secure interrupts are signaled on the IRQ line always */ + if (type == INTR_TYPE_NS) + return __builtin_ctz(SCR_IRQ_BIT); + + /* + * Secure interrupts are signaled using the IRQ line if the FIQ is + * not enabled else they are signaled using the FIQ line. + */ + return ((gicv2_is_fiq_enabled()) ? __builtin_ctz(SCR_FIQ_BIT) : + __builtin_ctz(SCR_IRQ_BIT)); +} diff --git a/plat/common/plat_gicv3.c b/plat/common/plat_gicv3.c new file mode 100644 index 00000000..249caf8e --- /dev/null +++ b/plat/common/plat_gicv3.c @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include <arch_helpers.h> +#include <assert.h> +#include <bl_common.h> +#include <cassert.h> +#include <gic_common.h> +#include <gicv3.h> +#include <interrupt_mgmt.h> +#include <platform.h> + +#if IMAGE_BL31 + +/* + * The following platform GIC functions are weakly defined. They + * provide typical implementations that may be re-used by multiple + * platforms but may also be overridden by a platform if required. + */ +#pragma weak plat_ic_get_pending_interrupt_id +#pragma weak plat_ic_get_pending_interrupt_type +#pragma weak plat_ic_acknowledge_interrupt +#pragma weak plat_ic_get_interrupt_type +#pragma weak plat_ic_end_of_interrupt +#pragma weak plat_interrupt_type_to_line + +CASSERT((INTR_TYPE_S_EL1 == INTR_GROUP1S) && + (INTR_TYPE_NS == INTR_GROUP1NS) && + (INTR_TYPE_EL3 == INTR_GROUP0), assert_interrupt_type_mismatch); + +/* + * This function returns the highest priority pending interrupt at + * the Interrupt controller + */ +uint32_t plat_ic_get_pending_interrupt_id(void) +{ + unsigned int irqnr; + + assert(IS_IN_EL3()); + irqnr = gicv3_get_pending_interrupt_id(); + return (gicv3_is_intr_id_special_identifier(irqnr)) ? + INTR_ID_UNAVAILABLE : irqnr; +} + +/* + * This function returns the type of the highest priority pending interrupt + * at the Interrupt controller. In the case of GICv3, the Highest Priority + * Pending interrupt system register (`ICC_HPPIR0_EL1`) is read to determine + * the id of the pending interrupt. The type of interrupt depends upon the + * id value as follows. + * 1. id = PENDING_G1S_INTID (1020) is reported as a S-EL1 interrupt + * 2. id = PENDING_G1NS_INTID (1021) is reported as a Non-secure interrupt. + * 3. id = GIC_SPURIOUS_INTERRUPT (1023) is reported as an invalid interrupt + * type. + * 4. All other interrupt id's are reported as EL3 interrupt. + */ +uint32_t plat_ic_get_pending_interrupt_type(void) +{ + unsigned int irqnr; + + assert(IS_IN_EL3()); + irqnr = gicv3_get_pending_interrupt_type(); + + switch (irqnr) { + case PENDING_G1S_INTID: + return INTR_TYPE_S_EL1; + case PENDING_G1NS_INTID: + return INTR_TYPE_NS; + case GIC_SPURIOUS_INTERRUPT: + return INTR_TYPE_INVAL; + default: + return INTR_TYPE_EL3; + } +} + +/* + * This function returns the highest priority pending interrupt at + * the Interrupt controller and indicates to the Interrupt controller + * that the interrupt processing has started. + */ +uint32_t plat_ic_acknowledge_interrupt(void) +{ + assert(IS_IN_EL3()); + return gicv3_acknowledge_interrupt(); +} + +/* + * This function returns the type of the interrupt `id`, depending on how + * the interrupt has been configured in the interrupt controller + */ +uint32_t plat_ic_get_interrupt_type(uint32_t id) +{ + assert(IS_IN_EL3()); + return gicv3_get_interrupt_type(id, plat_my_core_pos()); +} + +/* + * This functions is used to indicate to the interrupt controller that + * the processing of the interrupt corresponding to the `id` has + * finished. + */ +void plat_ic_end_of_interrupt(uint32_t id) +{ + assert(IS_IN_EL3()); + gicv3_end_of_interrupt(id); +} + +/* + * An ARM processor signals interrupt exceptions through the IRQ and FIQ pins. + * The interrupt controller knows which pin/line it uses to signal a type of + * interrupt. It lets the interrupt management framework determine for a type of + * interrupt and security state, which line should be used in the SCR_EL3 to + * control its routing to EL3. The interrupt line is represented as the bit + * position of the IRQ or FIQ bit in the SCR_EL3. + */ +uint32_t plat_interrupt_type_to_line(uint32_t type, + uint32_t security_state) +{ + assert(type == INTR_TYPE_S_EL1 || + type == INTR_TYPE_EL3 || + type == INTR_TYPE_NS); + + assert(sec_state_is_valid(security_state)); + assert(IS_IN_EL3()); + + switch (type) { + case INTR_TYPE_S_EL1: + /* + * The S-EL1 interrupts are signaled as IRQ in S-EL0/1 contexts + * and as FIQ in the NS-EL0/1/2 contexts + */ + if (security_state == SECURE) + return __builtin_ctz(SCR_IRQ_BIT); + else + return __builtin_ctz(SCR_FIQ_BIT); + case INTR_TYPE_NS: + /* + * The Non secure interrupts will be signaled as FIQ in S-EL0/1 + * contexts and as IRQ in the NS-EL0/1/2 contexts. + */ + if (security_state == SECURE) + return __builtin_ctz(SCR_FIQ_BIT); + else + return __builtin_ctz(SCR_IRQ_BIT); + default: + assert(0); + /* Fall through in the release build */ + case INTR_TYPE_EL3: + /* + * The EL3 interrupts are signaled as FIQ in both S-EL0/1 and + * NS-EL0/1/2 contexts + */ + return __builtin_ctz(SCR_FIQ_BIT); + } +} +#endif +#if IMAGE_BL32 + +#pragma weak plat_ic_get_pending_interrupt_id +#pragma weak plat_ic_acknowledge_interrupt +#pragma weak plat_ic_end_of_interrupt + +/* + * This function returns the highest priority pending interrupt at + * the Interrupt controller + */ +uint32_t plat_ic_get_pending_interrupt_id(void) +{ + unsigned int irqnr; + + assert(IS_IN_EL1()); + irqnr = gicv3_get_pending_interrupt_id_sel1(); + return (irqnr == GIC_SPURIOUS_INTERRUPT) ? + INTR_ID_UNAVAILABLE : irqnr; +} + +/* + * This function returns the highest priority pending interrupt at + * the Interrupt controller and indicates to the Interrupt controller + * that the interrupt processing has started. + */ +uint32_t plat_ic_acknowledge_interrupt(void) +{ + assert(IS_IN_EL1()); + return gicv3_acknowledge_interrupt_sel1(); +} + +/* + * This functions is used to indicate to the interrupt controller that + * the processing of the interrupt corresponding to the `id` has + * finished. + */ +void plat_ic_end_of_interrupt(uint32_t id) +{ + assert(IS_IN_EL1()); + gicv3_end_of_interrupt_sel1(id); +} +#endif diff --git a/plat/nvidia/tegra/common/aarch64/tegra_helpers.S b/plat/nvidia/tegra/common/aarch64/tegra_helpers.S index d9f287c9..a4caf5ef 100644 --- a/plat/nvidia/tegra/common/aarch64/tegra_helpers.S +++ b/plat/nvidia/tegra/common/aarch64/tegra_helpers.S @@ -36,9 +36,9 @@ #include <tegra_def.h> /* Global functions */ - .globl platform_is_primary_cpu - .globl platform_get_core_pos - .globl platform_get_entrypoint + .globl plat_is_my_cpu_primary + .globl plat_my_core_pos + .globl plat_get_my_entrypoint .globl plat_secondary_cold_boot_setup .globl platform_mem_init .globl plat_crash_console_init @@ -47,7 +47,7 @@ .globl plat_reset_handler /* Global variables */ - .globl sec_entry_point + .globl tegra_sec_entry_point .globl ns_image_entrypoint .globl tegra_bl31_phys_base @@ -115,28 +115,47 @@ .endm /* ----------------------------------------------------- - * int platform_is_primary_cpu(int mpidr); + * unsigned int plat_is_my_cpu_primary(void); * * This function checks if this is the Primary CPU * ----------------------------------------------------- */ -func platform_is_primary_cpu +func plat_is_my_cpu_primary + mrs x0, mpidr_el1 and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK) cmp x0, #TEGRA_PRIMARY_CPU cset x0, eq ret -endfunc platform_is_primary_cpu +endfunc plat_is_my_cpu_primary /* ----------------------------------------------------- - * int platform_get_core_pos(int mpidr); + * unsigned int plat_my_core_pos(void); + * + * result: CorePos = CoreId + (ClusterId << 2) + * ----------------------------------------------------- + */ +func plat_my_core_pos + mrs x0, mpidr_el1 + and x1, x0, #MPIDR_CPU_MASK + and x0, x0, #MPIDR_CLUSTER_MASK + add x0, x1, x0, LSR #6 + ret +endfunc plat_my_core_pos + + /* ----------------------------------------------------- + * unsigned long plat_get_my_entrypoint (void); + * + * Main job of this routine is to distinguish between + * a cold and warm boot. If the tegra_sec_entry_point for + * this CPU is present, then it's a warm boot. * - * With this function: CorePos = CoreId * ----------------------------------------------------- */ -func platform_get_core_pos - and x0, x0, #MPIDR_CPU_MASK +func plat_get_my_entrypoint + adr x1, tegra_sec_entry_point + ldr x0, [x1] ret -endfunc platform_get_core_pos +endfunc plat_get_my_entrypoint /* ----------------------------------------------------- * void plat_secondary_cold_boot_setup (void); @@ -151,22 +170,6 @@ func plat_secondary_cold_boot_setup ret endfunc plat_secondary_cold_boot_setup - /* ----------------------------------------------------- - * void platform_get_entrypoint (unsigned int mpidr); - * - * Main job of this routine is to distinguish between - * a cold and warm boot. If the sec_entry_point for - * this CPU is present, then it's a warm boot. - * - * ----------------------------------------------------- - */ -func platform_get_entrypoint - and x0, x0, #MPIDR_CPU_MASK - adr x1, sec_entry_point - ldr x0, [x1, x0, lsl #3] - ret -endfunc platform_get_entrypoint - /* -------------------------------------------------------- * void platform_mem_init (void); * @@ -336,8 +339,7 @@ restore_oslock: * Get secure world's entry point and jump to it * -------------------------------------------------- */ - mrs x0, mpidr_el1 - bl platform_get_entrypoint + bl plat_get_my_entrypoint br x0 endfunc tegra_secure_entrypoint @@ -345,13 +347,11 @@ endfunc tegra_secure_entrypoint .align 3 /* -------------------------------------------------- - * Per-CPU Secure entry point - resume from suspend + * CPU Secure entry point - resume from suspend * -------------------------------------------------- */ -sec_entry_point: - .rept PLATFORM_CORE_COUNT +tegra_sec_entry_point: .quad 0 - .endr /* -------------------------------------------------- * NS world's cold boot entry point diff --git a/plat/nvidia/tegra/common/drivers/flowctrl/flowctrl.c b/plat/nvidia/tegra/common/drivers/flowctrl/flowctrl.c index b473dd65..35717589 100644 --- a/plat/nvidia/tegra/common/drivers/flowctrl/flowctrl.c +++ b/plat/nvidia/tegra/common/drivers/flowctrl/flowctrl.c @@ -98,9 +98,9 @@ static void tegra_fc_prepare_suspend(int cpu_id, uint32_t csr) } /******************************************************************************* - * Suspend the current CPU + * Powerdn the current CPU ******************************************************************************/ -void tegra_fc_cpu_idle(uint32_t mpidr) +void tegra_fc_cpu_powerdn(uint32_t mpidr) { int cpu = mpidr & MPIDR_CPU_MASK; diff --git a/plat/nvidia/tegra/common/tegra_common.mk b/plat/nvidia/tegra/common/tegra_common.mk index e1c0d84d..fcebde30 100644 --- a/plat/nvidia/tegra/common/tegra_common.mk +++ b/plat/nvidia/tegra/common/tegra_common.mk @@ -51,6 +51,7 @@ BL31_SOURCES += drivers/arm/gic/gic_v2.c \ drivers/delay_timer/delay_timer.c \ drivers/ti/uart/16550_console.S \ plat/common/aarch64/platform_mp_stack.S \ + plat/common/aarch64/plat_psci_common.c \ ${COMMON_DIR}/aarch64/tegra_helpers.S \ ${COMMON_DIR}/drivers/memctrl/memctrl.c \ ${COMMON_DIR}/drivers/pmc/pmc.c \ diff --git a/plat/nvidia/tegra/common/tegra_pm.c b/plat/nvidia/tegra/common/tegra_pm.c index c2c73f63..6fb3e9c6 100644 --- a/plat/nvidia/tegra/common/tegra_pm.c +++ b/plat/nvidia/tegra/common/tegra_pm.c @@ -44,35 +44,34 @@ #include <tegra_private.h> extern uint64_t tegra_bl31_phys_base; -extern uint64_t sec_entry_point[PLATFORM_CORE_COUNT]; -static int system_suspended; +extern uint64_t tegra_sec_entry_point; /* * The following platform setup functions are weakly defined. They * provide typical implementations that will be overridden by a SoC. */ -#pragma weak tegra_soc_prepare_cpu_suspend -#pragma weak tegra_soc_prepare_cpu_on -#pragma weak tegra_soc_prepare_cpu_off -#pragma weak tegra_soc_prepare_cpu_on_finish +#pragma weak tegra_soc_pwr_domain_suspend +#pragma weak tegra_soc_pwr_domain_on +#pragma weak tegra_soc_pwr_domain_off +#pragma weak tegra_soc_pwr_domain_on_finish #pragma weak tegra_soc_prepare_system_reset -int tegra_soc_prepare_cpu_suspend(unsigned int id, unsigned int afflvl) +int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state) { return PSCI_E_NOT_SUPPORTED; } -int tegra_soc_prepare_cpu_on(unsigned long mpidr) +int tegra_soc_pwr_domain_on(u_register_t mpidr) { return PSCI_E_SUCCESS; } -int tegra_soc_prepare_cpu_off(unsigned long mpidr) +int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state) { return PSCI_E_SUCCESS; } -int tegra_soc_prepare_cpu_on_finish(unsigned long mpidr) +int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state) { return PSCI_E_SUCCESS; } @@ -83,33 +82,25 @@ int tegra_soc_prepare_system_reset(void) } /******************************************************************************* - * Track system suspend entry. - ******************************************************************************/ -void tegra_pm_system_suspend_entry(void) -{ - system_suspended = 1; -} - -/******************************************************************************* - * Track system suspend exit. - ******************************************************************************/ -void tegra_pm_system_suspend_exit(void) + * This handler is called by the PSCI implementation during the `SYSTEM_SUSPEND` + * call to get the `power_state` parameter. This allows the platform to encode + * the appropriate State-ID field within the `power_state` parameter which can + * be utilized in `pwr_domain_suspend()` to suspend to system affinity level. +******************************************************************************/ +void tegra_get_sys_suspend_power_state(psci_power_state_t *req_state) { - system_suspended = 0; -} + /* lower affinities use PLAT_MAX_OFF_STATE */ + for (int i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++) + req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE; -/******************************************************************************* - * Get the system suspend state. - ******************************************************************************/ -int tegra_system_suspended(void) -{ - return system_suspended; + /* max affinity uses system suspend state id */ + req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PSTATE_ID_SOC_POWERDN; } /******************************************************************************* * Handler called when an affinity instance is about to enter standby. ******************************************************************************/ -void tegra_affinst_standby(unsigned int power_state) +void tegra_cpu_standby(plat_local_state_t cpu_state) { /* * Enter standby state @@ -120,132 +111,45 @@ void tegra_affinst_standby(unsigned int power_state) } /******************************************************************************* - * This handler is called by the PSCI implementation during the `SYSTEM_SUSPEND` - * call to get the `power_state` parameter. This allows the platform to encode - * the appropriate State-ID field within the `power_state` parameter which can - * be utilized in `affinst_suspend()` to suspend to system affinity level. -******************************************************************************/ -unsigned int tegra_get_sys_suspend_power_state(void) -{ - unsigned int power_state; - - power_state = psci_make_powerstate(PLAT_SYS_SUSPEND_STATE_ID, - PSTATE_TYPE_POWERDOWN, MPIDR_AFFLVL2); - - return power_state; -} - -/******************************************************************************* - * Handler called to check the validity of the power state parameter. - ******************************************************************************/ -int32_t tegra_validate_power_state(unsigned int power_state) -{ - return tegra_soc_validate_power_state(power_state); -} - -/******************************************************************************* * Handler called when an affinity instance is about to be turned on. The * level and mpidr determine the affinity instance. ******************************************************************************/ -int tegra_affinst_on(unsigned long mpidr, - unsigned long sec_entrypoint, - unsigned int afflvl, - unsigned int state) +int tegra_pwr_domain_on(u_register_t mpidr) { - int cpu = mpidr & MPIDR_CPU_MASK; - - /* - * Support individual CPU power on only. - */ - if (afflvl > MPIDR_AFFLVL0) - return PSCI_E_SUCCESS; - - /* - * Flush entrypoint variable to PoC since it will be - * accessed after a reset with the caches turned off. - */ - sec_entry_point[cpu] = sec_entrypoint; - flush_dcache_range((uint64_t)&sec_entry_point[cpu], sizeof(uint64_t)); - - return tegra_soc_prepare_cpu_on(mpidr); + return tegra_soc_pwr_domain_on(mpidr); } /******************************************************************************* - * Handler called when an affinity instance is about to be turned off. The - * level determines the affinity instance. The 'state' arg. allows the - * platform to decide whether the cluster is being turned off and take apt - * actions. - * - * CAUTION: This function is called with coherent stacks so that caches can be - * turned off, flushed and coherency disabled. There is no guarantee that caches - * will remain turned on across calls to this function as each affinity level is - * dealt with. So do not write & read global variables across calls. It will be - * wise to do flush a write to the global to prevent unpredictable results. + * Handler called when a power domain is about to be turned off. The + * target_state encodes the power state that each level should transition to. ******************************************************************************/ -void tegra_affinst_off(unsigned int afflvl, unsigned int state) +void tegra_pwr_domain_off(const psci_power_state_t *target_state) { - /* - * Support individual CPU power off only. - */ - if (afflvl > MPIDR_AFFLVL0) - return; - - tegra_soc_prepare_cpu_off(read_mpidr()); + tegra_soc_pwr_domain_off(target_state); } /******************************************************************************* - * Handler called when an affinity instance is about to be suspended. The - * level and mpidr determine the affinity instance. The 'state' arg. allows the - * platform to decide whether the cluster is being turned off and take apt - * actions. - * - * CAUTION: This function is called with coherent stacks so that caches can be - * turned off, flushed and coherency disabled. There is no guarantee that caches - * will remain turned on across calls to this function as each affinity level is - * dealt with. So do not write & read global variables across calls. It will be - * wise to flush a write to the global variable, to prevent unpredictable - * results. + * Handler called when called when a power domain is about to be suspended. The + * target_state encodes the power state that each level should transition to. ******************************************************************************/ -void tegra_affinst_suspend(unsigned long sec_entrypoint, - unsigned int afflvl, - unsigned int state) +void tegra_pwr_domain_suspend(const psci_power_state_t *target_state) { - int id = psci_get_suspend_stateid(); - int cpu = read_mpidr() & MPIDR_CPU_MASK; - - if (afflvl > PLATFORM_MAX_AFFLVL) - return; - - /* - * Flush entrypoint variable to PoC since it will be - * accessed after a reset with the caches turned off. - */ - sec_entry_point[cpu] = sec_entrypoint; - flush_dcache_range((uint64_t)&sec_entry_point[cpu], sizeof(uint64_t)); - - tegra_soc_prepare_cpu_suspend(id, afflvl); + tegra_soc_pwr_domain_suspend(target_state); /* disable GICC */ tegra_gic_cpuif_deactivate(); } /******************************************************************************* - * Handler called when an affinity instance has just been powered on after - * being turned off earlier. The level determines the affinity instance. - * The 'state' arg. allows the platform to decide whether the cluster was - * turned off prior to wakeup and do what's necessary to set it up. + * Handler called when a power domain has just been powered on after + * being turned off earlier. The target_state encodes the low power state that + * each level has woken up from. ******************************************************************************/ -void tegra_affinst_on_finish(unsigned int afflvl, unsigned int state) +void tegra_pwr_domain_on_finish(const psci_power_state_t *target_state) { plat_params_from_bl2_t *plat_params; /* - * Support individual CPU power on only. - */ - if (afflvl > MPIDR_AFFLVL0) - return; - - /* * Initialize the GIC cpu and distributor interfaces */ tegra_gic_setup(); @@ -253,7 +157,8 @@ void tegra_affinst_on_finish(unsigned int afflvl, unsigned int state) /* * Check if we are exiting from deep sleep. */ - if (tegra_system_suspended()) { + if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] == + PSTATE_ID_SOC_POWERDN) { /* * Lock scratch registers which hold the CPU vectors. @@ -276,18 +181,17 @@ void tegra_affinst_on_finish(unsigned int afflvl, unsigned int state) /* * Reset hardware settings. */ - tegra_soc_prepare_cpu_on_finish(read_mpidr()); + tegra_soc_pwr_domain_on_finish(target_state); } /******************************************************************************* - * Handler called when an affinity instance has just been powered on after - * having been suspended earlier. The level and mpidr determine the affinity - * instance. + * Handler called when a power domain has just been powered on after + * having been suspended earlier. The target_state encodes the low power state + * that each level has woken up from. ******************************************************************************/ -void tegra_affinst_suspend_finish(unsigned int afflvl, unsigned int state) +void tegra_pwr_domain_suspend_finish(const psci_power_state_t *target_state) { - if (afflvl == MPIDR_AFFLVL0) - tegra_affinst_on_finish(afflvl, state); + tegra_pwr_domain_on_finish(target_state); } /******************************************************************************* @@ -314,35 +218,77 @@ __dead2 void tegra_system_reset(void) } /******************************************************************************* + * Handler called to check the validity of the power state parameter. + ******************************************************************************/ +int32_t tegra_validate_power_state(unsigned int power_state, + psci_power_state_t *req_state) +{ + int pwr_lvl = psci_get_pstate_pwrlvl(power_state); + + assert(req_state); + + if (pwr_lvl > PLAT_MAX_PWR_LVL) + return PSCI_E_INVALID_PARAMS; + + return tegra_soc_validate_power_state(power_state, req_state); +} + +/******************************************************************************* + * Platform handler called to check the validity of the non secure entrypoint. + ******************************************************************************/ +int tegra_validate_ns_entrypoint(uintptr_t entrypoint) +{ + /* + * Check if the non secure entrypoint lies within the non + * secure DRAM. + */ + if ((entrypoint >= TEGRA_DRAM_BASE) && (entrypoint <= TEGRA_DRAM_END)) + return PSCI_E_SUCCESS; + + return PSCI_E_INVALID_ADDRESS; +} + +/******************************************************************************* * Export the platform handlers to enable psci to invoke them ******************************************************************************/ -static const plat_pm_ops_t tegra_plat_pm_ops = { - .affinst_standby = tegra_affinst_standby, - .affinst_on = tegra_affinst_on, - .affinst_off = tegra_affinst_off, - .affinst_suspend = tegra_affinst_suspend, - .affinst_on_finish = tegra_affinst_on_finish, - .affinst_suspend_finish = tegra_affinst_suspend_finish, - .system_off = tegra_system_off, - .system_reset = tegra_system_reset, - .validate_power_state = tegra_validate_power_state, - .get_sys_suspend_power_state = tegra_get_sys_suspend_power_state +static const plat_psci_ops_t tegra_plat_psci_ops = { + .cpu_standby = tegra_cpu_standby, + .pwr_domain_on = tegra_pwr_domain_on, + .pwr_domain_off = tegra_pwr_domain_off, + .pwr_domain_suspend = tegra_pwr_domain_suspend, + .pwr_domain_on_finish = tegra_pwr_domain_on_finish, + .pwr_domain_suspend_finish = tegra_pwr_domain_suspend_finish, + .system_off = tegra_system_off, + .system_reset = tegra_system_reset, + .validate_power_state = tegra_validate_power_state, + .validate_ns_entrypoint = tegra_validate_ns_entrypoint, + .get_sys_suspend_power_state = tegra_get_sys_suspend_power_state, }; /******************************************************************************* - * Export the platform specific power ops & initialize the fvp power controller + * Export the platform specific power ops and initialize Power Controller ******************************************************************************/ -int platform_setup_pm(const plat_pm_ops_t **plat_ops) +int plat_setup_psci_ops(uintptr_t sec_entrypoint, + const plat_psci_ops_t **psci_ops) { + psci_power_state_t target_state = { { PSCI_LOCAL_STATE_RUN } }; + + /* + * Flush entrypoint variable to PoC since it will be + * accessed after a reset with the caches turned off. + */ + tegra_sec_entry_point = sec_entrypoint; + flush_dcache_range((uint64_t)&tegra_sec_entry_point, sizeof(uint64_t)); + /* * Reset hardware settings. */ - tegra_soc_prepare_cpu_on_finish(read_mpidr()); + tegra_soc_pwr_domain_on_finish(&target_state); /* - * Initialize PM ops struct + * Initialize PSCI ops struct */ - *plat_ops = &tegra_plat_pm_ops; + *psci_ops = &tegra_plat_psci_ops; return 0; } diff --git a/plat/nvidia/tegra/common/tegra_topology.c b/plat/nvidia/tegra/common/tegra_topology.c index 220e697b..0431d98a 100644 --- a/plat/nvidia/tegra/common/tegra_topology.c +++ b/plat/nvidia/tegra/common/tegra_topology.c @@ -28,45 +28,47 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include <arch_helpers.h> +#include <arch.h> #include <platform_def.h> #include <psci.h> +extern const unsigned char tegra_power_domain_tree_desc[]; + /******************************************************************************* - * This function implements a part of the critical interface between the psci - * generic layer and the platform to allow the former to detect the platform - * topology. psci queries the platform to determine how many affinity instances - * are present at a particular level for a given mpidr. + * This function returns the Tegra default topology tree information. ******************************************************************************/ -unsigned int plat_get_aff_count(unsigned int aff_lvl, - unsigned long mpidr) +const unsigned char *plat_get_power_domain_tree_desc(void) { - switch (aff_lvl) { - case MPIDR_AFFLVL2: - /* Last supported affinity level */ - return 1; - - case MPIDR_AFFLVL1: - /* Return # of clusters */ - return PLATFORM_CLUSTER_COUNT; - - case MPIDR_AFFLVL0: - /* # of cpus per cluster */ - return PLATFORM_MAX_CPUS_PER_CLUSTER; - - default: - return PSCI_AFF_ABSENT; - } + return tegra_power_domain_tree_desc; } /******************************************************************************* * This function implements a part of the critical interface between the psci - * generic layer and the platform to allow the former to detect the state of a - * affinity instance in the platform topology. psci queries the platform to - * determine whether an affinity instance is present or absent. + * generic layer and the platform that allows the former to query the platform + * to convert an MPIDR to a unique linear index. An error code (-1) is returned + * in case the MPIDR is invalid. ******************************************************************************/ -unsigned int plat_get_aff_state(unsigned int aff_lvl, - unsigned long mpidr) +int plat_core_pos_by_mpidr(u_register_t mpidr) { - return (aff_lvl <= MPIDR_AFFLVL2) ? PSCI_AFF_PRESENT : PSCI_AFF_ABSENT; + unsigned int cluster_id, cpu_id; + + mpidr &= MPIDR_AFFINITY_MASK; + + if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)) + return -1; + + cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; + cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK; + + if (cluster_id >= PLATFORM_CLUSTER_COUNT) + return -1; + + /* + * Validate cpu_id by checking whether it represents a CPU in + * one of the two clusters present on the platform. + */ + if (cpu_id >= PLATFORM_MAX_CPUS_PER_CLUSTER) + return -1; + + return (cpu_id + (cluster_id * 4)); } diff --git a/plat/nvidia/tegra/include/drivers/flowctrl.h b/plat/nvidia/tegra/include/drivers/flowctrl.h index 8bc821d1..23909e80 100644 --- a/plat/nvidia/tegra/include/drivers/flowctrl.h +++ b/plat/nvidia/tegra/include/drivers/flowctrl.h @@ -73,8 +73,8 @@ static inline void tegra_fc_write_32(uint32_t off, uint32_t val) mmio_write_32(TEGRA_FLOWCTRL_BASE + off, val); } -void tegra_fc_cpu_idle(uint32_t mpidr); void tegra_fc_cluster_idle(uint32_t midr); +void tegra_fc_cpu_powerdn(uint32_t mpidr); void tegra_fc_cluster_powerdn(uint32_t midr); void tegra_fc_soc_powerdn(uint32_t midr); void tegra_fc_cpu_on(int cpu); diff --git a/plat/nvidia/tegra/include/platform_def.h b/plat/nvidia/tegra/include/platform_def.h index c59e2beb..2a7935fd 100644 --- a/plat/nvidia/tegra/include/platform_def.h +++ b/plat/nvidia/tegra/include/platform_def.h @@ -33,6 +33,7 @@ #include <arch.h> #include <common_def.h> +#include <tegra_def.h> /******************************************************************************* * Generic platform constants @@ -47,13 +48,19 @@ #define TEGRA_PRIMARY_CPU 0x0 -#define PLATFORM_MAX_AFFLVL MPIDR_AFFLVL2 +#define PLAT_MAX_PWR_LVL MPIDR_AFFLVL2 #define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER_COUNT * \ PLATFORM_MAX_CPUS_PER_CLUSTER) -#define PLATFORM_NUM_AFFS (PLATFORM_CORE_COUNT + \ +#define PLAT_NUM_PWR_DOMAINS (PLATFORM_CORE_COUNT + \ PLATFORM_CLUSTER_COUNT + 1) /******************************************************************************* + * Platform power states + ******************************************************************************/ +#define PLAT_MAX_RET_STATE 1 +#define PLAT_MAX_OFF_STATE (PSTATE_ID_SOC_POWERDN + 1) + +/******************************************************************************* * Platform console related constants ******************************************************************************/ #define TEGRA_CONSOLE_BAUDRATE 115200 diff --git a/plat/nvidia/tegra/include/t132/tegra_def.h b/plat/nvidia/tegra/include/t132/tegra_def.h index 2fb9ed70..683c9038 100644 --- a/plat/nvidia/tegra/include/t132/tegra_def.h +++ b/plat/nvidia/tegra/include/t132/tegra_def.h @@ -37,7 +37,7 @@ * This value is used by the PSCI implementation during the `SYSTEM_SUSPEND` * call as the `state-id` field in the 'power state' parameter. ******************************************************************************/ -#define PLAT_SYS_SUSPEND_STATE_ID 0xD +#define PSTATE_ID_SOC_POWERDN 0xD /******************************************************************************* * GIC memory map diff --git a/plat/nvidia/tegra/include/tegra_private.h b/plat/nvidia/tegra/include/tegra_private.h index 952e2d8b..6fa943ff 100644 --- a/plat/nvidia/tegra/include/tegra_private.h +++ b/plat/nvidia/tegra/include/tegra_private.h @@ -31,8 +31,10 @@ #ifndef __TEGRA_PRIVATE_H__ #define __TEGRA_PRIVATE_H__ -#include <xlat_tables.h> +#include <arch.h> #include <platform_def.h> +#include <psci.h> +#include <xlat_tables.h> /******************************************************************************* * Tegra DRAM memory base address @@ -45,7 +47,8 @@ typedef struct plat_params_from_bl2 { } plat_params_from_bl2_t; /* Declarations for plat_psci_handlers.c */ -int32_t tegra_soc_validate_power_state(unsigned int power_state); +int32_t tegra_soc_validate_power_state(unsigned int power_state, + psci_power_state_t *req_state); /* Declarations for plat_setup.c */ const mmap_region_t *plat_get_mmio_map(void); diff --git a/plat/nvidia/tegra/platform.mk b/plat/nvidia/tegra/platform.mk index b9093354..cec7caff 100644 --- a/plat/nvidia/tegra/platform.mk +++ b/plat/nvidia/tegra/platform.mk @@ -28,7 +28,10 @@ # POSSIBILITY OF SUCH DAMAGE. # -SOC_DIR := plat/nvidia/tegra/soc/${TARGET_SOC} +SOC_DIR := plat/nvidia/tegra/soc/${TARGET_SOC} + +# Disable the PSCI platform compatibility layer +ENABLE_PLAT_COMPAT := 0 include plat/nvidia/tegra/common/tegra_common.mk include ${SOC_DIR}/platform_${TARGET_SOC}.mk diff --git a/plat/nvidia/tegra/soc/t132/plat_psci_handlers.c b/plat/nvidia/tegra/soc/t132/plat_psci_handlers.c index 46e59409..48a2fbaa 100644 --- a/plat/nvidia/tegra/soc/t132/plat_psci_handlers.c +++ b/plat/nvidia/tegra/soc/t132/plat_psci_handlers.c @@ -56,28 +56,55 @@ static int cpu_powergate_mask[PLATFORM_MAX_CPUS_PER_CLUSTER]; -int32_t tegra_soc_validate_power_state(unsigned int power_state) +int32_t tegra_soc_validate_power_state(unsigned int power_state, + psci_power_state_t *req_state) { + int pwr_lvl = psci_get_pstate_pwrlvl(power_state); + int state_id = psci_get_pstate_id(power_state); + int cpu = read_mpidr() & MPIDR_CPU_MASK; + + if (pwr_lvl > PLAT_MAX_PWR_LVL) + return PSCI_E_INVALID_PARAMS; + /* Sanity check the requested afflvl */ if (psci_get_pstate_type(power_state) == PSTATE_TYPE_STANDBY) { /* * It's possible to enter standby only on affinity level 0 i.e. * a cpu on Tegra. Ignore any other affinity level. */ - if (psci_get_pstate_afflvl(power_state) != MPIDR_AFFLVL0) + if (pwr_lvl != MPIDR_AFFLVL0) return PSCI_E_INVALID_PARAMS; + + /* power domain in standby state */ + req_state->pwr_domain_state[pwr_lvl] = PLAT_MAX_RET_STATE; + + return PSCI_E_SUCCESS; } - /* Sanity check the requested state id */ - if (psci_get_pstate_id(power_state) != PLAT_SYS_SUSPEND_STATE_ID) { - ERROR("unsupported state id\n"); - return PSCI_E_NOT_SUPPORTED; + /* + * Sanity check the requested state id, power level and CPU number. + * Currently T132 only supports SYSTEM_SUSPEND on last standing CPU + * i.e. CPU 0 + */ + if ((pwr_lvl != PLAT_MAX_PWR_LVL) || + (state_id != PSTATE_ID_SOC_POWERDN) || + (cpu != 0)) { + ERROR("unsupported state id @ power level\n"); + return PSCI_E_INVALID_PARAMS; } + /* Set lower power states to PLAT_MAX_OFF_STATE */ + for (int i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++) + req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE; + + /* Set the SYSTEM_SUSPEND state-id */ + req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = + PSTATE_ID_SOC_POWERDN; + return PSCI_E_SUCCESS; } -int tegra_soc_prepare_cpu_on(unsigned long mpidr) +int tegra_soc_pwr_domain_on(u_register_t mpidr) { int cpu = mpidr & MPIDR_CPU_MASK; uint32_t mask = CPU_CORE_RESET_MASK << cpu; @@ -101,29 +128,29 @@ int tegra_soc_prepare_cpu_on(unsigned long mpidr) return PSCI_E_SUCCESS; } -int tegra_soc_prepare_cpu_off(unsigned long mpidr) +int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state) { - tegra_fc_cpu_off(mpidr & MPIDR_CPU_MASK); + tegra_fc_cpu_off(read_mpidr() & MPIDR_CPU_MASK); return PSCI_E_SUCCESS; } -int tegra_soc_prepare_cpu_suspend(unsigned int id, unsigned int afflvl) +int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state) { - /* Nothing to be done for lower affinity levels */ - if (afflvl < MPIDR_AFFLVL2) - return PSCI_E_SUCCESS; +#if DEBUG + int cpu = read_mpidr() & MPIDR_CPU_MASK; - /* Enter system suspend state */ - tegra_pm_system_suspend_entry(); + /* SYSTEM_SUSPEND only on CPU0 */ + assert(cpu == 0); +#endif /* Allow restarting CPU #1 using PMC on suspend exit */ cpu_powergate_mask[1] = 0; /* Program FC to enter suspend state */ - tegra_fc_cpu_idle(read_mpidr()); + tegra_fc_cpu_powerdn(read_mpidr()); /* Suspend DCO operations */ - write_actlr_el1(id); + write_actlr_el1(target_state->pwr_domain_state[PLAT_MAX_PWR_LVL]); return PSCI_E_SUCCESS; } diff --git a/plat/nvidia/tegra/soc/t132/plat_setup.c b/plat/nvidia/tegra/soc/t132/plat_setup.c index a76999c5..6ff2831f 100644 --- a/plat/nvidia/tegra/soc/t132/plat_setup.c +++ b/plat/nvidia/tegra/soc/t132/plat_setup.c @@ -31,6 +31,21 @@ #include <xlat_tables.h> #include <tegra_def.h> +/******************************************************************************* + * The Tegra power domain tree has a single system level power domain i.e. a + * single root node. The first entry in the power domain descriptor specifies + * the number of power domains at the highest power level. + ******************************************************************************* + */ +const unsigned char tegra_power_domain_tree_desc[] = { + /* No of root nodes */ + 1, + /* No of clusters */ + PLATFORM_CLUSTER_COUNT, + /* No of CPU cores */ + PLATFORM_CORE_COUNT, +}; + /* sets of MMIO ranges setup */ #define MMIO_RANGE_0_ADDR 0x50000000 #define MMIO_RANGE_1_ADDR 0x60000000 diff --git a/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c b/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c index 73358d4d..b184063d 100644 --- a/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c +++ b/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c @@ -55,83 +55,139 @@ static int cpu_powergate_mask[PLATFORM_MAX_CPUS_PER_CLUSTER]; -int32_t tegra_soc_validate_power_state(unsigned int power_state) +int32_t tegra_soc_validate_power_state(unsigned int power_state, + psci_power_state_t *req_state) { + int pwr_lvl = psci_get_pstate_pwrlvl(power_state); + int state_id = psci_get_pstate_id(power_state); + + if (pwr_lvl > PLAT_MAX_PWR_LVL) { + ERROR("%s: unsupported power_state (0x%x)\n", __func__, + power_state); + return PSCI_E_INVALID_PARAMS; + } + /* Sanity check the requested afflvl */ if (psci_get_pstate_type(power_state) == PSTATE_TYPE_STANDBY) { /* * It's possible to enter standby only on affinity level 0 i.e. * a cpu on Tegra. Ignore any other affinity level. */ - if (psci_get_pstate_afflvl(power_state) != MPIDR_AFFLVL0) + if (pwr_lvl != MPIDR_AFFLVL0) return PSCI_E_INVALID_PARAMS; + + /* power domain in standby state */ + req_state->pwr_domain_state[pwr_lvl] = PLAT_MAX_RET_STATE; + + return PSCI_E_SUCCESS; } /* Sanity check the requested state id */ - switch (psci_get_pstate_id(power_state)) { + switch (state_id) { case PSTATE_ID_CORE_POWERDN: + /* + * Core powerdown request only for afflvl 0 + */ + if (pwr_lvl != MPIDR_AFFLVL0) + goto error; + + req_state->pwr_domain_state[MPIDR_AFFLVL0] = state_id & 0xff; + + break; + case PSTATE_ID_CLUSTER_IDLE: case PSTATE_ID_CLUSTER_POWERDN: + /* + * Cluster powerdown/idle request only for afflvl 1 + */ + if (pwr_lvl != MPIDR_AFFLVL1) + goto error; + + req_state->pwr_domain_state[MPIDR_AFFLVL1] = state_id; + req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_OFF_STATE; + + break; + case PSTATE_ID_SOC_POWERDN: + /* + * System powerdown request only for afflvl 2 + */ + if (pwr_lvl != PLAT_MAX_PWR_LVL) + goto error; + + for (int i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++) + req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE; + + req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = + PLAT_SYS_SUSPEND_STATE_ID; + break; default: - ERROR("unsupported state id\n"); - return PSCI_E_NOT_SUPPORTED; + ERROR("%s: unsupported state id (%d)\n", __func__, state_id); + return PSCI_E_INVALID_PARAMS; } return PSCI_E_SUCCESS; + +error: + ERROR("%s: unsupported state id (%d)\n", __func__, state_id); + return PSCI_E_INVALID_PARAMS; } -int tegra_soc_prepare_cpu_suspend(unsigned int id, unsigned int afflvl) +int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state) { - /* There's nothing to be done for affinity level 1 */ - if (afflvl == MPIDR_AFFLVL1) - return PSCI_E_SUCCESS; + u_register_t mpidr = read_mpidr(); + const plat_local_state_t *pwr_domain_state = + target_state->pwr_domain_state; + unsigned int stateid_afflvl2 = pwr_domain_state[MPIDR_AFFLVL2]; + unsigned int stateid_afflvl1 = pwr_domain_state[MPIDR_AFFLVL1]; + unsigned int stateid_afflvl0 = pwr_domain_state[MPIDR_AFFLVL0]; - switch (id) { - /* Prepare for cpu idle */ - case PSTATE_ID_CORE_POWERDN: - tegra_fc_cpu_idle(read_mpidr()); - return PSCI_E_SUCCESS; + if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) { - /* Prepare for cluster idle */ - case PSTATE_ID_CLUSTER_IDLE: - tegra_fc_cluster_idle(read_mpidr()); - return PSCI_E_SUCCESS; + assert(stateid_afflvl0 == PLAT_MAX_OFF_STATE); + assert(stateid_afflvl1 == PLAT_MAX_OFF_STATE); - /* Prepare for cluster powerdn */ - case PSTATE_ID_CLUSTER_POWERDN: - tegra_fc_cluster_powerdn(read_mpidr()); - return PSCI_E_SUCCESS; + /* suspend the entire soc */ + tegra_fc_soc_powerdn(mpidr); - /* Prepare for system idle */ - case PSTATE_ID_SOC_POWERDN: + } else if (stateid_afflvl1 == PSTATE_ID_CLUSTER_IDLE) { - /* Enter system suspend state */ - tegra_pm_system_suspend_entry(); + assert(stateid_afflvl0 == PLAT_MAX_OFF_STATE); - /* suspend the entire soc */ - tegra_fc_soc_powerdn(read_mpidr()); + /* Prepare for cluster idle */ + tegra_fc_cluster_idle(mpidr); - return PSCI_E_SUCCESS; + } else if (stateid_afflvl1 == PSTATE_ID_CLUSTER_POWERDN) { - default: - ERROR("Unknown state id (%d)\n", id); - break; + assert(stateid_afflvl0 == PLAT_MAX_OFF_STATE); + + /* Prepare for cluster powerdn */ + tegra_fc_cluster_powerdn(mpidr); + + } else if (stateid_afflvl0 == PSTATE_ID_CORE_POWERDN) { + + /* Prepare for cpu powerdn */ + tegra_fc_cpu_powerdn(mpidr); + + } else { + ERROR("%s: Unknown state id\n", __func__); + return PSCI_E_NOT_SUPPORTED; } - return PSCI_E_NOT_SUPPORTED; + return PSCI_E_SUCCESS; } -int tegra_soc_prepare_cpu_on_finish(unsigned long mpidr) +int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state) { uint32_t val; /* * Check if we are exiting from SOC_POWERDN. */ - if (tegra_system_suspended()) { + if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] == + PLAT_SYS_SUSPEND_STATE_ID) { /* * Enable WRAP to INCR burst type conversions for @@ -147,11 +203,6 @@ int tegra_soc_prepare_cpu_on_finish(unsigned long mpidr) * address and reset it. */ tegra_fc_reset_bpmp(); - - /* - * System resume complete. - */ - tegra_pm_system_suspend_exit(); } /* @@ -159,13 +210,12 @@ int tegra_soc_prepare_cpu_on_finish(unsigned long mpidr) * used for power management and boot purposes. Inform the BPMP that * we have completed the cluster power up. */ - if (psci_get_max_phys_off_afflvl() == MPIDR_AFFLVL1) - tegra_fc_lock_active_cluster(); + tegra_fc_lock_active_cluster(); return PSCI_E_SUCCESS; } -int tegra_soc_prepare_cpu_on(unsigned long mpidr) +int tegra_soc_pwr_domain_on(u_register_t mpidr) { int cpu = mpidr & MPIDR_CPU_MASK; uint32_t mask = CPU_CORE_RESET_MASK << cpu; @@ -184,9 +234,9 @@ int tegra_soc_prepare_cpu_on(unsigned long mpidr) return PSCI_E_SUCCESS; } -int tegra_soc_prepare_cpu_off(unsigned long mpidr) +int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state) { - tegra_fc_cpu_off(mpidr & MPIDR_CPU_MASK); + tegra_fc_cpu_off(read_mpidr() & MPIDR_CPU_MASK); return PSCI_E_SUCCESS; } diff --git a/plat/nvidia/tegra/soc/t210/plat_setup.c b/plat/nvidia/tegra/soc/t210/plat_setup.c index cbe7a042..3fce8a2a 100644 --- a/plat/nvidia/tegra/soc/t210/plat_setup.c +++ b/plat/nvidia/tegra/soc/t210/plat_setup.c @@ -32,6 +32,23 @@ #include <tegra_def.h> #include <xlat_tables.h> +/******************************************************************************* + * The Tegra power domain tree has a single system level power domain i.e. a + * single root node. The first entry in the power domain descriptor specifies + * the number of power domains at the highest power level. + ******************************************************************************* + */ +const unsigned char tegra_power_domain_tree_desc[] = { + /* No of root nodes */ + 1, + /* No of clusters */ + PLATFORM_CLUSTER_COUNT, + /* No of CPU cores - cluster0 */ + PLATFORM_MAX_CPUS_PER_CLUSTER, + /* No of CPU cores - cluster1 */ + PLATFORM_MAX_CPUS_PER_CLUSTER +}; + /* sets of MMIO ranges setup */ #define MMIO_RANGE_0_ADDR 0x50000000 #define MMIO_RANGE_1_ADDR 0x60000000 diff --git a/services/spd/tspd/tspd.mk b/services/spd/tspd/tspd.mk index 139c7d77..ede25047 100644 --- a/services/spd/tspd/tspd.mk +++ b/services/spd/tspd/tspd.mk @@ -55,7 +55,17 @@ NEED_BL32 := yes # Flag used to enable routing of non-secure interrupts to EL3 when they are # generated while the code is executing in S-EL1/0. -TSPD_ROUTE_IRQ_TO_EL3 := 0 +TSP_NS_INTR_ASYNC_PREEMPT := 0 -$(eval $(call assert_boolean,TSPD_ROUTE_IRQ_TO_EL3)) -$(eval $(call add_define,TSPD_ROUTE_IRQ_TO_EL3)) +# If TSPD_ROUTE_IRQ_TO_EL3 build flag is defined, use it to define value for +# TSP_NS_INTR_ASYNC_PREEMPT for backward compatibility. +ifdef TSPD_ROUTE_IRQ_TO_EL3 +ifeq (${ERROR_DEPRECATED},1) +$(error "TSPD_ROUTE_IRQ_TO_EL3 is deprecated. Please use the new build flag TSP_NS_INTR_ASYNC_PREEMPT") +endif +$(warning "TSPD_ROUTE_IRQ_TO_EL3 is deprecated. Please use the new build flag TSP_NS_INTR_ASYNC_PREEMPT") +TSP_NS_INTR_ASYNC_PREEMPT := ${TSPD_ROUTE_IRQ_TO_EL3} +endif + +$(eval $(call assert_boolean,TSP_NS_INTR_ASYNC_PREEMPT)) +$(eval $(call add_define,TSP_NS_INTR_ASYNC_PREEMPT)) diff --git a/services/spd/tspd/tspd_main.c b/services/spd/tspd/tspd_main.c index 62231601..4b894258 100644 --- a/services/spd/tspd/tspd_main.c +++ b/services/spd/tspd/tspd_main.c @@ -72,9 +72,16 @@ DEFINE_SVC_UUID(tsp_uuid, int32_t tspd_init(void); +/* + * This helper function handles Secure EL1 preemption. The preemption could be + * due Non Secure interrupts or EL3 interrupts. In both the cases we context + * switch to the normal world and in case of EL3 interrupts, it will again be + * routed to EL3 which will get handled at the exception vectors. + */ uint64_t tspd_handle_sp_preemption(void *handle) { cpu_context_t *ns_cpu_context; + assert(handle == cm_get_context(SECURE)); cm_el1_sysregs_context_save(SECURE); /* Get a reference to the non-secure context */ @@ -82,18 +89,30 @@ uint64_t tspd_handle_sp_preemption(void *handle) assert(ns_cpu_context); /* - * Restore non-secure state. The secure system - * register context will be saved when required. + * To allow Secure EL1 interrupt handler to re-enter TSP while TSP + * is preempted, the secure system register context which will get + * overwritten must be additionally saved. This is currently done + * by the TSPD S-EL1 interrupt handler. + */ + + /* + * Restore non-secure state. */ cm_el1_sysregs_context_restore(NON_SECURE); cm_set_next_eret_context(NON_SECURE); + /* + * The TSP was preempted during STD SMC execution. + * Return back to the normal world with SMC_PREEMPTED as error + * code in x0. + */ SMC_RET1(ns_cpu_context, SMC_PREEMPTED); } + /******************************************************************************* * This function is the handler registered for S-EL1 interrupts by the TSPD. It * validates the interrupt and upon success arranges entry into the TSP at - * 'tsp_fiq_entry()' for handling the interrupt. + * 'tsp_sel1_intr_entry()' for handling the interrupt. ******************************************************************************/ static uint64_t tspd_sel1_interrupt_handler(uint32_t id, uint32_t flags, @@ -121,44 +140,44 @@ static uint64_t tspd_sel1_interrupt_handler(uint32_t id, * Determine if the TSP was previously preempted. Its last known * context has to be preserved in this case. * The TSP should return control to the TSPD after handling this - * FIQ. Preserve essential EL3 context to allow entry into the - * TSP at the FIQ entry point using the 'cpu_context' structure. - * There is no need to save the secure system register context - * since the TSP is supposed to preserve it during S-EL1 interrupt - * handling. + * S-EL1 interrupt. Preserve essential EL3 context to allow entry into + * the TSP at the S-EL1 interrupt entry point using the 'cpu_context' + * structure. There is no need to save the secure system register + * context since the TSP is supposed to preserve it during S-EL1 + * interrupt handling. */ if (get_std_smc_active_flag(tsp_ctx->state)) { tsp_ctx->saved_spsr_el3 = SMC_GET_EL3(&tsp_ctx->cpu_ctx, CTX_SPSR_EL3); tsp_ctx->saved_elr_el3 = SMC_GET_EL3(&tsp_ctx->cpu_ctx, CTX_ELR_EL3); -#if TSPD_ROUTE_IRQ_TO_EL3 +#if TSP_NS_INTR_ASYNC_PREEMPT /*Need to save the previously interrupted secure context */ memcpy(&tsp_ctx->sp_ctx, &tsp_ctx->cpu_ctx, TSPD_SP_CTX_SIZE); #endif } cm_el1_sysregs_context_restore(SECURE); - cm_set_elr_spsr_el3(SECURE, (uint64_t) &tsp_vectors->fiq_entry, + cm_set_elr_spsr_el3(SECURE, (uint64_t) &tsp_vectors->sel1_intr_entry, SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS)); cm_set_next_eret_context(SECURE); /* - * Tell the TSP that it has to handle an FIQ synchronously. Also the - * instruction in normal world where the interrupt was generated is - * passed for debugging purposes. It is safe to retrieve this address - * from ELR_EL3 as the secure context will not take effect until - * el3_exit(). + * Tell the TSP that it has to handle a S-EL1 interrupt synchronously. + * Also the instruction in normal world where the interrupt was + * generated is passed for debugging purposes. It is safe to retrieve + * this address from ELR_EL3 as the secure context will not take effect + * until el3_exit(). */ - SMC_RET2(&tsp_ctx->cpu_ctx, TSP_HANDLE_FIQ_AND_RETURN, read_elr_el3()); + SMC_RET2(&tsp_ctx->cpu_ctx, TSP_HANDLE_SEL1_INTR_AND_RETURN, read_elr_el3()); } -#if TSPD_ROUTE_IRQ_TO_EL3 +#if TSP_NS_INTR_ASYNC_PREEMPT /******************************************************************************* - * This function is the handler registered for S-EL1 interrupts by the TSPD. It - * validates the interrupt and upon success arranges entry into the TSP at - * 'tsp_fiq_entry()' for handling the interrupt. + * This function is the handler registered for Non secure interrupts by the + * TSPD. It validates the interrupt and upon success arranges entry into the + * normal world for handling the interrupt. ******************************************************************************/ static uint64_t tspd_ns_interrupt_handler(uint32_t id, uint32_t flags, @@ -312,10 +331,11 @@ uint64_t tspd_smc_handler(uint32_t smc_fid, /* * This function ID is used only by the TSP to indicate that it has - * finished handling a S-EL1 FIQ interrupt. Execution should resume + * finished handling a S-EL1 interrupt or was preempted by a higher + * priority pending EL3 interrupt. Execution should resume * in the normal world. */ - case TSP_HANDLED_S_EL1_FIQ: + case TSP_HANDLED_S_EL1_INTR: if (ns) SMC_RET1(handle, SMC_UNK); @@ -332,7 +352,7 @@ uint64_t tspd_smc_handler(uint32_t smc_fid, SMC_SET_EL3(&tsp_ctx->cpu_ctx, CTX_ELR_EL3, tsp_ctx->saved_elr_el3); -#if TSPD_ROUTE_IRQ_TO_EL3 +#if TSP_NS_INTR_ASYNC_PREEMPT /* * Need to restore the previously interrupted * secure context. @@ -356,35 +376,6 @@ uint64_t tspd_smc_handler(uint32_t smc_fid, SMC_RET0((uint64_t) ns_cpu_context); - - /* - * This function ID is used only by the TSP to indicate that it was - * interrupted due to a EL3 FIQ interrupt. Execution should resume - * in the normal world. - */ - case TSP_EL3_FIQ: - if (ns) - SMC_RET1(handle, SMC_UNK); - - assert(handle == cm_get_context(SECURE)); - - /* Assert that standard SMC execution has been preempted */ - assert(get_std_smc_active_flag(tsp_ctx->state)); - - /* Save the secure system register state */ - cm_el1_sysregs_context_save(SECURE); - - /* Get a reference to the non-secure context */ - ns_cpu_context = cm_get_context(NON_SECURE); - assert(ns_cpu_context); - - /* Restore non-secure state */ - cm_el1_sysregs_context_restore(NON_SECURE); - cm_set_next_eret_context(NON_SECURE); - - SMC_RET1(ns_cpu_context, TSP_EL3_FIQ); - - /* * This function ID is used only by the SP to indicate it has * finished initialising itself after a cold boot @@ -422,7 +413,7 @@ uint64_t tspd_smc_handler(uint32_t smc_fid, if (rc) panic(); -#if TSPD_ROUTE_IRQ_TO_EL3 +#if TSP_NS_INTR_ASYNC_PREEMPT /* * Register an interrupt handler for NS interrupts when * generated during code executing in secure state are @@ -438,8 +429,7 @@ uint64_t tspd_smc_handler(uint32_t smc_fid, panic(); /* - * Disable the interrupt NS locally since it will be enabled globally - * within cm_init_my_context. + * Disable the NS interrupt locally. */ disable_intr_rm_local(INTR_TYPE_NS, SECURE); #endif @@ -561,7 +551,7 @@ uint64_t tspd_smc_handler(uint32_t smc_fid, set_std_smc_active_flag(tsp_ctx->state); cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->std_smc_entry); -#if TSPD_ROUTE_IRQ_TO_EL3 +#if TSP_NS_INTR_ASYNC_PREEMPT /* * Enable the routing of NS interrupts to EL3 * during STD SMC processing on this core. @@ -592,7 +582,7 @@ uint64_t tspd_smc_handler(uint32_t smc_fid, cm_set_next_eret_context(NON_SECURE); if (GET_SMC_TYPE(smc_fid) == SMC_TYPE_STD) { clr_std_smc_active_flag(tsp_ctx->state); -#if TSPD_ROUTE_IRQ_TO_EL3 +#if TSP_NS_INTR_ASYNC_PREEMPT /* * Disable the routing of NS interrupts to EL3 * after STD SMC processing is finished on this @@ -635,7 +625,7 @@ uint64_t tspd_smc_handler(uint32_t smc_fid, * We are done stashing the non-secure context. Ask the * secure payload to do the work now. */ -#if TSPD_ROUTE_IRQ_TO_EL3 +#if TSP_NS_INTR_ASYNC_PREEMPT /* * Enable the routing of NS interrupts to EL3 during resumption * of STD SMC call on this core. diff --git a/services/spd/tspd/tspd_pm.c b/services/spd/tspd/tspd_pm.c index 5089420d..55562ba4 100644 --- a/services/spd/tspd/tspd_pm.c +++ b/services/spd/tspd/tspd_pm.c @@ -130,7 +130,7 @@ static void tspd_cpu_on_finish_handler(uint64_t unused) /* Initialise this cpu's secure context */ cm_init_my_context(&tsp_on_entrypoint); -#if TSPD_ROUTE_IRQ_TO_EL3 +#if TSP_NS_INTR_ASYNC_PREEMPT /* * Disable the NS interrupt locally since it will be enabled globally * within cm_init_my_context. diff --git a/services/spd/tspd/tspd_private.h b/services/spd/tspd/tspd_private.h index 5f6fb2b7..cadc6aaa 100644 --- a/services/spd/tspd/tspd_private.h +++ b/services/spd/tspd/tspd_private.h @@ -183,10 +183,10 @@ CASSERT(TSPD_SP_CTX_SIZE == sizeof(sp_ctx_regs_t), \ /******************************************************************************* * Structure which helps the SPD to maintain the per-cpu state of the SP. - * 'saved_spsr_el3' - temporary copy to allow FIQ handling when the TSP has been - * preempted. - * 'saved_elr_el3' - temporary copy to allow FIQ handling when the TSP has been - * preempted. + * 'saved_spsr_el3' - temporary copy to allow S-EL1 interrupt handling when + * the TSP has been preempted. + * 'saved_elr_el3' - temporary copy to allow S-EL1 interrupt handling when + * the TSP has been preempted. * 'state' - collection of flags to track SP state e.g. on/off * 'mpidr' - mpidr to associate a context with a cpu * 'c_rt_ctx' - stack address to restore C runtime context from after @@ -207,7 +207,7 @@ typedef struct tsp_context { uint64_t c_rt_ctx; cpu_context_t cpu_ctx; uint64_t saved_tsp_args[TSP_NUM_ARGS]; -#if TSPD_ROUTE_IRQ_TO_EL3 +#if TSP_NS_INTR_ASYNC_PREEMPT sp_ctx_regs_t sp_ctx; #endif } tsp_context_t; diff --git a/tools/cert_create/include/ext.h b/tools/cert_create/include/ext.h index 3c65473b..0ede3651 100644 --- a/tools/cert_create/include/ext.h +++ b/tools/cert_create/include/ext.h @@ -72,6 +72,8 @@ typedef struct ext_s { X509V3_EXT_METHOD method; /* This field may be used to define a custom * function to print the contents of the * extension */ + + int optional; /* This field may be used optionally to exclude an image */ } ext_t; enum { diff --git a/tools/cert_create/include/tbbr/tbb_cert.h b/tools/cert_create/include/tbbr/tbb_cert.h index 21626c72..2bc3be63 100644 --- a/tools/cert_create/include/tbbr/tbb_cert.h +++ b/tools/cert_create/include/tbbr/tbb_cert.h @@ -46,7 +46,8 @@ enum { BL32_KEY_CERT, BL32_CERT, BL33_KEY_CERT, - BL33_CERT + BL33_CERT, + FWU_CERT }; #endif /* TBB_CERT_H_ */ diff --git a/tools/cert_create/include/tbbr/tbb_ext.h b/tools/cert_create/include/tbbr/tbb_ext.h index 03b12d7a..ecbe8669 100644 --- a/tools/cert_create/include/tbbr/tbb_ext.h +++ b/tools/cert_create/include/tbbr/tbb_ext.h @@ -46,7 +46,10 @@ enum { BL32_CONTENT_CERT_PK_EXT, BL32_HASH_EXT, BL33_CONTENT_CERT_PK_EXT, - BL33_HASH_EXT + BL33_HASH_EXT, + SCP_BL2U_HASH_EXT, + BL2U_HASH_EXT, + NS_BL2U_HASH_EXT }; #endif /* TBB_EXT_H_ */ diff --git a/tools/cert_create/src/main.c b/tools/cert_create/src/main.c index b7ad33fe..de15ef6f 100644 --- a/tools/cert_create/src/main.c +++ b/tools/cert_create/src/main.c @@ -217,8 +217,11 @@ static void check_cmd_params(void) } break; case EXT_TYPE_HASH: - /* Binary image must be specified */ - if (ext->data.fn == NULL) { + /* + * Binary image must be specified + * unless it is explicitly made optional. + */ + if ((!ext->optional) && (ext->data.fn == NULL)) { ERROR("Image for '%s' not specified\n", ext->ln); exit(1); @@ -410,12 +413,20 @@ int main(int argc, char *argv[]) break; case EXT_TYPE_HASH: if (ext->data.fn == NULL) { - break; - } - if (!sha_file(ext->data.fn, md)) { - ERROR("Cannot calculate hash of %s\n", - ext->data.fn); - exit(1); + if (ext->optional) { + /* Include a hash filled with zeros */ + memset(md, 0x0, SHA256_DIGEST_LENGTH); + } else { + /* Do not include this hash in the certificate */ + break; + } + } else { + /* Calculate the hash of the file */ + if (!sha_file(ext->data.fn, md)) { + ERROR("Cannot calculate hash of %s\n", + ext->data.fn); + exit(1); + } } CHECK_NULL(cert_ext, ext_new_hash(ext_nid, EXT_CRIT, md_info, md, diff --git a/tools/cert_create/src/tbbr/tbb_cert.c b/tools/cert_create/src/tbbr/tbb_cert.c index 770bd6a0..59a1cd9c 100644 --- a/tools/cert_create/src/tbbr/tbb_cert.c +++ b/tools/cert_create/src/tbbr/tbb_cert.c @@ -160,6 +160,20 @@ static cert_t tbb_certs[] = { BL33_HASH_EXT }, .num_ext = 1 + }, + [FWU_CERT] = { + .id = FWU_CERT, + .opt = "fwu-cert", + .fn = NULL, + .cn = "FWU Certificate", + .key = ROT_KEY, + .issuer = FWU_CERT, + .ext = { + SCP_BL2U_HASH_EXT, + BL2U_HASH_EXT, + NS_BL2U_HASH_EXT + }, + .num_ext = 3 } }; diff --git a/tools/cert_create/src/tbbr/tbb_ext.c b/tools/cert_create/src/tbbr/tbb_ext.c index c39c9e6a..b0af6f1a 100644 --- a/tools/cert_create/src/tbbr/tbb_ext.c +++ b/tools/cert_create/src/tbbr/tbb_ext.c @@ -145,6 +145,33 @@ static ext_t tbb_ext[] = { .ln = "Non-Trusted World (BL33) hash (SHA256)", .asn1_type = V_ASN1_OCTET_STRING, .type = EXT_TYPE_HASH + }, + [SCP_BL2U_HASH_EXT] = { + .oid = SCP_BL2U_HASH_OID, + .opt = "scp_bl2u", + .sn = "SCPFWUpdateConfig", + .ln = "SCP Firmware Update Config (SCP_BL2U) hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + [BL2U_HASH_EXT] = { + .oid = BL2U_HASH_OID, + .opt = "bl2u", + .sn = "APFWUpdateConfig", + .ln = "AP Firmware Update Config (BL2U) hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + [NS_BL2U_HASH_EXT] = { + .oid = NS_BL2U_HASH_OID, + .opt = "ns_bl2u", + .sn = "FWUpdaterHash", + .ln = "Firmware Updater (NS_BL2U) hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 } }; diff --git a/tools/fip_create/fip_create.c b/tools/fip_create/fip_create.c index c6869f95..57131840 100644 --- a/tools/fip_create/fip_create.c +++ b/tools/fip_create/fip_create.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2014-2015, ARM Limited and Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -55,6 +55,14 @@ uuid_t uuid_null = {0}; /* The images used depends on the platform. */ static entry_lookup_list_t toc_entry_lookup_list[] = { + { "SCP Firmware Updater Configuration FWU SCP_BL2U", UUID_TRUSTED_UPDATE_FIRMWARE_SCP_BL2U, + "scp_bl2u", NULL, FLAG_FILENAME }, + { "AP Firmware Updater Configuration BL2U", UUID_TRUSTED_UPDATE_FIRMWARE_BL2U, + "bl2u", NULL, FLAG_FILENAME }, + { "Firmware Updater NS_BL2U", UUID_TRUSTED_UPDATE_FIRMWARE_NS_BL2U, + "ns_bl2u", NULL, FLAG_FILENAME }, + { "Non-Trusted Firmware Updater certificate", UUID_TRUSTED_FWU_CERT, + "fwu-cert", NULL, FLAG_FILENAME}, { "Trusted Boot Firmware BL2", UUID_TRUSTED_BOOT_FIRMWARE_BL2, "bl2", NULL, FLAG_FILENAME }, { "SCP Firmware BL3-0", UUID_SCP_FIRMWARE_BL30, |