interrupts.cc revision 8851
1360SN/A/*
21458SN/A * Copyright (c) 2008 The Hewlett-Packard Development Company
3360SN/A * All rights reserved.
4360SN/A *
5360SN/A * The license below extends only to copyright in the software and shall
6360SN/A * not be construed as granting a license to any other intellectual
7360SN/A * property including but not limited to intellectual property relating
8360SN/A * to a hardware implementation of the functionality of the software
9360SN/A * licensed hereunder.  You may use the software subject to the license
10360SN/A * terms below provided that you ensure that this notice is replicated
11360SN/A * unmodified and in its entirety in all distributions of the software,
12360SN/A * modified or unmodified, in source code or in binary form.
13360SN/A *
14360SN/A * Redistribution and use in source and binary forms, with or without
15360SN/A * modification, are permitted provided that the following conditions are
16360SN/A * met: redistributions of source code must retain the above copyright
17360SN/A * notice, this list of conditions and the following disclaimer;
18360SN/A * redistributions in binary form must reproduce the above copyright
19360SN/A * notice, this list of conditions and the following disclaimer in the
20360SN/A * documentation and/or other materials provided with the distribution;
21360SN/A * neither the name of the copyright holders nor the names of its
22360SN/A * contributors may be used to endorse or promote products derived from
23360SN/A * this software without specific prior written permission.
24360SN/A *
25360SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26360SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
272665Ssaidi@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
282665Ssaidi@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
292665Ssaidi@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30360SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31360SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
322553SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
332221SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
342048SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35360SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36360SN/A *
372680Sktlim@umich.edu * Authors: Gabe Black
382093SN/A */
392093SN/A
402093SN/A#include "arch/x86/regs/apic.hh"
412093SN/A#include "arch/x86/interrupts.hh"
42360SN/A#include "arch/x86/intmessage.hh"
43360SN/A#include "cpu/base.hh"
442107SN/A#include "debug/LocalApic.hh"
45360SN/A#include "dev/x86/i82094aa.hh"
462149SN/A#include "dev/x86/pc.hh"
472149SN/A#include "dev/x86/south_bridge.hh"
482093SN/A#include "mem/packet_access.hh"
492093SN/A#include "sim/system.hh"
503114Sgblack@eecs.umich.edu#include "sim/full_system.hh"
512680Sktlim@umich.edu
522093SN/Aint
532680Sktlim@umich.edudivideFromConf(uint32_t conf)
54360SN/A{
552093SN/A    // This figures out what division we want from the division configuration
562093SN/A    // register in the local APIC. The encoding is a little odd but it can
572093SN/A    // be deciphered fairly easily.
582093SN/A    int shift = ((conf & 0x8) >> 1) | (conf & 0x3);
592093SN/A    shift = (shift + 1) % 8;
60360SN/A    return 1 << shift;
612680Sktlim@umich.edu}
622093SN/A
632093SN/Anamespace X86ISA
64360SN/A{
652093SN/A
662093SN/AApicRegIndex
672093SN/AdecodeAddr(Addr paddr)
682093SN/A{
693114Sgblack@eecs.umich.edu    ApicRegIndex regNum;
702680Sktlim@umich.edu    paddr &= ~mask(3);
712093SN/A    switch (paddr)
722680Sktlim@umich.edu    {
732680Sktlim@umich.edu      case 0x20:
742064SN/A        regNum = APIC_ID;
752093SN/A        break;
762064SN/A      case 0x30:
772093SN/A        regNum = APIC_VERSION;
782680Sktlim@umich.edu        break;
792093SN/A      case 0x80:
802093SN/A        regNum = APIC_TASK_PRIORITY;
812680Sktlim@umich.edu        break;
822093SN/A      case 0x90:
832093SN/A        regNum = APIC_ARBITRATION_PRIORITY;
84360SN/A        break;
852093SN/A      case 0xA0:
862093SN/A        regNum = APIC_PROCESSOR_PRIORITY;
872093SN/A        break;
882093SN/A      case 0xB0:
891999SN/A        regNum = APIC_EOI;
901999SN/A        break;
912093SN/A      case 0xD0:
922093SN/A        regNum = APIC_LOGICAL_DESTINATION;
93360SN/A        break;
942093SN/A      case 0xE0:
952093SN/A        regNum = APIC_DESTINATION_FORMAT;
963114Sgblack@eecs.umich.edu        break;
972680Sktlim@umich.edu      case 0xF0:
982093SN/A        regNum = APIC_SPURIOUS_INTERRUPT_VECTOR;
992680Sktlim@umich.edu        break;
1002680Sktlim@umich.edu      case 0x100:
101360SN/A      case 0x108:
1022093SN/A      case 0x110:
103360SN/A      case 0x118:
1042093SN/A      case 0x120:
1052680Sktlim@umich.edu      case 0x128:
1062093SN/A      case 0x130:
1072680Sktlim@umich.edu      case 0x138:
1082093SN/A      case 0x140:
1092093SN/A      case 0x148:
1102093SN/A      case 0x150:
1112093SN/A      case 0x158:
1122093SN/A      case 0x160:
1132093SN/A      case 0x168:
1142093SN/A      case 0x170:
1152093SN/A      case 0x178:
1162093SN/A        regNum = APIC_IN_SERVICE((paddr - 0x100) / 0x8);
117360SN/A        break;
118360SN/A      case 0x180:
1192093SN/A      case 0x188:
1202093SN/A      case 0x190:
121360SN/A      case 0x198:
122360SN/A      case 0x1A0:
1232093SN/A      case 0x1A8:
124360SN/A      case 0x1B0:
125360SN/A      case 0x1B8:
126360SN/A      case 0x1C0:
127360SN/A      case 0x1C8:
128360SN/A      case 0x1D0:
129360SN/A      case 0x1D8:
130360SN/A      case 0x1E0:
131360SN/A      case 0x1E8:
132360SN/A      case 0x1F0:
133360SN/A      case 0x1F8:
134511SN/A        regNum = APIC_TRIGGER_MODE((paddr - 0x180) / 0x8);
135360SN/A        break;
136360SN/A      case 0x200:
137360SN/A      case 0x208:
138360SN/A      case 0x210:
1392553SN/A      case 0x218:
1401999SN/A      case 0x220:
141360SN/A      case 0x228:
142360SN/A      case 0x230:
143360SN/A      case 0x238:
1442238SN/A      case 0x240:
145360SN/A      case 0x248:
146360SN/A      case 0x250:
147360SN/A      case 0x258:
1482238SN/A      case 0x260:
149360SN/A      case 0x268:
150360SN/A      case 0x270:
151360SN/A      case 0x278:
152360SN/A        regNum = APIC_INTERRUPT_REQUEST((paddr - 0x200) / 0x8);
153360SN/A        break;
154360SN/A      case 0x280:
155360SN/A        regNum = APIC_ERROR_STATUS;
156360SN/A        break;
157360SN/A      case 0x300:
158360SN/A        regNum = APIC_INTERRUPT_COMMAND_LOW;
159360SN/A        break;
160360SN/A      case 0x310:
161360SN/A        regNum = APIC_INTERRUPT_COMMAND_HIGH;
162360SN/A        break;
163360SN/A      case 0x320:
164360SN/A        regNum = APIC_LVT_TIMER;
1653079Sstever@eecs.umich.edu        break;
1662238SN/A      case 0x330:
167360SN/A        regNum = APIC_LVT_THERMAL_SENSOR;
168360SN/A        break;
1692553SN/A      case 0x340:
170360SN/A        regNum = APIC_LVT_PERFORMANCE_MONITORING_COUNTERS;
1712238SN/A        break;
172360SN/A      case 0x350:
173360SN/A        regNum = APIC_LVT_LINT0;
174360SN/A        break;
175360SN/A      case 0x360:
176360SN/A        regNum = APIC_LVT_LINT1;
177360SN/A        break;
1782553SN/A      case 0x370:
179360SN/A        regNum = APIC_LVT_ERROR;
180360SN/A        break;
181360SN/A      case 0x380:
182360SN/A        regNum = APIC_INITIAL_COUNT;
183360SN/A        break;
184360SN/A      case 0x390:
185360SN/A        regNum = APIC_CURRENT_COUNT;
186360SN/A        break;
187360SN/A      case 0x3E0:
188360SN/A        regNum = APIC_DIVIDE_CONFIGURATION;
189360SN/A        break;
190360SN/A      default:
1912553SN/A        // A reserved register field.
1922553SN/A        panic("Accessed reserved register field %#x.\n", paddr);
193360SN/A        break;
194360SN/A    }
1952553SN/A    return regNum;
196360SN/A}
197360SN/A}
198360SN/A
199360SN/ATick
200360SN/AX86ISA::Interrupts::read(PacketPtr pkt)
201360SN/A{
202360SN/A    Addr offset = pkt->getAddr() - pioAddr;
203360SN/A    //Make sure we're at least only accessing one register.
204360SN/A    if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3)))
205360SN/A        panic("Accessed more than one register at a time in the APIC!\n");
206360SN/A    ApicRegIndex reg = decodeAddr(offset);
207360SN/A    uint32_t val = htog(readReg(reg));
208360SN/A    DPRINTF(LocalApic,
209360SN/A            "Reading Local APIC register %d at offset %#x as %#x.\n",
210360SN/A            reg, offset, val);
211360SN/A    pkt->setData(((uint8_t *)&val) + (offset & mask(3)));
212360SN/A    pkt->makeAtomicResponse();
213360SN/A    return latency;
214360SN/A}
2152553SN/A
216360SN/ATick
217360SN/AX86ISA::Interrupts::write(PacketPtr pkt)
218360SN/A{
219360SN/A    Addr offset = pkt->getAddr() - pioAddr;
220360SN/A    //Make sure we're at least only accessing one register.
221360SN/A    if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3)))
222360SN/A        panic("Accessed more than one register at a time in the APIC!\n");
223360SN/A    ApicRegIndex reg = decodeAddr(offset);
224360SN/A    uint32_t val = regs[reg];
225360SN/A    pkt->writeData(((uint8_t *)&val) + (offset & mask(3)));
226360SN/A    DPRINTF(LocalApic,
227360SN/A            "Writing Local APIC register %d at offset %#x as %#x.\n",
228360SN/A            reg, offset, gtoh(val));
229360SN/A    setReg(reg, gtoh(val));
230360SN/A    pkt->makeAtomicResponse();
231360SN/A    return latency;
232360SN/A}
233360SN/Avoid
234360SN/AX86ISA::Interrupts::requestInterrupt(uint8_t vector,
235360SN/A        uint8_t deliveryMode, bool level)
236360SN/A{
237360SN/A    /*
238360SN/A     * Fixed and lowest-priority delivery mode interrupts are handled
239360SN/A     * using the IRR/ISR registers, checking against the TPR, etc.
240360SN/A     * The SMI, NMI, ExtInt, INIT, etc interrupts go straight through.
241360SN/A     */
242360SN/A    if (deliveryMode == DeliveryMode::Fixed ||
243360SN/A            deliveryMode == DeliveryMode::LowestPriority) {
244360SN/A        DPRINTF(LocalApic, "Interrupt is an %s.\n",
2452553SN/A                DeliveryMode::names[deliveryMode]);
246360SN/A        // Queue up the interrupt in the IRR.
2471999SN/A        if (vector > IRRV)
2482553SN/A            IRRV = vector;
249360SN/A        if (!getRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, vector)) {
250360SN/A            setRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, vector);
251360SN/A            if (level) {
252511SN/A                setRegArrayBit(APIC_TRIGGER_MODE_BASE, vector);
253360SN/A            } else {
254360SN/A                clearRegArrayBit(APIC_TRIGGER_MODE_BASE, vector);
255360SN/A            }
256360SN/A        }
257360SN/A    } else if (!DeliveryMode::isReserved(deliveryMode)) {
258360SN/A        DPRINTF(LocalApic, "Interrupt is an %s.\n",
259360SN/A                DeliveryMode::names[deliveryMode]);
260360SN/A        if (deliveryMode == DeliveryMode::SMI && !pendingSmi) {
261360SN/A            pendingUnmaskableInt = pendingSmi = true;
262360SN/A            smiVector = vector;
263360SN/A        } else if (deliveryMode == DeliveryMode::NMI && !pendingNmi) {
264360SN/A            pendingUnmaskableInt = pendingNmi = true;
265360SN/A            nmiVector = vector;
266360SN/A        } else if (deliveryMode == DeliveryMode::ExtInt && !pendingExtInt) {
267360SN/A            pendingExtInt = true;
2682553SN/A            extIntVector = vector;
269511SN/A        } else if (deliveryMode == DeliveryMode::INIT && !pendingInit) {
270360SN/A            pendingUnmaskableInt = pendingInit = true;
271360SN/A            initVector = vector;
272360SN/A        } else if (deliveryMode == DeliveryMode::SIPI &&
273360SN/A                !pendingStartup && !startedUp) {
274360SN/A            pendingUnmaskableInt = pendingStartup = true;
275360SN/A            startupVector = vector;
276360SN/A        }
277360SN/A    }
278360SN/A    if (FullSystem)
279360SN/A        cpu->wakeup();
280360SN/A}
281360SN/A
282360SN/A
283360SN/Avoid
284360SN/AX86ISA::Interrupts::setCPU(BaseCPU * newCPU)
285360SN/A{
286360SN/A    assert(newCPU);
287360SN/A    if (cpu != NULL && cpu->cpuId() != newCPU->cpuId()) {
288360SN/A        panic("Local APICs can't be moved between CPUs"
289360SN/A                " with different IDs.\n");
290360SN/A    }
291360SN/A    cpu = newCPU;
292360SN/A    initialApicId = cpu->cpuId();
293360SN/A    regs[APIC_ID] = (initialApicId << 24);
294360SN/A}
295360SN/A
296360SN/A
297360SN/Avoid
298360SN/AX86ISA::Interrupts::init()
299360SN/A{
300360SN/A    //
301360SN/A    // The local apic must register its address ranges on both its pio port
302360SN/A    // via the basicpiodevice(piodevice) init() function and its int port
303360SN/A    // that it inherited from IntDev.  Note IntDev is not a SimObject itself.
304360SN/A    //
305360SN/A    BasicPioDevice::init();
306360SN/A    IntDev::init();
307360SN/A}
308360SN/A
309360SN/A
310360SN/ATick
311360SN/AX86ISA::Interrupts::recvMessage(PacketPtr pkt)
312360SN/A{
313360SN/A    Addr offset = pkt->getAddr() - x86InterruptAddress(initialApicId, 0);
314360SN/A    assert(pkt->cmd == MemCmd::MessageReq);
315360SN/A    switch(offset)
316360SN/A    {
317360SN/A      case 0:
318360SN/A        {
319360SN/A            TriggerIntMessage message = pkt->get<TriggerIntMessage>();
320360SN/A            DPRINTF(LocalApic,
321360SN/A                    "Got Trigger Interrupt message with vector %#x.\n",
322360SN/A                    message.vector);
323360SN/A
324360SN/A            requestInterrupt(message.vector,
325360SN/A                    message.deliveryMode, message.trigger);
326360SN/A        }
327360SN/A        break;
328360SN/A      default:
329360SN/A        panic("Local apic got unknown interrupt message at offset %#x.\n",
330360SN/A                offset);
331360SN/A        break;
332360SN/A    }
333360SN/A    pkt->makeAtomicResponse();
334360SN/A    return latency;
335360SN/A}
336360SN/A
337360SN/A
338360SN/ATick
339360SN/AX86ISA::Interrupts::recvResponse(PacketPtr pkt)
340360SN/A{
341360SN/A    assert(!pkt->isError());
342360SN/A    assert(pkt->cmd == MemCmd::MessageResp);
343360SN/A    if (--pendingIPIs == 0) {
344360SN/A        InterruptCommandRegLow low = regs[APIC_INTERRUPT_COMMAND_LOW];
345360SN/A        // Record that the ICR is now idle.
346360SN/A        low.deliveryStatus = 0;
347360SN/A        regs[APIC_INTERRUPT_COMMAND_LOW] = low;
348360SN/A    }
349360SN/A    DPRINTF(LocalApic, "ICR is now idle.\n");
350360SN/A    return 0;
351360SN/A}
352360SN/A
353360SN/A
354360SN/AAddrRangeList
355360SN/AX86ISA::Interrupts::getAddrRanges()
356360SN/A{
357360SN/A    AddrRangeList ranges;
358360SN/A    Range<Addr> range = RangeEx(x86LocalAPICAddress(initialApicId, 0),
359360SN/A                                x86LocalAPICAddress(initialApicId, 0) +
360360SN/A                                PageBytes);
361360SN/A    ranges.push_back(range);
362360SN/A    pioAddr = range.start;
363360SN/A    return ranges;
364360SN/A}
365360SN/A
366360SN/A
367360SN/AAddrRangeList
368360SN/AX86ISA::Interrupts::getIntAddrRange()
369360SN/A{
370360SN/A    AddrRangeList ranges;
371360SN/A    ranges.push_back(RangeEx(x86InterruptAddress(initialApicId, 0),
372360SN/A                             x86InterruptAddress(initialApicId, 0) +
373360SN/A                             PhysAddrAPICRangeSize));
374360SN/A    return ranges;
375360SN/A}
376360SN/A
377360SN/A
378360SN/Auint32_t
379360SN/AX86ISA::Interrupts::readReg(ApicRegIndex reg)
380360SN/A{
381360SN/A    if (reg >= APIC_TRIGGER_MODE(0) &&
382360SN/A            reg <= APIC_TRIGGER_MODE(15)) {
383360SN/A        panic("Local APIC Trigger Mode registers are unimplemented.\n");
384360SN/A    }
385360SN/A    switch (reg) {
386360SN/A      case APIC_ARBITRATION_PRIORITY:
387360SN/A        panic("Local APIC Arbitration Priority register unimplemented.\n");
388360SN/A        break;
389360SN/A      case APIC_PROCESSOR_PRIORITY:
390360SN/A        panic("Local APIC Processor Priority register unimplemented.\n");
391360SN/A        break;
392360SN/A      case APIC_ERROR_STATUS:
393360SN/A        regs[APIC_INTERNAL_STATE] &= ~ULL(0x1);
394360SN/A        break;
395360SN/A      case APIC_CURRENT_COUNT:
396360SN/A        {
397360SN/A            if (apicTimerEvent.scheduled()) {
398360SN/A                assert(clock);
399360SN/A                // Compute how many m5 ticks happen per count.
400360SN/A                uint64_t ticksPerCount = clock *
401360SN/A                    divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]);
402360SN/A                // Compute how many m5 ticks are left.
403360SN/A                uint64_t val = apicTimerEvent.when() - curTick();
404360SN/A                // Turn that into a count.
405360SN/A                val = (val + ticksPerCount - 1) / ticksPerCount;
406360SN/A                return val;
407360SN/A            } else {
408360SN/A                return 0;
409360SN/A            }
410360SN/A        }
411360SN/A      default:
412360SN/A        break;
413360SN/A    }
414360SN/A    return regs[reg];
415360SN/A}
416360SN/A
417360SN/Avoid
418360SN/AX86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val)
419360SN/A{
420360SN/A    uint32_t newVal = val;
421360SN/A    if (reg >= APIC_IN_SERVICE(0) &&
422360SN/A            reg <= APIC_IN_SERVICE(15)) {
423360SN/A        panic("Local APIC In-Service registers are unimplemented.\n");
424360SN/A    }
425360SN/A    if (reg >= APIC_TRIGGER_MODE(0) &&
426360SN/A            reg <= APIC_TRIGGER_MODE(15)) {
427360SN/A        panic("Local APIC Trigger Mode registers are unimplemented.\n");
428360SN/A    }
429360SN/A    if (reg >= APIC_INTERRUPT_REQUEST(0) &&
430360SN/A            reg <= APIC_INTERRUPT_REQUEST(15)) {
431360SN/A        panic("Local APIC Interrupt Request registers "
432360SN/A                "are unimplemented.\n");
433360SN/A    }
434360SN/A    switch (reg) {
435360SN/A      case APIC_ID:
436360SN/A        newVal = val & 0xFF;
437360SN/A        break;
438360SN/A      case APIC_VERSION:
439360SN/A        // The Local APIC Version register is read only.
440360SN/A        return;
441360SN/A      case APIC_TASK_PRIORITY:
442360SN/A        newVal = val & 0xFF;
443360SN/A        break;
444360SN/A      case APIC_ARBITRATION_PRIORITY:
445360SN/A        panic("Local APIC Arbitration Priority register unimplemented.\n");
446360SN/A        break;
447360SN/A      case APIC_PROCESSOR_PRIORITY:
448360SN/A        panic("Local APIC Processor Priority register unimplemented.\n");
449360SN/A        break;
450511SN/A      case APIC_EOI:
451360SN/A        // Remove the interrupt that just completed from the local apic state.
452360SN/A        clearRegArrayBit(APIC_IN_SERVICE_BASE, ISRV);
453360SN/A        updateISRV();
454360SN/A        return;
455360SN/A      case APIC_LOGICAL_DESTINATION:
456360SN/A        newVal = val & 0xFF000000;
457360SN/A        break;
458360SN/A      case APIC_DESTINATION_FORMAT:
459360SN/A        newVal = val | 0x0FFFFFFF;
460360SN/A        break;
461360SN/A      case APIC_SPURIOUS_INTERRUPT_VECTOR:
462360SN/A        regs[APIC_INTERNAL_STATE] &= ~ULL(1 << 1);
463360SN/A        regs[APIC_INTERNAL_STATE] |= val & (1 << 8);
464360SN/A        if (val & (1 << 9))
465360SN/A            warn("Focus processor checking not implemented.\n");
466360SN/A        break;
467360SN/A      case APIC_ERROR_STATUS:
468360SN/A        {
469360SN/A            if (regs[APIC_INTERNAL_STATE] & 0x1) {
470360SN/A                regs[APIC_INTERNAL_STATE] &= ~ULL(0x1);
471360SN/A                newVal = 0;
472360SN/A            } else {
473360SN/A                regs[APIC_INTERNAL_STATE] |= ULL(0x1);
474360SN/A                return;
475360SN/A            }
476360SN/A
477360SN/A        }
478360SN/A        break;
479511SN/A      case APIC_INTERRUPT_COMMAND_LOW:
480360SN/A        {
481360SN/A            InterruptCommandRegLow low = regs[APIC_INTERRUPT_COMMAND_LOW];
482360SN/A            // Check if we're already sending an IPI.
483360SN/A            if (low.deliveryStatus) {
484360SN/A                newVal = low;
485360SN/A                break;
4862553SN/A            }
487360SN/A            low = val;
488360SN/A            InterruptCommandRegHigh high = regs[APIC_INTERRUPT_COMMAND_HIGH];
489360SN/A            // Record that an IPI is being sent.
4902553SN/A            low.deliveryStatus = 1;
4912553SN/A            TriggerIntMessage message = 0;
492360SN/A            message.destination = high.destination;
493360SN/A            message.vector = low.vector;
494360SN/A            message.deliveryMode = low.deliveryMode;
495360SN/A            message.destMode = low.destMode;
496360SN/A            message.level = low.level;
497360SN/A            message.trigger = low.trigger;
498360SN/A            bool timing = sys->getMemoryMode() == Enums::timing;
499360SN/A            // Be careful no updates of the delivery status bit get lost.
500360SN/A            regs[APIC_INTERRUPT_COMMAND_LOW] = low;
501360SN/A            ApicList apics;
502360SN/A            int numContexts = sys->numContexts();
503360SN/A            switch (low.destShorthand) {
504360SN/A              case 0:
505360SN/A                if (message.deliveryMode == DeliveryMode::LowestPriority) {
506360SN/A                    panic("Lowest priority delivery mode "
507360SN/A                            "IPIs aren't implemented.\n");
508360SN/A                }
509360SN/A                if (message.destMode == 1) {
510360SN/A                    int dest = message.destination;
511360SN/A                    hack_once("Assuming logical destinations are 1 << id.\n");
512360SN/A                    for (int i = 0; i < numContexts; i++) {
513360SN/A                        if (dest & 0x1)
514360SN/A                            apics.push_back(i);
515360SN/A                        dest = dest >> 1;
516360SN/A                    }
517360SN/A                } else {
518360SN/A                    if (message.destination == 0xFF) {
519360SN/A                        for (int i = 0; i < numContexts; i++) {
520360SN/A                            if (i == initialApicId) {
521543SN/A                                requestInterrupt(message.vector,
522543SN/A                                        message.deliveryMode, message.trigger);
523543SN/A                            } else {
524543SN/A                                apics.push_back(i);
525543SN/A                            }
526543SN/A                        }
527543SN/A                    } else {
528543SN/A                        if (message.destination == initialApicId) {
529543SN/A                            requestInterrupt(message.vector,
530543SN/A                                    message.deliveryMode, message.trigger);
531543SN/A                        } else {
532543SN/A                            apics.push_back(message.destination);
533543SN/A                        }
534543SN/A                    }
535543SN/A                }
536543SN/A                break;
537543SN/A              case 1:
538543SN/A                newVal = val;
539543SN/A                requestInterrupt(message.vector,
540543SN/A                        message.deliveryMode, message.trigger);
541543SN/A                break;
542543SN/A              case 2:
543543SN/A                requestInterrupt(message.vector,
544543SN/A                        message.deliveryMode, message.trigger);
545543SN/A                // Fall through
546543SN/A              case 3:
547543SN/A                {
548543SN/A                    for (int i = 0; i < numContexts; i++) {
549543SN/A                        if (i != initialApicId) {
550543SN/A                            apics.push_back(i);
5511999SN/A                        }
5521999SN/A                    }
5532553SN/A                }
5542553SN/A                break;
5551999SN/A            }
5561999SN/A            pendingIPIs += apics.size();
5571999SN/A            intPort.sendMessage(apics, message, timing);
5581999SN/A            newVal = regs[APIC_INTERRUPT_COMMAND_LOW];
5591999SN/A        }
5601999SN/A        break;
5611999SN/A      case APIC_LVT_TIMER:
5621999SN/A      case APIC_LVT_THERMAL_SENSOR:
5631999SN/A      case APIC_LVT_PERFORMANCE_MONITORING_COUNTERS:
5641999SN/A      case APIC_LVT_LINT0:
5651999SN/A      case APIC_LVT_LINT1:
5661999SN/A      case APIC_LVT_ERROR:
5671999SN/A        {
5681999SN/A            uint64_t readOnlyMask = (1 << 12) | (1 << 14);
569360SN/A            newVal = (val & ~readOnlyMask) |
570360SN/A                     (regs[reg] & readOnlyMask);
571360SN/A        }
572360SN/A        break;
5732423SN/A      case APIC_INITIAL_COUNT:
574360SN/A        {
575360SN/A            assert(clock);
576360SN/A            newVal = bits(val, 31, 0);
577360SN/A            // Compute how many timer ticks we're being programmed for.
5783114Sgblack@eecs.umich.edu            uint64_t newCount = newVal *
5793669Sbinkertn@umich.edu                (divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]));
5803114Sgblack@eecs.umich.edu            // Schedule on the edge of the next tick plus the new count.
5813114Sgblack@eecs.umich.edu            Tick offset = curTick() % clock;
5823114Sgblack@eecs.umich.edu            if (offset) {
5833114Sgblack@eecs.umich.edu                reschedule(apicTimerEvent,
5843114Sgblack@eecs.umich.edu                        curTick() + (newCount + 1) * clock - offset, true);
5853114Sgblack@eecs.umich.edu            } else {
5862474SN/A                reschedule(apicTimerEvent,
5873669Sbinkertn@umich.edu                        curTick() + newCount * clock, true);
5882093SN/A            }
589360SN/A        }
5902423SN/A        break;
591360SN/A      case APIC_CURRENT_COUNT:
5922093SN/A        //Local APIC Current Count register is read only.
5932093SN/A        return;
5942093SN/A      case APIC_DIVIDE_CONFIGURATION:
5952093SN/A        newVal = val & 0xB;
5962093SN/A        break;
5972093SN/A      default:
5982093SN/A        break;
5992093SN/A    }
6002093SN/A    regs[reg] = newVal;
6012093SN/A    return;
602}
603
604
605X86ISA::Interrupts::Interrupts(Params * p) :
606    BasicPioDevice(p), IntDev(this, p->int_latency), latency(p->pio_latency),
607    clock(0),
608    apicTimerEvent(this),
609    pendingSmi(false), smiVector(0),
610    pendingNmi(false), nmiVector(0),
611    pendingExtInt(false), extIntVector(0),
612    pendingInit(false), initVector(0),
613    pendingStartup(false), startupVector(0),
614    startedUp(false), pendingUnmaskableInt(false),
615    pendingIPIs(0), cpu(NULL),
616    intSlavePort(name() + ".int_slave", this, this, latency)
617{
618    pioSize = PageBytes;
619    memset(regs, 0, sizeof(regs));
620    //Set the local apic DFR to the flat model.
621    regs[APIC_DESTINATION_FORMAT] = (uint32_t)(-1);
622    ISRV = 0;
623    IRRV = 0;
624}
625
626
627bool
628X86ISA::Interrupts::checkInterrupts(ThreadContext *tc) const
629{
630    RFLAGS rflags = tc->readMiscRegNoEffect(MISCREG_RFLAGS);
631    if (pendingUnmaskableInt) {
632        DPRINTF(LocalApic, "Reported pending unmaskable interrupt.\n");
633        return true;
634    }
635    if (rflags.intf) {
636        if (pendingExtInt) {
637            DPRINTF(LocalApic, "Reported pending external interrupt.\n");
638            return true;
639        }
640        if (IRRV > ISRV && bits(IRRV, 7, 4) >
641               bits(regs[APIC_TASK_PRIORITY], 7, 4)) {
642            DPRINTF(LocalApic, "Reported pending regular interrupt.\n");
643            return true;
644        }
645    }
646    return false;
647}
648
649Fault
650X86ISA::Interrupts::getInterrupt(ThreadContext *tc)
651{
652    assert(checkInterrupts(tc));
653    // These are all probably fairly uncommon, so we'll make them easier to
654    // check for.
655    if (pendingUnmaskableInt) {
656        if (pendingSmi) {
657            DPRINTF(LocalApic, "Generated SMI fault object.\n");
658            return new SystemManagementInterrupt();
659        } else if (pendingNmi) {
660            DPRINTF(LocalApic, "Generated NMI fault object.\n");
661            return new NonMaskableInterrupt(nmiVector);
662        } else if (pendingInit) {
663            DPRINTF(LocalApic, "Generated INIT fault object.\n");
664            return new InitInterrupt(initVector);
665        } else if (pendingStartup) {
666            DPRINTF(LocalApic, "Generating SIPI fault object.\n");
667            return new StartupInterrupt(startupVector);
668        } else {
669            panic("pendingUnmaskableInt set, but no unmaskable "
670                    "ints were pending.\n");
671            return NoFault;
672        }
673    } else if (pendingExtInt) {
674        DPRINTF(LocalApic, "Generated external interrupt fault object.\n");
675        return new ExternalInterrupt(extIntVector);
676    } else {
677        DPRINTF(LocalApic, "Generated regular interrupt fault object.\n");
678        // The only thing left are fixed and lowest priority interrupts.
679        return new ExternalInterrupt(IRRV);
680    }
681}
682
683void
684X86ISA::Interrupts::updateIntrInfo(ThreadContext *tc)
685{
686    assert(checkInterrupts(tc));
687    if (pendingUnmaskableInt) {
688        if (pendingSmi) {
689            DPRINTF(LocalApic, "SMI sent to core.\n");
690            pendingSmi = false;
691        } else if (pendingNmi) {
692            DPRINTF(LocalApic, "NMI sent to core.\n");
693            pendingNmi = false;
694        } else if (pendingInit) {
695            DPRINTF(LocalApic, "Init sent to core.\n");
696            pendingInit = false;
697            startedUp = false;
698        } else if (pendingStartup) {
699            DPRINTF(LocalApic, "SIPI sent to core.\n");
700            pendingStartup = false;
701            startedUp = true;
702        }
703        if (!(pendingSmi || pendingNmi || pendingInit || pendingStartup))
704            pendingUnmaskableInt = false;
705    } else if (pendingExtInt) {
706        pendingExtInt = false;
707    } else {
708        DPRINTF(LocalApic, "Interrupt %d sent to core.\n", IRRV);
709        // Mark the interrupt as "in service".
710        ISRV = IRRV;
711        setRegArrayBit(APIC_IN_SERVICE_BASE, ISRV);
712        // Clear it out of the IRR.
713        clearRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, IRRV);
714        updateIRRV();
715    }
716}
717
718void
719X86ISA::Interrupts::serialize(std::ostream &os)
720{
721    SERIALIZE_ARRAY(regs, NUM_APIC_REGS);
722    SERIALIZE_SCALAR(clock);
723    SERIALIZE_SCALAR(pendingSmi);
724    SERIALIZE_SCALAR(smiVector);
725    SERIALIZE_SCALAR(pendingNmi);
726    SERIALIZE_SCALAR(nmiVector);
727    SERIALIZE_SCALAR(pendingExtInt);
728    SERIALIZE_SCALAR(extIntVector);
729    SERIALIZE_SCALAR(pendingInit);
730    SERIALIZE_SCALAR(initVector);
731    SERIALIZE_SCALAR(pendingStartup);
732    SERIALIZE_SCALAR(startupVector);
733    SERIALIZE_SCALAR(startedUp);
734    SERIALIZE_SCALAR(pendingUnmaskableInt);
735    SERIALIZE_SCALAR(pendingIPIs);
736    SERIALIZE_SCALAR(IRRV);
737    SERIALIZE_SCALAR(ISRV);
738    bool apicTimerEventScheduled = apicTimerEvent.scheduled();
739    SERIALIZE_SCALAR(apicTimerEventScheduled);
740    Tick apicTimerEventTick = apicTimerEvent.when();
741    SERIALIZE_SCALAR(apicTimerEventTick);
742}
743
744void
745X86ISA::Interrupts::unserialize(Checkpoint *cp, const std::string &section)
746{
747    UNSERIALIZE_ARRAY(regs, NUM_APIC_REGS);
748    UNSERIALIZE_SCALAR(clock);
749    UNSERIALIZE_SCALAR(pendingSmi);
750    UNSERIALIZE_SCALAR(smiVector);
751    UNSERIALIZE_SCALAR(pendingNmi);
752    UNSERIALIZE_SCALAR(nmiVector);
753    UNSERIALIZE_SCALAR(pendingExtInt);
754    UNSERIALIZE_SCALAR(extIntVector);
755    UNSERIALIZE_SCALAR(pendingInit);
756    UNSERIALIZE_SCALAR(initVector);
757    UNSERIALIZE_SCALAR(pendingStartup);
758    UNSERIALIZE_SCALAR(startupVector);
759    UNSERIALIZE_SCALAR(startedUp);
760    UNSERIALIZE_SCALAR(pendingUnmaskableInt);
761    UNSERIALIZE_SCALAR(pendingIPIs);
762    UNSERIALIZE_SCALAR(IRRV);
763    UNSERIALIZE_SCALAR(ISRV);
764    bool apicTimerEventScheduled;
765    UNSERIALIZE_SCALAR(apicTimerEventScheduled);
766    if (apicTimerEventScheduled) {
767        Tick apicTimerEventTick;
768        UNSERIALIZE_SCALAR(apicTimerEventTick);
769        if (apicTimerEvent.scheduled()) {
770            reschedule(apicTimerEvent, apicTimerEventTick, true);
771        } else {
772            schedule(apicTimerEvent, apicTimerEventTick);
773        }
774    }
775}
776
777X86ISA::Interrupts *
778X86LocalApicParams::create()
779{
780    return new X86ISA::Interrupts(this);
781}
782