diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2014-04-15 19:18:43 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2014-04-17 21:34:04 +0100 |
commit | f502cfc207ff288ec1f3dac10024c51ffe64a65d (patch) | |
tree | 077d1d264d00c01eee62a9de83cd0a87bc525c83 /target-arm/internals.h | |
parent | a0618a1990e4df30a76cf5b441b4aa7f002b0d64 (diff) | |
download | qemu-f502cfc207ff288ec1f3dac10024c51ffe64a65d.zip |
target-arm: Implement SP_EL0, SP_EL1
Implement handling for the AArch64 SP_EL0 system register.
This holds the EL0 stack pointer, and is only accessible when
it's not being used as the stack pointer, ie when we're in EL1
and EL1 is using its own stack pointer. We also provide a
definition of the SP_EL1 register; this isn't guest visible
as a system register for an implementation like QEMU which
doesn't provide EL2 or EL3; however it is useful for ensuring
the underlying state is migrated.
We need to update the state fields in the CPU state whenever
we switch stack pointers; this happens when we take an exception
and also when SPSEL is used to change the bit in PSTATE which
indicates which stack pointer EL1 should use.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Diffstat (limited to 'target-arm/internals.h')
-rw-r--r-- | target-arm/internals.h | 25 |
1 files changed, 25 insertions, 0 deletions
diff --git a/target-arm/internals.h b/target-arm/internals.h index a527f02ff5..de79dfc316 100644 --- a/target-arm/internals.h +++ b/target-arm/internals.h @@ -60,6 +60,31 @@ enum arm_fprounding { int arm_rmode_to_sf(int rmode); +static inline void update_spsel(CPUARMState *env, uint32_t imm) +{ + /* Update PSTATE SPSel bit; this requires us to update the + * working stack pointer in xregs[31]. + */ + if (!((imm ^ env->pstate) & PSTATE_SP)) { + return; + } + env->pstate = deposit32(env->pstate, 0, 1, imm); + + /* EL0 has no access rights to update SPSel, and this code + * assumes we are updating SP for EL1 while running as EL1. + */ + assert(arm_current_pl(env) == 1); + if (env->pstate & PSTATE_SP) { + /* Switch from using SP_EL0 to using SP_ELx */ + env->sp_el[0] = env->xregs[31]; + env->xregs[31] = env->sp_el[1]; + } else { + /* Switch from SP_EL0 to SP_ELx */ + env->sp_el[1] = env->xregs[31]; + env->xregs[31] = env->sp_el[0]; + } +} + /* Valid Syndrome Register EC field values */ enum arm_exception_class { EC_UNCATEGORIZED = 0x00, |