summaryrefslogtreecommitdiff
path: root/src/arch/arm/insts/static_inst.cc
diff options
context:
space:
mode:
authorAndreas Sandberg <andreas.sandberg@arm.com>2016-06-02 13:41:26 +0100
committerAndreas Sandberg <andreas.sandberg@arm.com>2016-06-02 13:41:26 +0100
commit660fbd543f7c84dec81cd17bdb4ff08f954aec77 (patch)
treea03fb18c83b32031b5331767e3067a026d641775 /src/arch/arm/insts/static_inst.cc
parentf48ad5b29d6f291b4f3679ff5fb7b5beae10d6fa (diff)
downloadgem5-660fbd543f7c84dec81cd17bdb4ff08f954aec77.tar.xz
arm: Rewrite ERET to behave according to the ARMv8 ARM
The ERET instruction doesn't set PSTATE correctly in some cases (particularly when returning to aarch32 code). Among other things, this breaks EL0 thumb code when using a 64-bit kernel. This changeset updates the ERET implementation to match the ARM ARM. Change-Id: I408e7c69a23cce437859313dfe84e68744b07c98 Signed-off-by: Andreas Sandberg <andreas.sandberg@arm.com> Reviewed-by: Nathanael Premillieu <nathanael.premillieu@arm.com>
Diffstat (limited to 'src/arch/arm/insts/static_inst.cc')
-rw-r--r--src/arch/arm/insts/static_inst.cc111
1 files changed, 111 insertions, 0 deletions
diff --git a/src/arch/arm/insts/static_inst.cc b/src/arch/arm/insts/static_inst.cc
index d4ea1bcdf..3defc07c2 100644
--- a/src/arch/arm/insts/static_inst.cc
+++ b/src/arch/arm/insts/static_inst.cc
@@ -727,4 +727,115 @@ ArmStaticInst::checkAdvSIMDOrFPEnabled32(ThreadContext *tc,
}
+static uint8_t
+getRestoredITBits(ThreadContext *tc, CPSR spsr)
+{
+ // See: shared/functions/system/RestoredITBits in the ARM ARM
+
+ const ExceptionLevel el = opModeToEL((OperatingMode) (uint8_t)spsr.mode);
+ const uint8_t it = itState(spsr);
+
+ if (!spsr.t || spsr.il)
+ return 0;
+
+ // The IT bits are forced to zero when they are set to a reserved
+ // value.
+ if (bits(it, 7, 4) != 0 && bits(it, 3, 0) == 0)
+ return 0;
+
+ const bool itd = el == EL2 ?
+ ((SCTLR)tc->readMiscReg(MISCREG_HSCTLR)).itd :
+ ((SCTLR)tc->readMiscReg(MISCREG_SCTLR)).itd;
+
+ // The IT bits are forced to zero when returning to A32 state, or
+ // when returning to an EL with the ITD bit set to 1, and the IT
+ // bits are describing a multi-instruction block.
+ if (itd && bits(it, 2, 0) != 0)
+ return 0;
+
+ return it;
+}
+
+static bool
+illegalExceptionReturn(ThreadContext *tc, CPSR cpsr, CPSR spsr)
+{
+ const OperatingMode mode = (OperatingMode) (uint8_t)spsr.mode;
+ if (badMode(mode))
+ return true;
+
+ const OperatingMode cur_mode = (OperatingMode) (uint8_t)cpsr.mode;
+ const ExceptionLevel target_el = opModeToEL(mode);
+ if (target_el > opModeToEL(cur_mode))
+ return true;
+
+ if (target_el == EL3 && !ArmSystem::haveSecurity(tc))
+ return true;
+
+ if (target_el == EL2 && !ArmSystem::haveVirtualization(tc))
+ return true;
+
+ if (!spsr.width) {
+ // aarch64
+ if (!ArmSystem::highestELIs64(tc))
+ return true;
+
+ if (spsr & 0x2)
+ return true;
+ if (target_el == EL0 && spsr.sp)
+ return true;
+ if (target_el == EL2 && !((SCR)tc->readMiscReg(MISCREG_SCR_EL3)).ns)
+ return false;
+ } else {
+ return badMode32(mode);
+ }
+
+ return false;
+}
+
+CPSR
+ArmStaticInst::getPSTATEFromPSR(ThreadContext *tc, CPSR cpsr, CPSR spsr) const
+{
+ CPSR new_cpsr = 0;
+
+ // gem5 doesn't implement single-stepping, so force the SS bit to
+ // 0.
+ new_cpsr.ss = 0;
+
+ if (illegalExceptionReturn(tc, cpsr, spsr)) {
+ new_cpsr.il = 1;
+ } else {
+ new_cpsr.il = spsr.il;
+ if (spsr.width && badMode32((OperatingMode)(uint8_t)spsr.mode)) {
+ new_cpsr.il = 1;
+ } else if (spsr.width) {
+ new_cpsr.mode = spsr.mode;
+ } else {
+ new_cpsr.el = spsr.el;
+ new_cpsr.sp = spsr.sp;
+ }
+ }
+
+ new_cpsr.nz = spsr.nz;
+ new_cpsr.c = spsr.c;
+ new_cpsr.v = spsr.v;
+ if (new_cpsr.width) {
+ // aarch32
+ const ITSTATE it = getRestoredITBits(tc, spsr);
+ new_cpsr.q = spsr.q;
+ new_cpsr.ge = spsr.ge;
+ new_cpsr.e = spsr.e;
+ new_cpsr.aif = spsr.aif;
+ new_cpsr.t = spsr.t;
+ new_cpsr.it2 = it.top6;
+ new_cpsr.it1 = it.bottom2;
+ } else {
+ // aarch64
+ new_cpsr.daif = spsr.daif;
+ }
+
+ return new_cpsr;
+}
+
+
+
}