From 557bde43c331024eb5cecf4093a24a5b7a9cc266 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 12 Oct 2008 13:28:54 -0700 Subject: X86: Make APICs communicate through the memory system. --- src/arch/x86/X86LocalApic.py | 1 + src/arch/x86/interrupts.cc | 21 ++++++++++ src/arch/x86/interrupts.hh | 21 ++++++++-- src/arch/x86/intmessage.hh | 84 ++++++++++++++++++++++++++++++++++++++ src/arch/x86/x86_traits.hh | 8 ++++ src/cpu/BaseCPU.py | 3 +- src/dev/x86/I82094AA.py | 1 + src/dev/x86/SouthBridge.py | 1 + src/dev/x86/i82094aa.cc | 96 +++++++++++++++++++++++++++++--------------- src/dev/x86/i82094aa.hh | 15 +++++++ src/dev/x86/i8259.hh | 6 +-- src/dev/x86/intdev.hh | 68 ++++++++++++++++++++++++++++++- 12 files changed, 285 insertions(+), 40 deletions(-) create mode 100644 src/arch/x86/intmessage.hh diff --git a/src/arch/x86/X86LocalApic.py b/src/arch/x86/X86LocalApic.py index 94e32ae50..483c65ef8 100644 --- a/src/arch/x86/X86LocalApic.py +++ b/src/arch/x86/X86LocalApic.py @@ -33,3 +33,4 @@ class X86LocalApic(BasicPioDevice): type = 'X86LocalApic' cxx_class = 'X86ISA::Interrupts' pio_latency = Param.Latency('1ns', 'Programmed IO latency in simticks') + int_port = Port("Port for sending and receiving interrupt messages") diff --git a/src/arch/x86/interrupts.cc b/src/arch/x86/interrupts.cc index 6f1920de0..5614a37eb 100644 --- a/src/arch/x86/interrupts.cc +++ b/src/arch/x86/interrupts.cc @@ -239,6 +239,27 @@ X86ISA::Interrupts::write(PacketPtr pkt) return latency; } +Tick +X86ISA::Interrupts::recvMessage(PacketPtr pkt) +{ + Addr offset = pkt->getAddr() - x86InterruptAddress(0, 0); + assert(pkt->cmd == MemCmd::MessageReq); + switch(offset) + { + case 0: + DPRINTF(LocalApic, "Got Trigger Interrupt message.\n"); + break; + default: + panic("Local apic got unknown interrupt message at offset %#x.\n", + offset); + break; + } + delete pkt->req; + delete pkt; + return latency; +} + + uint32_t X86ISA::Interrupts::readReg(ApicRegIndex reg) { diff --git a/src/arch/x86/interrupts.hh b/src/arch/x86/interrupts.hh index 1d5f600bd..c4760dc0f 100644 --- a/src/arch/x86/interrupts.hh +++ b/src/arch/x86/interrupts.hh @@ -62,16 +62,16 @@ #include "arch/x86/faults.hh" #include "cpu/thread_context.hh" #include "dev/io_device.hh" +#include "dev/x86/intdev.hh" #include "params/X86LocalApic.hh" #include "sim/eventq.hh" -#include "sim/sim_object.hh" class ThreadContext; namespace X86ISA { -class Interrupts : public BasicPioDevice +class Interrupts : public BasicPioDevice, IntDev { protected: uint32_t regs[NUM_APIC_REGS]; @@ -108,6 +108,7 @@ class Interrupts : public BasicPioDevice Tick read(PacketPtr pkt); Tick write(PacketPtr pkt); + Tick recvMessage(PacketPtr pkt); void addressRanges(AddrRangeList &range_list) { @@ -116,6 +117,13 @@ class Interrupts : public BasicPioDevice x86LocalAPICAddress(0, 0) + PageBytes)); } + void getIntAddrRange(AddrRangeList &range_list) + { + range_list.clear(); + range_list.push_back(RangeEx(x86InterruptAddress(0, 0), + x86InterruptAddress(0, 0) + PhysAddrAPICRangeSize)); + } + uint32_t readReg(ApicRegIndex miscReg); void setReg(ApicRegIndex reg, uint32_t val); void setRegNoEffect(ApicRegIndex reg, uint32_t val) @@ -123,7 +131,7 @@ class Interrupts : public BasicPioDevice regs[reg] = val; } - Interrupts(Params * p) : BasicPioDevice(p), + Interrupts(Params * p) : BasicPioDevice(p), IntDev(this), latency(p->pio_latency), clock(0) { pioSize = PageBytes; @@ -133,6 +141,13 @@ class Interrupts : public BasicPioDevice clear_all(); } + Port *getPort(const std::string &if_name, int idx = -1) + { + if (if_name == "int_port") + return intPort; + return BasicPioDevice::getPort(if_name, idx); + } + int InterruptLevel(uint64_t softint) { panic("Interrupts::InterruptLevel unimplemented!\n"); diff --git a/src/arch/x86/intmessage.hh b/src/arch/x86/intmessage.hh new file mode 100644 index 000000000..64e821a41 --- /dev/null +++ b/src/arch/x86/intmessage.hh @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2008 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __ARCH_X86_INTMESSAGE_HH__ +#define __ARCH_X86_INTMESSAGE_HH__ + +#include "arch/x86/x86_traits.hh" +#include "base/bitunion.hh" +#include "mem/packet.hh" +#include "mem/request.hh" +#include "sim/host.hh" + +namespace X86ISA +{ + BitUnion32(TriggerIntMessage) + Bitfield<7, 0> destination; + Bitfield<15, 8> vector; + Bitfield<18, 16> deliveryMode; + Bitfield<19> destMode; + EndBitUnion(TriggerIntMessage) + + static const Addr TriggerIntOffset = 0; + + static inline PacketPtr + prepIntRequest(const uint8_t id, Addr offset, Addr size) + { + RequestPtr req = new Request(x86InterruptAddress(id, offset), + size, UNCACHEABLE); + PacketPtr pkt = new Packet(req, MemCmd::MessageReq, Packet::Broadcast); + pkt->allocate(); + return pkt; + } + + template + PacketPtr + buildIntRequest(const uint8_t id, T payload, Addr offset, Addr size) + { + PacketPtr pkt = prepIntRequest(id, offset, size); + pkt->set(payload); + return pkt; + } + + static inline PacketPtr + buildIntRequest(const uint8_t id, TriggerIntMessage payload) + { + return buildIntRequest(id, payload, TriggerIntOffset, + sizeof(TriggerIntMessage)); + } + + static inline PacketPtr + buildIntResponse() + { + panic("buildIntResponse not implemented.\n"); + } +} + +#endif diff --git a/src/arch/x86/x86_traits.hh b/src/arch/x86/x86_traits.hh index 6b4671a08..be7572517 100644 --- a/src/arch/x86/x86_traits.hh +++ b/src/arch/x86/x86_traits.hh @@ -93,6 +93,7 @@ namespace X86ISA const Addr PhysAddrPrefixIO = ULL(0x8000000000000000); const Addr PhysAddrPrefixPciConfig = ULL(0xC000000000000000); const Addr PhysAddrPrefixLocalAPIC = ULL(0xA000000000000000); + const Addr PhysAddrPrefixInterrupts = ULL(0x2000000000000000); // Each APIC gets two pages. One page is used for local apics to field // accesses from the CPU, and the other is for all APICs to communicate. const Addr PhysAddrAPICRangeSize = 1 << 12; @@ -115,6 +116,13 @@ namespace X86ISA assert(addr < (1 << 12)); return PhysAddrPrefixLocalAPIC | (id * (1 << 12)) | addr; } + + static inline Addr + x86InterruptAddress(const uint8_t id, const uint16_t addr) + { + assert(addr < PhysAddrAPICRangeSize); + return PhysAddrPrefixInterrupts | (id * PhysAddrAPICRangeSize) | addr; + } } #endif //__ARCH_X86_X86TRAITS_HH__ diff --git a/src/cpu/BaseCPU.py b/src/cpu/BaseCPU.py index 78b9ae944..51d447f0b 100644 --- a/src/cpu/BaseCPU.py +++ b/src/cpu/BaseCPU.py @@ -144,7 +144,8 @@ class BaseCPU(MemObject): if build_env['TARGET_ISA'] == 'x86' and build_env['FULL_SYSTEM']: _mem_ports = ["itb.walker.port", "dtb.walker.port", - "interrupts.pio"] + "interrupts.pio", + "interrupts.int_port"] def connectMemPorts(self, bus): for p in self._mem_ports: diff --git a/src/dev/x86/I82094AA.py b/src/dev/x86/I82094AA.py index 731d831f0..b4ad96a9f 100644 --- a/src/dev/x86/I82094AA.py +++ b/src/dev/x86/I82094AA.py @@ -36,6 +36,7 @@ class I82094AA(BasicPioDevice): cxx_class = 'X86ISA::I82094AA' pio_latency = Param.Latency('1ns', "Programmed IO latency in simticks") pio_addr = Param.Addr("Device address") + int_port = Port("Port for sending and receiving interrupt messages") def pin(self, line): return X86IntPin(device=self, line=line) diff --git a/src/dev/x86/SouthBridge.py b/src/dev/x86/SouthBridge.py index 15ffe153f..8a9bea01b 100644 --- a/src/dev/x86/SouthBridge.py +++ b/src/dev/x86/SouthBridge.py @@ -72,3 +72,4 @@ class SouthBridge(SimObject): self.pit.pio = bus.port self.speaker.pio = bus.port self.io_apic.pio = bus.port + self.io_apic.int_port = bus.port diff --git a/src/dev/x86/i82094aa.cc b/src/dev/x86/i82094aa.cc index 713f59592..f944e7171 100644 --- a/src/dev/x86/i82094aa.cc +++ b/src/dev/x86/i82094aa.cc @@ -28,12 +28,13 @@ * Authors: Gabe Black */ +#include "arch/x86/intmessage.hh" #include "dev/x86/i82094aa.hh" #include "mem/packet.hh" #include "mem/packet_access.hh" #include "sim/system.hh" -X86ISA::I82094AA::I82094AA(Params *p) : PioDevice(p), +X86ISA::I82094AA::I82094AA(Params *p) : PioDevice(p), IntDev(this), latency(p->pio_latency), pioAddr(p->pio_addr) { // This assumes there's only one I/O APIC in the system @@ -140,11 +141,56 @@ X86ISA::I82094AA::signalInterrupt(int line) DPRINTF(I82094AA, "Entry was masked.\n"); 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: + 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; + } + DPRINTF(I82094AA, "Vector is %#x.\n", entry.vector); + } + + TriggerIntMessage message; + message.destination = entry.dest; + message.vector = entry.vector; + message.deliveryMode = entry.deliveryMode; + message.destMode = entry.destMode; + if (entry.destMode == 0) { DPRINTF(I82094AA, - "Would send interrupt to APIC ID %d.\n", entry.dest); + "Sending interrupt to APIC ID %d.\n", entry.dest); + PacketPtr pkt = buildIntRequest(entry.dest, message); + if (sys->getMemoryMode() == Enums::timing) + intPort->sendMessageTiming(pkt, latency); + else if (sys->getMemoryMode() == Enums::atomic) + intPort->sendMessageAtomic(pkt); + else + panic("Unrecognized memory mode.\n"); } else { - DPRINTF(I82094AA, "Would send interrupts to APIC IDs:" + DPRINTF(I82094AA, "Sending interrupts to APIC IDs:" "%s%s%s%s%s%s%s%s\n", bits((int)entry.dest, 0) ? " 0": "", bits((int)entry.dest, 1) ? " 1": "", @@ -155,36 +201,22 @@ X86ISA::I82094AA::signalInterrupt(int line) bits((int)entry.dest, 6) ? " 6": "", bits((int)entry.dest, 7) ? " 7": "" ); + uint8_t dests = entry.dest; + uint8_t id = 0; + while(dests) { + if (dests & 0x1) { + PacketPtr pkt = buildIntRequest(id, message); + if (sys->getMemoryMode() == Enums::timing) + intPort->sendMessageTiming(pkt, latency); + else if (sys->getMemoryMode() == Enums::atomic) + intPort->sendMessageAtomic(pkt); + else + panic("Unrecognized memory mode.\n"); + } + dests >>= 1; + id++; + } } - 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: - 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; - } - DPRINTF(I82094AA, "Vector is %#x.\n", entry.vector); } } diff --git a/src/dev/x86/i82094aa.hh b/src/dev/x86/i82094aa.hh index b442e3e92..6c874a5f9 100644 --- a/src/dev/x86/i82094aa.hh +++ b/src/dev/x86/i82094aa.hh @@ -60,6 +60,7 @@ class I82094AA : public PioDevice, public IntDev EndBitUnion(RedirTableEntry) protected: + System * system; Tick latency; Addr pioAddr; @@ -95,9 +96,23 @@ class I82094AA : public PioDevice, public IntDev range_list.push_back(RangeEx(pioAddr + 16, pioAddr + 20)); } + void getIntAddrRange(AddrRangeList &range_list) + { + range_list.clear(); + range_list.push_back(RangeEx(x86InterruptAddress(1, 0), + x86InterruptAddress(1, 0) + PhysAddrAPICRangeSize)); + } + void writeReg(uint8_t offset, uint32_t value); uint32_t readReg(uint8_t offset); + Port *getPort(const std::string &if_name, int idx = -1) + { + if (if_name == "int_port") + return intPort; + return PioDevice::getPort(if_name, idx); + } + void signalInterrupt(int line); }; diff --git a/src/dev/x86/i8259.hh b/src/dev/x86/i8259.hh index f38644222..1c14e5397 100644 --- a/src/dev/x86/i8259.hh +++ b/src/dev/x86/i8259.hh @@ -74,9 +74,9 @@ class I8259 : public BasicPioDevice, public IntDev return dynamic_cast(_params); } - I8259(Params * p) : BasicPioDevice(p), latency(p->pio_latency), - output(p->output), mode(p->mode), readIRR(true), - initControlWord(0) + I8259(Params * p) : BasicPioDevice(p), IntDev(this), + latency(p->pio_latency), output(p->output), + mode(p->mode), readIRR(true), initControlWord(0) { pioSize = 2; } diff --git a/src/dev/x86/intdev.hh b/src/dev/x86/intdev.hh index 7a369f8fa..d36ed462a 100644 --- a/src/dev/x86/intdev.hh +++ b/src/dev/x86/intdev.hh @@ -32,7 +32,11 @@ #define __DEV_X86_INTDEV_HH__ #include +#include +#include "arch/x86/x86_traits.hh" +#include "mem/mem_object.hh" +#include "mem/mport.hh" #include "sim/sim_object.hh" #include "params/X86IntPin.hh" @@ -40,11 +44,73 @@ namespace X86ISA { class IntDev { + protected: + class IntPort : public MessagePort + { + IntDev * device; + Tick latency; + Addr intAddr; + public: + IntPort(const std::string &_name, MemObject * _parent, + IntDev *dev, Tick _latency) : + MessagePort(_name, _parent), device(dev), latency(_latency) + { + } + + void getDeviceAddressRanges(AddrRangeList &resp, bool &snoop) + { + snoop = false; + device->getIntAddrRange(resp); + } + + Tick recvMessage(PacketPtr pkt) + { + return device->recvMessage(pkt); + } + + void recvStatusChange(Status status) + { + if (status == RangeChange) { + sendStatusChange(Port::RangeChange); + } + } + + }; + + IntPort * intPort; + public: + IntDev(MemObject * parent, Tick latency = 0) + { + if (parent != NULL) { + intPort = new IntPort(parent->name() + ".int_port", + parent, this, latency); + } else { + intPort = NULL; + } + } + virtual ~IntDev() {} + + virtual void + signalInterrupt(int line) + { + panic("signalInterrupt not implemented.\n"); + } + + virtual Tick + recvMessage(PacketPtr pkt) + { + panic("recvMessage not implemented.\n"); + return 0; + } + virtual void - signalInterrupt(int line) = 0; + getIntAddrRange(AddrRangeList &range_list) + { + panic("intAddrRange not implemented.\n"); + } }; class IntPin : public SimObject -- cgit v1.2.3