diff options
author | Mitch Hayenga <mitch.hayenga@arm.com> | 2015-09-30 11:14:19 -0500 |
---|---|---|
committer | Mitch Hayenga <mitch.hayenga@arm.com> | 2015-09-30 11:14:19 -0500 |
commit | a5c4eb3de9deb3a71a6a5230a25ff5962e584980 (patch) | |
tree | 874b659c6a5eaa1316cde9eb82ec7d08badf638a | |
parent | e255fa053f8d105de8d188077a318124a3aad9ce (diff) | |
download | gem5-a5c4eb3de9deb3a71a6a5230a25ff5962e584980.tar.xz |
isa,cpu: Add support for FS SMT Interrupts
Adds per-thread interrupt controllers and thread/context logic
so that interrupts properly get routed in SMT systems.
-rw-r--r-- | configs/example/fs.py | 6 | ||||
-rw-r--r-- | configs/example/se.py | 6 | ||||
-rw-r--r-- | src/arch/alpha/isa/decoder.isa | 2 | ||||
-rw-r--r-- | src/arch/arm/faults.cc | 8 | ||||
-rw-r--r-- | src/arch/arm/isa.cc | 6 | ||||
-rw-r--r-- | src/arch/arm/isa/insts/misc.isa | 11 | ||||
-rw-r--r-- | src/arch/sparc/isa.cc | 4 | ||||
-rw-r--r-- | src/arch/sparc/tlb.cc | 12 | ||||
-rw-r--r-- | src/arch/sparc/ua2005.cc | 32 | ||||
-rw-r--r-- | src/arch/x86/utility.cc | 2 | ||||
-rw-r--r-- | src/cpu/BaseCPU.py | 40 | ||||
-rw-r--r-- | src/cpu/base.cc | 17 | ||||
-rw-r--r-- | src/cpu/base.hh | 24 | ||||
-rw-r--r-- | src/cpu/dummy_checker.cc | 1 | ||||
-rw-r--r-- | src/cpu/intr_control.cc | 4 | ||||
-rw-r--r-- | src/cpu/kvm/x86_cpu.cc | 12 | ||||
-rw-r--r-- | src/cpu/minor/execute.cc | 6 | ||||
-rw-r--r-- | src/cpu/o3/checker.cc | 1 | ||||
-rw-r--r-- | src/cpu/o3/cpu.cc | 6 | ||||
-rw-r--r-- | src/cpu/simple/base.cc | 4 | ||||
-rw-r--r-- | src/dev/x86/i82094aa.cc | 2 | ||||
-rw-r--r-- | tests/configs/pc-simple-timing-ruby.py | 6 | ||||
-rw-r--r-- | util/cpt_upgraders/smt-interrupts.py | 19 |
23 files changed, 129 insertions, 102 deletions
diff --git a/configs/example/fs.py b/configs/example/fs.py index 70a3b950e..9d8b87aaa 100644 --- a/configs/example/fs.py +++ b/configs/example/fs.py @@ -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: diff --git a/configs/example/se.py b/configs/example/se.py index afd916cdb..0928482b7 100644 --- a/configs/example/se.py +++ b/configs/example/se.py @@ -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: diff --git a/src/arch/alpha/isa/decoder.isa b/src/arch/alpha/isa/decoder.isa index c77ca434f..e61bb43ff 100644 --- a/src/arch/alpha/isa/decoder.isa +++ b/src/arch/alpha/isa/decoder.isa @@ -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 { diff --git a/src/arch/arm/faults.cc b/src/arch/arm/faults.cc index 9d373e469..a2b1120ec 100644 --- a/src/arch/arm/faults.cc +++ b/src/arch/arm/faults.cc @@ -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 diff --git a/src/arch/arm/isa.cc b/src/arch/arm/isa.cc index bac7bab89..f90b8a2df 100644 --- a/src/arch/arm/isa.cc +++ b/src/arch/arm/isa.cc @@ -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(); } diff --git a/src/arch/arm/isa/insts/misc.isa b/src/arch/arm/isa/insts/misc.isa index 6ecaa78de..c8b1de1d8 100644 --- a/src/arch/arm/isa/insts/misc.isa +++ b/src/arch/arm/isa/insts/misc.isa @@ -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); } } ''' diff --git a/src/arch/sparc/isa.cc b/src/arch/sparc/isa.cc index a588eaf66..aa10a0b46 100644 --- a/src/arch/sparc/isa.cc +++ b/src/arch/sparc/isa.cc @@ -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: diff --git a/src/arch/sparc/tlb.cc b/src/arch/sparc/tlb.cc index c0c28f952..b4a761293 100644 --- a/src/arch/sparc/tlb.cc +++ b/src/arch/sparc/tlb.cc @@ -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: diff --git a/src/arch/sparc/ua2005.cc b/src/arch/sparc/ua2005.cc index b207f2fac..2c100957f 100644 --- a/src/arch/sparc/ua2005.cc +++ b/src/arch/sparc/ua2005.cc @@ -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: diff --git a/src/arch/x86/utility.cc b/src/arch/x86/utility.cc index f7d0f816e..cf6d2d910 100644 --- a/src/arch/x86/utility.cc +++ b/src/arch/x86/utility.cc @@ -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); diff --git a/src/cpu/BaseCPU.py b/src/cpu/BaseCPU.py index 9aa24c97b..a54a63b46 100644 --- a/src/cpu/BaseCPU.py +++ b/src/cpu/BaseCPU.py @@ -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'] diff --git a/src/cpu/base.cc b/src/cpu/base.cc index 3b0809d09..a1dfa42ce 100644 --- a/src/cpu/base.cc +++ b/src/cpu/base.cc @@ -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); } } diff --git a/src/cpu/base.hh b/src/cpu/base.hh index 0286ac45b..2a57c01ba 100644 --- a/src/cpu/base.hh +++ b/src/cpu/base.hh @@ -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 diff --git a/src/cpu/dummy_checker.cc b/src/cpu/dummy_checker.cc index bbd905492..aa4d45e2f 100644 --- a/src/cpu/dummy_checker.cc +++ b/src/cpu/dummy_checker.cc @@ -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); diff --git a/src/cpu/intr_control.cc b/src/cpu/intr_control.cc index 8f3808889..ca24495f4 100644 --- a/src/cpu/intr_control.cc +++ b/src/cpu/intr_control.cc @@ -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 * diff --git a/src/cpu/kvm/x86_cpu.cc b/src/cpu/kvm/x86_cpu.cc index cd46370a4..5312ca55a 100644 --- a/src/cpu/kvm/x86_cpu.cc +++ b/src/cpu/kvm/x86_cpu.cc @@ -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"); diff --git a/src/cpu/minor/execute.cc b/src/cpu/minor/execute.cc index 001515eff..0a2c4b8c8 100644 --- a/src/cpu/minor/execute.cc +++ b/src/cpu/minor/execute.cc @@ -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); diff --git a/src/cpu/o3/checker.cc b/src/cpu/o3/checker.cc index ce7a99f0f..be685d7c2 100644 --- a/src/cpu/o3/checker.cc +++ b/src/cpu/o3/checker.cc @@ -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); diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc index 4ab004817..d4ee5ffe7 100644 --- a/src/cpu/o3/cpu.cc +++ b/src/cpu/o3/cpu.cc @@ -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); diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc index 6e8845bf7..b0810517f 100644 --- a/src/cpu/simple/base.cc +++ b/src/cpu/simple/base.cc @@ -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(); } diff --git a/src/dev/x86/i82094aa.cc b/src/dev/x86/i82094aa.cc index ffc631210..7388036fb 100644 --- a/src/dev/x86/i82094aa.cc +++ b/src/dev/x86/i82094aa.cc @@ -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()); diff --git a/tests/configs/pc-simple-timing-ruby.py b/tests/configs/pc-simple-timing-ruby.py index 782cda60d..006aeb6a4 100644 --- a/tests/configs/pc-simple-timing-ruby.py +++ b/tests/configs/pc-simple-timing-ruby.py @@ -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 index 000000000..2c7109c04 --- /dev/null +++ b/util/cpt_upgraders/smt-interrupts.py @@ -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') |