ARM: Don't reset CPUs that are going to be switched in.
[gem5.git] / src / arch / arm / isa.cc
index 20cddcff16c5b808a20bfd3fdab466fc51e92e57..b8a0fe2823572e7d674e515c2de110c47cdb3237 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 ARM Limited
+ * Copyright (c) 2010-2012 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
  */
 
 #include "arch/arm/isa.hh"
+#include "config/use_checker.hh"
+#include "debug/Arm.hh"
+#include "debug/MiscRegs.hh"
 #include "sim/faults.hh"
+#include "sim/stat_control.hh"
+#include "sim/system.hh"
+
+#if USE_CHECKER
+#include "cpu/checker/cpu.hh"
+#endif
 
 namespace ArmISA
 {
@@ -48,7 +57,7 @@ void
 ISA::clear()
 {
     SCTLR sctlr_rst = miscRegs[MISCREG_SCTLR_RST];
-
+    uint32_t midr = miscRegs[MISCREG_MIDR];
     memset(miscRegs, 0, sizeof(miscRegs));
     CPSR cpsr = 0;
     cpsr.mode = MODE_USER;
@@ -67,21 +76,12 @@ ISA::clear()
     miscRegs[MISCREG_SCTLR] = sctlr;
     miscRegs[MISCREG_SCTLR_RST] = sctlr_rst;
 
+    // Preserve MIDR accross reset
+    miscRegs[MISCREG_MIDR] = midr;
+
     /* Start with an event in the mailbox */
     miscRegs[MISCREG_SEV_MAILBOX] = 1;
 
-    /*
-     * Implemented = '5' from "M5",
-     * Variant = 0,
-     */
-    miscRegs[MISCREG_MIDR] =
-        (0x35 << 24) | // Implementor is '5' from "M5"
-        (0 << 20)    | // Variant
-        (0xf << 16)  | // Architecture from CPUID scheme
-        (0xf00 << 4) | // Primary part number
-        (0 << 0)     | // Revision
-        0;
-
     // Separate Instruction and Data TLBs.
     miscRegs[MISCREG_TLBTR] = 1;
 
@@ -142,6 +142,16 @@ ISA::clear()
 
     miscRegs[MISCREG_CPACR] = 0;
     miscRegs[MISCREG_FPSID] = 0x410430A0;
+
+    // See section B4.1.84 of ARM ARM
+    // All values are latest for ARMv7-A profile
+    miscRegs[MISCREG_ID_ISAR0] = 0x02101111;
+    miscRegs[MISCREG_ID_ISAR1] = 0x02112111;
+    miscRegs[MISCREG_ID_ISAR2] = 0x21232141;
+    miscRegs[MISCREG_ID_ISAR3] = 0x01112131;
+    miscRegs[MISCREG_ID_ISAR4] = 0x10010142;
+    miscRegs[MISCREG_ID_ISAR5] = 0x00000000;
+
     //XXX We need to initialize the rest of the state.
 }
 
@@ -173,15 +183,29 @@ ISA::readMiscReg(int misc_reg, ThreadContext *tc)
         cpsr.t = pc.thumb() ? 1 : 0;
         return cpsr;
     }
-    if (misc_reg >= MISCREG_CP15_UNIMP_START &&
-        misc_reg < MISCREG_CP15_END) {
+    if (misc_reg >= MISCREG_CP15_UNIMP_START)
         panic("Unimplemented CP15 register %s read.\n",
               miscRegName[misc_reg]);
-    }
+
     switch (misc_reg) {
+      case MISCREG_MPIDR:
+
+        return 0x80000000 | // multiprocessor extensions available
+               tc->cpuId();
+        break;
+      case MISCREG_ID_MMFR0:
+        return 0x03; // VMSAv7 support
+      case MISCREG_ID_MMFR2:
+        return 0x01230000; // no HW access | WFI stalling | ISB and DSB
+                           // | all TLB maintenance | no Harvard
+      case MISCREG_ID_MMFR3:
+        return 0xF0102211; // SuperSec | Coherent TLB | Bcast Maint |
+                           // BP Maint | Cache Maint Set/way | Cache Maint MVA
       case MISCREG_CLIDR:
         warn_once("The clidr register always reports 0 caches.\n");
-        break;
+        warn_once("clidr LoUIS field of 0b001 to match current "
+                  "ARM implementations.\n");
+        return 0x00200000;
       case MISCREG_CCSIDR:
         warn_once("The ccsidr register isn't implemented and "
                 "always reads as 0.\n");
@@ -190,8 +214,8 @@ ISA::readMiscReg(int misc_reg, ThreadContext *tc)
         warn("Returning thumbEE disabled for now since we don't support CP14"
              "config registers and jumping to ThumbEE vectors\n");
         return 0x0031; // !ThumbEE | !Jazelle | Thumb | ARM
-      case MISCREG_ID_MMFR0:
-        return 0x03; //VMSAz7
+      case MISCREG_ID_PFR1:
+        return 0x00001; // !Timer | !Virti | !M Profile | !TrustZone | ARMv4
       case MISCREG_CTR:
         return 0x86468006; // V7, 64 byte cache line, load/exclusive is exact
       case MISCREG_ACTLR:
@@ -200,10 +224,30 @@ ISA::readMiscReg(int misc_reg, ThreadContext *tc)
       case MISCREG_PMCR:
       case MISCREG_PMCCNTR:
       case MISCREG_PMSELR:
-        warn("Not doing anyhting for read to miscreg %s\n",
+        warn("Not doing anything for read to miscreg %s\n",
                 miscRegName[misc_reg]);
         break;
-
+      case MISCREG_CPSR_Q:
+        panic("shouldn't be reading this register seperately\n");
+      case MISCREG_FPSCR_QC:
+        return readMiscRegNoEffect(MISCREG_FPSCR) & ~FpscrQcMask;
+      case MISCREG_FPSCR_EXC:
+        return readMiscRegNoEffect(MISCREG_FPSCR) & ~FpscrExcMask;
+      case MISCREG_L2CTLR:
+        {
+            // mostly unimplemented, just set NumCPUs field from sim and return
+            L2CTLR l2ctlr = 0;
+            // b00:1CPU to b11:4CPUs
+            l2ctlr.numCPUs = tc->getSystemPtr()->numContexts() - 1;
+            return l2ctlr;
+        }
+      case MISCREG_DBGDIDR:
+        /* For now just implement the version number.
+         * Return 0 as we don't support debug architecture yet.
+         */
+         return 0;
+      case MISCREG_DBGDSCR_INT:
+        return 0;
     }
     return readMiscRegNoEffect(misc_reg);
 }
@@ -227,49 +271,58 @@ ISA::setMiscRegNoEffect(int misc_reg, const MiscReg &val)
 void
 ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc)
 {
+
     MiscReg newVal = val;
+    int x;
+    System *sys;
+    ThreadContext *oc;
+
     if (misc_reg == MISCREG_CPSR) {
         updateRegMap(val);
+
+
+        CPSR old_cpsr = miscRegs[MISCREG_CPSR];
+        int old_mode = old_cpsr.mode;
         CPSR cpsr = val;
+        if (old_mode != cpsr.mode) {
+            tc->getITBPtr()->invalidateMiscReg();
+            tc->getDTBPtr()->invalidateMiscReg();
+        }
+
         DPRINTF(Arm, "Updating CPSR from %#x to %#x f:%d i:%d a:%d mode:%#x\n",
                 miscRegs[misc_reg], cpsr, cpsr.f, cpsr.i, cpsr.a, cpsr.mode);
         PCState pc = tc->pcState();
         pc.nextThumb(cpsr.t);
         pc.nextJazelle(cpsr.j);
+#if USE_CHECKER
+        tc->pcStateNoRecord(pc);
+#else
         tc->pcState(pc);
+#endif //USE_CHECKER
     } else if (misc_reg >= MISCREG_CP15_UNIMP_START &&
         misc_reg < MISCREG_CP15_END) {
         panic("Unimplemented CP15 register %s wrote with %#x.\n",
               miscRegName[misc_reg], val);
     } else {
         switch (misc_reg) {
-          case MISCREG_ITSTATE:
-            {
-                ITSTATE itstate = newVal;
-                CPSR cpsr = miscRegs[MISCREG_CPSR];
-                cpsr.it1 = itstate.bottom2;
-                cpsr.it2 = itstate.top6;
-                miscRegs[MISCREG_CPSR] = cpsr;
-                DPRINTF(MiscRegs,
-                        "Updating ITSTATE -> %#x in CPSR -> %#x.\n",
-                        (uint8_t)itstate, (uint32_t)cpsr);
-            }
-            break;
           case MISCREG_CPACR:
             {
-                CPACR newCpacr = 0;
-                CPACR valCpacr = val;
-                newCpacr.cp10 = valCpacr.cp10;
-                newCpacr.cp11 = valCpacr.cp11;
-                //XXX d32dis isn't implemented. The manual says whether or not
-                //it works is implementation defined.
-                newCpacr.asedis = valCpacr.asedis;
-                newVal = newCpacr;
+
+                const uint32_t ones = (uint32_t)(-1);
+                CPACR cpacrMask = 0;
+                // Only cp10, cp11, and ase are implemented, nothing else should
+                // be writable
+                cpacrMask.cp10 = ones;
+                cpacrMask.cp11 = ones;
+                cpacrMask.asedis = ones;
+                newVal &= cpacrMask;
+                DPRINTF(MiscRegs, "Writing misc reg %s: %#x\n",
+                        miscRegName[misc_reg], newVal);
             }
             break;
           case MISCREG_CSSELR:
             warn_once("The csselr register isn't implemented.\n");
-            break;
+            return;
           case MISCREG_FPSCR:
             {
                 const uint32_t ones = (uint32_t)(-1);
@@ -295,8 +348,29 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc)
                          (miscRegs[MISCREG_FPSCR] & ~(uint32_t)fpscrMask);
             }
             break;
+          case MISCREG_CPSR_Q:
+            {
+                assert(!(newVal & ~CpsrMaskQ));
+                newVal = miscRegs[MISCREG_CPSR] | newVal;
+                misc_reg = MISCREG_CPSR;
+            }
+            break;
+          case MISCREG_FPSCR_QC:
+            {
+                newVal = miscRegs[MISCREG_FPSCR] | (newVal & FpscrQcMask);
+                misc_reg = MISCREG_FPSCR;
+            }
+            break;
+          case MISCREG_FPSCR_EXC:
+            {
+                newVal = miscRegs[MISCREG_FPSCR] | (newVal & FpscrExcMask);
+                misc_reg = MISCREG_FPSCR;
+            }
+            break;
           case MISCREG_FPEXC:
             {
+                // vfpv3 architecture, section B.6.1 of DDI04068
+                // bit 29 - valid only if fpexc[31] is 0
                 const uint32_t fpexcMask = 0x60000000;
                 newVal = (newVal & fpexcMask) |
                          (miscRegs[MISCREG_FPEXC] & ~fpexcMask);
@@ -309,6 +383,33 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc)
                 SCTLR new_sctlr = newVal;
                 new_sctlr.nmfi =  (bool)sctlr.nmfi;
                 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();
+#if USE_CHECKER
+                    CheckerCPU *checker =
+                        dynamic_cast<CheckerCPU*>(oc->getCheckerCpuPtr());
+                    if (checker) {
+                        checker->getDTBPtr()->allCpusCaching();
+                        checker->getITBPtr()->allCpusCaching();
+                    }
+#endif
+                }
                 return;
             }
           case MISCREG_TLBTR:
@@ -319,9 +420,21 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc)
             return;
           case MISCREG_TLBIALLIS:
           case MISCREG_TLBIALL:
-            warn_once("Need to flush all TLBs in MP\n");
-            tc->getITBPtr()->flushAll();
-            tc->getDTBPtr()->flushAll();
+            sys = tc->getSystemPtr();
+            for (x = 0; x < sys->numContexts(); x++) {
+                oc = sys->getThreadContext(x);
+                assert(oc->getITBPtr() && oc->getDTBPtr());
+                oc->getITBPtr()->flushAll();
+                oc->getDTBPtr()->flushAll();
+#if USE_CHECKER
+                CheckerCPU *checker =
+                    dynamic_cast<CheckerCPU*>(oc->getCheckerCpuPtr());
+                if (checker) {
+                    checker->getITBPtr()->flushAll();
+                    checker->getDTBPtr()->flushAll();
+                }
+#endif
+            }
             return;
           case MISCREG_ITLBIALL:
             tc->getITBPtr()->flushAll();
@@ -331,23 +444,61 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc)
             return;
           case MISCREG_TLBIMVAIS:
           case MISCREG_TLBIMVA:
-            warn_once("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));
+            sys = tc->getSystemPtr();
+            for (x = 0; x < sys->numContexts(); x++) {
+                oc = sys->getThreadContext(x);
+                assert(oc->getITBPtr() && oc->getDTBPtr());
+                oc->getITBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
+                        bits(newVal, 7,0));
+                oc->getDTBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
+                        bits(newVal, 7,0));
+#if USE_CHECKER
+                CheckerCPU *checker =
+                    dynamic_cast<CheckerCPU*>(oc->getCheckerCpuPtr());
+                if (checker) {
+                    checker->getITBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
+                            bits(newVal, 7,0));
+                    checker->getDTBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
+                            bits(newVal, 7,0));
+                }
+#endif
+            }
             return;
           case MISCREG_TLBIASIDIS:
           case MISCREG_TLBIASID:
-            warn_once("Need to flush all TLBs in MP\n");
-            tc->getITBPtr()->flushAsid(bits(newVal, 7,0));
-            tc->getDTBPtr()->flushAsid(bits(newVal, 7,0));
+            sys = tc->getSystemPtr();
+            for (x = 0; x < sys->numContexts(); x++) {
+                oc = sys->getThreadContext(x);
+                assert(oc->getITBPtr() && oc->getDTBPtr());
+                oc->getITBPtr()->flushAsid(bits(newVal, 7,0));
+                oc->getDTBPtr()->flushAsid(bits(newVal, 7,0));
+#if USE_CHECKER
+                CheckerCPU *checker =
+                    dynamic_cast<CheckerCPU*>(oc->getCheckerCpuPtr());
+                if (checker) {
+                    checker->getITBPtr()->flushAsid(bits(newVal, 7,0));
+                    checker->getDTBPtr()->flushAsid(bits(newVal, 7,0));
+                }
+#endif
+            }
             return;
           case MISCREG_TLBIMVAAIS:
           case MISCREG_TLBIMVAA:
-            warn_once("Need to flush all TLBs in MP\n");
-            tc->getITBPtr()->flushMva(mbits(newVal, 31,12));
-            tc->getDTBPtr()->flushMva(mbits(newVal, 31,12));
+            sys = tc->getSystemPtr();
+            for (x = 0; x < sys->numContexts(); x++) {
+                oc = sys->getThreadContext(x);
+                assert(oc->getITBPtr() && oc->getDTBPtr());
+                oc->getITBPtr()->flushMva(mbits(newVal, 31,12));
+                oc->getDTBPtr()->flushMva(mbits(newVal, 31,12));
+#if USE_CHECKER
+                CheckerCPU *checker =
+                    dynamic_cast<CheckerCPU*>(oc->getCheckerCpuPtr());
+                if (checker) {
+                    checker->getITBPtr()->flushMva(mbits(newVal, 31,12));
+                    checker->getDTBPtr()->flushMva(mbits(newVal, 31,12));
+                }
+#endif
+            }
             return;
           case MISCREG_ITLBIMVA:
             tc->getITBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
@@ -367,6 +518,18 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc)
             warn("Not doing anything for write of miscreg ACTLR\n");
             break;
           case MISCREG_PMCR:
+            {
+              // Performance counters not implemented.  Instead, interpret
+              //   a reset command to this register to reset the simulator
+              //   statistics.
+              // PMCR_E | PMCR_P | PMCR_C
+              const int ResetAndEnableCounters = 0x7;
+              if (newVal == ResetAndEnableCounters) {
+                  inform("Resetting all simobject stats\n");
+                  Stats::schedStatEvent(false, true);
+                  break;
+              }
+            }
           case MISCREG_PMCCNTR:
           case MISCREG_PMSELR:
             warn("Not doing anything for write to miscreg %s\n",
@@ -405,7 +568,9 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc)
                   default:
                       panic("Security Extensions not implemented!");
               }
-              req->setVirt(0, val, 1, flags, tc->pcState().pc());
+              warn("Translating via MISCREG in atomic mode! Fix Me!\n");
+              req->setVirt(0, val, 1, flags, tc->pcState().pc(),
+                      Request::funcMasterId);
               fault = tc->getDTBPtr()->translateAtomic(req, tc, mode);
               if (fault == NoFault) {
                   miscRegs[MISCREG_PAR] =
@@ -426,6 +591,23 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc)
               }
               return;
             }
+          case MISCREG_CONTEXTIDR:
+          case MISCREG_PRRR:
+          case MISCREG_NMRR:
+          case MISCREG_DACR:
+            tc->getITBPtr()->invalidateMiscReg();
+            tc->getDTBPtr()->invalidateMiscReg();
+            break;
+          case MISCREG_CPSR_MODE:
+            // This miscreg is used by copy*Regs to set the CPSR mode
+            // without updating other CPSR variables. It's used to
+            // make sure the register map is in such a state that we can
+            // see all of the registers for the copy.
+            updateRegMap(val);
+            return;
+          case MISCREG_L2CTLR:
+            warn("miscreg L2CTLR (%s) written with %#x. ignored...\n",
+                 miscRegName[misc_reg], uint32_t(val));
         }
     }
     setMiscRegNoEffect(misc_reg, newVal);