ARM: Implement the ARM TLB/Tablewalker. Needs performance improvements.
authorAli Saidi <Ali.Saidi@ARM.com>
Wed, 2 Jun 2010 17:58:16 +0000 (12:58 -0500)
committerAli Saidi <Ali.Saidi@ARM.com>
Wed, 2 Jun 2010 17:58:16 +0000 (12:58 -0500)
15 files changed:
src/arch/arm/ArmTLB.py
src/arch/arm/SConscript
src/arch/arm/faults.hh
src/arch/arm/isa.hh
src/arch/arm/isa/formats/misc.isa
src/arch/arm/isa/insts/ldr.isa
src/arch/arm/isa/insts/str.isa
src/arch/arm/miscregs.cc
src/arch/arm/miscregs.hh
src/arch/arm/pagetable.hh
src/arch/arm/table_walker.cc [new file with mode: 0644]
src/arch/arm/table_walker.hh [new file with mode: 0644]
src/arch/arm/tlb.cc
src/arch/arm/tlb.hh
src/cpu/BaseCPU.py

index 3dd2560fede0862d5478c0feccfd7ad7d6e71f54..f0d23445f4b024b030dbba10f649ed1daf46a131 100644 (file)
@@ -1,8 +1,17 @@
 # -*- mode:python -*-
 
-# Copyright (c) 2007-2008 The Florida State University
+# Copyright (c) 2009 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.
+#
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions are
 # met: redistributions of source code must retain the above copyright
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #
-# Authors: Stephen Hines
+# Authors: Ali Saidi
 
+from m5.defines import buildEnv
 from m5.SimObject import SimObject
 from m5.params import *
+from m5.proxy import *
+
+if buildEnv['FULL_SYSTEM']:
+    from MemObject import MemObject
+
+    class ArmTableWalker(MemObject):
+        type = 'ArmTableWalker'
+        cxx_class = 'ArmISA::TableWalker'
+        port = Port("Port for TableWalker to do walk the translation with")
+        sys = Param.System(Parent.any, "system object parameter")
+        min_backoff = Param.Tick(0, "Minimum backoff delay after failed send")
+        max_backoff = Param.Tick(100000, "Minimum backoff delay after failed send")
+
 
 class ArmTLB(SimObject):
     type = 'ArmTLB'
     cxx_class = 'ArmISA::TLB'
     size = Param.Int(64, "TLB size")
+    if buildEnv['FULL_SYSTEM']:
+       walker = Param.ArmTableWalker(ArmTableWalker(), "HW Table walker")
index 73fcc730b9761425184063761e0c4db31e17c257..67997f4e0cba88d0627c2594611777e8eee8669d 100644 (file)
@@ -65,12 +65,14 @@ if env['TARGET_ISA'] == 'arm':
     SimObject('ArmTLB.py')
 
     TraceFlag('Arm')
+    TraceFlag('TLBVerbose')
     TraceFlag('Faults', "Trace Exceptions, interrupts, svc/swi")
     TraceFlag('Predecoder', "Instructions returned by the predecoder")
     if env['FULL_SYSTEM']:
         Source('interrupts.cc')
         Source('stacktrace.cc')
         Source('system.cc')
+        Source('table_walker.cc')
         
         SimObject('ArmInterrupts.py')
         SimObject('ArmSystem.py')
index 7e4013a8592de8b3ae6af518400ff8f63600ce4a..6de9fee2829e18a8a0b06f5643487a6478523c9f 100644 (file)
@@ -75,16 +75,17 @@ class ArmFault : public FaultBase
         Translation1 = 0x7,
         SynchronousExternalAbort0 = 0x8,
         Domain0 = 0x9,
+        SynchronousExternalAbort1 = 0xa,
         Domain1 = 0xb,
-        TranslationTableWalk0 = 0xc,
+        TranslationTableWalkExtAbt0 = 0xc,
         Permission0 = 0xd,
-        SynchronousExternalAbort1 = 0xe,
+        TranslationTableWalkExtAbt1 = 0xe,
         Permission1 = 0xf,
         AsynchronousExternalAbort = 0x16,
         MemoryAccessAsynchronousParityError = 0x18,
         MemoryAccessSynchronousParityError = 0x19,
-        TranslationTableWalk1 = 0x1c,
-        SynchronousParityError = 0x1e
+        TranslationTableWalkPrtyErr0 = 0x1c,
+        TranslationTableWalkPrtyErr1 = 0x1e,
     };
 
     struct FaultVals
@@ -208,7 +209,7 @@ class DataAbort : public AbortFault<DataAbort>
     static const MiscRegIndex FsrIndex = MISCREG_DFSR;
     static const MiscRegIndex FarIndex = MISCREG_DFAR;
 
-    DataAbort(Addr _addr, bool _write, uint8_t _domain, uint8_t _status) :
+    DataAbort(Addr _addr, uint8_t _domain, bool _write, uint8_t _status) :
         AbortFault<DataAbort>(_addr, _write, _domain, _status)
     {}
 };
index c9c23794615bda1cc3bac902a0c7e3d9ed91c226..51503dbf68477f4fa63fccdd7b7353859374fd2d 100644 (file)
  */
 
 #ifndef __ARCH_ARM_ISA_HH__
-#define __ARCH_MRM_ISA_HH__
+#define __ARCH_ARM_ISA_HH__
 
 #include "arch/arm/registers.hh"
+#include "arch/arm/tlb.hh"
 #include "arch/arm/types.hh"
 
 class ThreadContext;
@@ -223,6 +224,8 @@ namespace ArmISA
                 warn("The ccsidr register isn't implemented and "
                         "always reads as 0.\n");
                 break;
+              case MISCREG_ID_PFR0:
+                return 0x1031; // ThumbEE | !Jazelle | Thumb | ARM
             }
             return readMiscRegNoEffect(misc_reg);
         }
@@ -347,6 +350,52 @@ namespace ArmISA
               case MISCREG_MPIDR:
               case MISCREG_FPSID:
                 return;
+              case MISCREG_TLBIALLIS:
+              case MISCREG_TLBIALL:
+                warn("Need to flush all TLBs in MP\n");
+                tc->getITBPtr()->flushAll();
+                tc->getDTBPtr()->flushAll();
+                return;
+              case MISCREG_ITLBIALL:
+                tc->getITBPtr()->flushAll();
+                return;
+              case MISCREG_DTLBIALL:
+                tc->getDTBPtr()->flushAll();
+                return;
+              case MISCREG_TLBIMVAIS:
+              case MISCREG_TLBIMVA:
+                warn("Need to flush all TLBs in MP\n");
+                tc->getITBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
+                        bits(newVal, 7,0));
+                tc->getDTBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
+                        bits(newVal, 7,0));
+                return;
+              case MISCREG_TLBIASIDIS:
+              case MISCREG_TLBIASID:
+                warn("Need to flush all TLBs in MP\n");
+                tc->getITBPtr()->flushAsid(bits(newVal, 7,0));
+                tc->getDTBPtr()->flushAsid(bits(newVal, 7,0));
+                return;
+              case MISCREG_TLBIMVAAIS:
+              case MISCREG_TLBIMVAA:
+                warn("Need to flush all TLBs in MP\n");
+                tc->getITBPtr()->flushMva(mbits(newVal, 31,12));
+                tc->getDTBPtr()->flushMva(mbits(newVal, 31,12));
+                return;
+              case MISCREG_ITLBIMVA:
+                tc->getITBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
+                        bits(newVal, 7,0));
+                return;
+              case MISCREG_DTLBIMVA:
+                tc->getDTBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
+                        bits(newVal, 7,0));
+                return;
+              case MISCREG_ITLBIASID:
+                tc->getITBPtr()->flushAsid(bits(newVal, 7,0));
+                return;
+              case MISCREG_DTLBIASID:
+                tc->getDTBPtr()->flushAsid(bits(newVal, 7,0));
+                return;
             }
             setMiscRegNoEffect(misc_reg, newVal);
         }
index 1c00a3d6b68eff816386c5dedc06ce9bf5183394..be0e639008011673b51cf44f934ea3d01f019ec1 100644 (file)
@@ -138,47 +138,25 @@ let {{
             return new WarnUnimplemented(
                     isRead ? "mrc bpiall" : "mcr bpiall", machInst);
           case MISCREG_TLBIALLIS:
-            return new WarnUnimplemented(
-                    isRead ? "mrc tlbiallis" : "mcr tlbiallis", machInst);
           case MISCREG_TLBIMVAIS:
-            return new WarnUnimplemented(
-                    isRead ? "mrc tlbimvais" : "mcr tlbimvais", machInst);
           case MISCREG_TLBIASIDIS:
-            return new WarnUnimplemented(
-                    isRead ? "mrc tlbiasidis" : "mcr tlbiasidis", machInst);
           case MISCREG_TLBIMVAAIS:
-            return new WarnUnimplemented(
-                    isRead ? "mrc tlbimvaais" : "mcr tlbimvaais", machInst);
           case MISCREG_ITLBIALL:
-            return new WarnUnimplemented(
-                    isRead ? "mrc itlbiall" : "mcr itlbiall", machInst);
           case MISCREG_ITLBIMVA:
-            return new WarnUnimplemented(
-                    isRead ? "mrc itlbimva" : "mcr itlbimva", machInst);
           case MISCREG_ITLBIASID:
-            return new WarnUnimplemented(
-                    isRead ? "mrc itlbiasid" : "mcr itlbiasid", machInst);
           case MISCREG_DTLBIALL:
-            return new WarnUnimplemented(
-                    isRead ? "mrc dtlbiall" : "mcr dtlbiall", machInst);
           case MISCREG_DTLBIMVA:
-            return new WarnUnimplemented(
-                    isRead ? "mrc dtlbimva" : "mcr dtlbimva", machInst);
           case MISCREG_DTLBIASID:
-            return new WarnUnimplemented(
-                    isRead ? "mrc dtlbiasid" : "mcr dtlbiasid", machInst);
           case MISCREG_TLBIALL:
-            return new WarnUnimplemented(
-                    isRead ? "mrc tlbiall" : "mcr tlbiall", machInst);
           case MISCREG_TLBIMVA:
-            return new WarnUnimplemented(
-                    isRead ? "mrc tlbimva" : "mcr tlbimva", machInst);
           case MISCREG_TLBIASID:
-            return new WarnUnimplemented(
-                    isRead ? "mrc tlbiasid" : "mcr tlbiasid", machInst);
           case MISCREG_TLBIMVAA:
-            return new WarnUnimplemented(
-                    isRead ? "mrc tlbimvaa" : "mcr tlbimvaa", machInst);
+            if (isRead) {
+                return new Unknown(machInst);
+            } else {
+                return new Mcr15(machInst, (IntRegIndex)miscReg, rt);
+            }
+
           default:
             if (isRead) {
                 return new Mrc15(machInst, rt, (IntRegIndex)miscReg);
index 40d9147df5f3f82d71c6d256ed054204f405b608..093ff7a60247676b1dbf72e7d4a87d4969901378 100644 (file)
@@ -93,6 +93,9 @@ let {{
         eaCode += ";"
 
         memFlags = ["ArmISA::TLB::MustBeOne", "%d" % (size - 1)]
+        if user:
+            memFlags.append("ArmISA::TLB::UserMode")
+
         if prefetch:
             Name = "%s_%s" % (mnem.upper(), Name)
             memFlags.append("Request::PREFETCH")
@@ -179,6 +182,9 @@ let {{
         eaCode += ";"
 
         memFlags = ["%d" % (size - 1), "ArmISA::TLB::MustBeOne"]
+        if user:
+            memFlags.append("ArmISA::TLB::UserMode")
+
         if prefetch:
             Name = "%s_%s" % (mnem.upper(), Name)
             memFlags.append("Request::PREFETCH")
index c8d2679fc84bfd3393f3ec22376235ad9b77b757..d860009477e8a7bd5a2d43d0450337eb6fe331b9 100644 (file)
@@ -107,6 +107,9 @@ let {{
             accCode += "Base = Base %s;\n" % offset
 
         memFlags = ["ArmISA::TLB::MustBeOne", "%d" % (size - 1)]
+        if user:
+            memFlags.append("ArmISA::TLB::UserMode")
+
         if strex:
             memFlags.append("Request::LLSC")
             Name = "%s_%s" % (mnem.upper(), Name)
@@ -184,10 +187,14 @@ let {{
             accCode += "Base = Base %s;\n" % offset
         base = buildMemBase("MemoryReg", post, writeback)
 
-        emitStore(name, Name, False, eaCode, accCode, "",\
-                ["ArmISA::TLB::MustBeOne", \
+        memFlags = ["ArmISA::TLB::MustBeOne", \
                  "ArmISA::TLB::AllowUnaligned", \
-                 "%d" % (size - 1)], [], base)
+                 "%d" % (size - 1)]
+        if user:
+            memFlags.append("ArmISA::TLB::UserMode")
+
+        emitStore(name, Name, False, eaCode, accCode, "",\
+                memFlags, [], base)
 
     def buildDoubleImmStore(mnem, post, add, writeback, \
                             strex=False, vstr=False):
index aedc0fce5ba467c91c8a78ce6948fbc297dfcc43..e4375fb8a8b2a4568ad1e598d44c9a0f38269c52 100644 (file)
@@ -38,6 +38,7 @@
  */
 
 #include "arch/arm/miscregs.hh"
+#include "base/misc.hh"
 
 namespace ArmISA
 {
@@ -424,6 +425,8 @@ decodeCP15Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2)
         // Implementation defined
         break;
     }
+    warn("Unknown miscreg: CRn: %d Opc1: %d CRm: %d opc2: %d\n",
+            crn, opc1, crm, opc2);
     // Unrecognized register
     return NUM_MISCREGS;
 }
index cdead87105954e8bdf1244bf0ce0b3d091d492f8..42431e777be37a442b60dda9feaed0d1dada4c53 100644 (file)
@@ -130,10 +130,13 @@ namespace ArmISA
         MISCREG_DFAR,
         MISCREG_IFAR,
         MISCREG_MPIDR,
+        MISCREG_PRRR,
+        MISCREG_NMRR,
+        MISCREG_TTBCR,
+        MISCREG_ID_PFR0,
         MISCREG_CP15_UNIMP_START,
         MISCREG_CTR = MISCREG_CP15_UNIMP_START,
         MISCREG_TCMTR,
-        MISCREG_ID_PFR0,
         MISCREG_ID_PFR1,
         MISCREG_ID_DFR0,
         MISCREG_ID_AFR0,
@@ -159,7 +162,6 @@ namespace ArmISA
         MISCREG_SCR,
         MISCREG_SDER,
         MISCREG_NSACR,
-        MISCREG_TTBCR,
         MISCREG_V2PCWPR,
         MISCREG_V2PCWPW,
         MISCREG_V2PCWUR,
@@ -168,8 +170,6 @@ namespace ArmISA
         MISCREG_V2POWPW,
         MISCREG_V2POWUR,
         MISCREG_V2POWUW,
-        MISCREG_PRRR,
-        MISCREG_NMRR,
         MISCREG_VBAR,
         MISCREG_MVBAR,
         MISCREG_ISR,
@@ -205,18 +205,20 @@ namespace ArmISA
         "dtlbiall", "dtlbimva", "dtlbiasid",
         "tlbiall", "tlbimva", "tlbiasid", "tlbimvaa",
         "dfsr", "ifsr", "dfar", "ifar", "mpidr",
+        "prrr", "nmrr",  "ttbcr", "id_pfr0",
+        // Unimplemented below
         "ctr", "tcmtr",
-        "id_pfr0", "id_pfr1", "id_dfr0", "id_afr0",
+        "id_pfr1", "id_dfr0", "id_afr0",
         "id_mmfr0", "id_mmfr1", "id_mmfr2", "id_mmfr3",
         "id_isar0", "id_isar1", "id_isar2", "id_isar3", "id_isar4", "id_isar5",
         "par", "aidr", "actlr",
         "adfsr", "aifsr",
         "dcimvac", "dcisw", "mccsw",
         "dccmvau",
-        "scr", "sder", "nsacr", "ttbcr",
+        "scr", "sder", "nsacr",
         "v2pcwpr", "v2pcwpw", "v2pcwur", "v2pcwuw",
         "v2powpr", "v2powpw", "v2powur", "v2powuw",
-        "prrr", "nmrr", "vbar", "mvbar", "isr", "fceidr",
+        "vbar", "mvbar", "isr", "fceidr",
         "nop", "raz"
     };
 
@@ -343,6 +345,49 @@ namespace ArmISA
         Bitfield<27, 24> vfpHalfPrecision;
         Bitfield<31, 28> raz;
     EndBitUnion(MVFR1)
+
+    BitUnion32(PRRR)
+       Bitfield<1,0> tr0;
+       Bitfield<3,2> tr1;
+       Bitfield<5,4> tr2;
+       Bitfield<7,6> tr3;
+       Bitfield<9,8> tr4;
+       Bitfield<11,10> tr5;
+       Bitfield<13,12> tr6;
+       Bitfield<15,14> tr7;
+       Bitfield<16> ds0;
+       Bitfield<17> ds1;
+       Bitfield<18> ns0;
+       Bitfield<19> ns1;
+       Bitfield<24> nos0;
+       Bitfield<25> nos1;
+       Bitfield<26> nos2;
+       Bitfield<27> nos3;
+       Bitfield<28> nos4;
+       Bitfield<29> nos5;
+       Bitfield<30> nos6;
+       Bitfield<31> nos7;
+   EndBitUnion(PRRR)
+
+   BitUnion32(NMRR)
+       Bitfield<1,0> ir0;
+       Bitfield<3,2> ir1;
+       Bitfield<5,4> ir2;
+       Bitfield<7,6> ir3;
+       Bitfield<9,8> ir4;
+       Bitfield<11,10> ir5;
+       Bitfield<13,12> ir6;
+       Bitfield<15,14> ir7;
+       Bitfield<17,16> or0;
+       Bitfield<19,18> or1;
+       Bitfield<21,20> or2;
+       Bitfield<23,22> or3;
+       Bitfield<25,24> or4;
+       Bitfield<27,26> or5;
+       Bitfield<29,28> or6;
+       Bitfield<31,30> or7;
+   EndBitUnion(NMRR)
+
 };
 
 #endif // __ARCH_ARM_MISCREGS_HH__
index 3d4943f9989375504075d9b84690f0e4d5c07d60..f1e86f0ccff3c7369a224a5a73423f865e5545e7 100644 (file)
@@ -37,9 +37,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * Authors: Nathan Binkert
- *          Steve Reinhardt
- *          Ali Saidi
+ * Authors: Ali Saidi
  */
 
 #ifndef __ARCH_ARM_PAGETABLE_H__
@@ -73,22 +71,91 @@ struct PTE
 
 };
 
-// ITB/DTB table entry
-struct TlbEntry
+struct TlbRange
 {
-    Addr tag;               // virtual page number tag
-    Addr ppn;               // physical page number
-    uint8_t asn;            // address space number
-    bool valid;             // valid page table entry
+    Addr va;
+    Addr size;
+    int contextId;
+    bool global;
 
+    inline bool
+    operator<(const TlbRange &r2) const
+    {
+        if (!(global || r2.global)) {
+            if (contextId < r2.contextId)
+                return true;
+            else if (contextId > r2.contextId)
+                return false;
+        }
+
+        if (va < r2.va)
+            return true;
+        return false;
+    }
 
-    //Construct an entry that maps to physical address addr.
+    inline bool
+    operator==(const TlbRange &r2) const
+    {
+        return va == r2.va &&
+               size == r2.size &&
+               contextId == r2.contextId &&
+               global == r2.global;
+    }
+};
+
+
+// ITB/DTB table entry
+struct TlbEntry
+{
+  public:
+    enum MemoryType {
+        StronglyOrdered,
+        Device,
+        Normal
+    };
+    enum DomainType {
+        DomainNoAccess = 0,
+        DomainClient,
+        DomainReserved,
+        DomainManager
+    };
+
+    // Matching variables
+    Addr pfn;
+    Addr size;              // Size of this entry, == Type of TLB Rec
+    Addr vpn;               // Virtual Page Number
+    uint32_t asid;          // Address Space Identifier
+    uint8_t N;              // Number of bits in pagesize
+    bool global;
+    bool valid;
+
+    // Type of memory
+    bool nonCacheable;     // Can we wrap this in mtype?
+    bool sNp;      // Section descriptor
+
+    // Access permissions
+    bool xn;                // Execute Never
+    uint8_t ap:3;           // Access permissions bits
+    uint8_t domain:4;       // Access Domain
+
+    TlbRange range;         // For fast TLB searching
+
+    //Construct an entry that maps to physical address addr for SE mode
     TlbEntry(Addr _asn, Addr _vaddr, Addr _paddr)
     {
-        tag = _vaddr >> PageShift;
-        ppn = _paddr >> PageShift;
-        asn = _asn;
+        pfn = _paddr >> PageShift;
+        size = PageBytes - 1;
+        asid = _asn;
+        global = false;
         valid = true;
+
+        vpn = _vaddr >> PageShift;
+
+        nonCacheable = sNp = false;
+
+        xn = 0;
+        ap = 0; // ???
+        domain = DomainClient; //???
     }
 
     TlbEntry()
@@ -97,13 +164,28 @@ struct TlbEntry
     void
     updateVaddr(Addr new_vaddr)
     {
-        tag = new_vaddr >> PageShift;
+        vpn = new_vaddr >> PageShift;
     }
 
     Addr
     pageStart()
     {
-        return ppn << PageShift;
+        return pfn << PageShift;
+    }
+
+    bool
+    match(Addr va, uint8_t cid)
+    {
+        Addr v = vpn << N;
+        if (valid && va >= v && va <= v + size && (global || cid == asid))
+            return true;
+        return false;
+    }
+
+    Addr
+    pAddr(Addr va)
+    {
+        return (pfn << N) | (va & size);
     }
 
     void serialize(std::ostream &os) { panic("Need to Implement\n"); }
diff --git a/src/arch/arm/table_walker.cc b/src/arch/arm/table_walker.cc
new file mode 100644 (file)
index 0000000..313b233
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ * 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.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ */
+
+#include "arch/arm/faults.hh"
+#include "arch/arm/table_walker.hh"
+#include "arch/arm/tlb.hh"
+#include "dev/io_device.hh"
+#include "cpu/thread_context.hh"
+
+
+using namespace ArmISA;
+
+TableWalker::TableWalker(const Params *p)
+    : MemObject(p), port(NULL), tlb(NULL), tc(NULL), req(NULL),
+      doL1DescEvent(this), doL2DescEvent(this)
+{}
+
+TableWalker::~TableWalker()
+{
+    ;
+}
+
+
+unsigned int
+drain(Event *de)
+{
+    panic("Not implemented\n");
+}
+
+Port*
+TableWalker::getPort(const std::string &if_name, int idx)
+{
+    if (if_name == "port") {
+        if (port != NULL)
+            fatal("%s: port already connected to %s",
+                  name(), port->getPeer()->name());
+        System *sys = params()->sys;
+        Tick minb = params()->min_backoff;
+        Tick maxb = params()->max_backoff;
+        port = new DmaPort(this, sys, minb, maxb);
+        return port;
+    }
+    return NULL;
+}
+
+Fault
+TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint8_t _cid, TLB::Mode mode,
+            TLB::Translation *_trans, bool _timing)
+{
+    // Right now 1 CPU == 1 TLB == 1 TLB walker
+    // In the future we might want to change this as multiple
+    // threads/contexts could share a walker and/or a TLB
+    if (tc || req)
+        panic("Overlapping TLB walks attempted\n");
+
+    tc = _tc;
+    transState = _trans;
+    req = _req;
+    fault = NoFault;
+    contextId = _cid;
+    timing = _timing;
+
+    // XXX These should be cached or grabbed from cached copies in
+    // the TLB, all these miscreg reads are expensive
+    vaddr = req->getVaddr() & ~PcModeMask;
+    sctlr = tc->readMiscReg(MISCREG_SCTLR);
+    cpsr = tc->readMiscReg(MISCREG_CPSR);
+    N = tc->readMiscReg(MISCREG_TTBCR);
+    Addr ttbr = 0;
+
+    isFetch = (mode == TLB::Execute);
+    isWrite = (mode == TLB::Write);
+    isPriv = (cpsr.mode != MODE_USER);
+
+    // If translation isn't enabled, we shouldn't be here
+    assert(sctlr.m);
+
+    if (N == 0 || mbits(vaddr, 31, 32-N)) {
+        ttbr = tc->readMiscReg(MISCREG_TTBR0);
+    } else {
+        ttbr = tc->readMiscReg(MISCREG_TTBR0);
+        N = 0;
+    }
+
+    Addr l1desc_addr = mbits(ttbr, 31, 14-N) | (bits(vaddr,31-N,20) << 2);
+    DPRINTF(TLB, "Begining table walk for address %#x at descriptor %#x\n",
+            vaddr, l1desc_addr);
+
+
+    // Trickbox address check
+    fault = tlb->walkTrickBoxCheck(l1desc_addr, vaddr, sizeof(uint32_t),
+            isFetch, 0, true);
+    if (fault) {
+       tc = NULL;
+       req = NULL;
+       return fault;
+    }
+
+    if (timing) {
+        port->dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t),
+                &doL1DescEvent, (uint8_t*)&l1Desc.data, (Tick)0);
+    } else {
+        port->dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t),
+                NULL, (uint8_t*)&l1Desc.data, (Tick)0);
+        doL1Descriptor();
+    }
+
+    return fault;
+}
+
+void
+TableWalker::memAttrs(TlbEntry &te, uint8_t texcb)
+{
+
+    if (sctlr.tre == 0) {
+        switch(texcb) {
+          case 0:
+          case 1:
+          case 4:
+          case 8:
+            te.nonCacheable = true;
+            break;
+          case 16:
+            if (bits(texcb, 1,0) == 0 || bits(texcb, 3,2) == 0)
+                te.nonCacheable = true;
+            break;
+        }
+    } else {
+        PRRR prrr = tc->readMiscReg(MISCREG_PRRR);
+        NMRR nmrr = tc->readMiscReg(MISCREG_NMRR);
+        switch(bits(texcb, 2,0)) {
+          case 0:
+            if (nmrr.ir0 == 0 || nmrr.or0 == 0 || prrr.tr0 != 0x2)
+                te.nonCacheable = true;
+            break;
+          case 1:
+            if (nmrr.ir1 == 0 || nmrr.or1 == 0 || prrr.tr1 != 0x2)
+                te.nonCacheable = true;
+            break;
+          case 2:
+            if (nmrr.ir2 == 0 || nmrr.or2 == 0 || prrr.tr2 != 0x2)
+                te.nonCacheable = true;
+            break;
+          case 3:
+            if (nmrr.ir3 == 0 || nmrr.or3 == 0 || prrr.tr3 != 0x2)
+                te.nonCacheable = true;
+            break;
+          case 4:
+            if (nmrr.ir4 == 0 || nmrr.or4 == 0 || prrr.tr4 != 0x2)
+                te.nonCacheable = true;
+            break;
+          case 5:
+            if (nmrr.ir5 == 0 || nmrr.or5 == 0 || prrr.tr5 != 0x2)
+                te.nonCacheable = true;
+            break;
+          case 6:
+            panic("Imp defined type\n");
+          case 7:
+            if (nmrr.ir7 == 0 || nmrr.or7 == 0 || prrr.tr7 != 0x2)
+                te.nonCacheable = true;
+            break;
+        }
+    }
+}
+
+void
+TableWalker::doL1Descriptor()
+{
+    DPRINTF(TLB, "L1 descriptor for %#x is %#x\n", vaddr, l1Desc.data);
+    TlbEntry te;
+
+    switch (l1Desc.type()) {
+      case L1Descriptor::Ignore:
+      case L1Descriptor::Reserved:
+        tc = NULL;
+        req = NULL;
+        fault = new DataAbort(vaddr, NULL, isWrite, ArmFault::Translation0);
+        return;
+      case L1Descriptor::Section:
+        if (sctlr.afe && bits(l1Desc.ap(), 0) == 0)
+            panic("Haven't implemented AFE\n");
+
+        if (l1Desc.supersection()) {
+            panic("Haven't implemented supersections\n");
+        }
+        te.N = 20;
+        te.pfn = l1Desc.pfn();
+        te.size = (1<<te.N) - 1;
+        te.global = !l1Desc.global();
+        te.valid = true;
+        te.vpn = vaddr >> te.N;
+        te.sNp = true;
+        te.xn = l1Desc.xn();
+        te.ap =  l1Desc.ap();
+        te.domain = l1Desc.domain();
+        te.asid = contextId;
+        memAttrs(te, l1Desc.texcb());
+
+        DPRINTF(TLB, "Inserting Section Descriptor into TLB\n");
+        DPRINTF(TLB, " - N%d pfn:%#x size: %#x global:%d valid: %d\n",
+                te.N, te.pfn, te.size, te.global, te.valid);
+        DPRINTF(TLB, " - vpn:%#x sNp: %d xn:%d ap:%d domain: %d asid:%d\n",
+                te.vpn, te.sNp, te.xn, te.ap, te.domain, te.asid);
+        DPRINTF(TLB, " - domain from l1 desc: %d data: %#x bits:%d\n",
+                l1Desc.domain(), l1Desc.data, (l1Desc.data >> 5) & 0xF );
+
+        tc = NULL;
+        req = NULL;
+        tlb->insert(vaddr, te);
+
+        return;
+      case L1Descriptor::PageTable:
+        Addr l2desc_addr;
+        l2desc_addr = l1Desc.l2Addr() | (bits(vaddr, 19,12) << 2);
+        DPRINTF(TLB, "L1 descriptor points to page table at: %#x\n", l2desc_addr);
+
+        // Trickbox address check
+        fault = tlb->walkTrickBoxCheck(l2desc_addr, vaddr, sizeof(uint32_t),
+                isFetch, l1Desc.domain(), false);
+        if (fault) {
+           tc = NULL;
+           req = NULL;
+           return;
+        }
+
+
+        if (timing) {
+            port->dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t),
+                    &doL2DescEvent, (uint8_t*)&l2Desc.data, 0);
+        } else {
+            port->dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t),
+                    NULL, (uint8_t*)&l2Desc.data, 0);
+            doL2Descriptor();
+        }
+        return;
+      default:
+        panic("A new type in a 2 bit field?\n");
+    }
+}
+
+void
+TableWalker::doL2Descriptor()
+{
+    DPRINTF(TLB, "L2 descriptor for %#x is %#x\n", vaddr, l2Desc.data);
+    TlbEntry te;
+
+    if (sctlr.afe && bits(l1Desc.ap(), 0) == 0)
+        panic("Haven't implemented AFE\n");
+
+    if (l2Desc.invalid()) {
+        DPRINTF(TLB, "L2 descriptor invalid, causing fault\n");
+        tc = NULL;
+        req = NULL;
+        fault = new DataAbort(vaddr, l1Desc.domain(), isWrite, ArmFault::Translation1);
+        return;
+    }
+
+    if (l2Desc.large()) {
+      te.N = 16;
+      te.pfn = l2Desc.pfn();
+    } else {
+      te.N = 12;
+      te.pfn = l2Desc.pfn();
+    }
+
+    te.valid = true;
+    te.size =  (1 << te.N) - 1;
+    te.asid = contextId;
+    te.sNp = false;
+    te.vpn = vaddr >> te.N;
+    te.global = l2Desc.global();
+    te.xn = l2Desc.xn();
+    te.ap = l2Desc.ap();
+    te.domain = l1Desc.domain();
+    memAttrs(te, l2Desc.texcb());
+
+    tc = NULL;
+    req = NULL;
+    tlb->insert(vaddr, te);
+}
+
+ArmISA::TableWalker *
+ArmTableWalkerParams::create()
+{
+    return new ArmISA::TableWalker(this);
+}
+
diff --git a/src/arch/arm/table_walker.hh b/src/arch/arm/table_walker.hh
new file mode 100644 (file)
index 0000000..d18b7c4
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * 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.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ */
+
+#ifndef __ARCH_ARM_TABLE_WALKER_HH__
+#define __ARCH_ARM_TABLE_WALKER_HH__
+
+#include "arch/arm/miscregs.hh"
+#include "arch/arm/tlb.hh"
+#include "mem/mem_object.hh"
+#include "mem/request.hh"
+#include "mem/request.hh"
+#include "params/ArmTableWalker.hh"
+#include "sim/faults.hh"
+#include "sim/eventq.hh"
+
+class DmaPort;
+class ThreadContext;
+
+namespace ArmISA {
+class Translation;
+class TLB;
+
+class TableWalker : public MemObject
+{
+  protected:
+    struct L1Descriptor {
+        /** Type of page table entry ARM DDI 0406B: B3-8*/
+        enum EntryType {
+            Ignore,
+            PageTable,
+            Section,
+            Reserved
+        };
+
+        uint32_t data;
+
+        EntryType type() const
+        {
+            return (EntryType)(data & 0x3);
+        }
+
+        /** Is the page a Supersection (16MB)?*/
+        bool supersection() const
+        {
+            return bits(data, 18);
+        }
+
+        /** Return the physcal address of the entry, bits in position*/
+        Addr paddr() const
+        {
+            if (supersection())
+                panic("Super sections not implemented\n");
+            return mbits(data, 31,20);
+        }
+
+        /** Return the physical frame, bits shifted right */
+        Addr pfn() const
+        {
+            if (supersection())
+                panic("Super sections not implemented\n");
+            return bits(data, 31,20);
+        }
+
+        /** Is the translation global (no asid used)? */
+        bool global() const
+        {
+            return bits(data, 17);
+        }
+
+        /** Is the translation not allow execution? */
+        bool xn() const
+        {
+            return bits(data, 17);
+        }
+
+        /** Three bit access protection flags */
+        uint8_t ap() const
+        {
+            return (bits(data, 15) << 2) | bits(data,11,10);
+        }
+
+        /** Domain Client/Manager: ARM DDI 0406B: B3-31 */
+        uint8_t domain() const
+        {
+            return bits(data,8,5);
+        }
+
+        /** Address of L2 descriptor if it exists */
+        Addr l2Addr() const
+        {
+            return mbits(data, 31,10);
+        }
+
+        /** Memory region attributes: ARM DDI 0406B: B3-32 */
+        uint8_t texcb() const
+        {
+            return bits(data, 2) | bits(data,3) << 1 | bits(data, 12, 14) << 2;
+        }
+
+    };
+
+    /** Level 2 page table descriptor */
+    struct L2Descriptor {
+
+        uint32_t data;
+
+        /** Is the entry invalid */
+        bool invalid() const
+        {
+            return bits(data, 1,0) == 0;;
+        }
+
+        /** What is the size of the mapping? */
+        bool large() const
+        {
+            return bits(data, 1) == 0;
+        }
+
+        /** Is execution allowed on this mapping? */
+        bool xn() const
+        {
+            return large() ? bits(data, 15) : bits(data, 0);
+        }
+
+        /** Is the translation global (no asid used)? */
+        bool global() const
+        {
+            return !bits(data, 11);
+        }
+
+        /** Three bit access protection flags */
+        uint8_t ap() const
+        {
+           return bits(data, 5, 4) | (bits(data, 9) << 2);
+        }
+
+        /** Memory region attributes: ARM DDI 0406B: B3-32 */
+        uint8_t texcb() const
+        {
+            return large() ?
+                (bits(data, 2) | (bits(data,3) << 1) | (bits(data, 12, 14) << 2)) :
+                (bits(data, 2) | (bits(data,3) << 1) | (bits(data, 6, 8) << 2));
+        }
+
+        /** Return the physical frame, bits shifted right */
+        Addr pfn() const
+        {
+            return large() ? bits(data, 31, 16) : bits(data, 31, 12);
+        }
+
+    };
+
+    /** Port to issue translation requests from */
+    DmaPort *port;
+
+    /** TLB that is initiating these table walks */
+    TLB *tlb;
+
+    /** Thread context that we're doing the walk for */
+    ThreadContext *tc;
+
+    /** Request that is currently being serviced */
+    RequestPtr req;
+
+    /** Context ID that we're servicing the request under */
+    uint8_t contextId;
+
+    /** Translation state for delayed requests */
+    TLB::Translation *transState;
+
+    /** The fault that we are going to return */
+    Fault fault;
+
+    /** The virtual address that is being translated */
+    Addr vaddr;
+
+    /** 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;
+
+    /** If the mode is timing or atomic */
+    bool timing;
+
+    L1Descriptor l1Desc;
+    L2Descriptor l2Desc;
+
+  public:
+    typedef ArmTableWalkerParams Params;
+    TableWalker(const Params *p);
+    virtual ~TableWalker();
+
+    const Params *
+    params() const
+    {
+        return dynamic_cast<const Params *>(_params);
+    }
+
+    virtual unsigned int drain(Event *de) { panic("write me\n"); }
+    virtual Port *getPort(const std::string &if_name, int idx = -1);
+
+    Fault walk(RequestPtr req, ThreadContext *tc, uint8_t cid, TLB::Mode mode,
+            TLB::Translation *_trans, bool timing);
+
+    void setTlb(TLB *_tlb) { tlb = _tlb; }
+
+  private:
+    void memAttrs(TlbEntry &te, uint8_t texcb);
+
+    void doL1Descriptor();
+    EventWrapper<TableWalker, &TableWalker::doL1Descriptor> doL1DescEvent;
+
+    void doL2Descriptor();
+    EventWrapper<TableWalker, &TableWalker::doL2Descriptor> doL2DescEvent;
+
+
+};
+
+
+} // namespace ArmISA
+
+#endif //__ARCH_ARM_TABLE_WALKER_HH__
+
index bbf9232c5bdbf56f577e18b89db8785ee8c69b8f..362020a9195496059eee377cf5f9397e03bff400 100644 (file)
@@ -47,6 +47,7 @@
 
 #include "arch/arm/faults.hh"
 #include "arch/arm/pagetable.hh"
+#include "arch/arm/table_walker.hh"
 #include "arch/arm/tlb.hh"
 #include "arch/arm/utility.hh"
 #include "base/inifile.hh"
 #include "params/ArmTLB.hh"
 #include "sim/process.hh"
 
-
 using namespace std;
 using namespace ArmISA;
 
 TLB::TLB(const Params *p)
     : BaseTLB(p), size(p->size), nlu(0)
+#if FULL_SYSTEM
+      , tableWalker(p->walker)
+#endif
 {
-    table = new ArmISA::PTE[size];
-    memset(table, 0, sizeof(ArmISA::PTE[size]));
+    table = new TlbEntry[size];
+    memset(table, 0, sizeof(TlbEntry[size]));
 
+    tableWalker->setTlb(this);
 }
 
 TLB::~TLB()
@@ -75,50 +79,157 @@ TLB::~TLB()
         delete [] table;
 }
 
-ArmISA::PTE *
-TLB::lookup(Addr vpn, uint8_t asn) const
+TlbEntry*
+TLB::lookup(Addr va, uint8_t cid)
 {
-    panic("lookup() not implemented for ARM\n");
+    // XXX This should either turn into a TlbMap or add caching
+
+    TlbEntry *retval = NULL;
+
+    // Do some kind of caching, fast indexing, anything
+
+    int x = 0;
+    while (retval == NULL && x < size) {
+        if (table[x].match(va, cid)) {
+            retval = &table[x];
+            if (x == nlu)
+                nextnlu();
+
+            break;
+        }
+        x++;
+    }
+
+    DPRINTF(TLBVerbose, "Lookup %#x, cid %#x -> %s ppn %#x size: %#x pa: %#x ap:%d\n",
+            va, cid, retval ? "hit" : "miss", retval ? retval->pfn : 0,
+            retval ? retval->size : 0, retval ? retval->pAddr(va) : 0,
+            retval ? retval->ap : 0);
+    ;
+    return retval;
 }
 
 // insert a new TLB entry
 void
-TLB::insert(Addr addr, ArmISA::PTE &pte)
+TLB::insert(Addr addr, TlbEntry &entry)
+{
+    DPRINTF(TLB, "Inserting entry into TLB with pfn:%#x size:%#x vpn: %#x"
+            " asid:%d N:%d global:%d valid:%d nc:%d sNp:%d xn:%d ap:%#x"
+            " domain:%#x\n", entry.pfn, entry.size, entry.vpn, entry.asid,
+            entry.N, entry.global, entry.valid, entry.nonCacheable, entry.sNp,
+            entry.xn, entry.ap, entry.domain);
+
+    if (table[nlu].valid)
+        DPRINTF(TLB, " - Replacing Valid entry %#x, asn %d ppn %#x size: %#x ap:%d\n",
+            table[nlu].vpn << table[nlu].N, table[nlu].asid, table[nlu].pfn << table[nlu].N,
+            table[nlu].size, table[nlu].ap);
+
+    // XXX Update caching, lookup table etc
+    table[nlu] = entry;
+
+    // XXX Figure out how entries are generally inserted in ARM
+    nextnlu();
+}
+
+void
+TLB::printTlb()
 {
-  fatal("TLB Insert not yet implemented\n");
+    int x = 0;
+    TlbEntry *te;
+    DPRINTF(TLB, "Current TLB contents:\n");
+    while (x < size) {
+       te = &table[x];
+       if (te->valid)
+           DPRINTF(TLB, " *  %#x, asn %d ppn %#x size: %#x ap:%d\n",
+                te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap);
+       x++;
+    }
 }
 
+
 void
 TLB::flushAll()
 {
-    DPRINTF(TLB, "flushAll\n");
-    memset(table, 0, sizeof(ArmISA::PTE[size]));
-    lookupTable.clear();
+    DPRINTF(TLB, "Flushing all TLB entries\n");
+    int x = 0;
+    TlbEntry *te;
+    while (x < size) {
+       te = &table[x];
+       if (te->valid)
+           DPRINTF(TLB, " -  %#x, asn %d ppn %#x size: %#x ap:%d\n",
+                te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap);
+       x++;
+    }
+
+    memset(table, 0, sizeof(TlbEntry[size]));
     nlu = 0;
 }
 
+
+void
+TLB::flushMvaAsid(Addr mva, uint64_t asn)
+{
+    DPRINTF(TLB, "Flushing mva %#x asid: %#x\n", mva, asn);
+    TlbEntry *te;
+
+    te = lookup(mva, asn);
+    while (te != NULL) {
+     DPRINTF(TLB, " -  %#x, asn %d ppn %#x size: %#x ap:%d\n",
+            te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap);
+        te->valid = false;
+        te = lookup(mva,asn);
+    }
+}
+
 void
-TLB::serialize(ostream &os)
+TLB::flushAsid(uint64_t asn)
 {
-    SERIALIZE_SCALAR(size);
-    SERIALIZE_SCALAR(nlu);
+    DPRINTF(TLB, "Flushing all entries with asid: %#x\n", asn);
 
-    for (int i = 0; i < size; i++) {
-        nameOut(os, csprintf("%s.PTE%d", name(), i));
-        table[i].serialize(os);
+    int x = 0;
+    TlbEntry *te;
+
+    while (x < size) {
+        te = &table[x];
+        if (te->asid == asn) {
+            te->valid = false;
+            DPRINTF(TLB, " -  %#x, asn %d ppn %#x size: %#x ap:%d\n",
+                te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap);
+        }
+        x++;
+    }
+}
+
+void
+TLB::flushMva(Addr mva)
+{
+    DPRINTF(TLB, "Flushing all entries with mva: %#x\n", mva);
+
+    int x = 0;
+    TlbEntry *te;
+
+    while (x < size) {
+        te = &table[x];
+        Addr v = te->vpn << te->N;
+        if (mva >= v && mva < v + te->size) {
+            te->valid = false;
+            DPRINTF(TLB, " -  %#x, asn %d ppn %#x size: %#x ap:%d\n",
+                te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap);
+        }
+        x++;
     }
 }
 
+void
+TLB::serialize(ostream &os)
+{
+    panic("Implement Serialize\n");
+}
+
 void
 TLB::unserialize(Checkpoint *cp, const string &section)
 {
-    UNSERIALIZE_SCALAR(size);
-    UNSERIALIZE_SCALAR(nlu);
 
     panic("Need to properly unserialize TLB\n");
-    for (int i = 0; i < size; i++) {
-        table[i].unserialize(cp, csprintf("%s.PTE%d", section, i));
-    }
 }
 
 void
@@ -182,50 +293,227 @@ TLB::regStats()
 }
 
 Fault
-TLB::translateAtomic(RequestPtr req, ThreadContext *tc, Mode mode)
+TLB::trickBoxCheck(RequestPtr req, Mode mode, uint8_t domain, bool sNp)
 {
+    return NoFault;
+}
+
+Fault
+TLB::walkTrickBoxCheck(Addr pa, Addr va, Addr sz, bool is_exec,
+        uint8_t domain, bool sNp)
+{
+    return NoFault;
+}
+
+#if !FULL_SYSTEM
+Fault
+TLB::translateSe(RequestPtr req, ThreadContext *tc, Mode mode,
+        Translation *translation, bool &delay, bool timing)
+{
+    // XXX Cache misc registers and have miscreg write function inv cache
     Addr vaddr = req->getVaddr() & ~PcModeMask;
     SCTLR sctlr = tc->readMiscReg(MISCREG_SCTLR);
     uint32_t flags = req->getFlags();
 
-    if (mode != Execute) {
-        assert(flags & MustBeOne);
+    bool is_fetch = (mode == Execute);
+    bool is_write = (mode == Write);
 
-        if (sctlr.a || (flags & AllowUnaligned) == 0) {
-            if ((vaddr & flags & AlignmentMask) != 0) {
-                return new DataAbort(vaddr, (mode == Write), 0,
-                            ArmFault::AlignmentFault);
+    if (!is_fetch) {
+        assert(flags & MustBeOne);
+        if (sctlr.a || !(flags & AllowUnaligned)) {
+            if (vaddr & flags & AlignmentMask) {
+                return new DataAbort(vaddr, 0, is_write, ArmFault::AlignmentFault);
             }
         }
     }
-#if !FULL_SYSTEM
-    Process * p = tc->getProcessPtr();
 
     Addr paddr;
+    Process *p = tc->getProcessPtr();
+
     if (!p->pTable->translate(vaddr, paddr))
         return Fault(new GenericPageTableFault(vaddr));
     req->setPaddr(paddr);
 
     return NoFault;
-#else
+}
+
+#else // FULL_SYSTEM
+
+Fault
+TLB::translateFs(RequestPtr req, ThreadContext *tc, Mode mode,
+        Translation *translation, bool &delay, bool timing)
+{
+    // XXX Cache misc registers and have miscreg write function inv cache
+    Addr vaddr = req->getVaddr() & ~PcModeMask;
+    SCTLR sctlr = tc->readMiscReg(MISCREG_SCTLR);
+    CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
+    uint32_t flags = req->getFlags();
+
+    bool is_fetch = (mode == Execute);
+    bool is_write = (mode == Write);
+    bool is_priv = (cpsr.mode != MODE_USER) && !(flags & UserMode);
+
+    DPRINTF(TLBVerbose, "CPSR is user:%d UserMode:%d\n", cpsr.mode == MODE_USER, flags
+            & UserMode);
+    if (!is_fetch) {
+        assert(flags & MustBeOne);
+        if (sctlr.a || !(flags & AllowUnaligned)) {
+            if (vaddr & flags & AlignmentMask) {
+                return new DataAbort(vaddr, 0, is_write, ArmFault::AlignmentFault);
+            }
+        }
+    }
+
+    uint32_t context_id = tc->readMiscReg(MISCREG_CONTEXTIDR);
+    Fault fault;
+
+
     if (!sctlr.m) {
         req->setPaddr(vaddr);
+        if (sctlr.tre == 0) {
+            req->setFlags(Request::UNCACHEABLE);
+        } else {
+            PRRR prrr = tc->readMiscReg(MISCREG_PRRR);
+            NMRR nmrr = tc->readMiscReg(MISCREG_NMRR);
+
+            if (nmrr.ir0 == 0 || nmrr.or0 == 0 || prrr.tr0 != 0x2)
+               req->setFlags(Request::UNCACHEABLE);
+        }
+        return trickBoxCheck(req, mode, 0, false);
+    }
+
+    DPRINTF(TLBVerbose, "Translating vaddr=%#x context=%d\n", vaddr, context_id);
+    // Translation enabled
+
+    TlbEntry *te = lookup(vaddr, context_id);
+    if (te == NULL) {
+        // start translation table walk, pass variables rather than
+        // re-retreaving in table walker for speed
+        DPRINTF(TLB, "TLB Miss: Starting hardware table walker for %#x(%d)\n",
+                vaddr, context_id);
+        fault = tableWalker->walk(req, tc, context_id, mode, translation,
+                timing);
+        if (timing)
+            delay = true;
+        if (fault)
+            return fault;
+
+        te = lookup(vaddr, context_id);
+        if (!te)
+            printTlb();
+        assert(te);
+    }
+
+    uint32_t dacr = tc->readMiscReg(MISCREG_DACR);
+    switch ( (dacr >> (te->domain * 2)) & 0x3) {
+      case 0:
+        DPRINTF(TLB, "TLB Fault: Data abort on domain. DACR: %#x domain: %#x"
+               " write:%d sNp:%d\n", dacr, te->domain, is_write, te->sNp);
+        if (is_fetch)
+            return new PrefetchAbort(vaddr,
+                (te->sNp ? ArmFault::Domain0 : ArmFault::Domain1));
+        else
+            return new DataAbort(vaddr, te->domain, is_write,
+                (te->sNp ? ArmFault::Domain0 : ArmFault::Domain1));
+      case 1:
+        // Continue with permissions check
+        break;
+      case 2:
+        panic("UNPRED domain\n");
+      case 3:
+        req->setPaddr(te->pAddr(vaddr));
+        fault = trickBoxCheck(req, mode, te->domain, te->sNp);
+        if (fault)
+            return fault;
         return NoFault;
     }
-    warn_once("MPU translation not implemented\n");
-    req->setPaddr(vaddr);
+
+    uint8_t ap = te->ap;
+
+    if (sctlr.afe == 1)
+        ap |= 1;
+
+    bool abt;
+
+    switch (ap) {
+      case 0:
+        abt = true;
+        break;
+      case 1:
+        abt = !is_priv;
+        break;
+      case 2:
+        abt = !is_priv && is_write;
+        break;
+      case 3:
+        abt = false;
+        break;
+      case 4:
+        panic("UNPRED premissions\n");
+      case 5:
+        abt = !is_priv || is_write;
+        break;
+      case 6:
+      case 7:
+        abt = is_write;
+        break;
+      default:
+        panic("Unknown permissions\n");
+    }
+    if ((is_fetch) && (abt || te->xn)) {
+        DPRINTF(TLB, "TLB Fault: Prefetch abort on permission check. AP:%d priv:%d"
+               " write:%d sNp:%d\n", ap, is_priv, is_write, te->sNp);
+        return new PrefetchAbort(vaddr,
+                (te->sNp ? ArmFault::Permission0 :
+                 ArmFault::Permission1));
+    } else if (abt) {
+        DPRINTF(TLB, "TLB Fault: Data abort on permission check. AP:%d priv:%d"
+               " write:%d sNp:%d\n", ap, is_priv, is_write, te->sNp);
+        return new DataAbort(vaddr, te->domain, is_write,
+                (te->sNp ? ArmFault::Permission0 :
+                 ArmFault::Permission1));
+    }
+
+    req->setPaddr(te->pAddr(vaddr));
+    // Check for a trickbox generated address fault
+    fault = trickBoxCheck(req, mode, te->domain, te->sNp);
+    if (fault)
+        return fault;
+
     return NoFault;
-    
+}
 
 #endif
+
+Fault
+TLB::translateAtomic(RequestPtr req, ThreadContext *tc, Mode mode)
+{
+    bool delay = false;
+    Fault fault;
+#if FULL_SYSTEM
+    fault = translateFs(req, tc, mode, NULL, delay, false);
+#else
+    fault = translateSe(req, tc, mode, NULL, delay, false);
+#endif
+    assert(!delay);
+    return fault;
 }
 
-void
+Fault
 TLB::translateTiming(RequestPtr req, ThreadContext *tc,
         Translation *translation, Mode mode)
 {
     assert(translation);
-    translation->finish(translateAtomic(req, tc, mode), req, tc, mode);
+    bool delay = false;
+    Fault fault;
+#if FULL_SYSTEM
+    fault = translateFs(req, tc, mode, translation, delay, true);
+#else
+    fault = translateSe(req, tc, mode, translation, delay, true);
+#endif
+    if (!delay)
+        translation->finish(fault, req, tc, mode);
+    return fault;
 }
 
 ArmISA::TLB *
index dfd7074444c0cf27b7bbd085e78ec73c3f0c961a..7193ac0e83cf77ddecbc73ebb5d34be09490f801 100644 (file)
@@ -59,6 +59,8 @@ class ThreadContext;
 
 namespace ArmISA {
 
+class TableWalker;
+
 class TLB : public BaseTLB
 {
   public:
@@ -71,21 +73,24 @@ class TLB : public BaseTLB
         AlignDoubleWord = 0x7,
 
         AllowUnaligned = 0x8,
+        // Priv code operating as if it wasn't
+        UserMode = 0x10,
         // Because zero otherwise looks like a valid setting and may be used
         // accidentally, this bit must be non-zero to show it was used on
         // purpose.
-        MustBeOne = 0x10
+        MustBeOne = 0x20
     };
   protected:
     typedef std::multimap<Addr, int> PageTable;
     PageTable lookupTable;     // Quick lookup into page table
 
-    ArmISA::PTE *table;        // the Page Table
+    TlbEntry *table;   // the Page Table
     int size;                  // TLB Size
     int nlu;                   // not last used entry (for replacement)
+    TableWalker *tableWalker;
 
     void nextnlu() { if (++nlu >= size) nlu = 0; }
-    ArmISA::PTE *lookup(Addr vpn, uint8_t asn) const;
+    TlbEntry *lookup(Addr vpn, uint8_t asn);
 
     // Access Stats
     mutable Stats::Scalar read_hits;
@@ -101,6 +106,7 @@ class TLB : public BaseTLB
     Stats::Formula invalids;
     Stats::Formula accesses;
 
+
   public:
     typedef ArmTLBParams Params;
     TLB(const Params *p);
@@ -108,17 +114,49 @@ class TLB : public BaseTLB
     virtual ~TLB();
     int getsize() const { return size; }
 
-    void insert(Addr vaddr, ArmISA::PTE &pte);
+    void insert(Addr vaddr, TlbEntry &pte);
+
+    /** Reset the entire TLB */
     void flushAll();
+
+    /** Remove any entries that match both a va and asn
+     * @param mva virtual address to flush
+     * @param asn contextid/asn to flush on match
+     */
+    void flushMvaAsid(Addr mva, uint64_t asn);
+
+    /** Remove any entries that match the asn
+     * @param asn contextid/asn to flush on match
+     */
+    void flushAsid(uint64_t asn);
+
+    /** Remove all entries that match the va regardless of asn
+     * @param mva address to flush from cache
+     */
+    void flushMva(Addr mva);
+
+    Fault trickBoxCheck(RequestPtr req, Mode mode, uint8_t domain, bool sNp);
+    Fault walkTrickBoxCheck(Addr pa, Addr va, Addr sz, bool is_exec, uint8_t
+            domain, bool sNp);
+
+    void printTlb();
+
     void demapPage(Addr vaddr, uint64_t asn)
     {
-        panic("demapPage unimplemented.\n");
+        flushMvaAsid(vaddr, asn);
     }
 
     static bool validVirtualAddress(Addr vaddr);
 
+#if FULL_SYSTEM
+    Fault translateFs(RequestPtr req, ThreadContext *tc, Mode mode,
+            Translation *translation, bool &delay, bool timing);
+#else
+    Fault translateSe(RequestPtr req, ThreadContext *tc, Mode mode,
+            Translation *translation, bool &delay, bool timing);
+#endif
     Fault translateAtomic(RequestPtr req, ThreadContext *tc, Mode mode);
-    void translateTiming(RequestPtr req, ThreadContext *tc,
+    Fault translateTiming(RequestPtr req, ThreadContext *tc,
             Translation *translation, Mode mode);
 
     // Checkpointing
index ac734e5ac409c0282d5386c6ef8546884f210125..402831f5ad7d154746b810a1415308eee9bea0f2 100644 (file)
@@ -114,7 +114,6 @@ class BaseCPU(MemObject):
             interrupts = Param.MipsInterrupts(
                     MipsInterrupts(), "Interrupt Controller")
     elif buildEnv['TARGET_ISA'] == 'arm':
-        UnifiedTLB = Param.Bool(True, "Is this a Unified TLB?")
         dtb = Param.ArmTLB(ArmTLB(), "Data TLB")
         itb = Param.ArmTLB(ArmTLB(), "Instruction TLB")
         if buildEnv['FULL_SYSTEM']:
@@ -158,6 +157,10 @@ class BaseCPU(MemObject):
                       "interrupts.pio",
                       "interrupts.int_port"]
 
+    if buildEnv['TARGET_ISA'] == 'arm' and buildEnv['FULL_SYSTEM']:
+        _mem_ports = ["itb.walker.port",
+                      "dtb.walker.port"]
+
     def connectMemPorts(self, bus):
         for p in self._mem_ports:
             if p != 'physmem_port':
@@ -170,8 +173,9 @@ class BaseCPU(MemObject):
         self.icache_port = ic.cpu_side
         self.dcache_port = dc.cpu_side
         self._mem_ports = ['icache.mem_side', 'dcache.mem_side']
-        if buildEnv['TARGET_ISA'] == 'x86' and buildEnv['FULL_SYSTEM']:
-            self._mem_ports += ["itb.walker_port", "dtb.walker_port"]
+        if buildEnv['FULL_SYSTEM']:
+            if buildEnv['TARGET_ISA'] in ['x86', 'arm']:
+                self._mem_ports += ["itb.walker.port", "dtb.walker.port"]
 
     def addTwoLevelCacheHierarchy(self, ic, dc, l2c):
         self.addPrivateSplitL1Caches(ic, dc)