diff options
author | Jeenu Viswambharan <jeenu.viswambharan@arm.com> | 2014-02-06 10:36:15 +0000 |
---|---|---|
committer | Dan Handley <dan.handley@arm.com> | 2014-02-17 18:51:44 +0000 |
commit | caa84939a4d8b1189dea8619ccc57bdb3026b125 (patch) | |
tree | a7eb5e977cc9971c051ef469877fc3d00cba24ad /common/psci/psci_common.c | |
parent | 07f4e078b6871e5c74f6cb38f2726a2cfcb2b746 (diff) |
Add support for handling runtime service requests
This patch uses the reworked exception handling support to handle
runtime service requests through SMCs following the SMC calling
convention. This is a giant commit since all the changes are
inter-related. It does the following:
1. Replace the old exception handling mechanism with the new one
2. Enforce that SP_EL0 is used C runtime stacks.
3. Ensures that the cold and warm boot paths use the 'cpu_context'
structure to program an ERET into the next lower EL.
4. Ensures that SP_EL3 always points to the next 'cpu_context'
structure prior to an ERET into the next lower EL
5. Introduces a PSCI SMC handler which completes the use of PSCI as a
runtime service
Change-Id: I661797f834c0803d2c674d20f504df1b04c2b852
Co-authored-by: Achin Gupta <achin.gupta@arm.com>
Diffstat (limited to 'common/psci/psci_common.c')
-rw-r--r-- | common/psci/psci_common.c | 49 |
1 files changed, 28 insertions, 21 deletions
diff --git a/common/psci/psci_common.c b/common/psci/psci_common.c index 193655dd..214db780 100644 --- a/common/psci/psci_common.c +++ b/common/psci/psci_common.c @@ -36,6 +36,7 @@ #include <platform.h> #include <psci.h> #include <psci_private.h> +#include <context_mgmt.h> #include <runtime_svc.h> #include "debug.h" @@ -86,7 +87,8 @@ int get_power_on_target_afflvl(unsigned long mpidr) unsigned int state; /* Retrieve our node from the topology tree */ - node = psci_get_aff_map_node(mpidr & MPIDR_AFFINITY_MASK, MPIDR_AFFLVL0); + node = psci_get_aff_map_node(mpidr & MPIDR_AFFINITY_MASK, + MPIDR_AFFLVL0); assert(node); /* @@ -222,13 +224,12 @@ int psci_validate_mpidr(unsigned long mpidr, int level) void psci_get_ns_entry_info(unsigned int index) { unsigned long sctlr = 0, scr, el_status, id_aa64pfr0; - gp_regs *ns_gp_regs; + uint64_t mpidr = read_mpidr(); + cpu_context *ns_entry_context; + gp_regs *ns_entry_gpregs; scr = read_scr(); - /* Switch to the non-secure view of the registers */ - write_scr(scr | SCR_NS_BIT); - /* Find out which EL we are going to */ id_aa64pfr0 = read_id_aa64pfr0_el1(); el_status = (id_aa64pfr0 >> ID_AA64PFR0_EL2_SHIFT) & @@ -257,23 +258,29 @@ void psci_get_ns_entry_info(unsigned int index) write_sctlr_el1(sctlr); /* Fulfill the cpu_on entry reqs. as per the psci spec */ - write_scr(scr); - write_elr(psci_ns_entry_info[index].eret_info.entrypoint); + ns_entry_context = (cpu_context *) cm_get_context(mpidr, NON_SECURE); + assert(ns_entry_context); /* - * Set the general purpose registers to ~0 upon entry into the - * non-secure world except for x0 which should contain the - * context id & spsr. This is done directly on the "would be" - * stack pointer. Prior to entry into the non-secure world, an - * offset equivalent to the size of the 'gp_regs' structure is - * added to the sp. This general purpose register context is - * retrieved then. + * Setup general purpose registers to return the context id and + * prevent leakage of secure information into the normal world. */ - ns_gp_regs = (gp_regs *) platform_get_stack(read_mpidr()); - ns_gp_regs--; - memset(ns_gp_regs, ~0, sizeof(*ns_gp_regs)); - ns_gp_regs->x0 = psci_ns_entry_info[index].context_id; - ns_gp_regs->spsr = psci_ns_entry_info[index].eret_info.spsr; + ns_entry_gpregs = get_gpregs_ctx(ns_entry_context); + write_ctx_reg(ns_entry_gpregs, + CTX_GPREG_X0, + psci_ns_entry_info[index].context_id); + + /* + * Tell the context management library to setup EL3 system registers to + * be able to ERET into the ns state, and SP_EL3 points to the right + * context to exit from EL3 correctly. + */ + cm_set_el3_eret_context(NON_SECURE, + psci_ns_entry_info[index].eret_info.entrypoint, + psci_ns_entry_info[index].eret_info.spsr, + scr); + + cm_set_next_eret_context(NON_SECURE); } /******************************************************************************* @@ -344,7 +351,7 @@ int psci_set_ns_entry_info(unsigned int index, */ spsr |= DAIF_ABT_BIT | DAIF_IRQ_BIT | DAIF_FIQ_BIT; spsr <<= PSR_DAIF_SHIFT; - if(ee) + if (ee) spsr |= SPSR32_EE_BIT; spsr |= mode; @@ -500,7 +507,7 @@ void psci_afflvl_power_on_finish(unsigned long mpidr, mpidr_aff_map_nodes mpidr_nodes; int rc; - mpidr &= MPIDR_AFFINITY_MASK;; + mpidr &= MPIDR_AFFINITY_MASK; /* * Collect the pointers to the nodes in the topology tree for |