diff options
-rw-r--r-- | src/arch/x86/apicregs.hh | 16 | ||||
-rw-r--r-- | src/arch/x86/interrupts.cc | 49 | ||||
-rw-r--r-- | src/arch/x86/intmessage.hh | 1 |
3 files changed, 52 insertions, 14 deletions
diff --git a/src/arch/x86/apicregs.hh b/src/arch/x86/apicregs.hh index 464c3af2d..dfea2650f 100644 --- a/src/arch/x86/apicregs.hh +++ b/src/arch/x86/apicregs.hh @@ -31,6 +31,8 @@ #ifndef __ARCH_X86_APICREGS_HH__ #define __ARCH_X86_APICREGS_HH__ +#include "base/bitunion.hh" + namespace X86ISA { enum ApicRegIndex @@ -86,6 +88,20 @@ namespace X86ISA { return (ApicRegIndex)(APIC_INTERRUPT_REQUEST_BASE + index); } + + BitUnion32(InterruptCommandRegLow) + Bitfield<7, 0> vector; + Bitfield<10, 8> deliveryMode; + Bitfield<11> destMode; + Bitfield<12> deliveryStatus; + Bitfield<14> level; + Bitfield<15> trigger; + Bitfield<19, 18> destShorthand; + EndBitUnion(InterruptCommandRegLow) + + BitUnion32(InterruptCommandRegHigh) + Bitfield<31, 24> destination; + EndBitUnion(InterruptCommandRegHigh) } #endif diff --git a/src/arch/x86/interrupts.cc b/src/arch/x86/interrupts.cc index 0603069a7..7043840d2 100644 --- a/src/arch/x86/interrupts.cc +++ b/src/arch/x86/interrupts.cc @@ -60,6 +60,7 @@ #include "arch/x86/intmessage.hh" #include "cpu/base.hh" #include "mem/packet_access.hh" +#include "sim/system.hh" int divideFromConf(uint32_t conf) @@ -366,14 +367,6 @@ X86ISA::Interrupts::readReg(ApicRegIndex reg) case APIC_ERROR_STATUS: regs[APIC_INTERNAL_STATE] &= ~ULL(0x1); break; - case APIC_INTERRUPT_COMMAND_LOW: - panic("Local APIC Interrupt Command low" - " register unimplemented.\n"); - break; - case APIC_INTERRUPT_COMMAND_HIGH: - panic("Local APIC Interrupt Command high" - " register unimplemented.\n"); - break; case APIC_CURRENT_COUNT: { if (apicTimerEvent.scheduled()) { @@ -459,12 +452,40 @@ X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val) } break; case APIC_INTERRUPT_COMMAND_LOW: - panic("Local APIC Interrupt Command low" - " register unimplemented.\n"); - break; - case APIC_INTERRUPT_COMMAND_HIGH: - panic("Local APIC Interrupt Command high" - " register unimplemented.\n"); + { + InterruptCommandRegLow low = regs[APIC_INTERRUPT_COMMAND_LOW]; + // Check if we're already sending an IPI. + if (low.deliveryStatus) { + newVal = low; + break; + } + low = val; + InterruptCommandRegHigh high = regs[APIC_INTERRUPT_COMMAND_HIGH]; + // Record that an IPI is being sent. + low.deliveryStatus = 1; + TriggerIntMessage message; + message.destination = high.destination; + message.vector = low.vector; + message.deliveryMode = low.deliveryMode; + message.destMode = low.destMode; + message.level = low.level; + message.trigger = low.trigger; + bool timing = sys->getMemoryMode() == Enums::timing; + switch (low.destShorthand) { + case 0: + intPort->sendMessage(message, timing); + break; + case 1: + panic("Self IPIs aren't implemented.\n"); + break; + case 2: + panic("Broadcast including self IPIs aren't implemented.\n"); + break; + case 3: + panic("Broadcast excluding self IPIs aren't implemented.\n"); + break; + } + } break; case APIC_LVT_TIMER: case APIC_LVT_THERMAL_SENSOR: diff --git a/src/arch/x86/intmessage.hh b/src/arch/x86/intmessage.hh index f5f8519e2..ec3a76c66 100644 --- a/src/arch/x86/intmessage.hh +++ b/src/arch/x86/intmessage.hh @@ -34,6 +34,7 @@ #include "arch/x86/x86_traits.hh" #include "base/bitunion.hh" #include "mem/packet.hh" +#include "mem/packet_access.hh" #include "mem/request.hh" #include "sim/host.hh" |