ARM: Implement functional virtual to physical address translation
for debugging and program introspection.
diff --git a/src/arch/arm/vtophys.cc b/src/arch/arm/vtophys.cc
index 01cbb3e..1691a38 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 @@
 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;
+}
+
+