arch-arm: Implement Armv8.2-LVA
authorJordi Vaquero <jordi.vaquero@metempsy.com>
Thu, 25 Jun 2020 08:54:59 +0000 (10:54 +0200)
committerJordi Vaquero <jordi.vaquero@metempsy.com>
Wed, 14 Oct 2020 06:56:47 +0000 (06:56 +0000)
Change-Id: I1b489a3629b2376e03e79b158631cb1d0cacc17e
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/35955
Reviewed-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Maintainer: Giacomo Travaglini <giacomo.travaglini@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
src/arch/arm/ArmISA.py
src/arch/arm/table_walker.cc
src/arch/arm/table_walker.hh
src/arch/arm/utility.cc
src/arch/arm/utility.hh

index a70989448027fa158578e5303c6cb51ab3e827ee..02f24d3f3e7593b839cf1def9f7cc29007ecdecb 100644 (file)
@@ -112,7 +112,8 @@ class ArmISA(BaseISA):
     # PAN | HPDS | VHE
     id_aa64mmfr1_el1 = Param.UInt64(0x0000000000101100,
         "AArch64 Memory Model Feature Register 1")
-    id_aa64mmfr2_el1 = Param.UInt64(0x0000000000000000,
+    # |VARANGE
+    id_aa64mmfr2_el1 = Param.UInt64(0x0000000000010000,
         "AArch64 Memory Model Feature Register 2")
 
     # Any access (read/write) to an unimplemented
index 9462e27430d2705f97c31b28910072002666c30a..d5027cf15cbcb3540d7486b700a6685aa005d56b 100644 (file)
@@ -746,14 +746,21 @@ TableWalker::processWalkLPAE()
     return f;
 }
 
-unsigned
-TableWalker::adjustTableSizeAArch64(unsigned tsz)
+bool
+TableWalker::checkVAddrSizeFaultAArch64(Addr addr, int top_bit,
+    GrainSize tg, int tsz, bool low_range)
 {
-    if (tsz < 25)
-        return 25;
-    if (tsz > 48)
-        return 48;
-    return tsz;
+    // The effective maximum input size is 48 if ARMv8.2-LVA is not
+    // supported or if the translation granule that is in use is 4KB or
+    // 16KB in size. When ARMv8.2-LVA is supported, for the 64KB
+    // translation granule size only, the effective minimum value of
+    // 52.
+    int in_max = (HaveLVA(currState->tc) && tg == Grain64KB) ? 52 : 48;
+    int in_min = 64 - (tg == Grain64KB ? 47 : 48);
+
+    return tsz > in_max || tsz < in_min || (low_range ?
+        bits(currState->vaddr, top_bit, tsz) != 0x0 :
+        bits(currState->vaddr, top_bit, tsz) != mask(top_bit - tsz + 1));
 }
 
 bool
@@ -784,8 +791,14 @@ TableWalker::processWalkAArch64()
     GrainSize tg = Grain4KB; // grain size computed from tg* field
     bool fault = false;
 
-    LookupLevel start_lookup_level = MAX_LOOKUP_LEVELS;
+    int top_bit = computeAddrTop(currState->tc,
+        bits(currState->vaddr, 55),
+        currState->mode==TLB::Execute,
+        currState->tcr,
+        currState->el);
 
+    LookupLevel start_lookup_level = MAX_LOOKUP_LEVELS;
+    bool vaddr_fault = false;
     switch (currState->el) {
       case EL0:
         {
@@ -804,24 +817,28 @@ TableWalker::processWalkAArch64()
               case 0:
                 DPRINTF(TLB, " - Selecting TTBR0 (AArch64)\n");
                 ttbr = ttbr0;
-                tsz = adjustTableSizeAArch64(64 - currState->tcr.t0sz);
+                tsz = 64 - currState->tcr.t0sz;
                 tg = GrainMap_tg0[currState->tcr.tg0];
                 currState->hpd = currState->tcr.hpd0;
                 currState->isUncacheable = currState->tcr.irgn0 == 0;
-                if (bits(currState->vaddr, 63, tsz) != 0x0 ||
-                    currState->tcr.epd0)
-                  fault = true;
+                vaddr_fault = checkVAddrSizeFaultAArch64(currState->vaddr,
+                    top_bit, tg, tsz, true);
+
+                if (vaddr_fault || currState->tcr.epd0)
+                    fault = true;
                 break;
               case 0xffff:
                 DPRINTF(TLB, " - Selecting TTBR1 (AArch64)\n");
                 ttbr = ttbr1;
-                tsz = adjustTableSizeAArch64(64 - currState->tcr.t1sz);
+                tsz = 64 - currState->tcr.t1sz;
                 tg = GrainMap_tg1[currState->tcr.tg1];
                 currState->hpd = currState->tcr.hpd1;
                 currState->isUncacheable = currState->tcr.irgn1 == 0;
-                if (bits(currState->vaddr, 63, tsz) != mask(64-tsz) ||
-                    currState->tcr.epd1)
-                  fault = true;
+                vaddr_fault = checkVAddrSizeFaultAArch64(currState->vaddr,
+                    top_bit, tg, tsz, false);
+
+                if (vaddr_fault || currState->tcr.epd1)
+                    fault = true;
                 break;
               default:
                 // top two bytes must be all 0s or all 1s, else invalid addr
@@ -858,28 +875,32 @@ TableWalker::processWalkAArch64()
             ps = currState->vtcr.ps;
             currState->isUncacheable = currState->vtcr.irgn0 == 0;
         } else {
-            switch (bits(currState->vaddr, 63,48)) {
+            switch (bits(currState->vaddr, top_bit)) {
               case 0:
-                DPRINTF(TLB, " - Selecting TTBR0 (AArch64)\n");
+                DPRINTF(TLB, " - Selecting TTBR0_EL1 (AArch64)\n");
                 ttbr = currState->tc->readMiscReg(MISCREG_TTBR0_EL1);
-                tsz = adjustTableSizeAArch64(64 - currState->tcr.t0sz);
+                tsz = 64 - currState->tcr.t0sz;
                 tg = GrainMap_tg0[currState->tcr.tg0];
                 currState->hpd = currState->tcr.hpd0;
                 currState->isUncacheable = currState->tcr.irgn0 == 0;
-                if (bits(currState->vaddr, 63, tsz) != 0x0 ||
-                    currState->tcr.epd0)
-                  fault = true;
+                vaddr_fault = checkVAddrSizeFaultAArch64(currState->vaddr,
+                    top_bit, tg, tsz, true);
+
+                if (vaddr_fault || currState->tcr.epd0)
+                    fault = true;
                 break;
-              case 0xffff:
-                DPRINTF(TLB, " - Selecting TTBR1 (AArch64)\n");
+              case 0x1:
+                DPRINTF(TLB, " - Selecting TTBR1_EL1 (AArch64)\n");
                 ttbr = currState->tc->readMiscReg(MISCREG_TTBR1_EL1);
-                tsz = adjustTableSizeAArch64(64 - currState->tcr.t1sz);
+                tsz = 64 - currState->tcr.t1sz;
                 tg = GrainMap_tg1[currState->tcr.tg1];
                 currState->hpd = currState->tcr.hpd1;
                 currState->isUncacheable = currState->tcr.irgn1 == 0;
-                if (bits(currState->vaddr, 63, tsz) != mask(64-tsz) ||
-                    currState->tcr.epd1)
-                  fault = true;
+                vaddr_fault = checkVAddrSizeFaultAArch64(currState->vaddr,
+                    top_bit, tg, tsz, false);
+
+                if (vaddr_fault || currState->tcr.epd1)
+                    fault = true;
                 break;
               default:
                 // top two bytes must be all 0s or all 1s, else invalid addr
@@ -889,27 +910,34 @@ TableWalker::processWalkAArch64()
         }
         break;
       case EL2:
-        switch(bits(currState->vaddr, 63,48)) {
+        switch(bits(currState->vaddr, top_bit)) {
           case 0:
             DPRINTF(TLB, " - Selecting TTBR0_EL2 (AArch64)\n");
             ttbr = currState->tc->readMiscReg(MISCREG_TTBR0_EL2);
-            tsz = adjustTableSizeAArch64(64 - currState->tcr.t0sz);
+            tsz = 64 - currState->tcr.t0sz;
             tg = GrainMap_tg0[currState->tcr.tg0];
             currState->hpd = currState->hcr.e2h ?
                 currState->tcr.hpd0 : currState->tcr.hpd;
             currState->isUncacheable = currState->tcr.irgn0 == 0;
+            vaddr_fault = checkVAddrSizeFaultAArch64(currState->vaddr,
+                top_bit, tg, tsz, true);
+
+            if (vaddr_fault || (currState->hcr.e2h && currState->tcr.epd0))
+                fault = true;
             break;
 
-          case 0xffff:
+          case 0x1:
             DPRINTF(TLB, " - Selecting TTBR1_EL2 (AArch64)\n");
             ttbr = currState->tc->readMiscReg(MISCREG_TTBR1_EL2);
-            tsz = adjustTableSizeAArch64(64 - currState->tcr.t1sz);
+            tsz = 64 - currState->tcr.t1sz;
             tg = GrainMap_tg1[currState->tcr.tg1];
             currState->hpd = currState->tcr.hpd1;
             currState->isUncacheable = currState->tcr.irgn1 == 0;
-            if (bits(currState->vaddr, 63, tsz) != mask(64-tsz) ||
-                currState->tcr.epd1 || !currState->hcr.e2h)
-              fault = true;
+            vaddr_fault = checkVAddrSizeFaultAArch64(currState->vaddr,
+                top_bit, tg, tsz, false);
+
+            if (vaddr_fault || !currState->hcr.e2h || currState->tcr.epd1)
+                fault = true;
             break;
 
            default:
@@ -919,18 +947,23 @@ TableWalker::processWalkAArch64()
         ps = currState->hcr.e2h ? currState->tcr.ips: currState->tcr.ps;
         break;
       case EL3:
-        switch(bits(currState->vaddr, 63,48)) {
-            case 0:
-                DPRINTF(TLB, " - Selecting TTBR0_EL3 (AArch64)\n");
-                ttbr = currState->tc->readMiscReg(MISCREG_TTBR0_EL3);
-                tsz = adjustTableSizeAArch64(64 - currState->tcr.t0sz);
-                tg = GrainMap_tg0[currState->tcr.tg0];
-                currState->hpd = currState->tcr.hpd;
-                currState->isUncacheable = currState->tcr.irgn0 == 0;
-                break;
-            default:
-                // invalid addr if top two bytes are not all 0s
+        switch(bits(currState->vaddr, top_bit)) {
+          case 0:
+            DPRINTF(TLB, " - Selecting TTBR0_EL3 (AArch64)\n");
+            ttbr = currState->tc->readMiscReg(MISCREG_TTBR0_EL3);
+            tsz = 64 - currState->tcr.t0sz;
+            tg = GrainMap_tg0[currState->tcr.tg0];
+            currState->hpd = currState->tcr.hpd;
+            currState->isUncacheable = currState->tcr.irgn0 == 0;
+            vaddr_fault = checkVAddrSizeFaultAArch64(currState->vaddr,
+                top_bit, tg, tsz, true);
+
+            if (vaddr_fault)
                 fault = true;
+            break;
+          default:
+            // invalid addr if top two bytes are not all 0s
+            fault = true;
         }
         ps = currState->tcr.ps;
         break;
index 8f4aaefd3ad344b9a5718ce1c63e27d13b438b64..ffb83ad490f7bac96e01f086f96494d5fbff7827 100644 (file)
@@ -956,7 +956,10 @@ class TableWalker : public ClockedObject
 
     Fault processWalk();
     Fault processWalkLPAE();
-    static unsigned adjustTableSizeAArch64(unsigned tsz);
+
+    bool checkVAddrSizeFaultAArch64(Addr addr, int top_bit,
+        GrainSize granule, int tsz, bool low_range);
+
     /// Returns true if the address exceeds the range permitted by the
     /// system-wide setting or by the TCR_ELx IPS/PS setting
     static bool checkAddrSizeFaultAArch64(Addr addr, int currPhysAddrRange);
index 4d866d09c92d1ebaccc4a6fd379bee774ca78e5b..bb4044ad56dd068476e039a549d54fad43055895 100644 (file)
@@ -326,6 +326,13 @@ HaveVirtHostExt(ThreadContext *tc)
     return id_aa64mmfr1.vh;
 }
 
+bool
+HaveLVA(ThreadContext *tc)
+{
+    const AA64MMFR2 mm_fr2 = tc->readMiscReg(MISCREG_ID_AA64MMFR2_EL1);
+    return (bool)mm_fr2.varange;
+}
+
 ExceptionLevel
 s1TranslationRegime(ThreadContext* tc, ExceptionLevel el)
 {
index 636625d8b76a007ef8b6d2159fbdce46f81adf49..6ec6403966956de1957b360b9324cc3270b6a19f 100644 (file)
@@ -153,6 +153,7 @@ currEL(CPSR cpsr)
 
 bool HavePACExt(ThreadContext *tc);
 bool HaveVirtHostExt(ThreadContext *tc);
+bool HaveLVA(ThreadContext *tc);
 bool HaveSecureEL2Ext(ThreadContext *tc);
 bool IsSecureEL2Enabled(ThreadContext *tc);
 bool EL2Enabled(ThreadContext *tc);