Commit c8afc789 authored by Achin Gupta's avatar Achin Gupta Committed by Dan Handley
Browse files

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
parent 994dfceb
...@@ -337,7 +337,7 @@ static unsigned int psci_afflvl0_on_finish(unsigned long mpidr, ...@@ -337,7 +337,7 @@ static unsigned int psci_afflvl0_on_finish(unsigned long mpidr,
* for restoring the re-entry info * for restoring the re-entry info
*/ */
index = cpu_node->data; index = cpu_node->data;
rc = psci_get_ns_entry_info(index); psci_get_ns_entry_info(index);
/* Clean caches before re-entering normal world */ /* Clean caches before re-entering normal world */
dcsw_op_louis(DCCSW); dcsw_op_louis(DCCSW);
......
...@@ -389,7 +389,7 @@ static unsigned int psci_afflvl0_suspend_finish(unsigned long mpidr, ...@@ -389,7 +389,7 @@ static unsigned int psci_afflvl0_suspend_finish(unsigned long mpidr,
* information that we had stashed away during the suspend * information that we had stashed away during the suspend
* call to set this cpu on it's way. * 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 */ /* Clean caches before re-entering normal world */
dcsw_op_louis(DCCSW); dcsw_op_louis(DCCSW);
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <platform.h> #include <platform.h>
#include <psci.h> #include <psci.h>
#include <psci_private.h> #include <psci_private.h>
#include <runtime_svc.h>
/******************************************************************************* /*******************************************************************************
* Arrays that contains information needs to resume a cpu's execution when woken * 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) ...@@ -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 * 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 * 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; unsigned long sctlr = 0, scr, el_status, id_aa64pfr0;
gp_regs *ns_gp_regs;
scr = read_scr(); scr = read_scr();
...@@ -318,10 +320,22 @@ unsigned int psci_get_ns_entry_info(unsigned int index) ...@@ -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 */ /* Fulfill the cpu_on entry reqs. as per the psci spec */
write_scr(scr); write_scr(scr);
write_spsr(psci_ns_entry_info[index].eret_info.spsr);
write_elr(psci_ns_entry_info[index].eret_info.entrypoint); 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;
} }
/******************************************************************************* /*******************************************************************************
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <platform.h> #include <platform.h>
#include <psci.h> #include <psci.h>
#include <psci_private.h> #include <psci_private.h>
#include <runtime_svc.h>
#include <asm_macros.S> #include <asm_macros.S>
.globl psci_aff_on_finish_entry .globl psci_aff_on_finish_entry
...@@ -77,7 +78,6 @@ psci_aff_common_finish_entry: ...@@ -77,7 +78,6 @@ psci_aff_common_finish_entry:
mov x0, x19 mov x0, x19
mov x1, #MPIDR_AFFLVL0 mov x1, #MPIDR_AFFLVL0
blr x22 blr x22
mov x21, x0
/* -------------------------------------------- /* --------------------------------------------
* Give ourselves a stack allocated in Normal * Give ourselves a stack allocated in Normal
...@@ -88,10 +88,13 @@ psci_aff_common_finish_entry: ...@@ -88,10 +88,13 @@ psci_aff_common_finish_entry:
bl platform_set_stack 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 * Jump back to the non-secure world assuming
......
...@@ -108,7 +108,7 @@ extern int get_max_afflvl(void); ...@@ -108,7 +108,7 @@ extern int get_max_afflvl(void);
extern unsigned int psci_get_phys_state(unsigned int); extern unsigned int psci_get_phys_state(unsigned int);
extern unsigned int psci_get_aff_phys_state(aff_map_node *); 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_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 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_change_state(unsigned long, int, int, unsigned int);
extern int psci_validate_mpidr(unsigned long, int); extern int psci_validate_mpidr(unsigned long, int);
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include <semihosting.h> #include <semihosting.h>
#include <bl_common.h> #include <bl_common.h>
#include <psci.h> #include <psci.h>
#include <runtime_svc.h>
/******************************************************************************* /*******************************************************************************
* Perform initialization of runtime services possibly across exception levels * Perform initialization of runtime services possibly across exception levels
......
...@@ -52,6 +52,10 @@ Detailed changes since last release ...@@ -52,6 +52,10 @@ Detailed changes since last release
* Definitions of some constants related to the PSCI api calls AFFINITY_INFO * Definitions of some constants related to the PSCI api calls AFFINITY_INFO
and CPU_SUSPEND have been corrected. and CPU_SUSPEND have been corrected.
* A bug which triggered an error condition in the code executed after a cpu
is powered on, if a non zero context id parameter was passed in the PSCI
CPU_ON and CPU_SUSPEND api calls has been corrected.
ARM Trusted Firmware - version 0.2 ARM Trusted Firmware - version 0.2
================================== ==================================
......
...@@ -188,8 +188,9 @@ the implementer chooses. In the ARM FVP port, they are implemented in ...@@ -188,8 +188,9 @@ the implementer chooses. In the ARM FVP port, they are implemented in
bytes) of the largest cache line amongst all caches implemented in the bytes) of the largest cache line amongst all caches implemented in the
system. A pointer to this memory should be exported with the name system. A pointer to this memory should be exported with the name
`platform_normal_stacks`. This pointer is used by the common platform helper `platform_normal_stacks`. This pointer is used by the common platform helper
function `platform_set_stack()` to allocate a stack to each CPU in the functions `platform_set_stack()` (to allocate a stack for each CPU in the
platform (see [../plat/common/aarch64/platform_helpers.S]). platform) & `platform_get_stack()` (to return the base address of that
stack) (see [../plat/common/aarch64/platform_helpers.S]).
2.2 Common optional modifications 2.2 Common optional modifications
...@@ -262,6 +263,20 @@ The size of the stack allocated to each CPU is specified by the platform defined ...@@ -262,6 +263,20 @@ The size of the stack allocated to each CPU is specified by the platform defined
constant `PLATFORM_STACK_SIZE`. constant `PLATFORM_STACK_SIZE`.
### Function : platform_get_stack()
Argument : unsigned long
Return : unsigned long
This function uses the `platform_normal_stacks` pointer variable to return the
base address of the stack memory reserved for a CPU. Further details are given
in the description of the `platform_normal_stacks` variable below. A CPU is
identified by its `MPIDR`, which is passed as the argument.
The size of the stack allocated to each CPU is specified by the platform defined
constant `PLATFORM_STACK_SIZE`.
### Function : plat_report_exception() ### Function : plat_report_exception()
Argument : unsigned int Argument : unsigned int
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
.globl pcpu_dv_mem_stack .globl pcpu_dv_mem_stack
.weak platform_get_core_pos .weak platform_get_core_pos
.weak platform_set_stack .weak platform_set_stack
.weak platform_get_stack
.weak platform_is_primary_cpu .weak platform_is_primary_cpu
.weak platform_set_coherent_stack .weak platform_set_coherent_stack
.weak platform_check_mpidr .weak platform_check_mpidr
...@@ -95,19 +96,28 @@ platform_is_primary_cpu:; .type platform_is_primary_cpu, %function ...@@ -95,19 +96,28 @@ platform_is_primary_cpu:; .type platform_is_primary_cpu, %function
cset x0, eq cset x0, eq
ret ret
/* ----------------------------------------------------- /* -----------------------------------------------------
* void platform_set_stack (int mpidr) * void platform_get_stack (unsigned long mpidr)
* ----------------------------------------------------- * -----------------------------------------------------
*/ */
platform_set_stack:; .type platform_set_stack, %function platform_get_stack:; .type platform_get_stack, %function
mov x9, x30 // lr mov x10, x30 // lr
bl platform_get_core_pos bl platform_get_core_pos
add x0, x0, #1 add x0, x0, #1
mov x1, #PLATFORM_STACK_SIZE mov x1, #PLATFORM_STACK_SIZE
mul x0, x0, x1 mul x0, x0, x1
ldr x1, =platform_normal_stacks ldr x1, =platform_normal_stacks
add sp, x1, x0 add x0, x1, x0
ret x10
/* -----------------------------------------------------
* void platform_set_stack (unsigned long mpidr)
* -----------------------------------------------------
*/
platform_set_stack:; .type platform_set_stack, %function
mov x9, x30 // lr
bl platform_get_stack
mov sp, x0
ret x9 ret x9
/* ----------------------------------------------------- /* -----------------------------------------------------
......
...@@ -331,6 +331,7 @@ extern unsigned long platform_get_cfgvar(unsigned int); ...@@ -331,6 +331,7 @@ extern unsigned long platform_get_cfgvar(unsigned int);
extern int platform_config_setup(void); extern int platform_config_setup(void);
extern void plat_report_exception(unsigned long); extern void plat_report_exception(unsigned long);
extern unsigned long plat_get_ns_image_entrypoint(void); extern unsigned long plat_get_ns_image_entrypoint(void);
extern unsigned long platform_get_stack(unsigned long mpidr);
/* Declarations for fvp_topology.c */ /* Declarations for fvp_topology.c */
extern int plat_setup_topology(void); extern int plat_setup_topology(void);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment