Jordi Vaquero has uploaded this change for review. (
https://gem5-review.googlesource.com/c/public/gem5/+/35956 )
Change subject: arch-arm: Implement Armv8.2-LPA
......................................................................
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
---
M src/arch/arm/pagetable.hh
M src/arch/arm/system.cc
M src/arch/arm/table_walker.cc
M src/arch/arm/table_walker.hh
M src/arch/arm/tlb.cc
M src/arch/arm/tlb.hh
M src/arch/arm/utility.cc
7 files changed, 105 insertions(+), 57 deletions(-)
diff --git a/src/arch/arm/pagetable.hh b/src/arch/arm/pagetable.hh
index 9d1df1f..84e1967 100644
--- a/src/arch/arm/pagetable.hh
+++ b/src/arch/arm/pagetable.hh
@@ -51,7 +51,7 @@
{
// 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 7009b31..20ebee2 100644
--- a/src/arch/arm/system.cc
+++ b/src/arch/arm/system.cc
@@ -95,7 +95,7 @@
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 d5027cf..26e20b2 100644
--- a/src/arch/arm/table_walker.cc
+++ b/src/arch/arm/table_walker.cc
@@ -81,12 +81,12 @@
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 @@
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 @@
}
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 @@
"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 @@
}
return f;
- }
+ }
// Determine descriptor address
Addr desc_addr = base_addr |
@@ -1119,6 +1128,7 @@
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 @@
{
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 @@
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 @@
.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 @@
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 ffb83ad..309c402 100644
--- a/src/arch/arm/table_walker.hh
+++ b/src/arch/arm/table_walker.hh
@@ -382,7 +382,10 @@
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 @@
* 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 @@
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 @@
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 @@
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 @@
/** 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 @@
bool haveSecurity;
bool _haveLPAE;
bool _haveVirtualization;
- uint8_t physAddrRange;
+ uint8_t _physAddrRange;
bool _haveLargeAsid64;
/** Statistics */
@@ -896,6 +928,7 @@
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 @@
/// 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 a0f837d..700988e 100644
--- a/src/arch/arm/tlb.cc
+++ b/src/arch/arm/tlb.cc
@@ -89,6 +89,7 @@
haveLPAE = tableWalker->haveLPAE();
haveVirtualization = tableWalker->haveVirtualization();
haveLargeAsid64 = tableWalker->haveLargeAsid64();
+ physAddrRange = tableWalker->physAddrRange();
if (sys)
m5opRange = sys->m5opRange();
@@ -949,7 +950,7 @@
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 63928cb..e46d400 100644
--- a/src/arch/arm/tlb.hh
+++ b/src/arch/arm/tlb.hh
@@ -431,6 +431,7 @@
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 bb4044a..c224a87 100644
--- a/src/arch/arm/utility.cc
+++ b/src/arch/arm/utility.cc
@@ -1396,9 +1396,9 @@
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 @@
return 0x4;
case 48:
return 0x5;
+ case 52:
+ return 0x6;
default:
panic("Invalid phys. address range");
}
--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/35956
To unsubscribe, or for help writing mail filters, visit
https://gem5-review.googlesource.com/settings
Gerrit-Project: public/gem5
Gerrit-Branch: develop
Gerrit-Change-Id: If9b36e26cd2a72e55c8e929a632b7b50d909b282
Gerrit-Change-Number: 35956
Gerrit-PatchSet: 1
Gerrit-Owner: Jordi Vaquero <jordi.vaqu...@metempsy.com>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list -- gem5-dev@gem5.org
To unsubscribe send an email to gem5-dev-le...@gem5.org
%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s