arch-arm: Introduce update method in ArmFault class
authorGiacomo Travaglini <giacomo.travaglini@arm.com>
Fri, 9 Feb 2018 10:01:11 +0000 (10:01 +0000)
committerGiacomo Travaglini <giacomo.travaglini@arm.com>
Thu, 8 Mar 2018 10:11:36 +0000 (10:11 +0000)
There is a set of internal variables in ArmFault thats get updated once
the fault is invoked (ArmFault::invoke). Sometimes we rely on those even
if the fault is generated but not invoked (e.g. when checking if a
memory access is producing a fault). This patch is moving the update
functionalities inside a public method so that a client can make use of
it even when not invoking the fault.

Change-Id: I3ac5b6835023f28ec569fe25487dffa356e1b2fd
Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/8361
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>

src/arch/arm/faults.cc
src/arch/arm/faults.hh

index 1d6d015927c649db9b1e6f1f192d1dad5570fa6b..310545bc33833e77ee9cc6c43d5030ee7ac751d1 100644 (file)
@@ -426,36 +426,54 @@ ArmFault::setSyndrome(ThreadContext *tc, MiscRegIndex syndrome_reg)
 }
 
 void
-ArmFault::invoke(ThreadContext *tc, const StaticInstPtr &inst)
+ArmFault::update(ThreadContext *tc)
 {
     CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
 
-    if (ArmSystem::highestELIs64(tc)) {  // ARMv8
-        // Determine source exception level and mode
-        fromMode = (OperatingMode) (uint8_t) cpsr.mode;
-        fromEL = opModeToEL(fromMode);
-        if (opModeIs64(fromMode))
-            from64 = true;
-
-        // Determine target exception level
-        if (ArmSystem::haveSecurity(tc) && routeToMonitor(tc)) {
-            toEL = EL3;
-        } else if (ArmSystem::haveVirtualization(tc) && routeToHyp(tc)) {
-            toEL = EL2;
-            hypRouted = true;
-        } else {
-            toEL = opModeToEL(nextMode());
-        }
+    // Determine source exception level and mode
+    fromMode = (OperatingMode) (uint8_t) cpsr.mode;
+    fromEL = opModeToEL(fromMode);
+    if (opModeIs64(fromMode))
+        from64 = true;
+
+    // Determine target exception level (aarch64) or target execution
+    // mode (aarch32).
+    if (ArmSystem::haveSecurity(tc) && routeToMonitor(tc)) {
+        toMode = MODE_MON;
+        toEL = EL3;
+    } else if (ArmSystem::haveVirtualization(tc) && routeToHyp(tc)) {
+        toMode = MODE_HYP;
+        toEL = EL2;
+        hypRouted = true;
+    } else {
+        toMode = nextMode();
+        toEL = opModeToEL(toMode);
+    }
 
-        if (fromEL > toEL)
-            toEL = fromEL;
+    if (fromEL > toEL)
+        toEL = fromEL;
 
-        if (toEL == ArmSystem::highestEL(tc) || ELIs64(tc, toEL)) {
-            // Invoke exception handler in AArch64 state
-            to64 = true;
-            invoke64(tc, inst);
-            return;
-        }
+    to64 = ELIs64(tc, toEL);
+
+    // The fault specific informations have been updated; it is
+    // now possible to use them inside the fault.
+    faultUpdated = true;
+}
+
+void
+ArmFault::invoke(ThreadContext *tc, const StaticInstPtr &inst)
+{
+
+    // Update fault state informations, like the starting mode (aarch32)
+    // or EL (aarch64) and the ending mode or EL.
+    // From the update function we are also evaluating if the fault must
+    // be handled in AArch64 mode (to64).
+    update(tc);
+
+    if (to64) {
+        // Invoke exception handler in AArch64 state
+        invoke64(tc, inst);
+        return;
     }
 
     // ARMv7 (ARM ARM issue C B1.9)
@@ -489,15 +507,6 @@ ArmFault::invoke(ThreadContext *tc, const StaticInstPtr &inst)
         armInst->annotateFault(this);
     }
 
-    if (have_security && routeToMonitor(tc)) {
-        cpsr.mode = MODE_MON;
-    } else if (have_virtualization && routeToHyp(tc)) {
-        cpsr.mode = MODE_HYP;
-        hypRouted = true;
-    } else {
-        cpsr.mode = nextMode();
-    }
-
     // Ensure Secure state if initially in Monitor mode
     if (have_security && saved_cpsr.mode == MODE_MON) {
         SCR scr = tc->readMiscRegNoEffect(MISCREG_SCR);
@@ -507,6 +516,9 @@ ArmFault::invoke(ThreadContext *tc, const StaticInstPtr &inst)
         }
     }
 
+    CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
+    cpsr.mode = toMode;
+
     // some bits are set differently if we have been routed to hyp mode
     if (cpsr.mode == MODE_HYP) {
         SCTLR hsctlr = tc->readMiscReg(MISCREG_HSCTLR);
index 537405cf238a95efb4286914f31fc31bbd3f930e..f663b5cfc6b49c4c45c62fc299963313c3c79924 100644 (file)
@@ -71,7 +71,13 @@ class ArmFault : public FaultBase
     bool to64;  // True if the exception is taken in AArch64 state
     ExceptionLevel fromEL;  // Source exception level
     ExceptionLevel toEL;  // Target exception level
-    OperatingMode fromMode;  // Source operating mode
+    OperatingMode fromMode;  // Source operating mode (aarch32)
+    OperatingMode toMode;  // Next operating mode (aarch32)
+
+    // This variable is true if the above fault specific informations
+    // have been updated. This is to prevent that a client is using their
+    // un-updated default constructed value.
+    bool faultUpdated;
 
     bool hypRouted; // True if the fault has been routed to Hypervisor
 
@@ -191,7 +197,8 @@ class ArmFault : public FaultBase
 
     ArmFault(ExtMachInst _machInst = 0, uint32_t _iss = 0) :
         machInst(_machInst), issRaw(_iss), from64(false), to64(false),
-        fromEL(EL0), toEL(EL0), fromMode(MODE_UNDEFINED), hypRouted(false) {}
+        fromEL(EL0), toEL(EL0), fromMode(MODE_UNDEFINED),
+        faultUpdated(false), hypRouted(false) {}
 
     // Returns the actual syndrome register to use based on the target
     // exception level
@@ -204,6 +211,7 @@ class ArmFault : public FaultBase
                 StaticInst::nullStaticInstPtr) override;
     void invoke64(ThreadContext *tc, const StaticInstPtr &inst =
                   StaticInst::nullStaticInstPtr);
+    void update(ThreadContext *tc);
     virtual void annotate(AnnotationIDs id, uint64_t val) {}
     virtual FaultStat& countStat() = 0;
     virtual FaultOffset offset(ThreadContext *tc) = 0;