arm: Fix EL perceived at TLB for address translation instructions
authorDylan Johnson <Dylan.Johnson@ARM.com>
Tue, 2 Aug 2016 09:38:02 +0000 (10:38 +0100)
committerDylan Johnson <Dylan.Johnson@ARM.com>
Tue, 2 Aug 2016 09:38:02 +0000 (10:38 +0100)
During address translation instructions (such as AT S1E1R_Xt) the exception
level can be different than the current exception level. This patch fixes
how the TLB determines what EL to use during these instructions.

Change-Id: Ia9ce229404de9e284bc1f7479fd2c580efd55f8f

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

index 2300b925ed8f5f2ad71d6b7c3902554bc55c9a17..016e1eca01557b8130561819fdbd7f9bc09692b7 100644 (file)
@@ -1698,62 +1698,62 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc)
                 switch(misc_reg) {
                   case MISCREG_AT_S1E1R_Xt:
                     flags    = TLB::MustBeOne;
-                    tranType = TLB::S1CTran;
+                    tranType = TLB::S1E1Tran;
                     mode     = BaseTLB::Read;
                     break;
                   case MISCREG_AT_S1E1W_Xt:
                     flags    = TLB::MustBeOne;
-                    tranType = TLB::S1CTran;
+                    tranType = TLB::S1E1Tran;
                     mode     = BaseTLB::Write;
                     break;
                   case MISCREG_AT_S1E0R_Xt:
                     flags    = TLB::MustBeOne | TLB::UserMode;
-                    tranType = TLB::S1CTran;
+                    tranType = TLB::S1E0Tran;
                     mode     = BaseTLB::Read;
                     break;
                   case MISCREG_AT_S1E0W_Xt:
                     flags    = TLB::MustBeOne | TLB::UserMode;
-                    tranType = TLB::S1CTran;
+                    tranType = TLB::S1E0Tran;
                     mode     = BaseTLB::Write;
                     break;
                   case MISCREG_AT_S1E2R_Xt:
                     flags    = TLB::MustBeOne;
-                    tranType = TLB::HypMode;
+                    tranType = TLB::S1E2Tran;
                     mode     = BaseTLB::Read;
                     break;
                   case MISCREG_AT_S1E2W_Xt:
                     flags    = TLB::MustBeOne;
-                    tranType = TLB::HypMode;
+                    tranType = TLB::S1E2Tran;
                     mode     = BaseTLB::Write;
                     break;
                   case MISCREG_AT_S12E0R_Xt:
                     flags    = TLB::MustBeOne | TLB::UserMode;
-                    tranType = TLB::S1S2NsTran;
+                    tranType = TLB::S12E0Tran;
                     mode     = BaseTLB::Read;
                     break;
                   case MISCREG_AT_S12E0W_Xt:
                     flags    = TLB::MustBeOne | TLB::UserMode;
-                    tranType = TLB::S1S2NsTran;
+                    tranType = TLB::S12E0Tran;
                     mode     = BaseTLB::Write;
                     break;
                   case MISCREG_AT_S12E1R_Xt:
                     flags    = TLB::MustBeOne;
-                    tranType = TLB::S1S2NsTran;
+                    tranType = TLB::S12E1Tran;
                     mode     = BaseTLB::Read;
                     break;
                   case MISCREG_AT_S12E1W_Xt:
                     flags    = TLB::MustBeOne;
-                    tranType = TLB::S1S2NsTran;
+                    tranType = TLB::S12E1Tran;
                     mode     = BaseTLB::Write;
                     break;
                   case MISCREG_AT_S1E3R_Xt:
                     flags    = TLB::MustBeOne;
-                    tranType = TLB::HypMode; // There is no TZ mode defined.
+                    tranType = TLB::S1E3Tran;
                     mode     = BaseTLB::Read;
                     break;
                   case MISCREG_AT_S1E3W_Xt:
                     flags    = TLB::MustBeOne;
-                    tranType = TLB::HypMode; // There is no TZ mode defined.
+                    tranType = TLB::S1E3Tran;
                     mode     = BaseTLB::Write;
                     break;
                 }
@@ -1788,12 +1788,22 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc)
                     // Set fault bit and FSR
                     FSR fsr = armFault->getFsr(tc);
 
-                    newVal = ((fsr >> 9) & 1) << 11;
-                    // rearange fault status
-                    newVal |= ((fsr >>  0) & 0x3f) << 1;
-                    newVal |= 0x1; // F bit
-                    newVal |= ((armFault->iss() >> 7) & 0x1) << 8;
-                    newVal |= armFault->isStage2() ? 0x200 : 0;
+                    CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
+                    if (cpsr.width) { // AArch32
+                        newVal = ((fsr >> 9) & 1) << 11;
+                        // rearrange fault status
+                        newVal |= ((fsr >>  0) & 0x3f) << 1;
+                        newVal |= 0x1; // F bit
+                        newVal |= ((armFault->iss() >> 7) & 0x1) << 8;
+                        newVal |= armFault->isStage2() ? 0x200 : 0;
+                    } else { // AArch64
+                        newVal = 1; // F bit
+                        newVal |= fsr << 1; // FST
+                        // TODO: DDI 0487A.f D7-2083, AbortFault's s1ptw bit.
+                        newVal |= armFault->isStage2() ? 1 << 8 : 0; // PTW
+                        newVal |= armFault->isStage2() ? 1 << 9 : 0; // S
+                        newVal |= 1 << 11; // RES1
+                    }
                     DPRINTF(MiscRegs,
                             "MISCREG: Translated addr %#x fault fsr %#x: PAR: %#x\n",
                             val, fsr, newVal);
index 864f0c28c395e0b9f065211eb5360ac32d0f4433..536fa51cd2c8b015fbe0e467d9ed8e6257cc8e15 100644 (file)
@@ -1220,7 +1220,30 @@ TLB::updateMiscReg(ThreadContext *tc, ArmTranslationType tranType)
         (opModeToEL(op_mode) == EL0 && ELIs64(tc, EL1));
 
     if (aarch64) {  // AArch64
-        aarch64EL = (ExceptionLevel) (uint8_t) cpsr.el;
+        // 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:
@@ -1258,7 +1281,8 @@ TLB::updateMiscReg(ThreadContext *tc, ArmTranslationType tranType)
             // compute it for every translation.
             stage2Req = isStage2 ||
                         (hcr.vm && !isHyp && !isSecure &&
-                         !(tranType & S1CTran) && (aarch64EL < EL2));
+                         !(tranType & S1CTran) && (aarch64EL < EL2) &&
+                         !(tranType & S1E1Tran)); // <--- FIX THIS HACK
             directToStage2 = !isStage2 && stage2Req && !sctlr.m;
         } else {
             vmid           = 0;
index 298c603b9856fabd1c086196fb1b59c6e55175c0..ef05bb421ced2db8b947365cf46610e8b0d57d45 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2013 ARM Limited
+ * Copyright (c) 2010-2013, 2016 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -127,7 +127,17 @@ class TLB : public BaseTLB
         HypMode = 0x2,
         // Secure code operating as if it wasn't (required by some Address
         // Translate operations)
-        S1S2NsTran = 0x4
+        S1S2NsTran = 0x4,
+        // Address translation instructions (eg AT S1E0R_Xt) need to be handled
+        // in special ways during translation because they could need to act
+        // like a different EL than the current EL. The following flags are
+        // for these instructions
+        S1E0Tran = 0x8,
+        S1E1Tran = 0x10,
+        S1E2Tran = 0x20,
+        S1E3Tran = 0x40,
+        S12E0Tran = 0x80,
+        S12E1Tran = 0x100
     };
   protected:
     TlbEntry* table;     // the Page Table