/*
- * Copyright (c) 2010-2013, 2016-2018 ARM Limited
+ * Copyright (c) 2010-2013, 2016-2019 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
TlbEntry*
TLB::lookup(Addr va, uint16_t asn, uint8_t vmid, bool hyp, bool secure,
- bool functional, bool ignore_asn, uint8_t target_el)
+ bool functional, bool ignore_asn, ExceptionLevel target_el)
{
TlbEntry *retval = NULL;
}
void
-TLB::flushAllSecurity(bool secure_lookup, uint8_t target_el, bool ignore_el)
+TLB::flushAllSecurity(bool secure_lookup, ExceptionLevel target_el,
+ bool ignore_el)
{
DPRINTF(TLB, "Flushing all TLB entries (%s lookup)\n",
(secure_lookup ? "secure" : "non-secure"));
TlbEntry *te;
while (x < size) {
te = &table[x];
+ const bool el_match = ignore_el ?
+ true : te->checkELMatch(target_el);
+
if (te->valid && secure_lookup == !te->nstid &&
- (te->vmid == vmid || secure_lookup) &&
- checkELMatch(target_el, te->el, ignore_el)) {
+ (te->vmid == vmid || secure_lookup) && el_match) {
DPRINTF(TLB, " - %s\n", te->print());
te->valid = false;
// If there's a second stage TLB (and we're not it) then flush it as well
// if we're currently in hyp mode
if (!isStage2 && isHyp) {
- stage2Tlb->flushAllSecurity(secure_lookup, true);
+ stage2Tlb->flushAllSecurity(secure_lookup, EL1, true);
}
}
void
-TLB::flushAllNs(bool hyp, uint8_t target_el, bool ignore_el)
+TLB::flushAllNs(ExceptionLevel target_el, bool ignore_el)
{
+ bool hyp = target_el == EL2;
+
DPRINTF(TLB, "Flushing all NS TLB entries (%s lookup)\n",
(hyp ? "hyp" : "non-hyp"));
int x = 0;
TlbEntry *te;
while (x < size) {
te = &table[x];
- if (te->valid && te->nstid && te->isHyp == hyp &&
- checkELMatch(target_el, te->el, ignore_el)) {
+ const bool el_match = ignore_el ?
+ true : te->checkELMatch(target_el);
+
+ if (te->valid && te->nstid && te->isHyp == hyp && el_match) {
DPRINTF(TLB, " - %s\n", te->print());
flushedEntries++;
// If there's a second stage TLB (and we're not it) then flush it as well
if (!isStage2 && !hyp) {
- stage2Tlb->flushAllNs(false, true);
+ stage2Tlb->flushAllNs(EL1, true);
}
}
void
-TLB::flushMvaAsid(Addr mva, uint64_t asn, bool secure_lookup, uint8_t target_el)
+TLB::flushMvaAsid(Addr mva, uint64_t asn, bool secure_lookup,
+ ExceptionLevel target_el)
{
DPRINTF(TLB, "Flushing TLB entries with mva: %#x, asid: %#x "
"(%s lookup)\n", mva, asn, (secure_lookup ?
"secure" : "non-secure"));
- _flushMva(mva, asn, secure_lookup, false, false, target_el);
+ _flushMva(mva, asn, secure_lookup, false, target_el);
flushTlbMvaAsid++;
}
void
-TLB::flushAsid(uint64_t asn, bool secure_lookup, uint8_t target_el)
+TLB::flushAsid(uint64_t asn, bool secure_lookup, ExceptionLevel target_el)
{
DPRINTF(TLB, "Flushing TLB entries with asid: %#x (%s lookup)\n", asn,
(secure_lookup ? "secure" : "non-secure"));
te = &table[x];
if (te->valid && te->asid == asn && secure_lookup == !te->nstid &&
(te->vmid == vmid || secure_lookup) &&
- checkELMatch(target_el, te->el, false)) {
+ te->checkELMatch(target_el)) {
te->valid = false;
DPRINTF(TLB, " - %s\n", te->print());
}
void
-TLB::flushMva(Addr mva, bool secure_lookup, bool hyp, uint8_t target_el)
+TLB::flushMva(Addr mva, bool secure_lookup, ExceptionLevel target_el)
{
DPRINTF(TLB, "Flushing TLB entries with mva: %#x (%s lookup)\n", mva,
(secure_lookup ? "secure" : "non-secure"));
- _flushMva(mva, 0xbeef, secure_lookup, hyp, true, target_el);
+ _flushMva(mva, 0xbeef, secure_lookup, true, target_el);
flushTlbMva++;
}
void
-TLB::_flushMva(Addr mva, uint64_t asn, bool secure_lookup, bool hyp,
- bool ignore_asn, uint8_t target_el)
+TLB::_flushMva(Addr mva, uint64_t asn, bool secure_lookup,
+ bool ignore_asn, ExceptionLevel target_el)
{
TlbEntry *te;
// D5.7.2: Sign-extend address to 64 bits
mva = sext<56>(mva);
+
+ bool hyp = target_el == EL2;
+
te = lookup(mva, asn, vmid, hyp, secure_lookup, false, ignore_asn,
target_el);
while (te != NULL) {
}
void
-TLB::flushIpaVmid(Addr ipa, bool secure_lookup, bool hyp, uint8_t target_el)
+TLB::flushIpaVmid(Addr ipa, bool secure_lookup, ExceptionLevel target_el)
{
assert(!isStage2);
- stage2Tlb->_flushMva(ipa, 0xbeef, secure_lookup, hyp, true, target_el);
-}
-
-bool
-TLB::checkELMatch(uint8_t target_el, uint8_t tentry_el, bool ignore_el)
-{
- bool elMatch = true;
- if (!ignore_el) {
- if (target_el == 2 || target_el == 3) {
- elMatch = (tentry_el == target_el);
- } else {
- elMatch = (tentry_el == 0) || (tentry_el == 1);
- }
- }
- return elMatch;
+ stage2Tlb->_flushMva(ipa, 0xbeef, secure_lookup, true, target_el);
}
void
bool is_write = (mode == Write);
if (!is_fetch) {
- assert(flags & MustBeOne);
+ assert(flags & MustBeOne || req->isPrefetch());
if (sctlr.a || !(flags & AllowUnaligned)) {
if (vaddr & mask(flags & AlignmentMask)) {
// LPAE is always disabled in SE mode
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:
break;
case EL1:
{
+ if (checkPAN(tc, ap, req, mode)) {
+ grant = false;
+ grant_read = false;
+ break;
+ }
+
uint8_t perm = (ap << 2) | (xn << 1) | pxn;
switch (perm) {
case 0:
}
break;
case EL2:
+ if (hcr.e2h && checkPAN(tc, ap, req, mode)) {
+ grant = false;
+ grant_read = false;
+ break;
+ }
+ M5_FALLTHROUGH;
case EL3:
{
uint8_t perm = (ap & 0x2) | xn;
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);
}
return NoFault;
}
+bool
+TLB::checkPAN(ThreadContext *tc, uint8_t ap, const RequestPtr &req, Mode mode)
+{
+ // The PAN bit has no effect on:
+ // 1) Instruction accesses.
+ // 2) Data Cache instructions other than DC ZVA
+ // 3) Address translation instructions, other than ATS1E1RP and
+ // ATS1E1WP when ARMv8.2-ATS1E1 is implemented. (Unimplemented in
+ // gem5)
+ // 4) Unprivileged instructions (Unimplemented in gem5)
+ AA64MMFR1 mmfr1 = tc->readMiscReg(MISCREG_ID_AA64MMFR1_EL1);
+ if (mmfr1.pan && cpsr.pan && (ap & 0x1) && mode != Execute &&
+ (!req->isCacheMaintenance() ||
+ (req->getFlags() & Request::CACHE_BLOCK_ZERO))) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
Fault
TLB::translateFs(const RequestPtr &req, ThreadContext *tc, Mode mode,
Translation *translation, bool &delay, bool timing,
req->setFlags(Request::STRICT_ORDER);
}
if (!is_fetch) {
- assert(flags & MustBeOne);
+ assert(flags & MustBeOne || req->isPrefetch());
if (sctlr.a || !(flags & AllowUnaligned)) {
if (vaddr & mask(flags & AlignmentMask)) {
alignFaults++;
return fault;
}
-BaseMasterPort*
-TLB::getMasterPort()
+Port *
+TLB::getTableWalkerPort()
{
- return &stage2Mmu->getPort();
+ return &stage2Mmu->getDMAPort();
}
void
isPriv = aarch64EL != EL0;
if (haveVirtualization) {
vmid = bits(tc->readMiscReg(MISCREG_VTTBR_EL2), 55, 48);
- isHyp = tranType & HypMode;
+ isHyp = aarch64EL == EL2;
+ isHyp |= tranType & HypMode;
isHyp &= (tranType & S1S2NsTran) == 0;
isHyp &= (tranType & S1CTran) == 0;
// Work out if we should skip the first stage of translation and go
case S1CTran:
case S1S2NsTran:
case HypMode:
- return opModeToEL((OperatingMode)(uint8_t)cpsr.mode);
+ return currEL(cpsr);
default:
panic("Unknown translation mode!\n");
Translation *translation, bool timing, bool functional,
bool is_secure, TLB::ArmTranslationType tranType)
{
+ // In a 2-stage system, the IPA->PA translation can be started via this
+ // call so make sure the miscRegs are correct.
+ if (isStage2) {
+ updateMiscReg(tc, tranType);
+ }
bool is_fetch = (mode == Execute);
bool is_write = (mode == Write);