// 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,
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);
}
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);
}
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
return std::make_shared<DataAbort>(
currState->vaddr_tainted,
TlbEntry::DomainType::NoAccess,
- currState->isWrite,
+ is_atomic ? false : currState->isWrite,
ArmFault::TranslationLL + L1,
isStage2,
ArmFault::LpaeTran);
return std::make_shared<DataAbort>(
currState->vaddr_tainted,
TlbEntry::DomainType::NoAccess,
- currState->isWrite,
+ is_atomic ? false : currState->isWrite,
ArmFault::TranslationLL + L1,
isStage2,
ArmFault::LpaeTran);
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);
}
break;
}
+ const bool is_atomic = currState->req->isAtomic();
+
if (fault) {
Fault f;
if (currState->isFetch)
f = std::make_shared<DataAbort>(
currState->vaddr_tainted,
TlbEntry::DomainType::NoAccess,
- currState->isWrite,
+ is_atomic ? false : currState->isWrite,
ArmFault::TranslationLL + L0,
isStage2, ArmFault::LpaeTran);
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);
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:
std::make_shared<DataAbort>(
currState->vaddr_tainted,
TlbEntry::DomainType::NoAccess,
- currState->isWrite,
+ is_atomic ? false : currState->isWrite,
ArmFault::TranslationLL + L1, isStage2,
ArmFault::VmsaTran);
return;
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);
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);
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:
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) {
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;
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);
}
bool is_fetch = (mode == Execute);
// Cache clean operations require read permissions to the specified VA
bool is_write = !req->isCacheClean() && mode == Write;
+ bool is_atomic = req->isAtomic();
bool is_priv M5_VAR_USED = isPriv && !(flags & UserMode);
updateMiscReg(tc, curTranType);
alignFaults++;
return std::make_shared<DataAbort>(
vaddr_tainted,
- TlbEntry::DomainType::NoAccess, is_write,
+ TlbEntry::DomainType::NoAccess,
+ is_atomic ? false : is_write,
ArmFault::AlignmentFault, isStage2,
ArmFault::LpaeTran);
}
bool r = !is_write && !is_fetch;
bool w = is_write;
bool x = is_fetch;
+
+ // grant_read is used for faults from an atomic instruction that
+ // both reads and writes from a memory location. From a ISS point
+ // of view they count as read if a read to that address would have
+ // generated the fault; they count as writes otherwise
+ bool grant_read = true;
DPRINTF(TLBVerbose, "Checking permissions: ap:%d, xn:%d, pxn:%d, r:%d, "
"w:%d, x:%d\n", ap, xn, pxn, r, w, x);
// The following permissions are described in ARM DDI 0487A.f
// D4-1802
uint8_t hap = 0x3 & te->hap;
+ grant_read = hap & 0x1;
if (is_fetch) {
// sctlr.wxn overrides the xn bit
grant = !sctlr.wxn && !xn;
} else if (is_write) {
grant = hap & 0x2;
} else { // is_read
- grant = hap & 0x1;
+ grant = grant_read;
}
} else {
switch (aarch64EL) {
case EL0:
{
+ grant_read = ap & 0x1;
uint8_t perm = (ap << 2) | (xn << 1) | pxn;
switch (perm) {
case 0:
{
if (checkPAN(tc, ap, req, mode)) {
grant = false;
+ grant_read = false;
break;
}
case EL2:
if (hcr.e2h && checkPAN(tc, ap, req, mode)) {
grant = false;
+ grant_read = false;
break;
}
M5_FALLTHROUGH;
DPRINTF(TLB, "TLB Fault: Data abort on permission check. AP:%d "
"priv:%d write:%d\n", ap, is_priv, is_write);
return std::make_shared<DataAbort>(
- vaddr_tainted, te->domain, is_write,
+ vaddr_tainted, te->domain,
+ (is_atomic && !grant_read) ? false : is_write,
ArmFault::PermissionLL + te->lookupLevel,
isStage2, ArmFault::LpaeTran);
}