ARM: Implement functional virtual to physical address translation

for debugging and program introspection.
This commit is contained in:
Ali Saidi 2010-10-01 16:03:27 -05:00
parent 518b5e5b1c
commit 521d68c82a
7 changed files with 134 additions and 15 deletions

View file

@ -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')

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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;
}

View file

@ -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__