From e90fb2ca4f730fb707fdf802db797d1dfff0e78f Mon Sep 17 00:00:00 2001 From: Jordi Vaquero Date: Thu, 25 Jun 2020 10:54:59 +0200 Subject: [PATCH] arch-arm: Implement Armv8.2-LVA Change-Id: I1b489a3629b2376e03e79b158631cb1d0cacc17e Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/35955 Reviewed-by: Giacomo Travaglini Maintainer: Giacomo Travaglini Tested-by: kokoro --- src/arch/arm/ArmISA.py | 3 +- src/arch/arm/table_walker.cc | 125 ++++++++++++++++++++++------------- src/arch/arm/table_walker.hh | 5 +- src/arch/arm/utility.cc | 7 ++ src/arch/arm/utility.hh | 1 + 5 files changed, 93 insertions(+), 48 deletions(-) diff --git a/src/arch/arm/ArmISA.py b/src/arch/arm/ArmISA.py index a70989448..02f24d3f3 100644 --- a/src/arch/arm/ArmISA.py +++ b/src/arch/arm/ArmISA.py @@ -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 diff --git a/src/arch/arm/table_walker.cc b/src/arch/arm/table_walker.cc index 9462e2743..d5027cf15 100644 --- a/src/arch/arm/table_walker.cc +++ b/src/arch/arm/table_walker.cc @@ -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; diff --git a/src/arch/arm/table_walker.hh b/src/arch/arm/table_walker.hh index 8f4aaefd3..ffb83ad49 100644 --- a/src/arch/arm/table_walker.hh +++ b/src/arch/arm/table_walker.hh @@ -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); diff --git a/src/arch/arm/utility.cc b/src/arch/arm/utility.cc index 4d866d09c..bb4044ad5 100644 --- a/src/arch/arm/utility.cc +++ b/src/arch/arm/utility.cc @@ -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) { diff --git a/src/arch/arm/utility.hh b/src/arch/arm/utility.hh index 636625d8b..6ec640396 100644 --- a/src/arch/arm/utility.hh +++ b/src/arch/arm/utility.hh @@ -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); -- 2.30.2