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
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 @@
  * 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 @@
 
 	/* 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;
 }
 
 /*******************************************************************************