diff options
Diffstat (limited to 'src/arch/x86')
-rw-r--r-- | src/arch/x86/faults.hh | 5 | ||||
-rw-r--r-- | src/arch/x86/interrupts.cc | 67 | ||||
-rw-r--r-- | src/arch/x86/interrupts.hh | 136 | ||||
-rw-r--r-- | src/arch/x86/intmessage.hh | 39 |
4 files changed, 207 insertions, 40 deletions
diff --git a/src/arch/x86/faults.hh b/src/arch/x86/faults.hh index a54bc8ee9..8fe90299d 100644 --- a/src/arch/x86/faults.hh +++ b/src/arch/x86/faults.hh @@ -351,9 +351,10 @@ namespace X86ISA class ExternalInterrupt : public X86Interrupt { + uint8_t vector; public: - ExternalInterrupt() : - X86Interrupt("External Interrupt", "#INTR") + ExternalInterrupt(uint8_t _vector) : + X86Interrupt("External Interrupt", "#INTR"), vector(_vector) {} }; diff --git a/src/arch/x86/interrupts.cc b/src/arch/x86/interrupts.cc index 5614a37eb..a7c238ace 100644 --- a/src/arch/x86/interrupts.cc +++ b/src/arch/x86/interrupts.cc @@ -57,7 +57,9 @@ #include "arch/x86/apicregs.hh" #include "arch/x86/interrupts.hh" +#include "arch/x86/intmessage.hh" #include "cpu/base.hh" +#include "mem/packet_access.hh" int divideFromConf(uint32_t conf) @@ -242,12 +244,43 @@ X86ISA::Interrupts::write(PacketPtr pkt) Tick X86ISA::Interrupts::recvMessage(PacketPtr pkt) { - Addr offset = pkt->getAddr() - x86InterruptAddress(0, 0); + uint8_t id = 0; + Addr offset = pkt->getAddr() - x86InterruptAddress(id, 0); assert(pkt->cmd == MemCmd::MessageReq); switch(offset) { case 0: - DPRINTF(LocalApic, "Got Trigger Interrupt message.\n"); + { + TriggerIntMessage message = pkt->get<TriggerIntMessage>(); + uint8_t vector = message.vector; + DPRINTF(LocalApic, + "Got Trigger Interrupt message with vector %#x.\n", + vector); + // Make sure we're really supposed to get this. + assert((message.destMode == 0 && message.destination == id) || + (bits((int)message.destination, id))); + if (DeliveryMode::isUnmaskable(message.deliveryMode)) { + DPRINTF(LocalApic, "Interrupt is an %s and unmaskable.\n", + DeliveryMode::names[message.deliveryMode]); + panic("Unmaskable interrupts aren't implemented.\n"); + } else if (DeliveryMode::isMaskable(message.deliveryMode)) { + DPRINTF(LocalApic, "Interrupt is an %s and maskable.\n", + DeliveryMode::names[message.deliveryMode]); + // Queue up the interrupt in the IRR. + if (vector > IRRV) + IRRV = vector; + if (!getRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, vector)) { + setRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, vector); + if (message.trigger) { + // Level triggered. + setRegArrayBit(APIC_TRIGGER_MODE_BASE, vector); + } else { + // Edge triggered. + clearRegArrayBit(APIC_TRIGGER_MODE_BASE, vector); + } + } + } + } break; default: panic("Local apic got unknown interrupt message at offset %#x.\n", @@ -414,6 +447,36 @@ X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val) return; } +bool +X86ISA::Interrupts::check_interrupts(ThreadContext * tc) const +{ + RFLAGS rflags = tc->readMiscRegNoEffect(MISCREG_RFLAGS); + if (IRRV > ISRV && rflags.intf && + bits(IRRV, 7, 4) > bits(regs[APIC_TASK_PRIORITY], 7, 4)) { + return true; + } + return false; +} + +Fault +X86ISA::Interrupts::getInterrupt(ThreadContext * tc) +{ + assert(check_interrupts(tc)); + return new ExternalInterrupt(IRRV); +} + +void +X86ISA::Interrupts::updateIntrInfo(ThreadContext * tc) +{ + assert(check_interrupts(tc)); + // Mark the interrupt as "in service". + ISRV = IRRV; + setRegArrayBit(APIC_IN_SERVICE_BASE, ISRV); + // Clear it out of the IRR. + clearRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, IRRV); + updateIRRV(); +} + X86ISA::Interrupts * X86LocalApicParams::create() { diff --git a/src/arch/x86/interrupts.hh b/src/arch/x86/interrupts.hh index c4760dc0f..cfc1ada9d 100644 --- a/src/arch/x86/interrupts.hh +++ b/src/arch/x86/interrupts.hh @@ -60,6 +60,7 @@ #include "arch/x86/apicregs.hh" #include "arch/x86/faults.hh" +#include "base/bitfield.hh" #include "cpu/thread_context.hh" #include "dev/io_device.hh" #include "dev/x86/intdev.hh" @@ -74,7 +75,12 @@ namespace X86ISA class Interrupts : public BasicPioDevice, IntDev { protected: + // Storage for the APIC registers uint32_t regs[NUM_APIC_REGS]; + + /* + * Timing related stuff. + */ Tick latency; Tick clock; @@ -92,7 +98,58 @@ class Interrupts : public BasicPioDevice, IntDev ApicTimerEvent apicTimerEvent; + /* + * IRR and ISR maintenance. + */ + uint8_t IRRV; + uint8_t ISRV; + + int + findRegArrayMSB(ApicRegIndex base) + { + int offset = 7; + do { + if (regs[base + offset] != 0) { + return offset * 32 + findMsbSet(regs[base + offset]); + } + } while (offset--); + return 0; + } + + void + updateIRRV() + { + IRRV = findRegArrayMSB(APIC_INTERRUPT_REQUEST_BASE); + } + + void + updateISRV() + { + ISRV = findRegArrayMSB(APIC_IN_SERVICE_BASE); + } + + void + setRegArrayBit(ApicRegIndex base, uint8_t vector) + { + regs[base + (vector % 32)] |= (1 << (vector >> 5)); + } + + void + clearRegArrayBit(ApicRegIndex base, uint8_t vector) + { + regs[base + (vector % 32)] &= ~(1 << (vector >> 5)); + } + + bool + getRegArrayBit(ApicRegIndex base, uint8_t vector) + { + return bits(regs[base + (vector % 32)], vector >> 5); + } + public: + /* + * Params stuff. + */ typedef X86LocalApicParams Params; void setClock(Tick newClock) @@ -106,6 +163,9 @@ class Interrupts : public BasicPioDevice, IntDev return dynamic_cast<const Params *>(_params); } + /* + * Functions to interact with the interrupt port from IntDev. + */ Tick read(PacketPtr pkt); Tick write(PacketPtr pkt); Tick recvMessage(PacketPtr pkt); @@ -124,6 +184,17 @@ class Interrupts : public BasicPioDevice, IntDev x86InterruptAddress(0, 0) + PhysAddrAPICRangeSize)); } + Port *getPort(const std::string &if_name, int idx = -1) + { + if (if_name == "int_port") + return intPort; + return BasicPioDevice::getPort(if_name, idx); + } + + /* + * Functions to access and manipulate the APIC's registers. + */ + uint32_t readReg(ApicRegIndex miscReg); void setReg(ApicRegIndex reg, uint32_t val); void setRegNoEffect(ApicRegIndex reg, uint32_t val) @@ -131,29 +202,47 @@ class Interrupts : public BasicPioDevice, IntDev regs[reg] = val; } + /* + * Constructor. + */ + Interrupts(Params * p) : BasicPioDevice(p), IntDev(this), latency(p->pio_latency), clock(0) { pioSize = PageBytes; + memset(regs, 0, sizeof(regs)); //Set the local apic DFR to the flat model. regs[APIC_DESTINATION_FORMAT] = (uint32_t)(-1); - memset(regs, 0, sizeof(regs)); - clear_all(); + ISRV = 0; + IRRV = 0; } - Port *getPort(const std::string &if_name, int idx = -1) + /* + * Functions for retrieving interrupts for the CPU to handle. + */ + + bool check_interrupts(ThreadContext * tc) const; + Fault getInterrupt(ThreadContext * tc); + void updateIntrInfo(ThreadContext * tc); + + /* + * Serialization. + */ + + void serialize(std::ostream & os) { - if (if_name == "int_port") - return intPort; - return BasicPioDevice::getPort(if_name, idx); + panic("Interrupts::serialize unimplemented!\n"); } - int InterruptLevel(uint64_t softint) + void unserialize(Checkpoint * cp, const std::string & section) { - panic("Interrupts::InterruptLevel unimplemented!\n"); - return 0; + panic("Interrupts::unserialize unimplemented!\n"); } + /* + * Old functions needed for compatability but which will be phased out + * eventually. + */ void post(int int_num, int index) { panic("Interrupts::post unimplemented!\n"); @@ -161,37 +250,12 @@ class Interrupts : public BasicPioDevice, IntDev void clear(int int_num, int index) { - warn("Interrupts::clear unimplemented!\n"); + panic("Interrupts::clear unimplemented!\n"); } void clear_all() { - warn("Interrupts::clear_all unimplemented!\n"); - } - - bool check_interrupts(ThreadContext * tc) const - { - return false; - } - - Fault getInterrupt(ThreadContext * tc) - { - return NoFault; - } - - void updateIntrInfo(ThreadContext * tc) - { - panic("Interrupts::updateIntrInfo unimplemented!\n"); - } - - void serialize(std::ostream & os) - { - panic("Interrupts::serialize unimplemented!\n"); - } - - void unserialize(Checkpoint * cp, const std::string & section) - { - panic("Interrupts::unserialize unimplemented!\n"); + panic("Interrupts::clear_all unimplemented!\n"); } }; diff --git a/src/arch/x86/intmessage.hh b/src/arch/x86/intmessage.hh index 64e821a41..a018a997b 100644 --- a/src/arch/x86/intmessage.hh +++ b/src/arch/x86/intmessage.hh @@ -44,8 +44,47 @@ namespace X86ISA Bitfield<15, 8> vector; Bitfield<18, 16> deliveryMode; Bitfield<19> destMode; + Bitfield<20> level; + Bitfield<21> trigger; EndBitUnion(TriggerIntMessage) + namespace DeliveryMode + { + enum IntDeliveryMode { + Fixed = 0, + LowestPriority = 1, + SMI = 2, + NMI = 4, + INIT = 5, + ExtInt = 7, + NumModes + }; + + static const char * const names[NumModes] = { + "Fixed", "LowestPriority", "SMI", "Reserved", + "NMI", "INIT", "Reserved", "ExtInt" + }; + + static inline bool + isUnmaskable(int mode) + { + return (mode == SMI || mode == NMI || + mode == INIT || mode == ExtInt); + } + + static inline bool + isMaskable(int mode) + { + return (mode == Fixed || mode == LowestPriority); + } + + static inline bool + isReserved(int mode) + { + return !(isMaskable(mode) || isUnmaskable(mode)); + } + } + static const Addr TriggerIntOffset = 0; static inline PacketPtr |