diff options
author | Giacomo Travaglini <giacomo.travaglini@arm.com> | 2019-07-31 09:41:48 +0100 |
---|---|---|
committer | Giacomo Travaglini <giacomo.travaglini@arm.com> | 2019-09-18 13:30:01 +0000 |
commit | a4bf7c3c20756f01f39e644d65f97fd9813502f0 (patch) | |
tree | f9488099d2ccdddce14473881d82d59be82b0605 /src/arch/arm/table_walker.cc | |
parent | dc70987e470d66f584e0ddf606e9f07da994ba75 (diff) | |
download | gem5-a4bf7c3c20756f01f39e644d65f97fd9813502f0.tar.xz |
arch-arm: Fix Data Abort ISS when caused by Atomic operation
Data Aborts caused by an atomic instruction have a special rule for
their syndrome:
From a ISS point of view they count as read if a read to that address
would generate a fault; they count as writes otherwise (ISS.WnR bit)
This patch is implementing this in the TLB. For permission faults we
need to explicitly check if a read would trigger a fault
(e.g. checking for the AP bits) since permissions can allow read-only
accesses.
For other MMU exceptions (like translation faults) we are confident the
nature of the access doesn't affect the genration of a fault.
This means that if the access is atomic, we treat it as a read from an
ISS.WnR point of view.
Change-Id: Ia524aa6ae07f81513cdc26c516b5fd9b01a931c3
Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/20981
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
Diffstat (limited to 'src/arch/arm/table_walker.cc')
-rw-r--r-- | src/arch/arm/table_walker.cc | 47 |
1 files changed, 30 insertions, 17 deletions
diff --git a/src/arch/arm/table_walker.cc b/src/arch/arm/table_walker.cc index 508170a55..bfa5ba7bb 100644 --- a/src/arch/arm/table_walker.cc +++ b/src/arch/arm/table_walker.cc @@ -457,6 +457,7 @@ TableWalker::processWalk() // If translation isn't enabled, we shouldn't be here assert(currState->sctlr.m || isStage2); + const bool is_atomic = currState->req->isAtomic(); DPRINTF(TLB, "Beginning table walk for address %#x, TTBCR: %#x, bits:%#x\n", currState->vaddr_tainted, currState->ttbcr, mbits(currState->vaddr, 31, @@ -478,7 +479,8 @@ TableWalker::processWalk() else return std::make_shared<DataAbort>( currState->vaddr_tainted, - TlbEntry::DomainType::NoAccess, currState->isWrite, + TlbEntry::DomainType::NoAccess, + is_atomic ? false : currState->isWrite, ArmFault::TranslationLL + L1, isStage2, ArmFault::VmsaTran); } @@ -497,7 +499,8 @@ TableWalker::processWalk() else return std::make_shared<DataAbort>( currState->vaddr_tainted, - TlbEntry::DomainType::NoAccess, currState->isWrite, + TlbEntry::DomainType::NoAccess, + is_atomic ? false : currState->isWrite, ArmFault::TranslationLL + L1, isStage2, ArmFault::VmsaTran); } @@ -591,6 +594,8 @@ TableWalker::processWalkLPAE() else ttbr1_min = (1ULL << (32 - currState->ttbcr.t0sz)); + const bool is_atomic = currState->req->isAtomic(); + // The following code snippet selects the appropriate translation table base // address (TTBR0 or TTBR1) and the appropriate starting lookup level // depending on the address range supported by the translation table (ARM @@ -609,7 +614,7 @@ TableWalker::processWalkLPAE() return std::make_shared<DataAbort>( currState->vaddr_tainted, TlbEntry::DomainType::NoAccess, - currState->isWrite, + is_atomic ? false : currState->isWrite, ArmFault::TranslationLL + L1, isStage2, ArmFault::LpaeTran); @@ -633,7 +638,7 @@ TableWalker::processWalkLPAE() return std::make_shared<DataAbort>( currState->vaddr_tainted, TlbEntry::DomainType::NoAccess, - currState->isWrite, + is_atomic ? false : currState->isWrite, ArmFault::TranslationLL + L1, isStage2, ArmFault::LpaeTran); @@ -655,7 +660,8 @@ TableWalker::processWalkLPAE() return std::make_shared<DataAbort>( currState->vaddr_tainted, TlbEntry::DomainType::NoAccess, - currState->isWrite, ArmFault::TranslationLL + L1, + is_atomic ? false : currState->isWrite, + ArmFault::TranslationLL + L1, isStage2, ArmFault::LpaeTran); } @@ -849,6 +855,8 @@ TableWalker::processWalkAArch64() break; } + const bool is_atomic = currState->req->isAtomic(); + if (fault) { Fault f; if (currState->isFetch) @@ -860,7 +868,7 @@ TableWalker::processWalkAArch64() f = std::make_shared<DataAbort>( currState->vaddr_tainted, TlbEntry::DomainType::NoAccess, - currState->isWrite, + is_atomic ? false : currState->isWrite, ArmFault::TranslationLL + L0, isStage2, ArmFault::LpaeTran); @@ -946,7 +954,7 @@ TableWalker::processWalkAArch64() f = std::make_shared<DataAbort>( currState->vaddr_tainted, TlbEntry::DomainType::NoAccess, - currState->isWrite, + is_atomic ? false : currState->isWrite, ArmFault::AddressSizeLL + start_lookup_level, isStage2, ArmFault::LpaeTran); @@ -1458,6 +1466,8 @@ TableWalker::doL1Descriptor() currState->vaddr_tainted, currState->l1Desc.data); TlbEntry te; + const bool is_atomic = currState->req->isAtomic(); + switch (currState->l1Desc.type()) { case L1Descriptor::Ignore: case L1Descriptor::Reserved: @@ -1478,7 +1488,7 @@ TableWalker::doL1Descriptor() std::make_shared<DataAbort>( currState->vaddr_tainted, TlbEntry::DomainType::NoAccess, - currState->isWrite, + is_atomic ? false : currState->isWrite, ArmFault::TranslationLL + L1, isStage2, ArmFault::VmsaTran); return; @@ -1492,7 +1502,7 @@ TableWalker::doL1Descriptor() currState->fault = std::make_shared<DataAbort>( currState->vaddr_tainted, currState->l1Desc.domain(), - currState->isWrite, + is_atomic ? false : currState->isWrite, ArmFault::AccessFlagLL + L1, isStage2, ArmFault::VmsaTran); @@ -1555,7 +1565,7 @@ TableWalker::generateLongDescFault(ArmFault::FaultSource src) return std::make_shared<DataAbort>( currState->vaddr_tainted, TlbEntry::DomainType::NoAccess, - currState->isWrite, + currState->req->isAtomic() ? false : currState->isWrite, src + currState->longDesc.lookupLevel, isStage2, ArmFault::LpaeTran); @@ -1599,16 +1609,15 @@ TableWalker::doLongDescriptor() switch (currState->longDesc.type()) { case LongDescriptor::Invalid: - if (!currState->timing) { - currState->tc = NULL; - currState->req = NULL; - } - DPRINTF(TLB, "L%d descriptor Invalid, causing fault type %d\n", currState->longDesc.lookupLevel, ArmFault::TranslationLL + currState->longDesc.lookupLevel); currState->fault = generateLongDescFault(ArmFault::TranslationLL); + if (!currState->timing) { + currState->tc = NULL; + currState->req = NULL; + } return; case LongDescriptor::Block: @@ -1735,6 +1744,8 @@ TableWalker::doL2Descriptor() currState->vaddr_tainted, currState->l2Desc.data); TlbEntry te; + const bool is_atomic = currState->req->isAtomic(); + if (currState->l2Desc.invalid()) { DPRINTF(TLB, "L2 descriptor invalid, causing fault\n"); if (!currState->timing) { @@ -1750,7 +1761,8 @@ TableWalker::doL2Descriptor() else currState->fault = std::make_shared<DataAbort>( currState->vaddr_tainted, currState->l1Desc.domain(), - currState->isWrite, ArmFault::TranslationLL + L2, + is_atomic ? false : currState->isWrite, + ArmFault::TranslationLL + L2, isStage2, ArmFault::VmsaTran); return; @@ -1765,7 +1777,8 @@ TableWalker::doL2Descriptor() currState->fault = std::make_shared<DataAbort>( currState->vaddr_tainted, - TlbEntry::DomainType::NoAccess, currState->isWrite, + TlbEntry::DomainType::NoAccess, + is_atomic ? false : currState->isWrite, ArmFault::AccessFlagLL + L2, isStage2, ArmFault::VmsaTran); } |