X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Farch%2Fx86%2Finterrupts.cc;h=b418a7489bd4e8d5c9a9ad2a074d69a3cbd9de68;hb=52540b1b785aac9b307dfcc976527d94899deb94;hp=9ac4b20ba355cb99b4906fab462d5d4ea6179886;hpb=bdda224d4110dd8ebb6224bfa9bc2641957a8c57;p=gem5.git diff --git a/src/arch/x86/interrupts.cc b/src/arch/x86/interrupts.cc index 9ac4b20ba..b418a7489 100644 --- a/src/arch/x86/interrupts.cc +++ b/src/arch/x86/interrupts.cc @@ -1,44 +1,38 @@ /* - * Copyright (c) 2008 The Hewlett-Packard Development Company - * All rights reserved. + * Copyright (c) 2012 ARM Limited + * All rights reserved * - * Redistribution and use of this software in source and binary forms, - * with or without modification, are permitted provided that the - * following conditions are met: + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. * - * The software must be used only for Non-Commercial Use which means any - * use which is NOT directed to receiving any direct monetary - * compensation for, or commercial advantage from such use. Illustrative - * examples of non-commercial use are academic research, personal study, - * teaching, education and corporate research & development. - * Illustrative examples of commercial use are distributing products for - * commercial advantage and providing services using the software for - * commercial advantage. + * Copyright (c) 2008 The Hewlett-Packard Development Company + * All rights reserved. * - * If you wish to use this software or functionality therein that may be - * covered by patents for commercial use, please contact: - * Director of Intellectual Property Licensing - * Office of Strategy and Technology - * Hewlett-Packard Company - * 1501 Page Mill Road - * Palo Alto, California 94304 + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. * - * 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 HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its + * 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. No right of - * sublicense is granted herewith. Derivatives of the software and - * output created using the software may be prepared, but only for - * Non-Commercial Uses. Derivatives of the software may be shared with - * others provided: (i) the others agree to abide by the list of - * conditions herein which includes the Non-Commercial Use restrictions; - * and (ii) such Derivatives of the software include the above copyright - * notice to acknowledge the contribution from this software where - * applicable, this list of conditions and the disclaimer below. + * 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 @@ -55,12 +49,17 @@ * Authors: Gabe Black */ -#include "arch/x86/apicregs.hh" +#include "arch/x86/regs/apic.hh" #include "arch/x86/interrupts.hh" #include "arch/x86/intmessage.hh" #include "cpu/base.hh" +#include "debug/LocalApic.hh" +#include "dev/x86/i82094aa.hh" +#include "dev/x86/pc.hh" +#include "dev/x86/south_bridge.hh" #include "mem/packet_access.hh" #include "sim/system.hh" +#include "sim/full_system.hh" int divideFromConf(uint32_t conf) @@ -282,29 +281,52 @@ X86ISA::Interrupts::requestInterrupt(uint8_t vector, } else if (deliveryMode == DeliveryMode::INIT && !pendingInit) { pendingUnmaskableInt = pendingInit = true; initVector = vector; - } else if (deliveryMode == DeliveryMode::SIPI && !pendingStartup) { + } else if (deliveryMode == DeliveryMode::SIPI && + !pendingStartup && !startedUp) { pendingUnmaskableInt = pendingStartup = true; startupVector = vector; } - } - cpu->wakeup(); + } + if (FullSystem) + cpu->wakeup(); } void X86ISA::Interrupts::setCPU(BaseCPU * newCPU) { + assert(newCPU); + if (cpu != NULL && cpu->cpuId() != newCPU->cpuId()) { + panic("Local APICs can't be moved between CPUs" + " with different IDs.\n"); + } cpu = newCPU; - assert(cpu); - regs[APIC_ID] = (cpu->cpuId() << 24); + initialApicId = cpu->cpuId(); + regs[APIC_ID] = (initialApicId << 24); + pioAddr = x86LocalAPICAddress(initialApicId, 0); +} + + +void +X86ISA::Interrupts::init() +{ + // + // The local apic must register its address ranges on both its pio port + // via the basicpiodevice(piodevice) init() function and its int port + // that it inherited from IntDev. Note IntDev is not a SimObject itself. + // + BasicPioDevice::init(); + IntDev::init(); + + // the slave port has a range so inform the connected master + intSlavePort.sendRangeChange(); } Tick X86ISA::Interrupts::recvMessage(PacketPtr pkt) { - uint8_t id = (regs[APIC_ID] >> 24); - Addr offset = pkt->getAddr() - x86InterruptAddress(id, 0); + Addr offset = pkt->getAddr() - x86InterruptAddress(initialApicId, 0); assert(pkt->cmd == MemCmd::MessageReq); switch(offset) { @@ -314,9 +336,6 @@ X86ISA::Interrupts::recvMessage(PacketPtr pkt) DPRINTF(LocalApic, "Got Trigger Interrupt message with vector %#x.\n", message.vector); - // Make sure we're really supposed to get this. - assert((message.destMode == 0 && message.destination == id) || - (bits((int)message.destination, id))); requestInterrupt(message.vector, message.deliveryMode, message.trigger); @@ -332,25 +351,42 @@ X86ISA::Interrupts::recvMessage(PacketPtr pkt) } -void -X86ISA::Interrupts::addressRanges(AddrRangeList &range_list) +Tick +X86ISA::Interrupts::recvResponse(PacketPtr pkt) { - uint8_t id = (regs[APIC_ID] >> 24); - range_list.clear(); - Range range = RangeEx(x86LocalAPICAddress(id, 0), - x86LocalAPICAddress(id, 0) + PageBytes); - range_list.push_back(range); - pioAddr = range.start; + assert(!pkt->isError()); + assert(pkt->cmd == MemCmd::MessageResp); + if (--pendingIPIs == 0) { + InterruptCommandRegLow low = regs[APIC_INTERRUPT_COMMAND_LOW]; + // Record that the ICR is now idle. + low.deliveryStatus = 0; + regs[APIC_INTERRUPT_COMMAND_LOW] = low; + } + DPRINTF(LocalApic, "ICR is now idle.\n"); + return 0; } -void -X86ISA::Interrupts::getIntAddrRange(AddrRangeList &range_list) +AddrRangeList +X86ISA::Interrupts::getAddrRanges() const { - uint8_t id = (regs[APIC_ID] >> 24); - range_list.clear(); - range_list.push_back(RangeEx(x86InterruptAddress(id, 0), - x86InterruptAddress(id, 0) + PhysAddrAPICRangeSize)); + AddrRangeList ranges; + Range range = RangeEx(x86LocalAPICAddress(initialApicId, 0), + x86LocalAPICAddress(initialApicId, 0) + + PageBytes); + ranges.push_back(range); + return ranges; +} + + +AddrRangeList +X86ISA::Interrupts::getIntAddrRange() const +{ + AddrRangeList ranges; + ranges.push_back(RangeEx(x86InterruptAddress(initialApicId, 0), + x86InterruptAddress(initialApicId, 0) + + PhysAddrAPICRangeSize)); + return ranges; } @@ -379,7 +415,7 @@ X86ISA::Interrupts::readReg(ApicRegIndex reg) uint64_t ticksPerCount = clock * divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]); // Compute how many m5 ticks are left. - uint64_t val = apicTimerEvent.when() - curTick; + uint64_t val = apicTimerEvent.when() - curTick(); // Turn that into a count. val = (val + ticksPerCount - 1) / ticksPerCount; return val; @@ -467,7 +503,7 @@ X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val) InterruptCommandRegHigh high = regs[APIC_INTERRUPT_COMMAND_HIGH]; // Record that an IPI is being sent. low.deliveryStatus = 1; - TriggerIntMessage message; + TriggerIntMessage message = 0; message.destination = high.destination; message.vector = low.vector; message.deliveryMode = low.deliveryMode; @@ -475,20 +511,66 @@ X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val) message.level = low.level; message.trigger = low.trigger; bool timing = sys->getMemoryMode() == Enums::timing; + // Be careful no updates of the delivery status bit get lost. + regs[APIC_INTERRUPT_COMMAND_LOW] = low; + ApicList apics; + int numContexts = sys->numContexts(); switch (low.destShorthand) { case 0: - intPort->sendMessage(message, timing); + if (message.deliveryMode == DeliveryMode::LowestPriority) { + panic("Lowest priority delivery mode " + "IPIs aren't implemented.\n"); + } + if (message.destMode == 1) { + int dest = message.destination; + hack_once("Assuming logical destinations are 1 << id.\n"); + for (int i = 0; i < numContexts; i++) { + if (dest & 0x1) + apics.push_back(i); + dest = dest >> 1; + } + } else { + if (message.destination == 0xFF) { + for (int i = 0; i < numContexts; i++) { + if (i == initialApicId) { + requestInterrupt(message.vector, + message.deliveryMode, message.trigger); + } else { + apics.push_back(i); + } + } + } else { + if (message.destination == initialApicId) { + requestInterrupt(message.vector, + message.deliveryMode, message.trigger); + } else { + apics.push_back(message.destination); + } + } + } break; case 1: - panic("Self IPIs aren't implemented.\n"); + newVal = val; + requestInterrupt(message.vector, + message.deliveryMode, message.trigger); break; case 2: - panic("Broadcast including self IPIs aren't implemented.\n"); - break; + requestInterrupt(message.vector, + message.deliveryMode, message.trigger); + // Fall through case 3: - panic("Broadcast excluding self IPIs aren't implemented.\n"); + { + for (int i = 0; i < numContexts; i++) { + if (i != initialApicId) { + apics.push_back(i); + } + } + } break; } + pendingIPIs += apics.size(); + intMasterPort.sendMessage(apics, message, timing); + newVal = regs[APIC_INTERRUPT_COMMAND_LOW]; } break; case APIC_LVT_TIMER: @@ -511,13 +593,13 @@ X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val) uint64_t newCount = newVal * (divideFromConf(regs[APIC_DIVIDE_CONFIGURATION])); // Schedule on the edge of the next tick plus the new count. - Tick offset = curTick % clock; + Tick offset = curTick() % clock; if (offset) { reschedule(apicTimerEvent, - curTick + (newCount + 1) * clock - offset, true); + curTick() + (newCount + 1) * clock - offset, true); } else { reschedule(apicTimerEvent, - curTick + newCount * clock, true); + curTick() + newCount * clock, true); } } break; @@ -536,14 +618,17 @@ X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val) X86ISA::Interrupts::Interrupts(Params * p) : - BasicPioDevice(p), IntDev(this), latency(p->pio_latency), clock(0), + BasicPioDevice(p), IntDev(this, p->int_latency), latency(p->pio_latency), + clock(0), apicTimerEvent(this), pendingSmi(false), smiVector(0), pendingNmi(false), nmiVector(0), pendingExtInt(false), extIntVector(0), pendingInit(false), initVector(0), pendingStartup(false), startupVector(0), - pendingUnmaskableInt(false) + startedUp(false), pendingUnmaskableInt(false), + pendingIPIs(0), cpu(NULL), + intSlavePort(name() + ".int_slave", this, this, latency) { pioSize = PageBytes; memset(regs, 0, sizeof(regs)); @@ -624,9 +709,11 @@ X86ISA::Interrupts::updateIntrInfo(ThreadContext *tc) } else if (pendingInit) { DPRINTF(LocalApic, "Init sent to core.\n"); pendingInit = false; + startedUp = false; } else if (pendingStartup) { DPRINTF(LocalApic, "SIPI sent to core.\n"); pendingStartup = false; + startedUp = true; } if (!(pendingSmi || pendingNmi || pendingInit || pendingStartup)) pendingUnmaskableInt = false; @@ -643,6 +730,65 @@ X86ISA::Interrupts::updateIntrInfo(ThreadContext *tc) } } +void +X86ISA::Interrupts::serialize(std::ostream &os) +{ + SERIALIZE_ARRAY(regs, NUM_APIC_REGS); + SERIALIZE_SCALAR(clock); + SERIALIZE_SCALAR(pendingSmi); + SERIALIZE_SCALAR(smiVector); + SERIALIZE_SCALAR(pendingNmi); + SERIALIZE_SCALAR(nmiVector); + SERIALIZE_SCALAR(pendingExtInt); + SERIALIZE_SCALAR(extIntVector); + SERIALIZE_SCALAR(pendingInit); + SERIALIZE_SCALAR(initVector); + SERIALIZE_SCALAR(pendingStartup); + SERIALIZE_SCALAR(startupVector); + SERIALIZE_SCALAR(startedUp); + SERIALIZE_SCALAR(pendingUnmaskableInt); + SERIALIZE_SCALAR(pendingIPIs); + SERIALIZE_SCALAR(IRRV); + SERIALIZE_SCALAR(ISRV); + bool apicTimerEventScheduled = apicTimerEvent.scheduled(); + SERIALIZE_SCALAR(apicTimerEventScheduled); + Tick apicTimerEventTick = apicTimerEvent.when(); + SERIALIZE_SCALAR(apicTimerEventTick); +} + +void +X86ISA::Interrupts::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_ARRAY(regs, NUM_APIC_REGS); + UNSERIALIZE_SCALAR(clock); + UNSERIALIZE_SCALAR(pendingSmi); + UNSERIALIZE_SCALAR(smiVector); + UNSERIALIZE_SCALAR(pendingNmi); + UNSERIALIZE_SCALAR(nmiVector); + UNSERIALIZE_SCALAR(pendingExtInt); + UNSERIALIZE_SCALAR(extIntVector); + UNSERIALIZE_SCALAR(pendingInit); + UNSERIALIZE_SCALAR(initVector); + UNSERIALIZE_SCALAR(pendingStartup); + UNSERIALIZE_SCALAR(startupVector); + UNSERIALIZE_SCALAR(startedUp); + UNSERIALIZE_SCALAR(pendingUnmaskableInt); + UNSERIALIZE_SCALAR(pendingIPIs); + UNSERIALIZE_SCALAR(IRRV); + UNSERIALIZE_SCALAR(ISRV); + bool apicTimerEventScheduled; + UNSERIALIZE_SCALAR(apicTimerEventScheduled); + if (apicTimerEventScheduled) { + Tick apicTimerEventTick; + UNSERIALIZE_SCALAR(apicTimerEventTick); + if (apicTimerEvent.scheduled()) { + reschedule(apicTimerEvent, apicTimerEventTick, true); + } else { + schedule(apicTimerEvent, apicTimerEventTick); + } + } +} + X86ISA::Interrupts * X86LocalApicParams::create() {