diff options
author | Gabe Black <gblack@eecs.umich.edu> | 2008-10-12 13:44:24 -0700 |
---|---|---|
committer | Gabe Black <gblack@eecs.umich.edu> | 2008-10-12 13:44:24 -0700 |
commit | 876f4845f258ed09d348135d8af8cf4a17de1b8a (patch) | |
tree | 2d109af5103908a7f1561f3610b8e55add81ec7f /src | |
parent | 4d5c7f70389b8911e37d391b09023dbf6a6ab0d9 (diff) | |
download | gem5-876f4845f258ed09d348135d8af8cf4a17de1b8a.tar.xz |
X86: Make the local APIC handle interrupt messages from the IO APIC.
Diffstat (limited to 'src')
-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 | ||||
-rw-r--r-- | src/dev/x86/i82094aa.cc | 31 | ||||
-rw-r--r-- | src/dev/x86/i8259.hh | 3 | ||||
-rw-r--r-- | src/dev/x86/pc.cc | 3 |
7 files changed, 217 insertions, 67 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 diff --git a/src/dev/x86/i82094aa.cc b/src/dev/x86/i82094aa.cc index 1ae3b01cf..d7f479106 100644 --- a/src/dev/x86/i82094aa.cc +++ b/src/dev/x86/i82094aa.cc @@ -146,33 +146,12 @@ X86ISA::I82094AA::signalInterrupt(int line) return; } else { if (DTRACE(I82094AA)) { - switch(entry.deliveryMode) { - case 0: - DPRINTF(I82094AA, "Delivery mode is: Fixed.\n"); - break; - case 1: - DPRINTF(I82094AA, "Delivery mode is: Lowest Priority.\n"); - break; - case 2: - DPRINTF(I82094AA, "Delivery mode is: SMI.\n"); - break; - case 3: + if (DeliveryMode::isReserved(entry.deliveryMode)) { fatal("Tried to use reserved delivery mode " "for IO APIC entry %d.\n", line); - break; - case 4: - DPRINTF(I82094AA, "Delivery mode is: NMI.\n"); - break; - case 5: - DPRINTF(I82094AA, "Delivery mode is: INIT.\n"); - break; - case 6: - fatal("Tried to use reserved delivery mode " - "for IO APIC entry %d.\n", line); - break; - case 7: - DPRINTF(I82094AA, "Delivery mode is: ExtINT.\n"); - break; + } else { + DPRINTF(I82094AA, "Delivery mode is: %s.\n", + DeliveryMode::names[entry.deliveryMode]); } DPRINTF(I82094AA, "Vector is %#x.\n", entry.vector); } @@ -182,6 +161,8 @@ X86ISA::I82094AA::signalInterrupt(int line) message.vector = entry.vector; message.deliveryMode = entry.deliveryMode; message.destMode = entry.destMode; + message.level = entry.polarity; + message.trigger = entry.trigger; if (entry.destMode == 0) { DPRINTF(I82094AA, diff --git a/src/dev/x86/i8259.hh b/src/dev/x86/i8259.hh index 1c14e5397..7804fe3b7 100644 --- a/src/dev/x86/i8259.hh +++ b/src/dev/x86/i8259.hh @@ -76,7 +76,8 @@ class I8259 : public BasicPioDevice, public IntDev I8259(Params * p) : BasicPioDevice(p), IntDev(this), latency(p->pio_latency), output(p->output), - mode(p->mode), readIRR(true), initControlWord(0) + mode(p->mode), IRR(0), ISR(0), IMR(0), + readIRR(true), initControlWord(0) { pioSize = 2; } diff --git a/src/dev/x86/pc.cc b/src/dev/x86/pc.cc index 4cd81dd50..94fb23e21 100644 --- a/src/dev/x86/pc.cc +++ b/src/dev/x86/pc.cc @@ -36,6 +36,7 @@ #include <string> #include <vector> +#include "arch/x86/intmessage.hh" #include "arch/x86/x86_traits.hh" #include "cpu/intr_control.hh" #include "dev/terminal.hh" @@ -78,7 +79,7 @@ Pc::init() */ I82094AA & ioApic = *southBridge->ioApic; I82094AA::RedirTableEntry entry = 0; - entry.deliveryMode = 0x7; + entry.deliveryMode = DeliveryMode::ExtInt; entry.vector = 0x20; ioApic.writeReg(0x10, entry.bottomDW); ioApic.writeReg(0x11, entry.topDW); |