isa,cpu: Add support for FS SMT Interrupts
authorMitch Hayenga <mitch.hayenga@arm.com>
Wed, 30 Sep 2015 16:14:19 +0000 (11:14 -0500)
committerMitch Hayenga <mitch.hayenga@arm.com>
Wed, 30 Sep 2015 16:14:19 +0000 (11:14 -0500)
Adds per-thread interrupt controllers and thread/context logic
so that interrupts properly get routed in SMT systems.

23 files changed:
configs/example/fs.py
configs/example/se.py
src/arch/alpha/isa/decoder.isa
src/arch/arm/faults.cc
src/arch/arm/isa.cc
src/arch/arm/isa/insts/misc.isa
src/arch/sparc/isa.cc
src/arch/sparc/tlb.cc
src/arch/sparc/ua2005.cc
src/arch/x86/utility.cc
src/cpu/BaseCPU.py
src/cpu/base.cc
src/cpu/base.hh
src/cpu/dummy_checker.cc
src/cpu/intr_control.cc
src/cpu/kvm/x86_cpu.cc
src/cpu/minor/execute.cc
src/cpu/o3/checker.cc
src/cpu/o3/cpu.cc
src/cpu/simple/base.cc
src/dev/x86/i82094aa.cc
tests/configs/pc-simple-timing-ruby.py
util/cpt_upgraders/smt-interrupts.py [new file with mode: 0644]

index 70a3b950e42c142c8c753bb7ad00e7176ff92bb6..9d8b87aaa99ca3c6486cde625a668b2901b423f4 100644 (file)
@@ -176,9 +176,9 @@ def build_test_system(np):
                 cpu.itb.walker.port = test_sys.ruby._cpu_ports[i].slave
                 cpu.dtb.walker.port = test_sys.ruby._cpu_ports[i].slave
 
-                cpu.interrupts.pio = test_sys.ruby._cpu_ports[i].master
-                cpu.interrupts.int_master = test_sys.ruby._cpu_ports[i].slave
-                cpu.interrupts.int_slave = test_sys.ruby._cpu_ports[i].master
+                cpu.interrupts[0].pio = test_sys.ruby._cpu_ports[i].master
+                cpu.interrupts[0].int_master = test_sys.ruby._cpu_ports[i].slave
+                cpu.interrupts[0].int_slave = test_sys.ruby._cpu_ports[i].master
 
     else:
         if options.caches or options.l2cache:
index afd916cdb4cc56986fce1defdd8421ee22d967fb..0928482b7c704d4e89f20116c1a515358115983a 100644 (file)
@@ -265,9 +265,9 @@ if options.ruby:
         system.cpu[i].icache_port = ruby_port.slave
         system.cpu[i].dcache_port = ruby_port.slave
         if buildEnv['TARGET_ISA'] == 'x86':
-            system.cpu[i].interrupts.pio = ruby_port.master
-            system.cpu[i].interrupts.int_master = ruby_port.slave
-            system.cpu[i].interrupts.int_slave = ruby_port.master
+            system.cpu[i].interrupts[0].pio = ruby_port.master
+            system.cpu[i].interrupts[0].int_master = ruby_port.slave
+            system.cpu[i].interrupts[0].int_slave = ruby_port.master
             system.cpu[i].itb.walker.port = ruby_port.slave
             system.cpu[i].dtb.walker.port = ruby_port.slave
 else:
index c77ca434fb57fa1fda41100c892073dd8ad8bf0e..e61bb43ff6a12d30d48854051d13687771a6fd73 100644 (file)
@@ -943,7 +943,7 @@ decode OPCODE default Unknown::unknown() {
             0x01: quiesce({{
                 // Don't sleep if (unmasked) interrupts are pending
                 Interrupts* interrupts =
-                    xc->tcBase()->getCpuPtr()->getInterruptController();
+                    xc->tcBase()->getCpuPtr()->getInterruptController(0);
                 if (interrupts->checkInterrupts(xc->tcBase())) {
                     PseudoInst::quiesceSkip(xc->tcBase());
                 } else {
index 9d373e469082a0144774b6eb1992b49a502e8cf8..a2b1120ecf2ff13f6979849a3750f1b5f4c129dd 100644 (file)
@@ -681,7 +681,7 @@ void
 Reset::invoke(ThreadContext *tc, const StaticInstPtr &inst)
 {
     if (FullSystem) {
-        tc->getCpuPtr()->clearInterrupts();
+        tc->getCpuPtr()->clearInterrupts(tc->threadId());
         tc->clearArchRegs();
     }
     if (!ArmSystem::highestELIs64(tc)) {
@@ -938,7 +938,7 @@ AbortFault<T>::invoke(ThreadContext *tc, const StaticInstPtr &inst)
     }
 
     if (source == ArmFault::AsynchronousExternalAbort) {
-        tc->getCpuPtr()->clearInterrupt(INT_ABT, 0);
+        tc->getCpuPtr()->clearInterrupt(tc->threadId(), INT_ABT, 0);
     }
     // Get effective fault source encoding
     CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
@@ -1353,7 +1353,7 @@ SystemError::SystemError()
 void
 SystemError::invoke(ThreadContext *tc, const StaticInstPtr &inst)
 {
-    tc->getCpuPtr()->clearInterrupt(INT_ABT, 0);
+    tc->getCpuPtr()->clearInterrupt(tc->threadId(), INT_ABT, 0);
     ArmFault::invoke(tc, inst);
 }
 
@@ -1404,7 +1404,7 @@ ArmSev::invoke(ThreadContext *tc, const StaticInstPtr &inst) {
     // SEV execution and let pipeline continue as pcState is still
     // valid.
     tc->setMiscReg(MISCREG_SEV_MAILBOX, 1);
-    tc->getCpuPtr()->clearInterrupt(INT_SEV, 0);
+    tc->getCpuPtr()->clearInterrupt(tc->threadId(), INT_SEV, 0);
 }
 
 // Instantiate all the templates to make the linker happy
index bac7bab89fa74c52b6cfbb51a35a4a0a2a1647a4..f90b8a2df2e810af5aa69f0d34b3fcbd2c223b1d 100644 (file)
@@ -668,12 +668,12 @@ ISA::readMiscReg(int misc_reg, ThreadContext *tc)
       case MISCREG_DBGDSCRint:
         return 0;
       case MISCREG_ISR:
-        return tc->getCpuPtr()->getInterruptController()->getISR(
+        return tc->getCpuPtr()->getInterruptController(tc->threadId())->getISR(
             readMiscRegNoEffect(MISCREG_HCR),
             readMiscRegNoEffect(MISCREG_CPSR),
             readMiscRegNoEffect(MISCREG_SCR));
       case MISCREG_ISR_EL1:
-        return tc->getCpuPtr()->getInterruptController()->getISR(
+        return tc->getCpuPtr()->getInterruptController(tc->threadId())->getISR(
             readMiscRegNoEffect(MISCREG_HCR_EL2),
             readMiscRegNoEffect(MISCREG_CPSR),
             readMiscRegNoEffect(MISCREG_SCR_EL3));
@@ -1929,7 +1929,7 @@ ISA::getGenericTimer(ThreadContext *tc)
               "been configured to use a generic timer.\n");
     }
 
-    timer.reset(new GenericTimerISA(*generic_timer, tc->cpuId()));
+    timer.reset(new GenericTimerISA(*generic_timer, tc->contextId()));
     return *timer.get();
 }
 
index 6ecaa78de7f9a4d75bc2d4ea46c771a47a5db3f5..c8b1de1d8e5fe1f5747054edb1efa3ba91374bdf 100644 (file)
@@ -649,7 +649,8 @@ let {{
     if (SevMailbox == 1) {
         SevMailbox = 0;
         PseudoInst::quiesceSkip(tc);
-    } else if (tc->getCpuPtr()->getInterruptController()->checkInterrupts(tc)) {
+    } else if (tc->getCpuPtr()->getInterruptController(
+                tc->threadId())->checkInterrupts(tc)) {
         PseudoInst::quiesceSkip(tc);
     } else if (cpsr.el == EL0 && !sctlr.ntwe) {
         PseudoInst::quiesceSkip(tc);
@@ -692,8 +693,8 @@ let {{
 
     // WFI doesn't sleep if interrupts are pending (masked or not)
     ThreadContext *tc = xc->tcBase();
-    if (tc->getCpuPtr()->getInterruptController()->checkWfiWake(hcr, cpsr,
-                                                                scr)) {
+    if (tc->getCpuPtr()->getInterruptController(
+                tc->threadId())->checkWfiWake(hcr, cpsr, scr)) {
         PseudoInst::quiesceSkip(tc);
     } else if (cpsr.el == EL0 && !sctlr.ntwi) {
         PseudoInst::quiesceSkip(tc);
@@ -711,7 +712,7 @@ let {{
     } else {
         PseudoInst::quiesce(tc);
     }
-    tc->getCpuPtr()->clearInterrupt(INT_ABT, 0);
+    tc->getCpuPtr()->clearInterrupt(tc->threadId(), INT_ABT, 0);
     '''
     wfiIop = InstObjParams("wfi", "WfiInst", "PredOp", \
             { "code" : wfiCode, "predicate_test" : predicateTest },
@@ -731,7 +732,7 @@ let {{
         // Wake CPU with interrupt if they were sleeping
         if (oc->readMiscReg(MISCREG_SEV_MAILBOX) == 0) {
             // Post Interrupt and wake cpu if needed
-            oc->getCpuPtr()->postInterrupt(INT_SEV, 0);
+            oc->getCpuPtr()->postInterrupt(oc->threadId(), INT_SEV, 0);
         }
     }
     '''
index a588eaf666402c4c56671966d2628e0121f263b2..aa10a0b469619f91cb2435b267d55194939e592e 100644 (file)
@@ -591,9 +591,9 @@ ISA::setMiscReg(int miscReg, MiscReg val, ThreadContext * tc)
         {
             tl = val;
             if (hpstate.tlz && tl == 0 && !hpstate.hpriv)
-                tc->getCpuPtr()->postInterrupt(IT_TRAP_LEVEL_ZERO, 0);
+                tc->getCpuPtr()->postInterrupt(0, IT_TRAP_LEVEL_ZERO, 0);
             else
-                tc->getCpuPtr()->clearInterrupt(IT_TRAP_LEVEL_ZERO, 0);
+                tc->getCpuPtr()->clearInterrupt(0, IT_TRAP_LEVEL_ZERO, 0);
             return;
         }
       case MISCREG_CWP:
index c0c28f95261e6111b54fc3eeaeb7417924677e37..b4a76129349c28fde6d34fedf536df06debaea71 100644 (file)
@@ -1022,7 +1022,7 @@ TLB::doMmuRegRead(ThreadContext *tc, Packet *pkt)
         {
             SparcISA::Interrupts * interrupts =
                 dynamic_cast<SparcISA::Interrupts *>(
-                        tc->getCpuPtr()->getInterruptController());
+                        tc->getCpuPtr()->getInterruptController(0));
             pkt->set(interrupts->get_vec(IT_INT_VEC));
         }
         break;
@@ -1030,9 +1030,9 @@ TLB::doMmuRegRead(ThreadContext *tc, Packet *pkt)
         {
             SparcISA::Interrupts * interrupts =
                 dynamic_cast<SparcISA::Interrupts *>(
-                        tc->getCpuPtr()->getInterruptController());
+                        tc->getCpuPtr()->getInterruptController(0));
             temp = findMsbSet(interrupts->get_vec(IT_INT_VEC));
-            tc->getCpuPtr()->clearInterrupt(IT_INT_VEC, temp);
+            tc->getCpuPtr()->clearInterrupt(0, IT_INT_VEC, temp);
             pkt->set(temp);
         }
         break;
@@ -1278,16 +1278,16 @@ TLB::doMmuRegWrite(ThreadContext *tc, Packet *pkt)
             // clear all the interrupts that aren't set in the write
             SparcISA::Interrupts * interrupts =
                 dynamic_cast<SparcISA::Interrupts *>(
-                        tc->getCpuPtr()->getInterruptController());
+                        tc->getCpuPtr()->getInterruptController(0));
             while (interrupts->get_vec(IT_INT_VEC) & data) {
                 msb = findMsbSet(interrupts->get_vec(IT_INT_VEC) & data);
-                tc->getCpuPtr()->clearInterrupt(IT_INT_VEC, msb);
+                tc->getCpuPtr()->clearInterrupt(0, IT_INT_VEC, msb);
             }
         }
         break;
       case ASI_SWVR_UDB_INTR_W:
             tc->getSystemPtr()->threadContexts[bits(data,12,8)]->getCpuPtr()->
-            postInterrupt(bits(data, 5, 0), 0);
+            postInterrupt(0, bits(data, 5, 0), 0);
         break;
       default:
 doMmuWriteError:
index b207f2fac9957b0a77c04ef7fb5e443997976e6e..2c100957f7d316cf984a58b38d27f203519aec56 100644 (file)
@@ -49,20 +49,20 @@ ISA::checkSoftInt(ThreadContext *tc)
 
     // If PIL < 14, copy over the tm and sm bits
     if (pil < 14 && softint & 0x10000)
-        cpu->postInterrupt(IT_SOFT_INT, 16);
+        cpu->postInterrupt(0, IT_SOFT_INT, 16);
     else
-        cpu->clearInterrupt(IT_SOFT_INT, 16);
+        cpu->clearInterrupt(0, IT_SOFT_INT, 16);
     if (pil < 14 && softint & 0x1)
-        cpu->postInterrupt(IT_SOFT_INT, 0);
+        cpu->postInterrupt(0, IT_SOFT_INT, 0);
     else
-        cpu->clearInterrupt(IT_SOFT_INT, 0);
+        cpu->clearInterrupt(0, IT_SOFT_INT, 0);
 
     // Copy over any of the other bits that are set
     for (int bit = 15; bit > 0; --bit) {
         if (1 << bit & softint && bit > pil)
-            cpu->postInterrupt(IT_SOFT_INT, bit);
+            cpu->postInterrupt(0, IT_SOFT_INT, bit);
         else
-            cpu->clearInterrupt(IT_SOFT_INT, bit);
+            cpu->clearInterrupt(0, IT_SOFT_INT, bit);
     }
 }
 
@@ -149,9 +149,9 @@ ISA::setFSReg(int miscReg, const MiscReg &val, ThreadContext *tc)
       case MISCREG_HINTP:
         setMiscRegNoEffect(miscReg, val);
         if (hintp)
-            cpu->postInterrupt(IT_HINTP, 0);
+            cpu->postInterrupt(0, IT_HINTP, 0);
         else
-            cpu->clearInterrupt(IT_HINTP, 0);
+            cpu->clearInterrupt(0, IT_HINTP, 0);
         break;
 
       case MISCREG_HTBA:
@@ -163,25 +163,25 @@ ISA::setFSReg(int miscReg, const MiscReg &val, ThreadContext *tc)
       case MISCREG_QUEUE_CPU_MONDO_TAIL:
         setMiscRegNoEffect(miscReg, val);
         if (cpu_mondo_head != cpu_mondo_tail)
-            cpu->postInterrupt(IT_CPU_MONDO, 0);
+            cpu->postInterrupt(0, IT_CPU_MONDO, 0);
         else
-            cpu->clearInterrupt(IT_CPU_MONDO, 0);
+            cpu->clearInterrupt(0, IT_CPU_MONDO, 0);
         break;
       case MISCREG_QUEUE_DEV_MONDO_HEAD:
       case MISCREG_QUEUE_DEV_MONDO_TAIL:
         setMiscRegNoEffect(miscReg, val);
         if (dev_mondo_head != dev_mondo_tail)
-            cpu->postInterrupt(IT_DEV_MONDO, 0);
+            cpu->postInterrupt(0, IT_DEV_MONDO, 0);
         else
-            cpu->clearInterrupt(IT_DEV_MONDO, 0);
+            cpu->clearInterrupt(0, IT_DEV_MONDO, 0);
         break;
       case MISCREG_QUEUE_RES_ERROR_HEAD:
       case MISCREG_QUEUE_RES_ERROR_TAIL:
         setMiscRegNoEffect(miscReg, val);
         if (res_error_head != res_error_tail)
-            cpu->postInterrupt(IT_RES_ERROR, 0);
+            cpu->postInterrupt(0, IT_RES_ERROR, 0);
         else
-            cpu->clearInterrupt(IT_RES_ERROR, 0);
+            cpu->clearInterrupt(0, IT_RES_ERROR, 0);
         break;
       case MISCREG_QUEUE_NRES_ERROR_HEAD:
       case MISCREG_QUEUE_NRES_ERROR_TAIL:
@@ -213,9 +213,9 @@ ISA::setFSReg(int miscReg, const MiscReg &val, ThreadContext *tc)
             setMiscRegNoEffect(miscReg, newVal);
             newVal = hpstate;
             if (newVal.tlz && tl == 0 && !newVal.hpriv)
-                cpu->postInterrupt(IT_TRAP_LEVEL_ZERO, 0);
+                cpu->postInterrupt(0, IT_TRAP_LEVEL_ZERO, 0);
             else
-                cpu->clearInterrupt(IT_TRAP_LEVEL_ZERO, 0);
+                cpu->clearInterrupt(0, IT_TRAP_LEVEL_ZERO, 0);
             break;
         }
       case MISCREG_HTSTATE:
index f7d0f816e1e4ed92f8f5d3c4ac29a91cb547fef1..cf6d2d910482b0d10ed003ffda197898e9b97759 100644 (file)
@@ -183,7 +183,7 @@ void initCPU(ThreadContext *tc, int cpuId)
     tc->setMiscReg(MISCREG_APIC_BASE, lApicBase);
 
     Interrupts * interrupts = dynamic_cast<Interrupts *>(
-            tc->getCpuPtr()->getInterruptController());
+            tc->getCpuPtr()->getInterruptController(0));
     assert(interrupts);
 
     interrupts->setRegNoEffect(APIC_ID, cpuId << 24);
index 9aa24c97b3380d3f82df4e823e5d73ade9a5223c..a54a63b466ad9d3ffafb9b8471cb52f0edef142f 100644 (file)
@@ -149,40 +149,40 @@ class BaseCPU(MemObject):
     if buildEnv['TARGET_ISA'] == 'sparc':
         dtb = Param.SparcTLB(SparcTLB(), "Data TLB")
         itb = Param.SparcTLB(SparcTLB(), "Instruction TLB")
-        interrupts = Param.SparcInterrupts(
-                NULL, "Interrupt Controller")
+        interrupts = VectorParam.SparcInterrupts(
+                [], "Interrupt Controller")
         isa = VectorParam.SparcISA([ isa_class() ], "ISA instance")
     elif buildEnv['TARGET_ISA'] == 'alpha':
         dtb = Param.AlphaTLB(AlphaDTB(), "Data TLB")
         itb = Param.AlphaTLB(AlphaITB(), "Instruction TLB")
-        interrupts = Param.AlphaInterrupts(
-                NULL, "Interrupt Controller")
+        interrupts = VectorParam.AlphaInterrupts(
+                [], "Interrupt Controller")
         isa = VectorParam.AlphaISA([ isa_class() ], "ISA instance")
     elif buildEnv['TARGET_ISA'] == 'x86':
         dtb = Param.X86TLB(X86TLB(), "Data TLB")
         itb = Param.X86TLB(X86TLB(), "Instruction TLB")
-        interrupts = Param.X86LocalApic(NULL, "Interrupt Controller")
+        interrupts = VectorParam.X86LocalApic([], "Interrupt Controller")
         isa = VectorParam.X86ISA([ isa_class() ], "ISA instance")
     elif buildEnv['TARGET_ISA'] == 'mips':
         dtb = Param.MipsTLB(MipsTLB(), "Data TLB")
         itb = Param.MipsTLB(MipsTLB(), "Instruction TLB")
-        interrupts = Param.MipsInterrupts(
-                NULL, "Interrupt Controller")
+        interrupts = VectorParam.MipsInterrupts(
+                [], "Interrupt Controller")
         isa = VectorParam.MipsISA([ isa_class() ], "ISA instance")
     elif buildEnv['TARGET_ISA'] == 'arm':
         dtb = Param.ArmTLB(ArmTLB(), "Data TLB")
         itb = Param.ArmTLB(ArmTLB(), "Instruction TLB")
         istage2_mmu = Param.ArmStage2MMU(ArmStage2IMMU(), "Stage 2 trans")
         dstage2_mmu = Param.ArmStage2MMU(ArmStage2DMMU(), "Stage 2 trans")
-        interrupts = Param.ArmInterrupts(
-                NULL, "Interrupt Controller")
+        interrupts = VectorParam.ArmInterrupts(
+                [], "Interrupt Controller")
         isa = VectorParam.ArmISA([ isa_class() ], "ISA instance")
     elif buildEnv['TARGET_ISA'] == 'power':
         UnifiedTLB = Param.Bool(True, "Is this a Unified TLB?")
         dtb = Param.PowerTLB(PowerTLB(), "Data TLB")
         itb = Param.PowerTLB(PowerTLB(), "Instruction TLB")
-        interrupts = Param.PowerInterrupts(
-                NULL, "Interrupt Controller")
+        interrupts = VectorParam.PowerInterrupts(
+                [], "Interrupt Controller")
         isa = VectorParam.PowerISA([ isa_class() ], "ISA instance")
     else:
         print "Don't know what TLB to use for ISA %s" % \
@@ -218,27 +218,29 @@ class BaseCPU(MemObject):
     _uncached_slave_ports = []
     _uncached_master_ports = []
     if buildEnv['TARGET_ISA'] == 'x86':
-        _uncached_slave_ports += ["interrupts.pio", "interrupts.int_slave"]
-        _uncached_master_ports += ["interrupts.int_master"]
+        _uncached_slave_ports += ["interrupts[0].pio",
+                                  "interrupts[0].int_slave"]
+        _uncached_master_ports += ["interrupts[0].int_master"]
 
     def createInterruptController(self):
         if buildEnv['TARGET_ISA'] == 'sparc':
-            self.interrupts = SparcInterrupts()
+            self.interrupts = [SparcInterrupts() for i in xrange(self.numThreads)]
         elif buildEnv['TARGET_ISA'] == 'alpha':
-            self.interrupts = AlphaInterrupts()
+            self.interrupts = [AlphaInterrupts() for i in xrange(self.numThreads)]
         elif buildEnv['TARGET_ISA'] == 'x86':
             self.apic_clk_domain = DerivedClockDomain(clk_domain =
                                                       Parent.clk_domain,
                                                       clk_divider = 16)
-            self.interrupts = X86LocalApic(clk_domain = self.apic_clk_domain,
+            self.interrupts = [X86LocalApic(clk_domain = self.apic_clk_domain,
                                            pio_addr=0x2000000000000000)
+                               for i in xrange(self.numThreads)]
             _localApic = self.interrupts
         elif buildEnv['TARGET_ISA'] == 'mips':
-            self.interrupts = MipsInterrupts()
+            self.interrupts = [MipsInterrupts() for i in xrange(self.numThreads)]
         elif buildEnv['TARGET_ISA'] == 'arm':
-            self.interrupts = ArmInterrupts()
+            self.interrupts = [ArmInterrupts() for i in xrange(self.numThreads)]
         elif buildEnv['TARGET_ISA'] == 'power':
-            self.interrupts = PowerInterrupts()
+            self.interrupts = [PowerInterrupts() for i in xrange(self.numThreads)]
         else:
             print "Don't know what Interrupt Controller to use for ISA %s" % \
                 buildEnv['TARGET_ISA']
index 3b0809d09d5df35b0281fe071f1a875e5b830c5a..a1dfa42ce77ccecb69849c5d5bbdabbc90e36ddd 100644 (file)
@@ -237,8 +237,10 @@ BaseCPU::BaseCPU(Params *p, bool is_checker)
     // The interrupts should always be present unless this CPU is
     // switched in later or in case it is a checker CPU
     if (!params()->switched_out && !is_checker) {
-        if (interrupts) {
-            interrupts->setCPU(this);
+        if (!interrupts.empty()) {
+            for (ThreadID tid = 0; tid < numThreads; tid++) {
+                interrupts[tid]->setCPU(this);
+            }
         } else {
             fatal("CPU %s has no interrupt controller.\n"
                   "Ensure createInterruptController() is called.\n", name());
@@ -583,8 +585,10 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU)
     }
 
     interrupts = oldCPU->interrupts;
-    interrupts->setCPU(this);
-    oldCPU->interrupts = NULL;
+    for (ThreadID tid = 0; tid < numThreads; tid++) {
+        interrupts[tid]->setCPU(this);
+    }
+    oldCPU->interrupts.clear();
 
     if (FullSystem) {
         for (ThreadID i = 0; i < size; ++i)
@@ -656,11 +660,10 @@ BaseCPU::serialize(CheckpointOut &cp) const
          * system. */
         SERIALIZE_SCALAR(_pid);
 
-        interrupts->serialize(cp);
-
         // Serialize the threads, this is done by the CPU implementation.
         for (ThreadID i = 0; i < numThreads; ++i) {
             ScopedCheckpointSection sec(cp, csprintf("xc.%i", i));
+            interrupts[i]->serialize(cp);
             serializeThread(cp, i);
         }
     }
@@ -673,11 +676,11 @@ BaseCPU::unserialize(CheckpointIn &cp)
 
     if (!_switchedOut) {
         UNSERIALIZE_SCALAR(_pid);
-        interrupts->unserialize(cp);
 
         // Unserialize the threads, this is done by the CPU implementation.
         for (ThreadID i = 0; i < numThreads; ++i) {
             ScopedCheckpointSection sec(cp, csprintf("xc.%i", i));
+            interrupts[i]->unserialize(cp);
             unserializeThread(cp, i);
         }
     }
index 0286ac45b009994eecbe1912478b296bca8f101d..2a57c01ba653de3ea17f3b2a9272179f5465126b 100644 (file)
@@ -207,41 +207,45 @@ class BaseCPU : public MemObject
     TheISA::MicrocodeRom microcodeRom;
 
   protected:
-    TheISA::Interrupts *interrupts;
+    std::vector<TheISA::Interrupts*> interrupts;
 
   public:
     TheISA::Interrupts *
-    getInterruptController()
+    getInterruptController(ThreadID tid)
     {
-        return interrupts;
+        if (interrupts.empty())
+            return NULL;
+
+        assert(interrupts.size() > tid);
+        return interrupts[tid];
     }
 
     virtual void wakeup() = 0;
 
     void
-    postInterrupt(int int_num, int index)
+    postInterrupt(ThreadID tid, int int_num, int index)
     {
-        interrupts->post(int_num, index);
+        interrupts[tid]->post(int_num, index);
         if (FullSystem)
             wakeup();
     }
 
     void
-    clearInterrupt(int int_num, int index)
+    clearInterrupt(ThreadID tid, int int_num, int index)
     {
-        interrupts->clear(int_num, index);
+        interrupts[tid]->clear(int_num, index);
     }
 
     void
-    clearInterrupts()
+    clearInterrupts(ThreadID tid)
     {
-        interrupts->clearAll();
+        interrupts[tid]->clearAll();
     }
 
     bool
     checkInterrupts(ThreadContext *tc) const
     {
-        return FullSystem && interrupts->checkInterrupts(tc);
+        return FullSystem && interrupts[tc->threadId()]->checkInterrupts(tc);
     }
 
     class ProfileEvent : public Event
index bbd905492b2a94a5b816cd5324e80f4145bdeb58..aa4d45e2f35e3d70cb7ba74df3f6d001e3970ab2 100644 (file)
@@ -73,7 +73,6 @@ DummyCheckerParams::create()
     params->system = system;
     params->cpu_id = cpu_id;
     params->profile = profile;
-    params->interrupts = NULL;
     params->workload = workload;
 
     DummyChecker *cpu = new DummyChecker(params);
index 8f3808889e69979fd5caecd9f3db8cadb39853d7..ca24495f47a64fd2f58c54895669967ab865fe74 100644 (file)
@@ -51,7 +51,7 @@ IntrControl::post(int cpu_id, int int_num, int index)
     DPRINTF(IntrControl, "post  %d:%d (cpu %d)\n", int_num, index, cpu_id);
     std::vector<ThreadContext *> &tcvec = sys->threadContexts;
     BaseCPU *cpu = tcvec[cpu_id]->getCpuPtr();
-    cpu->postInterrupt(int_num, index);
+    cpu->postInterrupt(tcvec[cpu_id]->threadId(), int_num, index);
 }
 
 void
@@ -60,7 +60,7 @@ IntrControl::clear(int cpu_id, int int_num, int index)
     DPRINTF(IntrControl, "clear %d:%d (cpu %d)\n", int_num, index, cpu_id);
     std::vector<ThreadContext *> &tcvec = sys->threadContexts;
     BaseCPU *cpu = tcvec[cpu_id]->getCpuPtr();
-    cpu->clearInterrupt(int_num, index);
+    cpu->clearInterrupt(tcvec[cpu_id]->threadId(), int_num, index);
 }
 
 IntrControl *
index cd46370a4f99bba83a0aa4ff28b0d9d73f7fdde5..5312ca55a9e3974a13d370b4a42b8af1d30ba4c7 100644 (file)
@@ -1142,9 +1142,9 @@ X86KvmCPU::deliverInterrupts()
         // call across threads, we might still lose interrupts unless
         // they are getInterrupt() and updateIntrInfo() are called
         // atomically.
-        EventQueue::ScopedMigration migrate(interrupts->eventQueue());
-        fault = interrupts->getInterrupt(tc);
-        interrupts->updateIntrInfo(tc);
+        EventQueue::ScopedMigration migrate(interrupts[0]->eventQueue());
+        fault = interrupts[0]->getInterrupt(tc);
+        interrupts[0]->updateIntrInfo(tc);
     }
 
     X86Interrupt *x86int(dynamic_cast<X86Interrupt *>(fault.get()));
@@ -1187,8 +1187,8 @@ X86KvmCPU::kvmRun(Tick ticks)
 {
     struct kvm_run &kvm_run(*getKvmRunState());
 
-    if (interrupts->checkInterruptsRaw()) {
-        if (interrupts->hasPendingUnmaskable()) {
+    if (interrupts[0]->checkInterruptsRaw()) {
+        if (interrupts[0]->hasPendingUnmaskable()) {
             DPRINTF(KvmInt,
                     "Delivering unmaskable interrupt.\n");
             syncThreadContext();
@@ -1200,7 +1200,7 @@ X86KvmCPU::kvmRun(Tick ticks)
             // the thread context and check if there are /really/
             // interrupts that should be delivered now.
             syncThreadContext();
-            if (interrupts->checkInterrupts(tc)) {
+            if (interrupts[0]->checkInterrupts(tc)) {
                 DPRINTF(KvmInt,
                         "M5 has pending interrupts, delivering interrupt.\n");
 
index 001515eff931939dd4ee8338088892dbc53c27d2..0a2c4b8c87929b5bc86469a10caaca3fcdc307a2 100644 (file)
@@ -403,12 +403,12 @@ Execute::takeInterrupt(ThreadID thread_id, BranchData &branch)
     DPRINTF(MinorInterrupt, "Considering interrupt status from PC: %s\n",
         cpu.getContext(thread_id)->pcState());
 
-    Fault interrupt = cpu.getInterruptController()->getInterrupt
+    Fault interrupt = cpu.getInterruptController(thread_id)->getInterrupt
         (cpu.getContext(thread_id));
 
     if (interrupt != NoFault) {
         /* The interrupt *must* set pcState */
-        cpu.getInterruptController()->updateIntrInfo
+        cpu.getInterruptController(thread_id)->updateIntrInfo
             (cpu.getContext(thread_id));
         interrupt->invoke(cpu.getContext(thread_id));
 
@@ -1391,7 +1391,7 @@ Execute::evaluate()
     /* If there was an interrupt signalled, was it acted on now? */
     bool took_interrupt = false;
 
-    if (cpu.getInterruptController()) {
+    if (cpu.getInterruptController(0)) {
         /* This is here because it seems that after drainResume the
          * interrupt controller isn't always set */
         interrupted = drainState == NotDraining && isInterrupted(0);
index ce7a99f0f01f9d6b857da768a99789b3c5e647f6..be685d7c2034cca6acdf498ffd40f87857f0425d 100644 (file)
@@ -86,7 +86,6 @@ O3CheckerParams::create()
     params->system = system;
     params->cpu_id = cpu_id;
     params->profile = profile;
-    params->interrupts = NULL;
     params->workload = workload;
 
     O3Checker *cpu = new O3Checker(params);
index 4ab0048173d1225c2db406aaedb611f2df78225a..d4ee5ffe77067569ed4886e9638168bf4fb50f68 100644 (file)
@@ -392,7 +392,7 @@ FullO3CPU<Impl>::FullO3CPU(DerivO3CPUParams *params)
     }
 
     // FullO3CPU always requires an interrupt controller.
-    if (!params->switched_out && !interrupts) {
+    if (!params->switched_out && interrupts.empty()) {
         fatal("FullO3CPU %s has no interrupt controller.\n"
               "Ensure createInterruptController() is called.\n", name());
     }
@@ -935,7 +935,7 @@ Fault
 FullO3CPU<Impl>::getInterrupts()
 {
     // Check if there are any outstanding interrupts
-    return this->interrupts->getInterrupt(this->threadContexts[0]);
+    return this->interrupts[0]->getInterrupt(this->threadContexts[0]);
 }
 
 template <class Impl>
@@ -949,7 +949,7 @@ FullO3CPU<Impl>::processInterrupts(const Fault &interrupt)
     // @todo: Allow other threads to handle interrupts.
 
     assert(interrupt != NoFault);
-    this->interrupts->updateIntrInfo(this->threadContexts[0]);
+    this->interrupts[0]->updateIntrInfo(this->threadContexts[0]);
 
     DPRINTF(O3CPU, "Interrupt %s being handled\n", interrupt->name());
     this->trap(interrupt, 0, nullptr);
index 6e8845bf7dbe730c4a7ef47889685df10991e943..b0810517f61a41c624b853112e05b9b83d42084f 100644 (file)
@@ -435,11 +435,11 @@ BaseSimpleCPU::checkForInterrupts()
     ThreadContext* tc = thread->getTC();
 
     if (checkInterrupts(tc)) {
-        Fault interrupt = interrupts->getInterrupt(tc);
+        Fault interrupt = interrupts[curThread]->getInterrupt(tc);
 
         if (interrupt != NoFault) {
             t_info.fetchOffset = 0;
-            interrupts->updateIntrInfo(tc);
+            interrupts[curThread]->updateIntrInfo(tc);
             interrupt->invoke(tc);
             thread->decoder.reset();
         }
index ffc6312106602b40f9d68465707461e10469e091..7388036fb7e5e7d5d7854d1f3e171fc2f088d187 100644 (file)
@@ -224,7 +224,7 @@ X86ISA::I82094AA::signalInterrupt(int line)
         } else {
             for (int i = 0; i < numContexts; i++) {
                 Interrupts *localApic = sys->getThreadContext(i)->
-                    getCpuPtr()->getInterruptController();
+                    getCpuPtr()->getInterruptController(0);
                 if ((localApic->readReg(APIC_LOGICAL_DESTINATION) >> 24) &
                         message.destination) {
                     apics.push_back(localApic->getInitialApicId());
index 782cda60df1fbe7973ef4d3d3cc2decc291e6f33..006aeb6a43cd3b30d3d4a595bfac0df271722c33 100644 (file)
@@ -87,9 +87,9 @@ for (i, cpu) in enumerate(system.cpu):
     cpu.itb.walker.port = system.ruby._cpu_ports[i].slave
     cpu.dtb.walker.port = system.ruby._cpu_ports[i].slave
 
-    cpu.interrupts.pio = system.ruby._cpu_ports[i].master
-    cpu.interrupts.int_master = system.ruby._cpu_ports[i].slave
-    cpu.interrupts.int_slave = system.ruby._cpu_ports[i].master
+    cpu.interrupts[0].pio = system.ruby._cpu_ports[i].master
+    cpu.interrupts[0].int_master = system.ruby._cpu_ports[i].slave
+    cpu.interrupts[0].int_slave = system.ruby._cpu_ports[i].master
 
 root = Root(full_system = True, system = system)
 m5.ticks.setGlobalFrequency('1THz')
diff --git a/util/cpt_upgraders/smt-interrupts.py b/util/cpt_upgraders/smt-interrupts.py
new file mode 100644 (file)
index 0000000..2c7109c
--- /dev/null
@@ -0,0 +1,19 @@
+# Upgrade single-threaded checkpoints to be properly supported with SMT.
+# SMT adds per-thread interrupts.  Thus we must move the interrupt status
+# from the CPU and into the execution context.
+def upgrader(cpt):
+    for sec in cpt.sections():
+        import re
+
+        re_cpu_match = re.match('^(.*sys.*\.cpu[^._]*)$', sec)
+        if re_cpu_match != None:
+            interrupts = cpt.get(sec, 'interrupts')
+            intStatus = cpt.get(sec, 'intStatus')
+
+            cpu_name = re_cpu_match.group(1)
+
+            cpt.set(cpu_name + ".xc.0", 'interrupts', interrupts)
+            cpt.set(cpu_name + ".xc.0", 'intStatus', intStatus)
+
+            cpt.remove_option(sec, 'interrupts')
+            cpt.remove_option(sec, 'intStatus')