aboutsummaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorAchin Gupta <achin.gupta@arm.com>2013-11-25 18:45:02 +0000
committerDan Handley <dan.handley@arm.com>2013-12-05 12:28:50 +0000
commitc8afc789196cdd568e29aa1e54cb5d24be5adf70 (patch)
treec29ea6f222a2f76cda944ed976b6e734e393732e /common
parent994dfceb449a7b2fe34a1febd765cc5291172b39 (diff)
downloadarm-trusted-firmware-c8afc789196cdd568e29aa1e54cb5d24be5adf70.tar.gz
psci: fix error due to a non zero context id
In the previous psci implementation, the psci_afflvl_power_on_finish() function would run into an error condition if the value of the context id parameter in the cpu_on and cpu_suspend psci calls was != 0. The parameter was being restored as the return value of the affinity level 0 finisher function. A non zero context id would be treated as an error condition. This would prevent successful wake up of the cpu from a power down state. Also, the contents of the general purpose registers were not being cleared upon return to the non-secure world after a cpu power up. This could potentially allow the non-secure world to view secure data. This patch ensures that all general purpose registers are set to ~0 prior to the final eret that drops the execution to the non-secure world. The context id is used to initialize the general purpose register x0 prior to re-entry into the non-secure world and is no longer restored as a function return value. A platform helper (platform_get_stack()) has been introduced to facilitate this change. Change-Id: I2454911ffd75705d6aa8609a5d250d9b26fa097c
Diffstat (limited to 'common')
-rw-r--r--common/psci/psci_afflvl_on.c2
-rw-r--r--common/psci/psci_afflvl_suspend.c2
-rw-r--r--common/psci/psci_common.c20
-rw-r--r--common/psci/psci_entry.S9
-rw-r--r--common/psci/psci_private.h2
-rw-r--r--common/runtime_svc.c1
6 files changed, 27 insertions, 9 deletions
diff --git a/common/psci/psci_afflvl_on.c b/common/psci/psci_afflvl_on.c
index 7126b98..c118cab 100644
--- a/common/psci/psci_afflvl_on.c
+++ b/common/psci/psci_afflvl_on.c
@@ -337,7 +337,7 @@ static unsigned int psci_afflvl0_on_finish(unsigned long mpidr,
* for restoring the re-entry info
*/
index = cpu_node->data;
- rc = psci_get_ns_entry_info(index);
+ psci_get_ns_entry_info(index);
/* Clean caches before re-entering normal world */
dcsw_op_louis(DCCSW);
diff --git a/common/psci/psci_afflvl_suspend.c b/common/psci/psci_afflvl_suspend.c
index b68b4df..05b0aad 100644
--- a/common/psci/psci_afflvl_suspend.c
+++ b/common/psci/psci_afflvl_suspend.c
@@ -389,7 +389,7 @@ static unsigned int psci_afflvl0_suspend_finish(unsigned long mpidr,
* information that we had stashed away during the suspend
* call to set this cpu on it's way.
*/
- rc = psci_get_ns_entry_info(index);
+ psci_get_ns_entry_info(index);
/* Clean caches before re-entering normal world */
dcsw_op_louis(DCCSW);
diff --git a/common/psci/psci_common.c b/common/psci/psci_common.c
index 59126ba..8eb0213 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 <runtime_svc.h>
/*******************************************************************************
* Arrays that contains information needs to resume a cpu's execution when woken
@@ -280,9 +281,10 @@ unsigned int psci_calculate_affinity_state(aff_map_node *aff_node)
* resume a cpu's execution in the non-secure state after it has been physically
* powered on i.e. turned ON or resumed from SUSPEND
******************************************************************************/
-unsigned int psci_get_ns_entry_info(unsigned int index)
+void psci_get_ns_entry_info(unsigned int index)
{
unsigned long sctlr = 0, scr, el_status, id_aa64pfr0;
+ gp_regs *ns_gp_regs;
scr = read_scr();
@@ -318,10 +320,22 @@ unsigned int psci_get_ns_entry_info(unsigned int index)
/* Fulfill the cpu_on entry reqs. as per the psci spec */
write_scr(scr);
- write_spsr(psci_ns_entry_info[index].eret_info.spsr);
write_elr(psci_ns_entry_info[index].eret_info.entrypoint);
- return psci_ns_entry_info[index].context_id;
+ /*
+ * 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.
+ */
+ 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;
}
/*******************************************************************************
diff --git a/common/psci/psci_entry.S b/common/psci/psci_entry.S
index 2f39f36..74cdf95 100644
--- a/common/psci/psci_entry.S
+++ b/common/psci/psci_entry.S
@@ -32,6 +32,7 @@
#include <platform.h>
#include <psci.h>
#include <psci_private.h>
+#include <runtime_svc.h>
#include <asm_macros.S>
.globl psci_aff_on_finish_entry
@@ -77,7 +78,6 @@ psci_aff_common_finish_entry:
mov x0, x19
mov x1, #MPIDR_AFFLVL0
blr x22
- mov x21, x0
/* --------------------------------------------
* Give ourselves a stack allocated in Normal
@@ -88,10 +88,13 @@ psci_aff_common_finish_entry:
bl platform_set_stack
/* --------------------------------------------
- * Restore the context id. value
+ * Use the size of the general purpose register
+ * context to restore the register state
+ * stashed by earlier code
* --------------------------------------------
*/
- mov x0, x21
+ sub sp, sp, #SIZEOF_GPREGS
+ exception_exit restore_regs
/* --------------------------------------------
* Jump back to the non-secure world assuming
diff --git a/common/psci/psci_private.h b/common/psci/psci_private.h
index 4741397..e2100f8 100644
--- a/common/psci/psci_private.h
+++ b/common/psci/psci_private.h
@@ -108,7 +108,7 @@ extern int get_max_afflvl(void);
extern unsigned int psci_get_phys_state(unsigned int);
extern unsigned int psci_get_aff_phys_state(aff_map_node *);
extern unsigned int psci_calculate_affinity_state(aff_map_node *);
-extern unsigned int psci_get_ns_entry_info(unsigned int index);
+extern void psci_get_ns_entry_info(unsigned int index);
extern unsigned long mpidr_set_aff_inst(unsigned long,unsigned char, int);
extern int psci_change_state(unsigned long, int, int, unsigned int);
extern int psci_validate_mpidr(unsigned long, int);
diff --git a/common/runtime_svc.c b/common/runtime_svc.c
index 0aa4460..431cfa3 100644
--- a/common/runtime_svc.c
+++ b/common/runtime_svc.c
@@ -38,6 +38,7 @@
#include <semihosting.h>
#include <bl_common.h>
#include <psci.h>
+#include <runtime_svc.h>
/*******************************************************************************
* Perform initialization of runtime services possibly across exception levels