void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { /* Initialize the debug console as soon as possible */ console_16550_register(SUNXI_UART0_BASE, SUNXI_UART0_CLK_IN_HZ, SUNXI_UART0_BAUDRATE, &console); #ifdef BL32_BASE /* Populate entry point information for BL32 */ SET_PARAM_HEAD(&bl32_image_ep_info, PARAM_EP, VERSION_1, 0); SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE); bl32_image_ep_info.pc = BL32_BASE; #endif /* Populate entry point information for BL33 */ SET_PARAM_HEAD(&bl33_image_ep_info, PARAM_EP, VERSION_1, 0); /* * Tell BL31 where the non-trusted software image * is located and the entry state information */ bl33_image_ep_info.pc = plat_get_ns_image_entrypoint(); bl33_image_ep_info.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); /* Turn off all secondary CPUs */ sunxi_disable_secondary_cpus(plat_my_core_pos()); }
void bl1_plat_set_ep_info(unsigned int image_id, entry_point_info_t *ep_info) { unsigned int data = 0; uintptr_t tmp = HIKEY960_NS_TMP_OFFSET; if (image_id != NS_BL1U_IMAGE_ID) panic(); /* Copy NS BL1U from 0x1AC1_8000 to 0x1AC9_8000 */ memcpy((void *)tmp, (void *)HIKEY960_NS_IMAGE_OFFSET, NS_BL1U_SIZE); memcpy((void *)NS_BL1U_BASE, (void *)tmp, NS_BL1U_SIZE); inv_dcache_range(NS_BL1U_BASE, NS_BL1U_SIZE); /* Initialize the GIC driver, cpu and distributor interfaces */ gicv2_driver_init(&hikey960_gic_data); gicv2_distif_init(); gicv2_pcpu_distif_init(); gicv2_cpuif_enable(); /* CNTFRQ is read-only in EL1 */ write_cntfrq_el0(plat_get_syscnt_freq2()); data = read_cpacr_el1(); do { data |= 3 << 20; write_cpacr_el1(data); data = read_cpacr_el1(); } while ((data & (3 << 20)) != (3 << 20)); INFO("cpacr_el1:0x%x\n", data); ep_info->args.arg0 = 0xffff & read_mpidr(); ep_info->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); }
/******************************************************************************* * Given a secure payload entrypoint, register width, cpu id & pointer to a * context data structure, this function will create a secure context ready for * programming an entry into the secure payload. ******************************************************************************/ void tlkd_init_tlk_ep_state(struct entry_point_info *tlk_entry_point, uint32_t rw, uint64_t pc, tlk_context_t *tlk_ctx) { uint32_t ep_attr, spsr; /* Passing a NULL context is a critical programming error */ assert(tlk_ctx); assert(tlk_entry_point); assert(pc); /* Associate this context with the cpu specified */ tlk_ctx->mpidr = read_mpidr_el1(); clr_std_smc_active_flag(tlk_ctx->state); cm_set_context(&tlk_ctx->cpu_ctx, SECURE); if (rw == SP_AARCH64) spsr = SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); else spsr = SPSR_MODE32(MODE32_svc, SPSR_T_ARM, read_sctlr_el3() & SCTLR_EE_BIT, DISABLE_ALL_EXCEPTIONS); /* initialise an entrypoint to set up the CPU context */ ep_attr = SECURE | EP_ST_ENABLE; if (read_sctlr_el3() & SCTLR_EE_BIT) ep_attr |= EP_EE_BIG; SET_PARAM_HEAD(tlk_entry_point, PARAM_EP, VERSION_1, ep_attr); tlk_entry_point->pc = pc; tlk_entry_point->spsr = spsr; }
/******************************************************************************* * Before calling this function BL31 is loaded in memory and its entrypoint * is set by load_image. This is a placeholder for the platform to change * the entrypoint of BL31 and set SPSR and security state. * On ARM standard platforms we only set the security state of the entrypoint ******************************************************************************/ void bl2_plat_set_bl31_ep_info(image_info_t *bl31_image_info, entry_point_info_t *bl31_ep_info) { SET_SECURITY_STATE(bl31_ep_info->h.attr, SECURE); bl31_ep_info->spsr = SPSR_64(MODE_EL3, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); }
/******************************************************************************* * 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_sel1_intr_entry()' for handling the interrupt. ******************************************************************************/ static uint64_t tspd_sel1_interrupt_handler(uint32_t id, uint32_t flags, void *handle, void *cookie) { uint32_t linear_id; tsp_context_t *tsp_ctx; /* Check the security state when the exception was generated */ assert(get_interrupt_src_ss(flags) == NON_SECURE); /* Sanity check the pointer to this cpu's context */ assert(handle == cm_get_context(NON_SECURE)); /* Save the non-secure context before entering the TSP */ cm_el1_sysregs_context_save(NON_SECURE); /* Get a reference to this cpu's TSP context */ linear_id = plat_my_core_pos(); tsp_ctx = &tspd_sp_context[linear_id]; assert(&tsp_ctx->cpu_ctx == cm_get_context(SECURE)); /* * 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 * 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 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->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 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_SEL1_INTR_AND_RETURN, read_elr_el3()); }
/******************************************************************************* * This function determines the full entrypoint information for the requested * PSCI entrypoint on power on/resume and returns it. ******************************************************************************/ static int psci_get_ns_ep_info(entry_point_info_t *ep, uintptr_t entrypoint, u_register_t context_id) { unsigned long ep_attr, sctlr; unsigned int daif, ee, mode; unsigned long ns_scr_el3 = read_scr_el3(); unsigned long ns_sctlr_el1 = read_sctlr_el1(); sctlr = ns_scr_el3 & SCR_HCE_BIT ? read_sctlr_el2() : ns_sctlr_el1; ee = 0; ep_attr = NON_SECURE | EP_ST_DISABLE; if (sctlr & SCTLR_EE_BIT) { ep_attr |= EP_EE_BIG; ee = 1; } SET_PARAM_HEAD(ep, PARAM_EP, VERSION_1, ep_attr); ep->pc = entrypoint; memset(&ep->args, 0, sizeof(ep->args)); ep->args.arg0 = context_id; /* * Figure out whether the cpu enters the non-secure address space * in aarch32 or aarch64 */ if (ns_scr_el3 & SCR_RW_BIT) { /* * Check whether a Thumb entry point has been provided for an * aarch64 EL */ if (entrypoint & 0x1) return PSCI_E_INVALID_ADDRESS; mode = ns_scr_el3 & SCR_HCE_BIT ? MODE_EL2 : MODE_EL1; ep->spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); } else { mode = ns_scr_el3 & SCR_HCE_BIT ? MODE32_hyp : MODE32_svc; /* * TODO: Choose async. exception bits if HYP mode is not * implemented according to the values of SCR.{AW, FW} bits */ daif = DAIF_ABT_BIT | DAIF_IRQ_BIT | DAIF_FIQ_BIT; ep->spsr = SPSR_MODE32(mode, entrypoint & 0x1, ee, daif); } return PSCI_E_SUCCESS; }
/******************************************************************************* * This function changes the spsr for BL32 image to bypass * the check in BL1 AArch64 exception handler. This is needed in the aarch32 * boot flow as the core comes up in aarch64 and to enter the BL32 image a warm * reset in aarch32 state is required. ******************************************************************************/ int bl2_plat_handle_post_image_load(unsigned int image_id) { int err = arm_bl2_handle_post_image_load(image_id); if (!err && (image_id == BL32_IMAGE_ID)) { bl_mem_params_node_t *bl_mem_params = get_bl_mem_params_node(image_id); assert(bl_mem_params); bl_mem_params->ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); } return err; }
uint32_t tee_svc_sys_return_helper(uint32_t ret, bool panic, uint32_t panic_code, struct thread_svc_regs *regs) { if (panic) { TAMSG("TA panicked with code 0x%x usr_sp 0x%" PRIx64 " usr_lr 0x%" PRIx64, panic_code, regs->x13, regs->x14); } regs->x1 = panic; regs->x2 = panic_code; regs->elr = (uintptr_t)thread_unwind_user_mode; regs->spsr = SPSR_64(SPSR_64_MODE_EL1, SPSR_64_MODE_SP_EL0, 0); regs->spsr |= read_daif(); return ret; }
/* get SPSR for BL33 entry */ static uint32_t get_spsr_for_bl33_entry(void) { unsigned long el_status; unsigned long mode; uint32_t spsr; /* figure out what mode we enter the non-secure world */ el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT; el_status &= ID_AA64PFR0_ELX_MASK; mode = (el_status) ? MODE_EL2 : MODE_EL1; spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); return spsr; }
uint32_t hikey_get_spsr_for_bl33_entry(void) { unsigned int mode; uint32_t spsr; /* Figure out what mode we enter the non-secure world in */ mode = EL_IMPLEMENTED(2) ? MODE_EL2 : MODE_EL1; /* * TODO: Consider the possibility of specifying the SPSR in * the FIP ToC and allowing the platform to have a say as * well. */ spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); return spsr; }
/******************************************************************************* * This function prepare boot argument for 64 bit kernel entry ******************************************************************************/ static entry_point_info_t *bl31_plat_get_next_kernel64_ep_info(void) { entry_point_info_t *next_image_info; unsigned long el_status; unsigned int mode; el_status = 0; mode = 0; /* Kernel image is always non-secured */ next_image_info = &bl33_image_ep_info; /* Figure out what mode we enter the non-secure world in */ el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT; el_status &= ID_AA64PFR0_ELX_MASK; if (el_status) { INFO("Kernel_EL2\n"); mode = MODE_EL2; } else{ INFO("Kernel_EL1\n"); mode = MODE_EL1; } INFO("Kernel is 64Bit\n"); next_image_info->spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); next_image_info->pc = get_kernel_info_pc(); next_image_info->args.arg0 = get_kernel_info_r0(); next_image_info->args.arg1 = get_kernel_info_r1(); INFO("pc=0x%lx, r0=0x%lx, r1=0x%lx\n", next_image_info->pc, next_image_info->args.arg0, next_image_info->args.arg1); SET_SECURITY_STATE(next_image_info->h.attr, NON_SECURE); /* None of the images on this platform can have 0x0 as the entrypoint */ if (next_image_info->pc) return next_image_info; else return NULL; }
/******************************************************************************* * Perform any BL31 specific platform actions. Here is an opportunity to copy * parameters passed by the calling EL (S-EL1 in BL2 & S-EL3 in BL1) before they * are lost (potentially). This needs to be done before the MMU is initialized * so that the memory layout can be used while creating page tables. On the ZYNQMP * we know that BL2 has populated the parameters in secure DRAM. So we just use * the reference passed in 'from_bl2' instead of copying. The 'data' parameter * is not used since all the information is contained in 'from_bl2'. Also, BL2 * has flushed this information to memory, so we are guaranteed to pick up good * data ******************************************************************************/ void bl31_early_platform_setup(bl31_params_t *from_bl2, void *plat_params_from_bl2) { /* Initialize the console to provide early debug support */ console_init(RDO_UART0_BASE, zynqmp_get_uart_clk(), CADENCE_UART_BAUDRATE); /* Initialize the platform config for future decision making */ zynqmp_config_setup(); /* There are no parameters from BL2 if BL31 is a reset vector */ assert(from_bl2 == NULL); assert(plat_params_from_bl2 == NULL); /* * Do initial security configuration to allow DRAM/device access. On * Base ZYNQMP only DRAM security is programmable (via TrustZone), but * other platforms might have more programmable security devices * present. */ /* Populate entry point information for BL32 and BL33 */ SET_PARAM_HEAD(&bl32_image_ep_info, PARAM_EP, VERSION_1, 0); SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE); bl32_image_ep_info.pc = BL32_BASE; bl32_image_ep_info.spsr = arm_get_spsr_for_bl32_entry(); NOTICE("BL31: Secure code at 0x%lx\n", bl32_image_ep_info.pc); SET_PARAM_HEAD(&bl33_image_ep_info, PARAM_EP, VERSION_1, 0); /* * Tell BL31 where the non-trusted software image * is located and the entry state information */ bl33_image_ep_info.pc = plat_get_ns_image_entrypoint(); bl33_image_ep_info.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); NOTICE("BL31: Non secure code at 0x%lx\n", bl33_image_ep_info.pc); }
/* * Perform any BL31 specific platform actions. Here is an opportunity to copy * parameters passed by the calling EL (S-EL1 in BL2 & S-EL3 in BL1) before they * are lost (potentially). This needs to be done before the MMU is initialized * so that the memory layout can be used while creating page tables. */ void bl31_early_platform_setup(bl31_params_t *from_bl2, void *plat_params_from_bl2) { /* Initialize the console to provide early debug support */ console_init(ZYNQMP_UART_BASE, zynqmp_get_uart_clk(), ZYNQMP_UART_BAUDRATE); /* Initialize the platform config for future decision making */ zynqmp_config_setup(); /* There are no parameters from BL2 if BL31 is a reset vector */ assert(from_bl2 == NULL); assert(plat_params_from_bl2 == NULL); /* * Do initial security configuration to allow DRAM/device access. On * Base ZYNQMP only DRAM security is programmable (via TrustZone), but * other platforms might have more programmable security devices * present. */ /* Populate common information for BL32 and BL33 */ SET_PARAM_HEAD(&bl32_image_ep_info, PARAM_EP, VERSION_1, 0); SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE); SET_PARAM_HEAD(&bl33_image_ep_info, PARAM_EP, VERSION_1, 0); SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); if (zynqmp_get_bootmode() == ZYNQMP_BOOTMODE_JTAG) { /* use build time defaults in JTAG boot mode */ bl32_image_ep_info.pc = BL32_BASE; bl32_image_ep_info.spsr = arm_get_spsr_for_bl32_entry(); bl33_image_ep_info.pc = plat_get_ns_image_entrypoint(); bl33_image_ep_info.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); } else { /* use parameters from FSBL */ fsbl_atf_handover(&bl32_image_ep_info, &bl33_image_ep_info); } NOTICE("BL31: Secure code at 0x%lx\n", bl32_image_ep_info.pc); NOTICE("BL31: Non secure code at 0x%lx\n", bl33_image_ep_info.pc); }
/******************************************************************************* * Gets SPSR for BL33 entry ******************************************************************************/ uint32_t arm_get_spsr_for_bl33_entry(void) { unsigned long el_status; unsigned int mode; uint32_t spsr; /* Figure out what mode we enter the non-secure world in */ el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT; el_status &= ID_AA64PFR0_ELX_MASK; mode = (el_status) ? MODE_EL2 : MODE_EL1; /* * TODO: Consider the possibility of specifying the SPSR in * the FIP ToC and allowing the platform to have a say as * well. */ spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); return spsr; }
/******************************************************************************* * Given a secure payload entrypoint info pointer, entry point PC, register * width, cpu id & pointer to a context data structure, this function will * initialize tsp context and entry point info for the secure payload ******************************************************************************/ void tspd_init_tsp_ep_state(struct entry_point_info *tsp_entry_point, uint32_t rw, uint64_t pc, tsp_context_t *tsp_ctx) { uint32_t ep_attr; /* Passing a NULL context is a critical programming error */ assert(tsp_ctx); assert(tsp_entry_point); assert(pc); /* * We support AArch64 TSP for now. * TODO: Add support for AArch32 TSP */ assert(rw == TSP_AARCH64); /* Associate this context with the cpu specified */ tsp_ctx->mpidr = read_mpidr_el1(); tsp_ctx->state = 0; set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_OFF); clr_yield_smc_active_flag(tsp_ctx->state); cm_set_context(&tsp_ctx->cpu_ctx, SECURE); /* initialise an entrypoint to set up the CPU context */ ep_attr = SECURE | EP_ST_ENABLE; if (read_sctlr_el3() & SCTLR_EE_BIT) ep_attr |= EP_EE_BIG; SET_PARAM_HEAD(tsp_entry_point, PARAM_EP, VERSION_1, ep_attr); tsp_entry_point->pc = pc; tsp_entry_point->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); zeromem(&tsp_entry_point->args, sizeof(tsp_entry_point->args)); }
/******************************************************************************* * Perform any BL3-1 early platform setup, such as console init and deciding on * memory layout. ******************************************************************************/ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { /* There are no parameters from BL2 if BL31 is a reset vector */ assert(arg0 == 0U); assert(arg1 == 0U); bl31_console_setup(); #ifdef BL32_BASE /* Populate entry point information for BL32 */ SET_PARAM_HEAD(&bl32_image_ep_info, PARAM_EP, VERSION_1, 0); bl32_image_ep_info.pc = BL32_BASE; bl32_image_ep_info.spsr = SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE); #endif /* Populate entry point information for BL33 */ SET_PARAM_HEAD(&bl33_image_ep_info, PARAM_EP, VERSION_1, 0); bl33_image_ep_info.pc = PRELOADED_BL33_BASE; bl33_image_ep_info.spsr = k3_get_spsr_for_bl33_entry(); SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); #ifdef K3_HW_CONFIG_BASE /* * According to the file ``Documentation/arm64/booting.txt`` of the * Linux kernel tree, Linux expects the physical address of the device * tree blob (DTB) in x0, while x1-x3 are reserved for future use and * must be 0. */ bl33_image_ep_info.args.arg0 = (u_register_t)K3_HW_CONFIG_BASE; bl33_image_ep_info.args.arg1 = 0U; bl33_image_ep_info.args.arg2 = 0U; bl33_image_ep_info.args.arg3 = 0U; #endif }
void bl2_plat_set_bl33_ep_info(image_info_t *image, entry_point_info_t *bl33_ep_info) { unsigned long el_status; unsigned int mode; /* Figure out what mode we enter the non-secure world in */ el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT; el_status &= ID_AA64PFR0_ELX_MASK; if (el_status) mode = MODE_EL2; else mode = MODE_EL1; /* * TODO: Consider the possibility of specifying the SPSR in * the FIP ToC and allowing the platform to have a say as * well. */ bl33_ep_info->spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); SET_SECURITY_STATE(bl33_ep_info->h.attr, NON_SECURE); }
/* * Handle SMC from a lower exception level to switch its execution state * (either from AArch64 to AArch32, or vice versa). * * smc_fid: * SMC function ID - either ARM_SIP_SVC_STATE_SWITCH_64 or * ARM_SIP_SVC_STATE_SWITCH_32. * pc_hi, pc_lo: * PC upon re-entry to the calling exception level; width dependent on the * calling exception level. * cookie_hi, cookie_lo: * Opaque pointer pairs received from the caller to pass it back, upon * re-entry. * handle: * Handle to saved context. */ int arm_execution_state_switch(unsigned int smc_fid, uint32_t pc_hi, uint32_t pc_lo, uint32_t cookie_hi, uint32_t cookie_lo, void *handle) { /* Execution state can be switched only if EL3 is AArch64 */ #ifdef AARCH64 int caller_64, from_el2, el, endianness, thumb = 0; u_register_t spsr, pc, scr, sctlr; entry_point_info_t ep; cpu_context_t *ctx = (cpu_context_t *) handle; el3_state_t *el3_ctx = get_el3state_ctx(ctx); /* That the SMC originated from NS is already validated by the caller */ /* * Disallow state switch if any of the secondaries have been brought up. */ if (psci_secondaries_brought_up()) goto exec_denied; spsr = read_ctx_reg(el3_ctx, CTX_SPSR_EL3); caller_64 = (GET_RW(spsr) == MODE_RW_64); if (caller_64) { /* * If the call originated from AArch64, expect 32-bit pointers when * switching to AArch32. */ if ((pc_hi != 0) || (cookie_hi != 0)) goto invalid_param; pc = pc_lo; /* Instruction state when entering AArch32 */ thumb = pc & 1; } else { /* Construct AArch64 PC */ pc = (((u_register_t) pc_hi) << 32) | pc_lo; } /* Make sure PC is 4-byte aligned, except for Thumb */ if ((pc & 0x3) && !thumb) goto invalid_param; /* * EL3 controls register width of the immediate lower EL only. Expect * this request from EL2/Hyp unless: * * - EL2 is not implemented; * - EL2 is implemented, but was disabled. This can be inferred from * SCR_EL3.HCE. */ from_el2 = caller_64 ? (GET_EL(spsr) == MODE_EL2) : (GET_M32(spsr) == MODE32_hyp); scr = read_ctx_reg(el3_ctx, CTX_SCR_EL3); if (!from_el2) { /* The call is from NS privilege level other than HYP */ /* * Disallow switching state if there's a Hypervisor in place; * this request must be taken up with the Hypervisor instead. */ if (scr & SCR_HCE_BIT) goto exec_denied; } /* * Return to the caller using the same endianness. Extract * endianness bit from the respective system control register * directly. */ sctlr = from_el2 ? read_sctlr_el2() : read_sctlr_el1(); endianness = !!(sctlr & SCTLR_EE_BIT); /* Construct SPSR for the exception state we're about to switch to */ if (caller_64) { int impl; /* * Switching from AArch64 to AArch32. Ensure this CPU implements * the target EL in AArch32. */ impl = from_el2 ? EL_IMPLEMENTED(2) : EL_IMPLEMENTED(1); if (impl != EL_IMPL_A64_A32) goto exec_denied; /* Return to the equivalent AArch32 privilege level */ el = from_el2 ? MODE32_hyp : MODE32_svc; spsr = SPSR_MODE32(el, thumb ? SPSR_T_THUMB : SPSR_T_ARM, endianness, DISABLE_ALL_EXCEPTIONS); } else { /* * Switching from AArch32 to AArch64. Since it's not possible to * implement an EL as AArch32-only (from which this call was * raised), it's safe to assume AArch64 is also implemented. */ el = from_el2 ? MODE_EL2 : MODE_EL1; spsr = SPSR_64(el, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); } /* * Use the context management library to re-initialize the existing * context with the execution state flipped. Since the library takes * entry_point_info_t pointer as the argument, construct a dummy one * with PC, state width, endianness, security etc. appropriately set. * Other entries in the entry point structure are irrelevant for * purpose. */ zeromem(&ep, sizeof(ep)); ep.pc = pc; ep.spsr = spsr; SET_PARAM_HEAD(&ep, PARAM_EP, VERSION_1, ((endianness ? EP_EE_BIG : EP_EE_LITTLE) | NON_SECURE | EP_ST_DISABLE)); /* * Re-initialize the system register context, and exit EL3 as if for the * first time. State switch is effectively a soft reset of the * calling EL. */ cm_init_my_context(&ep); cm_prepare_el3_exit(NON_SECURE); /* * State switch success. The caller of SMC wouldn't see the SMC * returning. Instead, execution starts at the supplied entry point, * with context pointers populated in registers 0 and 1. */ SMC_RET2(handle, cookie_hi, cookie_lo); invalid_param: SMC_RET1(handle, STATE_SW_E_PARAM); exec_denied: #endif /* State switch denied */ SMC_RET1(handle, STATE_SW_E_DENIED); }
/******************************************************************************* * This function is the handler registered for S-EL1 interrupts by the FIQD. It * validates the interrupt and upon success arranges entry into the TSP at * 'tsp_fiq_entry()' for handling the interrupt. ******************************************************************************/ static uint64_t fiqd_sel1_interrupt_handler(uint32_t id, uint32_t flags, void *handle, void *cookie) { unsigned int iar; /* Check the security state when the exception was generated */ assert(get_interrupt_src_ss(flags) == NON_SECURE); #if IMF_READ_INTERRUPT_ID /* Check the security status of the interrupt */ assert(plat_ic_get_interrupt_type(id) == INTR_TYPE_S_EL1); #endif /* Sanity check the pointer to this cpu's context */ assert(handle == cm_get_context(NON_SECURE)); /* Save the non-secure context before entering the TSP */ cm_el1_sysregs_context_save(NON_SECURE); iar = get_ack_info(); ack_sgi(iar); if(id == WDT_IRQ_BIT_ID) { /* FIX-ME : change 0xFE to the kernel online CPU mask */ fiq_smp_call_function(0xFE, aee_wdt_dump, 0, 0); aee_wdt_dump(); } if(id == FIQ_SMP_CALL_SGI) { fiq_icc_isr(); } SMC_RET0(handle); #if 0 /* Get a reference to this cpu's TSP context */ linear_id = platform_get_core_pos(mpidr); tsp_ctx = &fiqd_sp_context[linear_id]; assert(&tsp_ctx->cpu_ctx == cm_get_context(SECURE)); /* * 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 FIQD 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. */ 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); } cm_el1_sysregs_context_restore(SECURE); cm_set_elr_spsr_el3(SECURE, (uint64_t) &tsp_vectors->fiq_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(). */ SMC_RET2(&tsp_ctx->cpu_ctx, TSP_HANDLE_FIQ_AND_RETURN, read_elr_el3()); #endif }
entry_point_info_t *bl31_plat_get_next_kernel_ep_info(uint32_t type) { entry_point_info_t *next_image_info; unsigned long el_status; unsigned int mode; #if RESET_TO_BL31 next_image_info = (type == NON_SECURE) ? &bl33_entrypoint_info : &bl32_entrypoint_info; mt_get_entry_point_info(type, next_image_info); #else next_image_info = (type == NON_SECURE) ? bl2_to_bl31_params->bl33_ep_info : bl2_to_bl31_params->bl32_ep_info; #endif /* Figure out what mode we enter the non-secure world in */ el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT; el_status &= ID_AA64PFR0_ELX_MASK; if (el_status) mode = MODE_EL2; else mode = MODE_EL1; #if 0 if (0 == rw) { printf("LK is AArch32\n"); printf("LK start_addr=x0x%x\n", bl33_ep_info->pc); mode = MODE32_svc; ee = 0; /* * TODO: Choose async. exception bits if HYP mode is not * implemented according to the values of SCR.{AW, FW} bits */ daif = DAIF_ABT_BIT | DAIF_IRQ_BIT | DAIF_FIQ_BIT; bl33_ep_info->spsr = SPSR_MODE32(mode, 0, ee, daif); /* * Pass boot argument to LK * ldr w4, =pl_boot_argument * ldr w5, =BOOT_ARGUMENT_SIZE */ bl33_ep_info->args.arg4=(unsigned long)(uintptr_t)&pl_boot_argument; bl33_ep_info->args.arg5=(unsigned long)(uintptr_t)BOOT_ARGUMENT_SIZE; } else #endif { printf("Kernel is 64Bit\n"); next_image_info->spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); next_image_info->pc = get_kernel_info_pc(); next_image_info->args.arg0=get_kernel_info_r0(); next_image_info->args.arg1=get_kernel_info_r1(); printf("pc=0x%llx, r0=0x%llx, r1=0x%llx\n", next_image_info->pc, next_image_info->args.arg0, next_image_info->args.arg1); } SET_SECURITY_STATE(next_image_info->h.attr, NON_SECURE); /* None of the images on this platform can have 0x0 as the entrypoint */ if (next_image_info->pc) return next_image_info; else return NULL; }
.next_handoff_image_id = INVALID_IMAGE_ID, }, { .image_id = BL31_IMAGE_ID, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, 0), .image_info.image_base = BL31_BASE, .image_info.image_max_size = BL31_LIMIT - BL31_BASE, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, SECURE | EXECUTABLE | EP_FIRST_EXE), .ep_info.pc = BL31_BASE, .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS), #ifdef UNIPHIER_LOAD_BL32 .next_handoff_image_id = BL32_IMAGE_ID, #else .next_handoff_image_id = BL33_IMAGE_ID, #endif }, #ifdef UNIPHIER_LOAD_BL32 { .image_id = BL32_IMAGE_ID, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, 0), .image_info.image_base = BL32_BASE, .image_info.image_max_size = BL32_LIMIT - BL32_BASE,