arch-arm: Implement Armv8.2-LPA
authorJordi Vaquero <jordi.vaquero@metempsy.com>
Fri, 3 Jul 2020 07:58:51 +0000 (09:58 +0200)
committerJordi Vaquero <jordi.vaquero@metempsy.com>
Wed, 14 Oct 2020 06:56:47 +0000 (06:56 +0000)
This is enabled by setting the ArmSystem.phys_addr_range64 to 52.
This will automatically set the ID_AA64MMFR0_EL1.PARange to 0b0110
which encodes the presence of Armv8.2-LPA

Change-Id: If9b36e26cd2a72e55c8e929a632b7b50d909b282
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/35956
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/pagetable.hh
src/arch/arm/system.cc
src/arch/arm/table_walker.cc
src/arch/arm/table_walker.hh
src/arch/arm/tlb.cc
src/arch/arm/tlb.hh
src/arch/arm/utility.cc

index 9d1df1f2153035aa2b99f205b9e5ee14045fab6a..84e1967b329f2e05024acc19347cc70ddc154ecf 100644 (file)
@@ -51,7 +51,7 @@ namespace ArmISA
 {
 
 // Max. physical address range in bits supported by the architecture
-const unsigned MaxPhysAddrRange = 48;
+const unsigned MaxPhysAddrRange = 52;
 
 // ITB/DTB page table entry
 struct PTE
index 7009b31ddbf5a49792c8b091ac90600143765c63..20ebee2df4141ec7d7061ffc2a23e0991f63406b 100644 (file)
@@ -95,7 +95,7 @@ ArmSystem::ArmSystem(Params *p)
 
     if (_highestELIs64 && (
             _physAddrRange64 < 32 ||
-            _physAddrRange64 > 48 ||
+            _physAddrRange64 > MaxPhysAddrRange ||
             (_physAddrRange64 % 4 != 0 && _physAddrRange64 != 42))) {
         fatal("Invalid physical address range (%d)\n", _physAddrRange64);
     }
index d5027cf15cbcb3540d7486b700a6685aa005d56b..26e20b280691c31c6f07f2dfcc42b344a4c55d4c 100644 (file)
@@ -81,12 +81,12 @@ TableWalker::TableWalker(const Params *p)
         haveSecurity = armSys->haveSecurity();
         _haveLPAE = armSys->haveLPAE();
         _haveVirtualization = armSys->haveVirtualization();
-        physAddrRange = armSys->physAddrRange();
+        _physAddrRange = armSys->physAddrRange();
         _haveLargeAsid64 = armSys->haveLargeAsid64();
     } else {
         haveSecurity = _haveLPAE = _haveVirtualization = false;
         _haveLargeAsid64 = false;
-        physAddrRange = 32;
+        _physAddrRange = 48;
     }
 
 }
@@ -252,7 +252,7 @@ TableWalker::walk(const RequestPtr &_req, ThreadContext *_tc, uint16_t _asid,
     currState->mode = _mode;
     currState->tranType = tranType;
     currState->isSecure = secure;
-    currState->physAddrRange = physAddrRange;
+    currState->physAddrRange = _physAddrRange;
 
     /** @todo These should be cached or grabbed from cached copies in
      the TLB, all these miscreg reads are expensive */
@@ -764,10 +764,10 @@ TableWalker::checkVAddrSizeFaultAArch64(Addr addr, int top_bit,
 }
 
 bool
-TableWalker::checkAddrSizeFaultAArch64(Addr addr, int currPhysAddrRange)
+TableWalker::checkAddrSizeFaultAArch64(Addr addr, int pa_range)
 {
-    return (currPhysAddrRange != MaxPhysAddrRange &&
-            bits(addr, MaxPhysAddrRange - 1, currPhysAddrRange));
+    return (pa_range != _physAddrRange &&
+            bits(addr, _physAddrRange - 1, pa_range));
 }
 
 Fault
@@ -1041,20 +1041,29 @@ TableWalker::processWalkAArch64()
                  "Table walker couldn't find lookup level\n");
     }
 
-    int stride = tg - 3;
+    // Clamp to lower limit
+    int pa_range = decodePhysAddrRange64(ps);
+    if (pa_range > _physAddrRange) {
+        currState->physAddrRange = _physAddrRange;
+    } else {
+        currState->physAddrRange = pa_range;
+    }
 
     // Determine table base address
+    int stride = tg - 3;
     int base_addr_lo = 3 + tsz - stride * (3 - start_lookup_level) - tg;
-    Addr base_addr = mbits(ttbr, 47, base_addr_lo);
+    Addr base_addr = 0;
+
+    if (pa_range == 52) {
+        int z = (base_addr_lo < 6) ? 6 : base_addr_lo;
+        base_addr = mbits(ttbr, 47, z);
+        base_addr |= (bits(ttbr, 5, 2) << 48);
+    } else {
+        base_addr = mbits(ttbr, 47, base_addr_lo);
+    }
 
     // Determine physical address size and raise an Address Size Fault if
     // necessary
-    int pa_range = decodePhysAddrRange64(ps);
-    // Clamp to lower limit
-    if (pa_range > physAddrRange)
-        currState->physAddrRange = physAddrRange;
-    else
-        currState->physAddrRange = pa_range;
     if (checkAddrSizeFaultAArch64(base_addr, currState->physAddrRange)) {
         DPRINTF(TLB, "Address size fault before any lookup\n");
         Fault f;
@@ -1084,7 +1093,7 @@ TableWalker::processWalkAArch64()
         }
         return f;
 
-   }
+    }
 
     // Determine descriptor address
     Addr desc_addr = base_addr |
@@ -1119,6 +1128,7 @@ TableWalker::processWalkAArch64()
     currState->longDesc.lookupLevel = start_lookup_level;
     currState->longDesc.aarch64 = true;
     currState->longDesc.grainSize = tg;
+    currState->longDesc.physAddrRange = _physAddrRange;
 
     if (currState->timing) {
         fetchDescriptor(desc_addr, (uint8_t*) &currState->longDesc.data,
@@ -1745,10 +1755,8 @@ TableWalker::doLongDescriptor()
         {
             auto fault_source = ArmFault::FaultSourceInvalid;
             // Check for address size fault
-            if (checkAddrSizeFaultAArch64(
-                    mbits(currState->longDesc.data, MaxPhysAddrRange - 1,
-                          currState->longDesc.offsetBits()),
-                    currState->physAddrRange)) {
+            if (checkAddrSizeFaultAArch64(currState->longDesc.paddr(),
+                currState->physAddrRange)) {
 
                 DPRINTF(TLB, "L%d descriptor causing Address Size Fault\n",
                         currState->longDesc.lookupLevel);
@@ -2305,6 +2313,7 @@ TableWalker::pageSizeNtoStatBin(uint8_t N)
         case 25: return 6; // 32M (using 16K granule in v8-64)
         case 29: return 7; // 512M (using 64K granule in v8-64)
         case 30: return 8; // 1G-LPAE
+        case 42: return 9; // 1G-LPAE
         default:
             panic("unknown page size");
             return 255;
@@ -2374,7 +2383,7 @@ TableWalker::TableWalkerStats::TableWalkerStats(Stats::Group *parent)
         .flags(Stats::pdf | Stats::dist | Stats::nozero | Stats::nonan);
 
     pageSizes // see DDI 0487A D4-1661
-        .init(9)
+        .init(10)
         .flags(Stats::total | Stats::pdf | Stats::dist | Stats::nozero);
     pageSizes.subname(0, "4K");
     pageSizes.subname(1, "16K");
@@ -2385,6 +2394,7 @@ TableWalker::TableWalkerStats::TableWalkerStats(Stats::Group *parent)
     pageSizes.subname(6, "32M");
     pageSizes.subname(7, "512M");
     pageSizes.subname(8, "1G");
+    pageSizes.subname(9, "4TB");
 
     requestOrigin
         .init(2,2) // Instruction/Data, requests/completed
index ffb83ad490f7bac96e01f086f96494d5fbff7827..309c402af721e6847ef873cfd30e90e643ddd652 100644 (file)
@@ -382,7 +382,10 @@ class TableWalker : public ClockedObject
             Page
         };
 
-        LongDescriptor() : data(0), _dirty(false) {}
+        LongDescriptor()
+          : data(0), _dirty(false), aarch64(false), grainSize(Grain4KB),
+            physAddrRange(0)
+        {}
 
         /** The raw bits of the entry */
         uint64_t data;
@@ -391,6 +394,15 @@ class TableWalker : public ClockedObject
          * written back to memory */
         bool _dirty;
 
+        /** True if the current lookup is performed in AArch64 state */
+        bool aarch64;
+
+        /** Width of the granule size in bits */
+        GrainSize grainSize;
+
+        uint8_t physAddrRange;
+
+
         virtual uint64_t getRawData() const
         {
             return (data);
@@ -417,12 +429,6 @@ class TableWalker : public ClockedObject
             return have_security && (currState->secureLookup && !bits(data, 5));
         }
 
-        /** True if the current lookup is performed in AArch64 state */
-        bool aarch64;
-
-        /** Width of the granule size in bits */
-        GrainSize grainSize;
-
         /** Return the descriptor type */
         EntryType type() const
         {
@@ -430,9 +436,31 @@ class TableWalker : public ClockedObject
               case 0x1:
                 // In AArch64 blocks are not allowed at L0 for the 4 KB granule
                 // and at L1 for 16/64 KB granules
-                if (grainSize > Grain4KB)
-                    return lookupLevel == L2 ? Block : Invalid;
-                return lookupLevel == L0 || lookupLevel == L3 ? Invalid : Block;
+                switch (grainSize) {
+                  case Grain4KB:
+                    if (lookupLevel == L0 || lookupLevel == L3)
+                        return Invalid;
+                    else
+                        return Block;
+
+                  case Grain16KB:
+                    if (lookupLevel == L2)
+                        return Block;
+                    else
+                        return Invalid;
+
+                  case Grain64KB:
+                    // With Armv8.2-LPA (52bit PA) L1 Block descriptors
+                    // are allowed for 64KB granule
+                    if ((lookupLevel == L1 && physAddrRange == 52) ||
+                        lookupLevel == L2)
+                        return Block;
+                    else
+                        return Invalid;
+
+                  default:
+                    return Invalid;
+                }
               case 0x3:
                 return lookupLevel == L3 ? Page : Table;
               default:
@@ -451,7 +479,8 @@ class TableWalker : public ClockedObject
                     case Grain16KB:
                         return 25  /* 32 MB */;
                     case Grain64KB:
-                        return 29 /* 512 MB */;
+                        return lookupLevel == L1 ? 42 /* 4TB MB */
+                                                 : 29 /* 512 MB */;
                     default:
                         panic("Invalid AArch64 VM granule size\n");
                 }
@@ -472,36 +501,39 @@ class TableWalker : public ClockedObject
         /** Return the physical frame, bits shifted right */
         Addr pfn() const
         {
-            if (aarch64)
-                return bits(data, 47, offsetBits());
-            return bits(data, 39, offsetBits());
-        }
-
-        /** Return the complete physical address given a VA */
-        Addr paddr(Addr va) const
-        {
-            int n = offsetBits();
-            if (aarch64)
-                return mbits(data, 47, n) | mbits(va, n - 1, 0);
-            return mbits(data, 39, n) | mbits(va, n - 1, 0);
+            return paddr() >> offsetBits();
         }
 
         /** Return the physical address of the entry */
         Addr paddr() const
         {
-            if (aarch64)
-                return mbits(data, 47, offsetBits());
-            return mbits(data, 39, offsetBits());
+            Addr addr = 0;
+            if (aarch64) {
+                addr = mbits(data, 47, offsetBits());
+                if (physAddrRange == 52 && grainSize == Grain64KB) {
+                    addr |= bits(data, 15, 12) << 48;
+                }
+            } else {
+                addr = mbits(data, 39, offsetBits());
+            }
+            return addr;
         }
 
         /** Return the address of the next page table */
         Addr nextTableAddr() const
         {
             assert(type() == Table);
-            if (aarch64)
-                return mbits(data, 47, grainSize);
-            else
-                return mbits(data, 39, 12);
+            Addr table_address = 0;
+            if (aarch64) {
+                table_address = mbits(data, 47, grainSize);
+                // Using 52bit if Armv8.2-LPA is implemented
+                if (physAddrRange == 52 && grainSize == Grain64KB)
+                    table_address |= bits(data, 15, 12) << 48;
+            } else {
+                table_address = mbits(data, 39, 12);
+            }
+
+            return table_address;
         }
 
         /** Return the address of the next descriptor */
@@ -854,7 +886,7 @@ class TableWalker : public ClockedObject
     bool haveSecurity;
     bool _haveLPAE;
     bool _haveVirtualization;
-    uint8_t physAddrRange;
+    uint8_t _physAddrRange;
     bool _haveLargeAsid64;
 
     /** Statistics */
@@ -896,6 +928,7 @@ class TableWalker : public ClockedObject
     bool haveLPAE() const { return _haveLPAE; }
     bool haveVirtualization() const { return _haveVirtualization; }
     bool haveLargeAsid64() const { return _haveLargeAsid64; }
+    uint8_t physAddrRange() const { return _physAddrRange; }
     /** Checks if all state is cleared and if so, completes drain */
     void completeDrain();
     DrainState drain() override;
@@ -962,7 +995,8 @@ class TableWalker : public ClockedObject
 
     /// 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);
+    bool checkAddrSizeFaultAArch64(Addr addr, int pa_range);
+
     Fault processWalkAArch64();
     void processWalkWrapper();
     EventFunctionWrapper doProcessEvent;
index a0f837df847ae98d46ce730e1575e85dad0b4e72..700988e4bd0710922f68d04ab2860f94564484e1 100644 (file)
@@ -89,6 +89,7 @@ TLB::TLB(const ArmTLBParams *p)
     haveLPAE = tableWalker->haveLPAE();
     haveVirtualization = tableWalker->haveVirtualization();
     haveLargeAsid64 = tableWalker->haveLargeAsid64();
+    physAddrRange = tableWalker->physAddrRange();
 
     if (sys)
         m5opRange = sys->m5opRange();
@@ -949,7 +950,7 @@ TLB::translateMmuOff(ThreadContext *tc, const RequestPtr &req, Mode mode,
         bool selbit = bits(vaddr, 55);
         TCR tcr1 = tc->readMiscReg(MISCREG_TCR_EL1);
         int topbit = computeAddrTop(tc, selbit, is_fetch, tcr1, currEL(tc));
-        int addr_sz = bits(vaddr, topbit, MaxPhysAddrRange);
+        int addr_sz = bits(vaddr, topbit, physAddrRange);
         if (addr_sz != 0){
             Fault f;
             if (is_fetch)
index 63928cb81f22e03252aa431f4c22488629e96300..e46d400a18446c04522163169de1f921b7f4c26c 100644 (file)
@@ -431,6 +431,7 @@ protected:
     bool haveLPAE;
     bool haveVirtualization;
     bool haveLargeAsid64;
+    uint8_t physAddrRange;
 
     AddrRange m5opRange;
 
index bb4044ad56dd068476e039a549d54fad43055895..c224a8743e380f0dcf2283cc5d0dd771aab7302e 100644 (file)
@@ -1396,9 +1396,9 @@ decodePhysAddrRange64(uint8_t pa_enc)
       case 0x4:
         return 44;
       case 0x5:
-      case 0x6:
-      case 0x7:
         return 48;
+      case 0x6:
+        return 52;
       default:
         panic("Invalid phys. address range encoding");
     }
@@ -1420,6 +1420,8 @@ encodePhysAddrRange64(int pa_size)
         return 0x4;
       case 48:
         return 0x5;
+      case 52:
+        return 0x6;
       default:
         panic("Invalid phys. address range");
     }