ARM: Mark some variables uncacheable until boot all CPUs are enabled.
authorAli Saidi <Ali.Saidi@ARM.com>
Fri, 19 Aug 2011 20:08:08 +0000 (15:08 -0500)
committerAli Saidi <Ali.Saidi@ARM.com>
Fri, 19 Aug 2011 20:08:08 +0000 (15:08 -0500)
There are a set of locations is the linux kernel that are managed via
cache maintence instructions until all processors enable their MMUs & TLBs.
Writes to these locations are manually flushed from the cache to main
memory when the occur so that cores operating without their MMU enabled
and only issuing uncached accesses can receive the correct data. Unfortuantely,
gem5 doesn't support any kind of software directed maintence of the cache.
Until such time as that support exists this patch marks the specific cache blocks
that need to be coherent as non-cacheable until all CPUs enable their MMU and
thus allows gem5 to boot MP systems with caches enabled (a requirement for
booting an O3 cpu and thus an O3 CPU regression).

src/arch/arm/isa.cc
src/arch/arm/linux/system.cc
src/arch/arm/linux/system.hh
src/arch/arm/system.hh
src/arch/arm/tlb.cc
src/arch/arm/tlb.hh

index 25bc3161b97da019664966bbbbd35f0f5d84a468..676abfa6896892b81381d532f9d3b2ee7cca7303 100644 (file)
@@ -360,6 +360,23 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc)
                 miscRegs[MISCREG_SCTLR] = (MiscReg)new_sctlr;
                 tc->getITBPtr()->invalidateMiscReg();
                 tc->getDTBPtr()->invalidateMiscReg();
+
+                // Check if all CPUs are booted with caches enabled
+                // so we can stop enforcing coherency of some kernel
+                // structures manually.
+                sys = tc->getSystemPtr();
+                for (x = 0; x < sys->numContexts(); x++) {
+                    oc = sys->getThreadContext(x);
+                    SCTLR other_sctlr = oc->readMiscRegNoEffect(MISCREG_SCTLR);
+                    if (!other_sctlr.c && oc->status() != ThreadContext::Halted)
+                        return;
+                }
+
+                for (x = 0; x < sys->numContexts(); x++) {
+                    oc = sys->getThreadContext(x);
+                    oc->getDTBPtr()->allCpusCaching();
+                    oc->getITBPtr()->allCpusCaching();
+                }
                 return;
             }
           case MISCREG_TLBTR:
index 445fa2f195cd6bf93c6c09baf29d6f35b9458414..66f4f26afb0fc1577689de6373af2cad6c394711 100644 (file)
@@ -117,6 +117,27 @@ LinuxArmSystem::LinuxArmSystem(Params *p)
     } else {
         panic("couldn't find kernel symbol \'udelay\'");
     }
+
+    secDataPtrAddr = 0;
+    secDataAddr = 0;
+    penReleaseAddr = 0;
+    kernelSymtab->findAddress("__secondary_data", secDataPtrAddr);
+    kernelSymtab->findAddress("secondary_data", secDataAddr);
+    kernelSymtab->findAddress("pen_release", penReleaseAddr);
+
+    secDataPtrAddr &= ~ULL(0x7F);
+    secDataAddr &= ~ULL(0x7F);
+    penReleaseAddr &= ~ULL(0x7F);
+}
+
+bool
+LinuxArmSystem::adderBootUncacheable(Addr a)
+{
+    Addr block = a & ~ULL(0x7F);
+    if (block == secDataPtrAddr || block == secDataAddr ||
+            block == penReleaseAddr)
+        return true;
+    return false;
 }
 
 void
index 2ef65fea28aad97b4e2da3b92d72a4d1fb42d967..54681096bd2e5c7a252727a54310fb4102525458 100644 (file)
@@ -69,6 +69,8 @@ class LinuxArmSystem : public ArmSystem
 
     void initState();
 
+    bool adderBootUncacheable(Addr a);
+
   private:
 #ifndef NDEBUG
     /** Event to halt the simulator if the kernel calls panic()  */
@@ -87,6 +89,15 @@ class LinuxArmSystem : public ArmSystem
      * Thus we need to do some division to get back to us.
      */
     Linux::UDelayEvent *constUDelaySkipEvent;
+
+    /** These variables store addresses of important data structures
+     * that are normaly kept coherent at boot with cache mainetence operations.
+     * Since these operations aren't supported in gem5, we keep them coherent
+     * by making them uncacheable until all processors in the system boot.
+     */
+    Addr secDataPtrAddr;
+    Addr secDataAddr;
+    Addr penReleaseAddr;
 };
 
 #endif // __ARCH_ARM_LINUX_SYSTEM_HH__
index 4898d433cb7ebfd4c260009d46c3fe9ae5a7eb5d..32b48a85b9c9a42652fa3b715c32125cf413d39b 100644 (file)
@@ -78,6 +78,15 @@ class ArmSystem : public System
 
     void initState();
 
+    /** Check if an address should be uncacheable until all caches are enabled.
+     * This exits because coherence on some addresses at boot is maintained via
+     * sw coherence until the caches are enbaled. Since we don't support sw
+     * coherence operations in gem5, this is a method that allows a system
+     * type to designate certain addresses that should remain uncachebale
+     * for a while.
+     */
+    virtual bool adderBootUncacheable(Addr a) { return false; }
+
     virtual Addr fixFuncEventAddr(Addr addr)
     {
         // Remove the low bit that thumb symbols have set
index c5949821295a24bc2e070f3993e092a4b3dd0d7a..942f85120531680fbc31a90043b1481e305cb41c 100644 (file)
@@ -61,6 +61,7 @@
 #include "sim/process.hh"
 
 #if FULL_SYSTEM
+#include "arch/arm/system.hh"
 #include "arch/arm/table_walker.hh"
 #endif
 
@@ -72,7 +73,7 @@ TLB::TLB(const Params *p)
 #if FULL_SYSTEM
       , tableWalker(p->walker)
 #endif
-    , rangeMRU(1), miscRegValid(false)
+    , rangeMRU(1), bootUncacheability(false), miscRegValid(false)
 {
     table = new TlbEntry[size];
     memset(table, 0, sizeof(TlbEntry) * size);
@@ -575,6 +576,11 @@ TLB::translateFs(RequestPtr req, ThreadContext *tc, Mode mode,
         }
     }
 
+
+    if (!bootUncacheability &&
+            ((ArmSystem*)tc->getSystemPtr())->adderBootUncacheable(vaddr))
+        req->setFlags(Request::UNCACHEABLE);
+
     switch ( (dacr >> (te->domain * 2)) & 0x3) {
       case 0:
         domainFaults++;
@@ -704,7 +710,7 @@ TLB::translateTiming(RequestPtr req, ThreadContext *tc,
 #else
     fault = translateSe(req, tc, mode, translation, delay, true);
 #endif
-    DPRINTF(TLB, "Translation returning delay=%d fault=%d\n", delay, fault !=
+    DPRINTF(TLBVerbose, "Translation returning delay=%d fault=%d\n", delay, fault !=
             NoFault);
     if (!delay)
         translation->finish(fault, req, tc, mode);
index bf6ae22f8c7e33e49c518c46e18927071175ceee..f78e38a3d6b9ff265db2607f0c6215e6c1904a31 100644 (file)
@@ -128,6 +128,8 @@ class TLB : public BaseTLB
 
     int rangeMRU; //On lookup, only move entries ahead when outside rangeMRU
 
+    bool bootUncacheability;
+
   public:
     typedef ArmTLBParams Params;
     TLB(const Params *p);
@@ -162,6 +164,7 @@ class TLB : public BaseTLB
 
     void printTlb();
 
+    void allCpusCaching() { bootUncacheability = true; }
     void demapPage(Addr vaddr, uint64_t asn)
     {
         flushMvaAsid(vaddr, asn);