aboutsummaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorJeenu Viswambharan <jeenu.viswambharan@arm.com>2014-02-06 10:36:15 +0000
committerDan Handley <dan.handley@arm.com>2014-02-17 18:51:44 +0000
commitcaa84939a4d8b1189dea8619ccc57bdb3026b125 (patch)
treea7eb5e977cc9971c051ef469877fc3d00cba24ad /common
parent07f4e078b6871e5c74f6cb38f2726a2cfcb2b746 (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')
-rw-r--r--common/psci/psci_common.c49
-rw-r--r--common/psci/psci_entry.S34
-rw-r--r--common/psci/psci_main.c70
-rw-r--r--common/psci/psci_private.h10
-rw-r--r--common/psci/psci_setup.c5
-rw-r--r--common/runtime_svc.c3
6 files changed, 129 insertions, 42 deletions
diff --git a/common/psci/psci_common.c b/common/psci/psci_common.c
index 193655d..214db78 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
diff --git a/common/psci/psci_entry.S b/common/psci/psci_entry.S
index 28a4143..15e074c 100644
--- a/common/psci/psci_entry.S
+++ b/common/psci/psci_entry.S
@@ -34,6 +34,7 @@
#include <psci_private.h>
#include <runtime_svc.h>
#include <asm_macros.S>
+#include <cm_macros.S>
.globl psci_aff_on_finish_entry
.globl psci_aff_suspend_finish_entry
@@ -74,6 +75,13 @@ psci_aff_common_finish_entry:
msr vbar_el3, x0
isb
+ /* ---------------------------------------------
+ * Use SP_EL0 for the C runtime stack.
+ * ---------------------------------------------
+ */
+ msr spsel, #0
+ isb
+
bl read_mpidr
mov x19, x0
bl platform_set_coherent_stack
@@ -102,31 +110,19 @@ psci_aff_common_finish_entry:
bl platform_set_stack
/* ---------------------------------------------
- * Now that the execution stack has been set
+ * Now that the context management has been set
* up, enable full runtime exception handling.
- * Since we're just about to leave this EL with
- * ERET, we don't need an ISB here
+ * SP_EL3 is pointing to a 'cpu_context'
+ * structure which has an exception stack
+ * allocated. Since we're just about to leave
+ * this EL with ERET, we don't need an ISB here
* ---------------------------------------------
*/
adr x0, runtime_exceptions
msr vbar_el3, x0
- /* --------------------------------------------
- * Use the size of the general purpose register
- * context to restore the register state
- * stashed by earlier code
- * --------------------------------------------
- */
- sub sp, sp, #SIZEOF_GPREGS
- exception_exit restore_regs
-
- /* --------------------------------------------
- * Jump back to the non-secure world assuming
- * that the elr and spsr setup has been done
- * by the finishers
- * --------------------------------------------
- */
- eret
+ zero_callee_saved_regs
+ b el3_exit
_panic:
b _panic
diff --git a/common/psci/psci_main.c b/common/psci/psci_main.c
index a70a21a..67f189d 100644
--- a/common/psci/psci_main.c
+++ b/common/psci/psci_main.c
@@ -35,6 +35,9 @@
#include <console.h>
#include <platform.h>
#include <psci_private.h>
+#include <runtime_svc.h>
+#include <debug.h>
+#include <context_mgmt.h>
/*******************************************************************************
* PSCI frontend api for servicing SMCs. Described in the PSCI spec.
@@ -199,3 +202,70 @@ void psci_system_reset(void)
assert(0);
}
+/*******************************************************************************
+ * PSCI top level handler for servicing SMCs.
+ ******************************************************************************/
+uint64_t psci_smc_handler(uint32_t smc_fid,
+ uint64_t x1,
+ uint64_t x2,
+ uint64_t x3,
+ uint64_t x4,
+ void *cookie,
+ void *handle,
+ uint64_t flags)
+{
+ uint64_t rc;
+
+ switch (smc_fid) {
+ case PSCI_VERSION:
+ rc = psci_version();
+ break;
+
+ case PSCI_CPU_OFF:
+ rc = __psci_cpu_off();
+ break;
+
+ case PSCI_CPU_SUSPEND_AARCH64:
+ case PSCI_CPU_SUSPEND_AARCH32:
+ rc = __psci_cpu_suspend(x1, x2, x3);
+ break;
+
+ case PSCI_CPU_ON_AARCH64:
+ case PSCI_CPU_ON_AARCH32:
+ rc = psci_cpu_on(x1, x2, x3);
+ break;
+
+ case PSCI_AFFINITY_INFO_AARCH32:
+ case PSCI_AFFINITY_INFO_AARCH64:
+ rc = psci_affinity_info(x1, x2);
+ break;
+
+ case PSCI_MIG_AARCH32:
+ case PSCI_MIG_AARCH64:
+ rc = psci_migrate(x1);
+ break;
+
+ case PSCI_MIG_INFO_TYPE:
+ rc = psci_migrate_info_type();
+ break;
+
+ case PSCI_MIG_INFO_UP_CPU_AARCH32:
+ case PSCI_MIG_INFO_UP_CPU_AARCH64:
+ rc = psci_migrate_info_up_cpu();
+ break;
+
+ case PSCI_SYSTEM_OFF:
+ psci_system_off();
+ assert(0);
+
+ case PSCI_SYSTEM_RESET:
+ psci_system_reset();
+ assert(0);
+
+ default:
+ rc = SMC_UNK;
+ WARN("Unimplemented psci call -> 0x%x \n", smc_fid);
+ }
+
+ SMC_RET1(handle, rc);
+}
diff --git a/common/psci/psci_private.h b/common/psci/psci_private.h
index de9c291..3d7ae74 100644
--- a/common/psci/psci_private.h
+++ b/common/psci/psci_private.h
@@ -151,6 +151,16 @@ extern int psci_afflvl_suspend(unsigned long,
int,
int);
extern unsigned int psci_afflvl_suspend_finish(unsigned long, int, int);
+
+/* Private exported functions from psci_main.c */
+extern uint64_t psci_smc_handler(uint32_t smc_fid,
+ uint64_t x1,
+ uint64_t x2,
+ uint64_t x3,
+ uint64_t x4,
+ void *cookie,
+ void *handle,
+ uint64_t flags);
#endif /*__ASSEMBLY__*/
#endif /* __PSCI_PRIVATE_H__ */
diff --git a/common/psci/psci_setup.c b/common/psci/psci_setup.c
index c471d1f..8d7903c 100644
--- a/common/psci/psci_setup.c
+++ b/common/psci/psci_setup.c
@@ -195,6 +195,9 @@ static void psci_init_aff_map_node(unsigned long mpidr,
cm_set_context(mpidr,
(void *) &psci_ns_context[linear_id],
NON_SECURE);
+
+ /* Initialize exception stack in the context */
+ cm_init_exception_stack(mpidr, NON_SECURE);
}
return;
@@ -348,5 +351,5 @@ DECLARE_RT_SVC(
OEN_STD_END,
SMC_TYPE_FAST,
psci_setup,
- NULL
+ psci_smc_handler
);
diff --git a/common/runtime_svc.c b/common/runtime_svc.c
index 0ea1bf5..6e8a1bb 100644
--- a/common/runtime_svc.c
+++ b/common/runtime_svc.c
@@ -41,6 +41,7 @@
#include <runtime_svc.h>
#include <context.h>
#include <debug.h>
+#include <context_mgmt.h>
/*******************************************************************************
* The 'rt_svc_descs' array holds the runtime service descriptors exported by
@@ -146,7 +147,7 @@ error:
void fault_handler(void *handle)
{
- gp_regs_next *gpregs_ctx = get_gpregs_ctx(handle);
+ gp_regs *gpregs_ctx = get_gpregs_ctx(handle);
ERROR("Unhandled synchronous fault. Register dump @ 0x%x \n",
gpregs_ctx);
panic();