for debugging and program introspection.
Source('predecoder.cc')
Source('nativetrace.cc')
Source('tlb.cc')
- Source('vtophys.cc')
Source('utility.cc')
SimObject('ArmNativeTrace.py')
Source('interrupts.cc')
Source('stacktrace.cc')
Source('system.cc')
+ Source('vtophys.cc')
Source('linux/system.cc')
Source('table_walker.cc')
currState->vaddr = currState->req->getVaddr() & ~PcModeMask;
currState->sctlr = currState->tc->readMiscReg(MISCREG_SCTLR);
sctlr = currState->sctlr;
- currState->cpsr = currState->tc->readMiscReg(MISCREG_CPSR);
currState->N = currState->tc->readMiscReg(MISCREG_TTBCR);
currState->isFetch = (currState->mode == TLB::Execute);
currState->isWrite = (currState->mode == TLB::Write);
- currState->isPriv = (currState->cpsr.mode != MODE_USER);
Addr ttbr = 0;
class TableWalker : public MemObject
{
- protected:
+ public:
struct L1Descriptor {
/** Type of page table entry ARM DDI 0406B: B3-8*/
enum EntryType {
panic("Super sections not implemented\n");
return mbits(data, 31,20);
}
+ /** Return the physcal address of the entry, bits in position*/
+ Addr paddr(Addr va) const
+ {
+ if (supersection())
+ panic("Super sections not implemented\n");
+ return mbits(data, 31,20) | mbits(va, 20, 0);
+ }
+
/** Return the physical frame, bits shifted right */
Addr pfn() const
return large() ? bits(data, 31, 16) : bits(data, 31, 12);
}
+ /** Return complete physical address given a VA */
+ Addr paddr(Addr va) const
+ {
+ if (large())
+ return mbits(data, 31, 16) | mbits(va, 15, 0);
+ else
+ return mbits(data, 31, 12) | mbits(va, 11, 0);
+ }
+
/** If the section is shareable. See texcb() comment. */
bool shareable() const
{
/** Cached copy of the sctlr as it existed when translation began */
SCTLR sctlr;
- /** Cached copy of the cpsr as it existed when the translation began */
- CPSR cpsr;
-
/** Width of the base address held in TTRB0 */
uint32_t N;
/** If the access is a write */
bool isWrite;
- /** If the access is not from user mode */
- bool isPriv;
-
/** If the access is a fetch (for execution, and no-exec) must be checked?*/
bool isFetch;
delete [] table;
}
+bool
+TLB::translateFunctional(ThreadContext *tc, Addr va, Addr &pa)
+{
+ uint32_t context_id = tc->readMiscReg(MISCREG_CONTEXTIDR);
+ TlbEntry *e = lookup(va, context_id, true);
+ if (!e)
+ return false;
+ pa = e->pAddr(va);
+ return true;
+}
+
TlbEntry*
-TLB::lookup(Addr va, uint8_t cid)
+TLB::lookup(Addr va, uint8_t cid, bool functional)
{
// XXX This should either turn into a TlbMap or add caching
while (retval == NULL && x < size) {
if (table[x].match(va, cid)) {
retval = &table[x];
- if (x == nlu)
+ if (x == nlu && !functional)
nextnlu();
break;
#endif
void nextnlu() { if (++nlu >= size) nlu = 0; }
- TlbEntry *lookup(Addr vpn, uint8_t asn);
+ /** Lookup an entry in the TLB
+ * @param vpn virtual address
+ * @param asn context id/address space id to use
+ * @param functional if the lookup should modify state
+ * @return pointer to TLB entrry if it exists
+ */
+ TlbEntry *lookup(Addr vpn, uint8_t asn, bool functional = false);
// Access Stats
mutable Stats::Scalar read_hits;
static bool validVirtualAddress(Addr vaddr);
+ /**
+ * Do a functional lookup on the TLB (for debugging)
+ * and don't modify any internal state
+ * @param tc thread context to get the context id from
+ * @param vaddr virtual address to translate
+ * @param pa returned physical address
+ * @return if the translation was successful
+ */
+ bool translateFunctional(ThreadContext *tc, Addr vaddr, Addr &paddr);
+
/** Accessor functions for memory attributes for last accessed TLB entry
*/
void
/*
+ * Copyright (c) 2010 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
* Copyright (c) 2002-2005 The Regents of The University of Michigan
* Copyright (c) 2007-2008 The Florida State University
* All rights reserved.
#include <string>
+#include "arch/arm/table_walker.hh"
+#include "arch/arm/tlb.hh"
#include "arch/arm/vtophys.hh"
#include "base/chunk_generator.hh"
#include "base/trace.hh"
Addr
ArmISA::vtophys(Addr vaddr)
{
- fatal("VTOPHYS: Can't convert vaddr to paddr on ARM without a thread context");
+ fatal("VTOPHYS: Can't convert vaddr to paddr on ARM without a thread context");
}
Addr
ArmISA::vtophys(ThreadContext *tc, Addr addr)
{
- fatal("VTOPHYS: Unimplemented on ARM\n");
+ SCTLR sctlr = tc->readMiscReg(MISCREG_SCTLR);
+ if (!sctlr.m) {
+ // Translation is currently disabled PA == VA
+ return addr;
+ }
+ bool success;
+ Addr pa;
+ ArmISA::TLB *tlb;
+
+ // Check the TLBs far a translation
+ // It's possible that there is a validy translation in the tlb
+ // that is no loger valid in the page table in memory
+ // so we need to check here first
+ tlb = static_cast<ArmISA::TLB*>(tc->getDTBPtr());
+ success = tlb->translateFunctional(tc, addr, pa);
+ if (success)
+ return pa;
+
+ tlb = static_cast<ArmISA::TLB*>(tc->getITBPtr());
+ success = tlb->translateFunctional(tc, addr, pa);
+ if (success)
+ return pa;
+
+ // We've failed everything, so we need to do a
+ // hardware tlb walk without messing with any
+ // state
+
+ uint32_t N = tc->readMiscReg(MISCREG_TTBCR);
+ Addr ttbr;
+ if (N == 0 || !mbits(addr, 31, 32-N)) {
+ ttbr = tc->readMiscReg(MISCREG_TTBR0);
+ } else {
+ ttbr = tc->readMiscReg(MISCREG_TTBR1);
+ N = 0;
+ }
+
+ FunctionalPort *port = tc->getPhysPort();
+ Addr l1desc_addr = mbits(ttbr, 31, 14-N) | (bits(addr,31-N,20) << 2);
+
+ TableWalker::L1Descriptor l1desc;
+ l1desc.data = port->read<uint32_t>(l1desc_addr);
+ if (l1desc.type() == TableWalker::L1Descriptor::Ignore ||
+ l1desc.type() == TableWalker::L1Descriptor::Reserved) {
+ warn("Unable to translate virtual address: %#x\n", addr);
+ return -1;
+ }
+ if (l1desc.type() == TableWalker::L1Descriptor::Section)
+ return l1desc.paddr(addr);
+
+ // Didn't find it at the first level, try againt
+ Addr l2desc_addr = l1desc.l2Addr() | (bits(addr, 19, 12) << 2);
+ TableWalker::L2Descriptor l2desc;
+ l2desc.data = port->read<uint32_t>(l2desc_addr);
+
+ if (l2desc.invalid()) {
+ warn("Unable to translate virtual address: %#x\n", addr);
+ return -1;
+ }
+
+ return l2desc.paddr(addr);
}
+bool
+ArmISA::virtvalid(ThreadContext *tc, Addr vaddr)
+{
+ if (vtophys(tc, vaddr) != -1)
+ return true;
+ return false;
+}
+
+
Addr vtophys(Addr vaddr);
Addr vtophys(ThreadContext *tc, Addr vaddr);
+ bool virtvalid(ThreadContext *tc, Addr vaddr);
};
#endif // __ARCH_ARM_VTOPHYS_H__