* Steve Reinhardt
*/
+#include "arch/arm/tlb.hh"
+
+#include <memory>
#include <string>
#include <vector>
#include "arch/arm/table_walker.hh"
#include "arch/arm/stage2_lookup.hh"
#include "arch/arm/stage2_mmu.hh"
-#include "arch/arm/tlb.hh"
#include "arch/arm/utility.hh"
#include "base/inifile.hh"
#include "base/str.hh"
TLB::TLB(const ArmTLBParams *p)
: BaseTLB(p), table(new TlbEntry[p->size]), size(p->size),
- isStage2(p->is_stage2), tableWalker(p->walker), stage2Tlb(NULL),
- stage2Mmu(NULL), rangeMRU(1), bootUncacheability(false),
- miscRegValid(false), curTranType(NormalTran)
+ isStage2(p->is_stage2), stage2Req(false), _attr(0),
+ directToStage2(false), tableWalker(p->walker), stage2Tlb(NULL),
+ stage2Mmu(NULL), rangeMRU(1),
+ aarch64(false), aarch64EL(EL0), isPriv(false), isSecure(false),
+ isHyp(false), asid(0), vmid(0), dacr(0),
+ miscRegValid(false), miscRegContext(0), curTranType(NormalTran)
{
tableWalker->setTlb(this);
}
void
-TLB::setMMU(Stage2MMU *m)
+TLB::setMMU(Stage2MMU *m, MasterID master_id)
{
stage2Mmu = m;
- tableWalker->setMMU(m);
+ tableWalker->setMMU(m, master_id);
}
bool
// than rangeMRU
if (x > rangeMRU && !functional) {
TlbEntry tmp_entry = table[x];
- for(int i = x; i > 0; i--)
+ for (int i = x; i > 0; i--)
table[i] = table[i - 1];
table[0] = tmp_entry;
retval = &table[0];
table[0] = entry;
inserts++;
+ ppRefills->notify(1);
}
void
haveLPAE = otlb->haveLPAE;
directToStage2 = otlb->directToStage2;
stage2Req = otlb->stage2Req;
- bootUncacheability = otlb->bootUncacheability;
/* Sync the stage2 MMU if they exist in both
* the old CPU and the new
}
void
-TLB::serialize(ostream &os)
+TLB::serialize(CheckpointOut &cp) const
{
DPRINTF(Checkpoint, "Serializing Arm TLB\n");
SERIALIZE_SCALAR(haveLPAE);
SERIALIZE_SCALAR(directToStage2);
SERIALIZE_SCALAR(stage2Req);
- SERIALIZE_SCALAR(bootUncacheability);
int num_entries = size;
SERIALIZE_SCALAR(num_entries);
- for(int i = 0; i < size; i++){
- nameOut(os, csprintf("%s.TlbEntry%d", name(), i));
- table[i].serialize(os);
- }
+ for (int i = 0; i < size; i++)
+ table[i].serializeSection(cp, csprintf("TlbEntry%d", i));
}
void
-TLB::unserialize(Checkpoint *cp, const string §ion)
+TLB::unserialize(CheckpointIn &cp)
{
DPRINTF(Checkpoint, "Unserializing Arm TLB\n");
UNSERIALIZE_SCALAR(haveLPAE);
UNSERIALIZE_SCALAR(directToStage2);
UNSERIALIZE_SCALAR(stage2Req);
- UNSERIALIZE_SCALAR(bootUncacheability);
int num_entries;
UNSERIALIZE_SCALAR(num_entries);
- for(int i = 0; i < min(size, num_entries); i++){
- table[i].unserialize(cp, csprintf("%s.TlbEntry%d", section, i));
- }
+ for (int i = 0; i < min(size, num_entries); i++)
+ table[i].unserializeSection(cp, csprintf("TlbEntry%d", i));
}
void
accesses = readAccesses + writeAccesses + instAccesses;
}
+void
+TLB::regProbePoints()
+{
+ ppRefills.reset(new ProbePoints::PMU(getProbeManager(), "Refills"));
+}
+
Fault
TLB::translateSe(RequestPtr req, ThreadContext *tc, Mode mode,
Translation *translation, bool &delay, bool timing)
Addr vaddr_tainted = req->getVaddr();
Addr vaddr = 0;
if (aarch64)
- vaddr = purifyTaggedAddr(vaddr_tainted, tc, aarch64EL);
+ vaddr = purifyTaggedAddr(vaddr_tainted, tc, aarch64EL, ttbcr);
else
vaddr = vaddr_tainted;
uint32_t flags = req->getFlags();
if (sctlr.a || !(flags & AllowUnaligned)) {
if (vaddr & mask(flags & AlignmentMask)) {
// LPAE is always disabled in SE mode
- return new DataAbort(vaddr_tainted,
- TlbEntry::DomainType::NoAccess, is_write,
- ArmFault::AlignmentFault, isStage2,
- ArmFault::VmsaTran);
+ return std::make_shared<DataAbort>(
+ vaddr_tainted,
+ TlbEntry::DomainType::NoAccess, is_write,
+ ArmFault::AlignmentFault, isStage2,
+ ArmFault::VmsaTran);
}
}
}
Process *p = tc->getProcessPtr();
if (!p->pTable->translate(vaddr, paddr))
- return Fault(new GenericPageTableFault(vaddr_tainted));
+ return std::make_shared<GenericPageTableFault>(vaddr_tainted);
req->setPaddr(paddr);
return NoFault;
// as a device or strongly ordered.
if (isStage2 && req->isPTWalk() && hcr.ptw &&
(te->mtype != TlbEntry::MemoryType::Normal)) {
- return new DataAbort(vaddr, te->domain, is_write,
- ArmFault::PermissionLL + te->lookupLevel,
- isStage2, tranMethod);
+ return std::make_shared<DataAbort>(
+ vaddr, te->domain, is_write,
+ ArmFault::PermissionLL + te->lookupLevel,
+ isStage2, tranMethod);
}
// Generate an alignment fault for unaligned data accesses to device or
if (te->mtype != TlbEntry::MemoryType::Normal) {
if (vaddr & mask(flags & AlignmentMask)) {
alignFaults++;
- return new DataAbort(vaddr, TlbEntry::DomainType::NoAccess, is_write,
- ArmFault::AlignmentFault, isStage2,
- tranMethod);
+ return std::make_shared<DataAbort>(
+ vaddr, TlbEntry::DomainType::NoAccess, is_write,
+ ArmFault::AlignmentFault, isStage2,
+ tranMethod);
}
}
}
if (req->isPrefetch()) {
// Here we can safely use the fault status for the short
// desc. format in all cases
- return new PrefetchAbort(vaddr, ArmFault::PrefetchUncacheable,
- isStage2, tranMethod);
+ return std::make_shared<PrefetchAbort>(
+ vaddr, ArmFault::PrefetchUncacheable,
+ isStage2, tranMethod);
}
}
" domain: %#x write:%d\n", dacr,
static_cast<uint8_t>(te->domain), is_write);
if (is_fetch)
- return new PrefetchAbort(vaddr,
- ArmFault::DomainLL + te->lookupLevel,
- isStage2, tranMethod);
+ return std::make_shared<PrefetchAbort>(
+ vaddr,
+ ArmFault::DomainLL + te->lookupLevel,
+ isStage2, tranMethod);
else
- return new DataAbort(vaddr, te->domain, is_write,
- ArmFault::DomainLL + te->lookupLevel,
- isStage2, tranMethod);
+ return std::make_shared<DataAbort>(
+ vaddr, te->domain, is_write,
+ ArmFault::DomainLL + te->lookupLevel,
+ isStage2, tranMethod);
case 1:
// Continue with permissions check
break;
DPRINTF(TLB, "TLB Fault: Prefetch abort on permission check. AP:%d "
"priv:%d write:%d ns:%d sif:%d sctlr.afe: %d \n",
ap, is_priv, is_write, te->ns, scr.sif,sctlr.afe);
- return new PrefetchAbort(vaddr,
- ArmFault::PermissionLL + te->lookupLevel,
- isStage2, tranMethod);
+ return std::make_shared<PrefetchAbort>(
+ vaddr,
+ ArmFault::PermissionLL + te->lookupLevel,
+ isStage2, tranMethod);
} else if (abt | hapAbt) {
permsFaults++;
DPRINTF(TLB, "TLB Fault: Data abort on permission check. AP:%d priv:%d"
" write:%d\n", ap, is_priv, is_write);
- return new DataAbort(vaddr, te->domain, is_write,
- ArmFault::PermissionLL + te->lookupLevel,
- isStage2 | !abt, tranMethod);
+ return std::make_shared<DataAbort>(
+ vaddr, te->domain, is_write,
+ ArmFault::PermissionLL + te->lookupLevel,
+ isStage2 | !abt, tranMethod);
}
return NoFault;
}
assert(aarch64);
Addr vaddr_tainted = req->getVaddr();
- Addr vaddr = purifyTaggedAddr(vaddr_tainted, tc, aarch64EL);
+ Addr vaddr = purifyTaggedAddr(vaddr_tainted, tc, aarch64EL, ttbcr);
uint32_t flags = req->getFlags();
bool is_fetch = (mode == Execute);
// as a device or strongly ordered.
if (isStage2 && req->isPTWalk() && hcr.ptw &&
(te->mtype != TlbEntry::MemoryType::Normal)) {
- return new DataAbort(vaddr_tainted, te->domain, is_write,
- ArmFault::PermissionLL + te->lookupLevel,
- isStage2, ArmFault::LpaeTran);
+ return std::make_shared<DataAbort>(
+ vaddr_tainted, te->domain, is_write,
+ ArmFault::PermissionLL + te->lookupLevel,
+ isStage2, ArmFault::LpaeTran);
}
// Generate an alignment fault for unaligned accesses to device or
if (te->mtype != TlbEntry::MemoryType::Normal) {
if (vaddr & mask(flags & AlignmentMask)) {
alignFaults++;
- return new DataAbort(vaddr_tainted,
- TlbEntry::DomainType::NoAccess, is_write,
- ArmFault::AlignmentFault, isStage2,
- ArmFault::LpaeTran);
+ return std::make_shared<DataAbort>(
+ vaddr_tainted,
+ TlbEntry::DomainType::NoAccess, is_write,
+ ArmFault::AlignmentFault, isStage2,
+ ArmFault::LpaeTran);
}
}
}
if (req->isPrefetch()) {
// Here we can safely use the fault status for the short
// desc. format in all cases
- return new PrefetchAbort(vaddr_tainted,
- ArmFault::PrefetchUncacheable,
- isStage2, ArmFault::LpaeTran);
+ return std::make_shared<PrefetchAbort>(
+ vaddr_tainted,
+ ArmFault::PrefetchUncacheable,
+ isStage2, ArmFault::LpaeTran);
}
}
ap, is_priv, is_write, te->ns, scr.sif, sctlr.afe);
// Use PC value instead of vaddr because vaddr might be aligned to
// cache line and should not be the address reported in FAR
- return new PrefetchAbort(req->getPC(),
- ArmFault::PermissionLL + te->lookupLevel,
- isStage2, ArmFault::LpaeTran);
+ return std::make_shared<PrefetchAbort>(
+ req->getPC(),
+ ArmFault::PermissionLL + te->lookupLevel,
+ isStage2, ArmFault::LpaeTran);
} else {
permsFaults++;
DPRINTF(TLB, "TLB Fault: Data abort on permission check. AP:%d "
"priv:%d write:%d\n", ap, is_priv, is_write);
- return new DataAbort(vaddr_tainted, te->domain, is_write,
- ArmFault::PermissionLL + te->lookupLevel,
- isStage2, ArmFault::LpaeTran);
+ return std::make_shared<DataAbort>(
+ vaddr_tainted, te->domain, is_write,
+ ArmFault::PermissionLL + te->lookupLevel,
+ isStage2, ArmFault::LpaeTran);
}
}
Addr vaddr_tainted = req->getVaddr();
Addr vaddr = 0;
if (aarch64)
- vaddr = purifyTaggedAddr(vaddr_tainted, tc, aarch64EL);
+ vaddr = purifyTaggedAddr(vaddr_tainted, tc, aarch64EL, ttbcr);
else
vaddr = vaddr_tainted;
uint32_t flags = req->getFlags();
"flags %#x tranType 0x%x\n", vaddr_tainted, mode, isStage2,
scr, sctlr, flags, tranType);
- // Generate an alignment fault for unaligned PC
- if (aarch64 && is_fetch && (req->getPC() & mask(2))) {
- return new PCAlignmentFault(req->getPC());
- }
-
- // If this is a clrex instruction, provide a PA of 0 with no fault
- // This will force the monitor to set the tracked address to 0
- // a bit of a hack but this effectively clrears this processors monitor
- if (flags & Request::CLEAR_LL){
- // @todo: check implications of security extensions
- req->setPaddr(0);
- req->setFlags(Request::UNCACHEABLE);
- req->setFlags(Request::CLEAR_LL);
- return NoFault;
- }
if ((req->isInstFetch() && (!sctlr.i)) ||
((!req->isInstFetch()) && (!sctlr.c))){
- req->setFlags(Request::UNCACHEABLE);
+ req->setFlags(Request::UNCACHEABLE | Request::STRICT_ORDER);
}
if (!is_fetch) {
assert(flags & MustBeOne);
if (sctlr.a || !(flags & AllowUnaligned)) {
if (vaddr & mask(flags & AlignmentMask)) {
alignFaults++;
- return new DataAbort(vaddr_tainted,
- TlbEntry::DomainType::NoAccess, is_write,
- ArmFault::AlignmentFault, isStage2,
- tranMethod);
+ return std::make_shared<DataAbort>(
+ vaddr_tainted,
+ TlbEntry::DomainType::NoAccess, is_write,
+ ArmFault::AlignmentFault, isStage2,
+ tranMethod);
}
}
}
// @todo: double check this (ARM ARM issue C B3.2.1)
if (long_desc_format || sctlr.tre == 0) {
- req->setFlags(Request::UNCACHEABLE);
+ req->setFlags(Request::UNCACHEABLE | Request::STRICT_ORDER);
} else {
if (nmrr.ir0 == 0 || nmrr.or0 == 0 || prrr.tr0 != 0x2)
- req->setFlags(Request::UNCACHEABLE);
+ req->setFlags(Request::UNCACHEABLE | Request::STRICT_ORDER);
}
// Set memory attributes
te->shareable, te->innerAttrs, te->outerAttrs,
static_cast<uint8_t>(te->mtype), isStage2);
setAttr(te->attributes);
- if (te->nonCacheable) {
- req->setFlags(Request::UNCACHEABLE);
- }
- if (!bootUncacheability &&
- ((ArmSystem*)tc->getSystemPtr())->adderBootUncacheable(vaddr)) {
+ if (te->nonCacheable)
req->setFlags(Request::UNCACHEABLE);
- }
- req->setPaddr(te->pAddr(vaddr));
+ // Require requests to be ordered if the request goes to
+ // strongly ordered or device memory (i.e., anything other
+ // than normal memory requires strict order).
+ if (te->mtype != TlbEntry::MemoryType::Normal)
+ req->setFlags(Request::STRICT_ORDER);
+
+ Addr pa = te->pAddr(vaddr);
+ req->setPaddr(pa);
+
if (isSecure && !te->ns) {
req->setFlags(Request::SECURE);
}
// Unaligned accesses to Device memory should always cause an
// abort regardless of sctlr.a
alignFaults++;
- return new DataAbort(vaddr_tainted,
- TlbEntry::DomainType::NoAccess, is_write,
- ArmFault::AlignmentFault, isStage2,
- tranMethod);
+ return std::make_shared<DataAbort>(
+ vaddr_tainted,
+ TlbEntry::DomainType::NoAccess, is_write,
+ ArmFault::AlignmentFault, isStage2,
+ tranMethod);
}
// Check for a trickbox generated address fault
// Generate Illegal Inst Set State fault if IL bit is set in CPSR
if (fault == NoFault) {
- CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
if (aarch64 && is_fetch && cpsr.il == 1) {
- return new IllegalInstSetStateFault();
+ return std::make_shared<IllegalInstSetStateFault>();
}
}
BaseMasterPort*
TLB::getMasterPort()
{
- return &tableWalker->getMasterPort("port");
-}
-
-DmaPort&
-TLB::getWalkerPort()
-{
- return tableWalker->getWalkerPort();
+ return &stage2Mmu->getPort();
}
void
// check if the regs have changed, or the translation mode is different.
// NOTE: the tran type doesn't affect stage 2 TLB's as they only handle
// one type of translation anyway
- if (miscRegValid && ((tranType == curTranType) || isStage2)) {
+ if (miscRegValid && miscRegContext == tc->contextId() &&
+ ((tranType == curTranType) || isStage2)) {
return;
}
DPRINTF(TLBVerbose, "TLB variables changed!\n");
- CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
+ cpsr = tc->readMiscReg(MISCREG_CPSR);
// Dependencies: SCR/SCR_EL3, CPSR
isSecure = inSecureState(tc);
isSecure &= (tranType & HypMode) == 0;
}
}
miscRegValid = true;
+ miscRegContext = tc->contextId();
curTranType = tranType;
}
Addr vaddr = 0;
ExceptionLevel target_el = aarch64 ? aarch64EL : EL1;
if (aarch64) {
- vaddr = purifyTaggedAddr(vaddr_tainted, tc, target_el);
+ vaddr = purifyTaggedAddr(vaddr_tainted, tc, target_el, ttbcr);
} else {
vaddr = vaddr_tainted;
}
// any further with the memory access (here we can safely use the
// fault status for the short desc. format in all cases)
prefetchFaults++;
- return new PrefetchAbort(vaddr_tainted, ArmFault::PrefetchTLBMiss, isStage2);
+ return std::make_shared<PrefetchAbort>(
+ vaddr_tainted, ArmFault::PrefetchTLBMiss, isStage2);
}
if (is_fetch)