summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/arch/arm/isa.cc17
-rw-r--r--src/arch/arm/linux/system.cc21
-rw-r--r--src/arch/arm/linux/system.hh11
-rw-r--r--src/arch/arm/system.hh9
-rw-r--r--src/arch/arm/tlb.cc10
-rw-r--r--src/arch/arm/tlb.hh3
6 files changed, 69 insertions, 2 deletions
diff --git a/src/arch/arm/isa.cc b/src/arch/arm/isa.cc
index 25bc3161b..676abfa68 100644
--- a/src/arch/arm/isa.cc
+++ b/src/arch/arm/isa.cc
@@ -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:
diff --git a/src/arch/arm/linux/system.cc b/src/arch/arm/linux/system.cc
index 445fa2f19..66f4f26af 100644
--- a/src/arch/arm/linux/system.cc
+++ b/src/arch/arm/linux/system.cc
@@ -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
diff --git a/src/arch/arm/linux/system.hh b/src/arch/arm/linux/system.hh
index 2ef65fea2..54681096b 100644
--- a/src/arch/arm/linux/system.hh
+++ b/src/arch/arm/linux/system.hh
@@ -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__
diff --git a/src/arch/arm/system.hh b/src/arch/arm/system.hh
index 4898d433c..32b48a85b 100644
--- a/src/arch/arm/system.hh
+++ b/src/arch/arm/system.hh
@@ -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
diff --git a/src/arch/arm/tlb.cc b/src/arch/arm/tlb.cc
index c59498212..942f85120 100644
--- a/src/arch/arm/tlb.cc
+++ b/src/arch/arm/tlb.cc
@@ -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);
diff --git a/src/arch/arm/tlb.hh b/src/arch/arm/tlb.hh
index bf6ae22f8..f78e38a3d 100644
--- a/src/arch/arm/tlb.hh
+++ b/src/arch/arm/tlb.hh
@@ -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);