From 05e60080dc2ecf24ebcb53097a0647ed5132c92f Mon Sep 17 00:00:00 2001 From: Jordi Vaquero Date: Fri, 3 Jul 2020 09:58:51 +0200 Subject: [PATCH] arch-arm: Implement Armv8.2-LPA 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 Maintainer: Giacomo Travaglini Tested-by: kokoro --- src/arch/arm/pagetable.hh | 2 +- src/arch/arm/system.cc | 2 +- src/arch/arm/table_walker.cc | 50 ++++++++++-------- src/arch/arm/table_walker.hh | 98 ++++++++++++++++++++++++------------ src/arch/arm/tlb.cc | 3 +- src/arch/arm/tlb.hh | 1 + src/arch/arm/utility.cc | 6 ++- 7 files changed, 105 insertions(+), 57 deletions(-) diff --git a/src/arch/arm/pagetable.hh b/src/arch/arm/pagetable.hh index 9d1df1f21..84e1967b3 100644 --- a/src/arch/arm/pagetable.hh +++ b/src/arch/arm/pagetable.hh @@ -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 diff --git a/src/arch/arm/system.cc b/src/arch/arm/system.cc index 7009b31dd..20ebee2df 100644 --- a/src/arch/arm/system.cc +++ b/src/arch/arm/system.cc @@ -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); } diff --git a/src/arch/arm/table_walker.cc b/src/arch/arm/table_walker.cc index d5027cf15..26e20b280 100644 --- a/src/arch/arm/table_walker.cc +++ b/src/arch/arm/table_walker.cc @@ -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 diff --git a/src/arch/arm/table_walker.hh b/src/arch/arm/table_walker.hh index ffb83ad49..309c402af 100644 --- a/src/arch/arm/table_walker.hh +++ b/src/arch/arm/table_walker.hh @@ -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; diff --git a/src/arch/arm/tlb.cc b/src/arch/arm/tlb.cc index a0f837df8..700988e4b 100644 --- a/src/arch/arm/tlb.cc +++ b/src/arch/arm/tlb.cc @@ -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) diff --git a/src/arch/arm/tlb.hh b/src/arch/arm/tlb.hh index 63928cb81..e46d400a1 100644 --- a/src/arch/arm/tlb.hh +++ b/src/arch/arm/tlb.hh @@ -431,6 +431,7 @@ protected: bool haveLPAE; bool haveVirtualization; bool haveLargeAsid64; + uint8_t physAddrRange; AddrRange m5opRange; diff --git a/src/arch/arm/utility.cc b/src/arch/arm/utility.cc index bb4044ad5..c224a8743 100644 --- a/src/arch/arm/utility.cc +++ b/src/arch/arm/utility.cc @@ -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"); } -- 2.30.2