49a50
> #include "arch/arm/table_walker.hh"
60d60
<
65a66,68
> #if FULL_SYSTEM
> , tableWalker(p->walker)
> #endif
67,68c70,71
< table = new ArmISA::PTE[size];
< memset(table, 0, sizeof(ArmISA::PTE[size]));
---
> table = new TlbEntry[size];
> memset(table, 0, sizeof(TlbEntry[size]));
69a73
> tableWalker->setTlb(this);
78,79c82,83
< ArmISA::PTE *
< TLB::lookup(Addr vpn, uint8_t asn) const
---
> TlbEntry*
> TLB::lookup(Addr va, uint8_t cid)
81c85,108
< panic("lookup() not implemented for ARM\n");
---
> // XXX This should either turn into a TlbMap or add caching
>
> TlbEntry *retval = NULL;
>
> // Do some kind of caching, fast indexing, anything
>
> int x = 0;
> while (retval == NULL && x < size) {
> if (table[x].match(va, cid)) {
> retval = &table[x];
> if (x == nlu)
> nextnlu();
>
> break;
> }
> x++;
> }
>
> DPRINTF(TLBVerbose, "Lookup %#x, cid %#x -> %s ppn %#x size: %#x pa: %#x ap:%d\n",
> va, cid, retval ? "hit" : "miss", retval ? retval->pfn : 0,
> retval ? retval->size : 0, retval ? retval->pAddr(va) : 0,
> retval ? retval->ap : 0);
> ;
> return retval;
86c113
< TLB::insert(Addr addr, ArmISA::PTE &pte)
---
> TLB::insert(Addr addr, TlbEntry &entry)
88c115,130
< fatal("TLB Insert not yet implemented\n");
---
> DPRINTF(TLB, "Inserting entry into TLB with pfn:%#x size:%#x vpn: %#x"
> " asid:%d N:%d global:%d valid:%d nc:%d sNp:%d xn:%d ap:%#x"
> " domain:%#x\n", entry.pfn, entry.size, entry.vpn, entry.asid,
> entry.N, entry.global, entry.valid, entry.nonCacheable, entry.sNp,
> entry.xn, entry.ap, entry.domain);
>
> if (table[nlu].valid)
> DPRINTF(TLB, " - Replacing Valid entry %#x, asn %d ppn %#x size: %#x ap:%d\n",
> table[nlu].vpn << table[nlu].N, table[nlu].asid, table[nlu].pfn << table[nlu].N,
> table[nlu].size, table[nlu].ap);
>
> // XXX Update caching, lookup table etc
> table[nlu] = entry;
>
> // XXX Figure out how entries are generally inserted in ARM
> nextnlu();
91a134,149
> TLB::printTlb()
> {
> int x = 0;
> TlbEntry *te;
> DPRINTF(TLB, "Current TLB contents:\n");
> while (x < size) {
> te = &table[x];
> if (te->valid)
> DPRINTF(TLB, " * %#x, asn %d ppn %#x size: %#x ap:%d\n",
> te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap);
> x++;
> }
> }
>
>
> void
94,96c152,163
< DPRINTF(TLB, "flushAll\n");
< memset(table, 0, sizeof(ArmISA::PTE[size]));
< lookupTable.clear();
---
> DPRINTF(TLB, "Flushing all TLB entries\n");
> int x = 0;
> TlbEntry *te;
> while (x < size) {
> te = &table[x];
> if (te->valid)
> DPRINTF(TLB, " - %#x, asn %d ppn %#x size: %#x ap:%d\n",
> te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap);
> x++;
> }
>
> memset(table, 0, sizeof(TlbEntry[size]));
99a167
>
101c169
< TLB::serialize(ostream &os)
---
> TLB::flushMvaAsid(Addr mva, uint64_t asn)
103,104c171,172
< SERIALIZE_SCALAR(size);
< SERIALIZE_SCALAR(nlu);
---
> DPRINTF(TLB, "Flushing mva %#x asid: %#x\n", mva, asn);
> TlbEntry *te;
106,108c174,179
< for (int i = 0; i < size; i++) {
< nameOut(os, csprintf("%s.PTE%d", name(), i));
< table[i].serialize(os);
---
> te = lookup(mva, asn);
> while (te != NULL) {
> DPRINTF(TLB, " - %#x, asn %d ppn %#x size: %#x ap:%d\n",
> te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap);
> te->valid = false;
> te = lookup(mva,asn);
112a184,228
> TLB::flushAsid(uint64_t asn)
> {
> DPRINTF(TLB, "Flushing all entries with asid: %#x\n", asn);
>
> int x = 0;
> TlbEntry *te;
>
> while (x < size) {
> te = &table[x];
> if (te->asid == asn) {
> te->valid = false;
> DPRINTF(TLB, " - %#x, asn %d ppn %#x size: %#x ap:%d\n",
> te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap);
> }
> x++;
> }
> }
>
> void
> TLB::flushMva(Addr mva)
> {
> DPRINTF(TLB, "Flushing all entries with mva: %#x\n", mva);
>
> int x = 0;
> TlbEntry *te;
>
> while (x < size) {
> te = &table[x];
> Addr v = te->vpn << te->N;
> if (mva >= v && mva < v + te->size) {
> te->valid = false;
> DPRINTF(TLB, " - %#x, asn %d ppn %#x size: %#x ap:%d\n",
> te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap);
> }
> x++;
> }
> }
>
> void
> TLB::serialize(ostream &os)
> {
> panic("Implement Serialize\n");
> }
>
> void
115,116d230
< UNSERIALIZE_SCALAR(size);
< UNSERIALIZE_SCALAR(nlu);
119,121d232
< for (int i = 0; i < size; i++) {
< table[i].unserialize(cp, csprintf("%s.PTE%d", section, i));
< }
185c296
< TLB::translateAtomic(RequestPtr req, ThreadContext *tc, Mode mode)
---
> TLB::trickBoxCheck(RequestPtr req, Mode mode, uint8_t domain, bool sNp)
186a298,313
> return NoFault;
> }
>
> Fault
> TLB::walkTrickBoxCheck(Addr pa, Addr va, Addr sz, bool is_exec,
> uint8_t domain, bool sNp)
> {
> return NoFault;
> }
>
> #if !FULL_SYSTEM
> Fault
> TLB::translateSe(RequestPtr req, ThreadContext *tc, Mode mode,
> Translation *translation, bool &delay, bool timing)
> {
> // XXX Cache misc registers and have miscreg write function inv cache
191,192c318,319
< if (mode != Execute) {
< assert(flags & MustBeOne);
---
> bool is_fetch = (mode == Execute);
> bool is_write = (mode == Write);
194,197c321,325
< if (sctlr.a || (flags & AllowUnaligned) == 0) {
< if ((vaddr & flags & AlignmentMask) != 0) {
< return new DataAbort(vaddr, (mode == Write), 0,
< ArmFault::AlignmentFault);
---
> if (!is_fetch) {
> assert(flags & MustBeOne);
> if (sctlr.a || !(flags & AllowUnaligned)) {
> if (vaddr & flags & AlignmentMask) {
> return new DataAbort(vaddr, 0, is_write, ArmFault::AlignmentFault);
201,202d328
< #if !FULL_SYSTEM
< Process * p = tc->getProcessPtr();
204a331,332
> Process *p = tc->getProcessPtr();
>
210c338,370
< #else
---
> }
>
> #else // FULL_SYSTEM
>
> Fault
> TLB::translateFs(RequestPtr req, ThreadContext *tc, Mode mode,
> Translation *translation, bool &delay, bool timing)
> {
> // XXX Cache misc registers and have miscreg write function inv cache
> Addr vaddr = req->getVaddr() & ~PcModeMask;
> SCTLR sctlr = tc->readMiscReg(MISCREG_SCTLR);
> CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
> uint32_t flags = req->getFlags();
>
> bool is_fetch = (mode == Execute);
> bool is_write = (mode == Write);
> bool is_priv = (cpsr.mode != MODE_USER) && !(flags & UserMode);
>
> DPRINTF(TLBVerbose, "CPSR is user:%d UserMode:%d\n", cpsr.mode == MODE_USER, flags
> & UserMode);
> if (!is_fetch) {
> assert(flags & MustBeOne);
> if (sctlr.a || !(flags & AllowUnaligned)) {
> if (vaddr & flags & AlignmentMask) {
> return new DataAbort(vaddr, 0, is_write, ArmFault::AlignmentFault);
> }
> }
> }
>
> uint32_t context_id = tc->readMiscReg(MISCREG_CONTEXTIDR);
> Fault fault;
>
>
212a373,427
> if (sctlr.tre == 0) {
> req->setFlags(Request::UNCACHEABLE);
> } else {
> PRRR prrr = tc->readMiscReg(MISCREG_PRRR);
> NMRR nmrr = tc->readMiscReg(MISCREG_NMRR);
>
> if (nmrr.ir0 == 0 || nmrr.or0 == 0 || prrr.tr0 != 0x2)
> req->setFlags(Request::UNCACHEABLE);
> }
> return trickBoxCheck(req, mode, 0, false);
> }
>
> DPRINTF(TLBVerbose, "Translating vaddr=%#x context=%d\n", vaddr, context_id);
> // Translation enabled
>
> TlbEntry *te = lookup(vaddr, context_id);
> if (te == NULL) {
> // start translation table walk, pass variables rather than
> // re-retreaving in table walker for speed
> DPRINTF(TLB, "TLB Miss: Starting hardware table walker for %#x(%d)\n",
> vaddr, context_id);
> fault = tableWalker->walk(req, tc, context_id, mode, translation,
> timing);
> if (timing)
> delay = true;
> if (fault)
> return fault;
>
> te = lookup(vaddr, context_id);
> if (!te)
> printTlb();
> assert(te);
> }
>
> uint32_t dacr = tc->readMiscReg(MISCREG_DACR);
> switch ( (dacr >> (te->domain * 2)) & 0x3) {
> case 0:
> DPRINTF(TLB, "TLB Fault: Data abort on domain. DACR: %#x domain: %#x"
> " write:%d sNp:%d\n", dacr, te->domain, is_write, te->sNp);
> if (is_fetch)
> return new PrefetchAbort(vaddr,
> (te->sNp ? ArmFault::Domain0 : ArmFault::Domain1));
> else
> return new DataAbort(vaddr, te->domain, is_write,
> (te->sNp ? ArmFault::Domain0 : ArmFault::Domain1));
> case 1:
> // Continue with permissions check
> break;
> case 2:
> panic("UNPRED domain\n");
> case 3:
> req->setPaddr(te->pAddr(vaddr));
> fault = trickBoxCheck(req, mode, te->domain, te->sNp);
> if (fault)
> return fault;
215,216c430,482
< warn_once("MPU translation not implemented\n");
< req->setPaddr(vaddr);
---
>
> uint8_t ap = te->ap;
>
> if (sctlr.afe == 1)
> ap |= 1;
>
> bool abt;
>
> switch (ap) {
> case 0:
> abt = true;
> break;
> case 1:
> abt = !is_priv;
> break;
> case 2:
> abt = !is_priv && is_write;
> break;
> case 3:
> abt = false;
> break;
> case 4:
> panic("UNPRED premissions\n");
> case 5:
> abt = !is_priv || is_write;
> break;
> case 6:
> case 7:
> abt = is_write;
> break;
> default:
> panic("Unknown permissions\n");
> }
> if ((is_fetch) && (abt || te->xn)) {
> DPRINTF(TLB, "TLB Fault: Prefetch abort on permission check. AP:%d priv:%d"
> " write:%d sNp:%d\n", ap, is_priv, is_write, te->sNp);
> return new PrefetchAbort(vaddr,
> (te->sNp ? ArmFault::Permission0 :
> ArmFault::Permission1));
> } else if (abt) {
> DPRINTF(TLB, "TLB Fault: Data abort on permission check. AP:%d priv:%d"
> " write:%d sNp:%d\n", ap, is_priv, is_write, te->sNp);
> return new DataAbort(vaddr, te->domain, is_write,
> (te->sNp ? ArmFault::Permission0 :
> ArmFault::Permission1));
> }
>
> req->setPaddr(te->pAddr(vaddr));
> // Check for a trickbox generated address fault
> fault = trickBoxCheck(req, mode, te->domain, te->sNp);
> if (fault)
> return fault;
>
218c484
<
---
> }
220a487,499
>
> Fault
> TLB::translateAtomic(RequestPtr req, ThreadContext *tc, Mode mode)
> {
> bool delay = false;
> Fault fault;
> #if FULL_SYSTEM
> fault = translateFs(req, tc, mode, NULL, delay, false);
> #else
> fault = translateSe(req, tc, mode, NULL, delay, false);
> #endif
> assert(!delay);
> return fault;
223c502
< void
---
> Fault
228c507,516
< translation->finish(translateAtomic(req, tc, mode), req, tc, mode);
---
> bool delay = false;
> Fault fault;
> #if FULL_SYSTEM
> fault = translateFs(req, tc, mode, translation, delay, true);
> #else
> fault = translateSe(req, tc, mode, translation, delay, true);
> #endif
> if (!delay)
> translation->finish(fault, req, tc, mode);
> return fault;