ARM: Implement functional virtual to physical address translation
for debugging and program introspection.
This commit is contained in:
parent
518b5e5b1c
commit
521d68c82a
7 changed files with 134 additions and 15 deletions
|
@ -59,7 +59,6 @@ if env['TARGET_ISA'] == 'arm':
|
|||
Source('predecoder.cc')
|
||||
Source('nativetrace.cc')
|
||||
Source('tlb.cc')
|
||||
Source('vtophys.cc')
|
||||
Source('utility.cc')
|
||||
|
||||
SimObject('ArmNativeTrace.py')
|
||||
|
@ -73,6 +72,7 @@ if env['TARGET_ISA'] == 'arm':
|
|||
Source('interrupts.cc')
|
||||
Source('stacktrace.cc')
|
||||
Source('system.cc')
|
||||
Source('vtophys.cc')
|
||||
Source('linux/system.cc')
|
||||
Source('table_walker.cc')
|
||||
|
||||
|
|
|
@ -110,12 +110,10 @@ TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint8_t _cid, TLB::Mode _
|
|||
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;
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ class TLB;
|
|||
|
||||
class TableWalker : public MemObject
|
||||
{
|
||||
protected:
|
||||
public:
|
||||
struct L1Descriptor {
|
||||
/** Type of page table entry ARM DDI 0406B: B3-8*/
|
||||
enum EntryType {
|
||||
|
@ -95,6 +95,14 @@ class TableWalker : public MemObject
|
|||
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
|
||||
|
@ -220,6 +228,15 @@ class TableWalker : public MemObject
|
|||
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
|
||||
{
|
||||
|
@ -266,18 +283,12 @@ class TableWalker : public MemObject
|
|||
/** 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;
|
||||
|
||||
|
|
|
@ -84,8 +84,19 @@ TLB::~TLB()
|
|||
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
|
||||
|
||||
|
@ -97,7 +108,7 @@ TLB::lookup(Addr va, uint8_t cid)
|
|||
while (retval == NULL && x < size) {
|
||||
if (table[x].match(va, cid)) {
|
||||
retval = &table[x];
|
||||
if (x == nlu)
|
||||
if (x == nlu && !functional)
|
||||
nextnlu();
|
||||
|
||||
break;
|
||||
|
|
|
@ -97,7 +97,13 @@ class TLB : public BaseTLB
|
|||
#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;
|
||||
|
@ -154,6 +160,16 @@ class TLB : public BaseTLB
|
|||
|
||||
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
|
||||
|
|
|
@ -1,4 +1,16 @@
|
|||
/*
|
||||
* 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.
|
||||
|
@ -33,6 +45,8 @@
|
|||
|
||||
#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"
|
||||
|
@ -45,12 +59,80 @@ using namespace ArmISA;
|
|||
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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ namespace ArmISA {
|
|||
|
||||
Addr vtophys(Addr vaddr);
|
||||
Addr vtophys(ThreadContext *tc, Addr vaddr);
|
||||
bool virtvalid(ThreadContext *tc, Addr vaddr);
|
||||
};
|
||||
|
||||
#endif // __ARCH_ARM_VTOPHYS_H__
|
||||
|
|
Loading…
Reference in a new issue