summaryrefslogtreecommitdiff
path: root/src/arch
diff options
context:
space:
mode:
authorAli Saidi <Ali.Saidi@ARM.com>2010-10-01 16:03:27 -0500
committerAli Saidi <Ali.Saidi@ARM.com>2010-10-01 16:03:27 -0500
commit521d68c82a2399bfe32f282aa58708103369b99c (patch)
treee1856347d34b43c3064cfbc898f92284527616d2 /src/arch
parent518b5e5b1c71259ce0badc29f98db46a73c59442 (diff)
downloadgem5-521d68c82a2399bfe32f282aa58708103369b99c.tar.xz
ARM: Implement functional virtual to physical address translation
for debugging and program introspection.
Diffstat (limited to 'src/arch')
-rw-r--r--src/arch/arm/SConscript2
-rw-r--r--src/arch/arm/table_walker.cc2
-rw-r--r--src/arch/arm/table_walker.hh25
-rw-r--r--src/arch/arm/tlb.cc15
-rw-r--r--src/arch/arm/tlb.hh18
-rw-r--r--src/arch/arm/vtophys.cc86
-rw-r--r--src/arch/arm/vtophys.hh1
7 files changed, 134 insertions, 15 deletions
diff --git a/src/arch/arm/SConscript b/src/arch/arm/SConscript
index 1c1f878a0..df84763b5 100644
--- a/src/arch/arm/SConscript
+++ b/src/arch/arm/SConscript
@@ -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')
diff --git a/src/arch/arm/table_walker.cc b/src/arch/arm/table_walker.cc
index ccd3a42bf..73dd24e1c 100644
--- a/src/arch/arm/table_walker.cc
+++ b/src/arch/arm/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;
diff --git a/src/arch/arm/table_walker.hh b/src/arch/arm/table_walker.hh
index 141bd7138..dc801dde8 100644
--- a/src/arch/arm/table_walker.hh
+++ b/src/arch/arm/table_walker.hh
@@ -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;
diff --git a/src/arch/arm/tlb.cc b/src/arch/arm/tlb.cc
index a48805c81..a8d78308f 100644
--- a/src/arch/arm/tlb.cc
+++ b/src/arch/arm/tlb.cc
@@ -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;
diff --git a/src/arch/arm/tlb.hh b/src/arch/arm/tlb.hh
index eec52d9d2..caccad873 100644
--- a/src/arch/arm/tlb.hh
+++ b/src/arch/arm/tlb.hh
@@ -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
diff --git a/src/arch/arm/vtophys.cc b/src/arch/arm/vtophys.cc
index 01cbb3e79..1691a387c 100644
--- a/src/arch/arm/vtophys.cc
+++ b/src/arch/arm/vtophys.cc
@@ -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;
+}
+
+
diff --git a/src/arch/arm/vtophys.hh b/src/arch/arm/vtophys.hh
index 16d8c7ceb..12b4846ed 100644
--- a/src/arch/arm/vtophys.hh
+++ b/src/arch/arm/vtophys.hh
@@ -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__