ARM: Implement functional virtual to physical address translation
authorAli Saidi <Ali.Saidi@ARM.com>
Fri, 1 Oct 2010 21:03:27 +0000 (16:03 -0500)
committerAli Saidi <Ali.Saidi@ARM.com>
Fri, 1 Oct 2010 21:03:27 +0000 (16:03 -0500)
for debugging and program introspection.

src/arch/arm/SConscript
src/arch/arm/table_walker.cc
src/arch/arm/table_walker.hh
src/arch/arm/tlb.cc
src/arch/arm/tlb.hh
src/arch/arm/vtophys.cc
src/arch/arm/vtophys.hh

index 1c1f878a04f0d6a351fa6ad8124c4fadeccdf381..df84763b5360b09ae77ff4afd36b563a1e1d2df6 100644 (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')
         
index ccd3a42bfee545d1a88d681aa4631ed3180bd7a8..73dd24e1c09839f9883e93eba3d45a38d89c1d00 100644 (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;
 
index 141bd7138391839a339bb630f5043dcfcfa77caf..dc801dde8a0ba7238406d00d32aba51c031079bb 100644 (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;
 
index a48805c813b333b22310a3110bed7f0db839ac1f..a8d78308fb3f291787b223a77de0af38827125c2 100644 (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;
index eec52d9d294650e41499658799db92bb21a33e26..caccad8730d07a0f283a7c1a77f699f9964b12ca 100644 (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
index 01cbb3e793c6ef7c60db827525190d4860fc982a..1691a387c6fb59e42f77aebbf04f84e17ee8cbf6 100644 (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;
+}
+
+
index 16d8c7ceb61b37a94981fb4dbbf62a43d77e1d94..12b4846edbcb873b5eb50b020d949b1047a0b857 100644 (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__