arch-arm: Respect EL from translation type
authorAndreas Sandberg <andreas.sandberg@arm.com>
Wed, 16 May 2018 15:16:04 +0000 (16:16 +0100)
committerAndreas Sandberg <andreas.sandberg@arm.com>
Wed, 6 Jun 2018 13:56:18 +0000 (13:56 +0000)
There are cases where instructions request translations in the context
of a lower EL. This is currently not respected in the TLB and the page
table walker. Fix that.

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

src/arch/arm/table_walker.cc
src/arch/arm/tlb.cc
src/arch/arm/tlb.hh

index 26a07d70e37d59e53f47bcc2654dbb80e05e6661..325a5128dd329400ed8ea2519ac8ab40d070d553 100644 (file)
@@ -230,9 +230,15 @@ TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint16_t _asid,
     // ARM DDI 0487A.f (ARMv8 ARM) pg J8-5672
     // aarch32/translation/translation/AArch32.TranslateAddress dictates
     // even AArch32 EL0 will use AArch64 translation if EL1 is in AArch64.
-    currState->aarch64 = isStage2 || opModeIs64(currOpMode(_tc)) ||
-                         ((currEL(_tc) == EL0) && ELIs64(_tc, EL1));
-    currState->el = currEL(_tc);
+    if (isStage2) {
+        currState->el = EL1;
+        currState->aarch64 = ELIs64(_tc, EL2);
+    } else {
+        currState->el =
+            TLB::tranTypeEL(_tc->readMiscReg(MISCREG_CPSR), tranType);
+        currState->aarch64 =
+            ELIs64(_tc, currState->el == EL0 ? EL1 : currState->el);
+    }
     currState->transState = _trans;
     currState->req = _req;
     currState->fault = NoFault;
@@ -363,17 +369,11 @@ TableWalker::processWalkWrapper()
     pendingChange();
     currState = pendingQueue.front();
 
-    ExceptionLevel target_el = EL0;
-    if (currState->aarch64)
-        target_el = currEL(currState->tc);
-    else
-        target_el = EL1;
-
     // Check if a previous walk filled this request already
     // @TODO Should this always be the TLB or should we look in the stage2 TLB?
     TlbEntry* te = tlb->lookup(currState->vaddr, currState->asid,
             currState->vmid, currState->isHyp, currState->isSecure, true, false,
-            target_el);
+            currState->el);
 
     // Check if we still need to have a walk for this request. If the requesting
     // instruction has been squashed, or a previous walk has filled the TLB with
@@ -439,7 +439,7 @@ TableWalker::processWalkWrapper()
             currState = pendingQueue.front();
             te = tlb->lookup(currState->vaddr, currState->asid,
                 currState->vmid, currState->isHyp, currState->isSecure, true,
-                false, target_el);
+                false, currState->el);
         } else {
             // Terminate the loop, nothing more to do
             currState = NULL;
index 5f104e96d1afb67b9bad50e29b2c1fd8f1e821be..192f01bcec570c19f5065f2dcedf87d183591e92 100644 (file)
@@ -1268,35 +1268,13 @@ TLB::updateMiscReg(ThreadContext *tc, ArmTranslationType tranType)
     isSecure = inSecureState(tc) &&
         !(tranType & HypMode) && !(tranType & S1S2NsTran);
 
-    const OperatingMode op_mode = (OperatingMode) (uint8_t)cpsr.mode;
-    aarch64 = opModeIs64(op_mode) ||
-        (opModeToEL(op_mode) == EL0 && ELIs64(tc, EL1));
+    aarch64EL = tranTypeEL(cpsr, tranType);
+    aarch64 = isStage2 ?
+        ELIs64(tc, EL2) :
+        ELIs64(tc, aarch64EL == EL0 ? EL1 : aarch64EL);
 
     if (aarch64) {  // AArch64
         // determine EL we need to translate in
-        switch (tranType) {
-            case S1E0Tran:
-            case S12E0Tran:
-                aarch64EL = EL0;
-                break;
-            case S1E1Tran:
-            case S12E1Tran:
-                aarch64EL = EL1;
-                break;
-            case S1E2Tran:
-                aarch64EL = EL2;
-                break;
-            case S1E3Tran:
-                aarch64EL = EL3;
-                break;
-            case NormalTran:
-            case S1CTran:
-            case S1S2NsTran:
-            case HypMode:
-                aarch64EL = (ExceptionLevel) (uint8_t) cpsr.el;
-                break;
-        }
-
         switch (aarch64EL) {
           case EL0:
           case EL1:
@@ -1396,6 +1374,35 @@ TLB::updateMiscReg(ThreadContext *tc, ArmTranslationType tranType)
     curTranType  = tranType;
 }
 
+ExceptionLevel
+TLB::tranTypeEL(CPSR cpsr, ArmTranslationType type)
+{
+    switch (type) {
+      case S1E0Tran:
+      case S12E0Tran:
+        return EL0;
+
+      case S1E1Tran:
+      case S12E1Tran:
+        return EL1;
+
+      case S1E2Tran:
+        return EL2;
+
+      case S1E3Tran:
+        return EL3;
+
+      case NormalTran:
+      case S1CTran:
+      case S1S2NsTran:
+      case HypMode:
+        return opModeToEL((OperatingMode)(uint8_t)cpsr.mode);
+
+      default:
+        panic("Unknown translation mode!\n");
+    }
+}
+
 Fault
 TLB::getTE(TlbEntry **te, RequestPtr req, ThreadContext *tc, Mode mode,
         Translation *translation, bool timing, bool functional,
index b0e0d0d7f805b44dcfe6214c9c47e8ccb8f3150e..b8ea9905457464e2b83312518a2b5052bcf2180e 100644 (file)
@@ -139,6 +139,14 @@ class TLB : public BaseTLB
         S12E0Tran = 0x80,
         S12E1Tran = 0x100
     };
+
+    /**
+     * Determine the EL to use for the purpose of a translation given
+     * a specific translation type. If the translation type doesn't
+     * specify an EL, we use the current EL.
+     */
+    static ExceptionLevel tranTypeEL(CPSR cpsr, ArmTranslationType type);
+
   protected:
     TlbEntry* table;     // the Page Table
     int size;            // TLB Size