arch-arm: ELUsingAArch32K from armarm pseudocode

This patch implements the ELUsingAArch32K pseudocode, which is returning
true if the provided Exception Level is using A32 ISA, but it is not
panicking (quitting simulation) if the information is unknown (see
documentation).
The panicking is the current behaviour of the ELIs32 utility in gem5.

Change-Id: Iad7b56077d7e0f8ee223b5b9593cb8097f26bb29
Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Reviewed-by: Nikos Nikoleris <nikos.nikoleris@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/7222
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
diff --git a/src/arch/arm/utility.cc b/src/arch/arm/utility.cc
index a49f829..4e99d98 100644
--- a/src/arch/arm/utility.cc
+++ b/src/arch/arm/utility.cc
@@ -243,20 +243,31 @@
 bool
 ELIs32(ThreadContext *tc, ExceptionLevel el)
 {
-    // Return true if the specified EL is in aarch32 state.
+    bool known, aarch32;
+    std::tie(known, aarch32) = ELUsingAArch32K(tc, el);
+    panic_if(!known, "EL state is UNKNOWN");
+    return aarch32;
+}
 
+std::pair<bool, bool>
+ELUsingAArch32K(ThreadContext *tc, ExceptionLevel el)
+{
+    // Return true if the specified EL is in aarch32 state.
     const bool have_el3 = ArmSystem::haveSecurity(tc);
     const bool have_el2 = ArmSystem::haveVirtualization(tc);
 
     panic_if(el == EL2 && !have_el2, "Asking for EL2 when it doesn't exist");
     panic_if(el == EL3 && !have_el3, "Asking for EL3 when it doesn't exist");
 
-    if (ArmSystem::highestELIs64(tc)
-              && ArmSystem::highestEL(tc) == el) {
-        return false;
+    bool known, aarch32;
+    known = aarch32 = false;
+    if (ArmSystem::highestELIs64(tc) && ArmSystem::highestEL(tc) == el) {
+        // Target EL is the highest one in a system where
+        // the highest is using AArch64.
+        known = true; aarch32 = false;
     } else if (!ArmSystem::highestELIs64(tc)) {
-        // All levels are using AArch32
-        return true;
+        // All ELs are using AArch32:
+        known = true; aarch32 = true;
     } else {
         SCR scr = tc->readMiscReg(MISCREG_SCR_EL3);
         bool aarch32_below_el3 = (have_el3 && scr.rw == 0);
@@ -268,15 +279,19 @@
 
         // Only know if EL0 using AArch32 from PSTATE
         if (el == EL0 && !aarch32_at_el1) {
-            CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
-            panic_if(cpsr.el != EL0, "EL0 state is UNKNOWN");
             // EL0 controlled by PSTATE
-            return cpsr.width != 0;
+            CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
+
+            known = (cpsr.el == EL0);
+            aarch32 = (cpsr.width == 1);
         } else {
-            return (aarch32_below_el3 && el != EL3)
-                     || (aarch32_at_el1 && (el == EL0 || el == EL1) );
+            known = true;
+            aarch32 = (aarch32_below_el3 && el != EL3)
+                      || (aarch32_at_el1 && (el == EL0 || el == EL1) );
         }
     }
+
+    return std::make_pair(known, aarch32);
 }
 
 bool
diff --git a/src/arch/arm/utility.hh b/src/arch/arm/utility.hh
index 6e4e76b..8efe4ad 100644
--- a/src/arch/arm/utility.hh
+++ b/src/arch/arm/utility.hh
@@ -157,6 +157,24 @@
     return (ExceptionLevel) (uint8_t) cpsr.el;
 }
 
+/**
+ * This function checks whether selected EL provided as an argument
+ * is using the AArch32 ISA. This information might be unavailable
+ * at the current EL status: it hence returns a pair of boolean values:
+ * a first boolean, true if information is available (known),
+ * and a second one, true if EL is using AArch32, false for AArch64.
+ *
+ * @param tc The thread context.
+ * @param el The target exception level.
+ * @retval known is FALSE for EL0 if the current Exception level
+ *               is not EL0 and EL1 is using AArch64, since it cannot
+ *               determine the state of EL0; TRUE otherwise.
+ * @retval aarch32 is TRUE if the specified Exception level is using AArch32;
+ *                 FALSE otherwise.
+ */
+std::pair<bool, bool>
+ELUsingAArch32K(ThreadContext *tc, ExceptionLevel el);
+
 bool ELIs32(ThreadContext *tc, ExceptionLevel el);
 
 bool ELIs64(ThreadContext *tc, ExceptionLevel el);