interrupts.cc revision 7823:dac01f14f20f
1/*
2 * Copyright (c) 2008 The Hewlett-Packard Development Company
3 * All rights reserved.
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Gabe Black
38 */
39
40#include "arch/x86/interrupts.hh"
41#include "arch/x86/intmessage.hh"
42#include "arch/x86/regs/apic.hh"
43#include "cpu/base.hh"
44#include "dev/x86/i82094aa.hh"
45#include "dev/x86/pc.hh"
46#include "dev/x86/south_bridge.hh"
47#include "mem/packet_access.hh"
48#include "sim/system.hh"
49
50int
51divideFromConf(uint32_t conf)
52{
53    // This figures out what division we want from the division configuration
54    // register in the local APIC. The encoding is a little odd but it can
55    // be deciphered fairly easily.
56    int shift = ((conf & 0x8) >> 1) | (conf & 0x3);
57    shift = (shift + 1) % 8;
58    return 1 << shift;
59}
60
61namespace X86ISA
62{
63
64ApicRegIndex
65decodeAddr(Addr paddr)
66{
67    ApicRegIndex regNum;
68    paddr &= ~mask(3);
69    switch (paddr)
70    {
71      case 0x20:
72        regNum = APIC_ID;
73        break;
74      case 0x30:
75        regNum = APIC_VERSION;
76        break;
77      case 0x80:
78        regNum = APIC_TASK_PRIORITY;
79        break;
80      case 0x90:
81        regNum = APIC_ARBITRATION_PRIORITY;
82        break;
83      case 0xA0:
84        regNum = APIC_PROCESSOR_PRIORITY;
85        break;
86      case 0xB0:
87        regNum = APIC_EOI;
88        break;
89      case 0xD0:
90        regNum = APIC_LOGICAL_DESTINATION;
91        break;
92      case 0xE0:
93        regNum = APIC_DESTINATION_FORMAT;
94        break;
95      case 0xF0:
96        regNum = APIC_SPURIOUS_INTERRUPT_VECTOR;
97        break;
98      case 0x100:
99      case 0x108:
100      case 0x110:
101      case 0x118:
102      case 0x120:
103      case 0x128:
104      case 0x130:
105      case 0x138:
106      case 0x140:
107      case 0x148:
108      case 0x150:
109      case 0x158:
110      case 0x160:
111      case 0x168:
112      case 0x170:
113      case 0x178:
114        regNum = APIC_IN_SERVICE((paddr - 0x100) / 0x8);
115        break;
116      case 0x180:
117      case 0x188:
118      case 0x190:
119      case 0x198:
120      case 0x1A0:
121      case 0x1A8:
122      case 0x1B0:
123      case 0x1B8:
124      case 0x1C0:
125      case 0x1C8:
126      case 0x1D0:
127      case 0x1D8:
128      case 0x1E0:
129      case 0x1E8:
130      case 0x1F0:
131      case 0x1F8:
132        regNum = APIC_TRIGGER_MODE((paddr - 0x180) / 0x8);
133        break;
134      case 0x200:
135      case 0x208:
136      case 0x210:
137      case 0x218:
138      case 0x220:
139      case 0x228:
140      case 0x230:
141      case 0x238:
142      case 0x240:
143      case 0x248:
144      case 0x250:
145      case 0x258:
146      case 0x260:
147      case 0x268:
148      case 0x270:
149      case 0x278:
150        regNum = APIC_INTERRUPT_REQUEST((paddr - 0x200) / 0x8);
151        break;
152      case 0x280:
153        regNum = APIC_ERROR_STATUS;
154        break;
155      case 0x300:
156        regNum = APIC_INTERRUPT_COMMAND_LOW;
157        break;
158      case 0x310:
159        regNum = APIC_INTERRUPT_COMMAND_HIGH;
160        break;
161      case 0x320:
162        regNum = APIC_LVT_TIMER;
163        break;
164      case 0x330:
165        regNum = APIC_LVT_THERMAL_SENSOR;
166        break;
167      case 0x340:
168        regNum = APIC_LVT_PERFORMANCE_MONITORING_COUNTERS;
169        break;
170      case 0x350:
171        regNum = APIC_LVT_LINT0;
172        break;
173      case 0x360:
174        regNum = APIC_LVT_LINT1;
175        break;
176      case 0x370:
177        regNum = APIC_LVT_ERROR;
178        break;
179      case 0x380:
180        regNum = APIC_INITIAL_COUNT;
181        break;
182      case 0x390:
183        regNum = APIC_CURRENT_COUNT;
184        break;
185      case 0x3E0:
186        regNum = APIC_DIVIDE_CONFIGURATION;
187        break;
188      default:
189        // A reserved register field.
190        panic("Accessed reserved register field %#x.\n", paddr);
191        break;
192    }
193    return regNum;
194}
195}
196
197Tick
198X86ISA::Interrupts::read(PacketPtr pkt)
199{
200    Addr offset = pkt->getAddr() - pioAddr;
201    //Make sure we're at least only accessing one register.
202    if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3)))
203        panic("Accessed more than one register at a time in the APIC!\n");
204    ApicRegIndex reg = decodeAddr(offset);
205    uint32_t val = htog(readReg(reg));
206    DPRINTF(LocalApic,
207            "Reading Local APIC register %d at offset %#x as %#x.\n",
208            reg, offset, val);
209    pkt->setData(((uint8_t *)&val) + (offset & mask(3)));
210    pkt->makeAtomicResponse();
211    return latency;
212}
213
214Tick
215X86ISA::Interrupts::write(PacketPtr pkt)
216{
217    Addr offset = pkt->getAddr() - pioAddr;
218    //Make sure we're at least only accessing one register.
219    if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3)))
220        panic("Accessed more than one register at a time in the APIC!\n");
221    ApicRegIndex reg = decodeAddr(offset);
222    uint32_t val = regs[reg];
223    pkt->writeData(((uint8_t *)&val) + (offset & mask(3)));
224    DPRINTF(LocalApic,
225            "Writing Local APIC register %d at offset %#x as %#x.\n",
226            reg, offset, gtoh(val));
227    setReg(reg, gtoh(val));
228    pkt->makeAtomicResponse();
229    return latency;
230}
231void
232X86ISA::Interrupts::requestInterrupt(uint8_t vector,
233        uint8_t deliveryMode, bool level)
234{
235    /*
236     * Fixed and lowest-priority delivery mode interrupts are handled
237     * using the IRR/ISR registers, checking against the TPR, etc.
238     * The SMI, NMI, ExtInt, INIT, etc interrupts go straight through.
239     */
240    if (deliveryMode == DeliveryMode::Fixed ||
241            deliveryMode == DeliveryMode::LowestPriority) {
242        DPRINTF(LocalApic, "Interrupt is an %s.\n",
243                DeliveryMode::names[deliveryMode]);
244        // Queue up the interrupt in the IRR.
245        if (vector > IRRV)
246            IRRV = vector;
247        if (!getRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, vector)) {
248            setRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, vector);
249            if (level) {
250                setRegArrayBit(APIC_TRIGGER_MODE_BASE, vector);
251            } else {
252                clearRegArrayBit(APIC_TRIGGER_MODE_BASE, vector);
253            }
254        }
255    } else if (!DeliveryMode::isReserved(deliveryMode)) {
256        DPRINTF(LocalApic, "Interrupt is an %s.\n",
257                DeliveryMode::names[deliveryMode]);
258        if (deliveryMode == DeliveryMode::SMI && !pendingSmi) {
259            pendingUnmaskableInt = pendingSmi = true;
260            smiVector = vector;
261        } else if (deliveryMode == DeliveryMode::NMI && !pendingNmi) {
262            pendingUnmaskableInt = pendingNmi = true;
263            nmiVector = vector;
264        } else if (deliveryMode == DeliveryMode::ExtInt && !pendingExtInt) {
265            pendingExtInt = true;
266            extIntVector = vector;
267        } else if (deliveryMode == DeliveryMode::INIT && !pendingInit) {
268            pendingUnmaskableInt = pendingInit = true;
269            initVector = vector;
270        } else if (deliveryMode == DeliveryMode::SIPI &&
271                !pendingStartup && !startedUp) {
272            pendingUnmaskableInt = pendingStartup = true;
273            startupVector = vector;
274        }
275    }
276    cpu->wakeup();
277}
278
279
280void
281X86ISA::Interrupts::setCPU(BaseCPU * newCPU)
282{
283    assert(newCPU);
284    if (cpu != NULL && cpu->cpuId() != newCPU->cpuId()) {
285        panic("Local APICs can't be moved between CPUs"
286                " with different IDs.\n");
287    }
288    cpu = newCPU;
289    initialApicId = cpu->cpuId();
290    regs[APIC_ID] = (initialApicId << 24);
291}
292
293
294void
295X86ISA::Interrupts::init()
296{
297    BasicPioDevice::init();
298    Pc * pc = dynamic_cast<Pc *>(platform);
299    assert(pc);
300    pc->southBridge->ioApic->registerLocalApic(initialApicId, this);
301}
302
303
304Tick
305X86ISA::Interrupts::recvMessage(PacketPtr pkt)
306{
307    Addr offset = pkt->getAddr() - x86InterruptAddress(initialApicId, 0);
308    assert(pkt->cmd == MemCmd::MessageReq);
309    switch(offset)
310    {
311      case 0:
312        {
313            TriggerIntMessage message = pkt->get<TriggerIntMessage>();
314            DPRINTF(LocalApic,
315                    "Got Trigger Interrupt message with vector %#x.\n",
316                    message.vector);
317
318            requestInterrupt(message.vector,
319                    message.deliveryMode, message.trigger);
320        }
321        break;
322      default:
323        panic("Local apic got unknown interrupt message at offset %#x.\n",
324                offset);
325        break;
326    }
327    pkt->makeAtomicResponse();
328    return latency;
329}
330
331
332Tick
333X86ISA::Interrupts::recvResponse(PacketPtr pkt)
334{
335    assert(!pkt->isError());
336    assert(pkt->cmd == MemCmd::MessageResp);
337    if (--pendingIPIs == 0) {
338        InterruptCommandRegLow low = regs[APIC_INTERRUPT_COMMAND_LOW];
339        // Record that the ICR is now idle.
340        low.deliveryStatus = 0;
341        regs[APIC_INTERRUPT_COMMAND_LOW] = low;
342    }
343    delete pkt->req;
344    delete pkt;
345    DPRINTF(LocalApic, "ICR is now idle.\n");
346    return 0;
347}
348
349
350void
351X86ISA::Interrupts::addressRanges(AddrRangeList &range_list)
352{
353    range_list.clear();
354    Range<Addr> range = RangeEx(x86LocalAPICAddress(initialApicId, 0),
355                                x86LocalAPICAddress(initialApicId, 0) +
356                                PageBytes);
357    range_list.push_back(range);
358    pioAddr = range.start;
359}
360
361
362void
363X86ISA::Interrupts::getIntAddrRange(AddrRangeList &range_list)
364{
365    range_list.clear();
366    range_list.push_back(RangeEx(x86InterruptAddress(initialApicId, 0),
367                x86InterruptAddress(initialApicId, 0) +
368                PhysAddrAPICRangeSize));
369}
370
371
372uint32_t
373X86ISA::Interrupts::readReg(ApicRegIndex reg)
374{
375    if (reg >= APIC_TRIGGER_MODE(0) &&
376            reg <= APIC_TRIGGER_MODE(15)) {
377        panic("Local APIC Trigger Mode registers are unimplemented.\n");
378    }
379    switch (reg) {
380      case APIC_ARBITRATION_PRIORITY:
381        panic("Local APIC Arbitration Priority register unimplemented.\n");
382        break;
383      case APIC_PROCESSOR_PRIORITY:
384        panic("Local APIC Processor Priority register unimplemented.\n");
385        break;
386      case APIC_ERROR_STATUS:
387        regs[APIC_INTERNAL_STATE] &= ~ULL(0x1);
388        break;
389      case APIC_CURRENT_COUNT:
390        {
391            if (apicTimerEvent.scheduled()) {
392                assert(clock);
393                // Compute how many m5 ticks happen per count.
394                uint64_t ticksPerCount = clock *
395                    divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]);
396                // Compute how many m5 ticks are left.
397                uint64_t val = apicTimerEvent.when() - curTick();
398                // Turn that into a count.
399                val = (val + ticksPerCount - 1) / ticksPerCount;
400                return val;
401            } else {
402                return 0;
403            }
404        }
405      default:
406        break;
407    }
408    return regs[reg];
409}
410
411void
412X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val)
413{
414    uint32_t newVal = val;
415    if (reg >= APIC_IN_SERVICE(0) &&
416            reg <= APIC_IN_SERVICE(15)) {
417        panic("Local APIC In-Service registers are unimplemented.\n");
418    }
419    if (reg >= APIC_TRIGGER_MODE(0) &&
420            reg <= APIC_TRIGGER_MODE(15)) {
421        panic("Local APIC Trigger Mode registers are unimplemented.\n");
422    }
423    if (reg >= APIC_INTERRUPT_REQUEST(0) &&
424            reg <= APIC_INTERRUPT_REQUEST(15)) {
425        panic("Local APIC Interrupt Request registers "
426                "are unimplemented.\n");
427    }
428    switch (reg) {
429      case APIC_ID:
430        newVal = val & 0xFF;
431        break;
432      case APIC_VERSION:
433        // The Local APIC Version register is read only.
434        return;
435      case APIC_TASK_PRIORITY:
436        newVal = val & 0xFF;
437        break;
438      case APIC_ARBITRATION_PRIORITY:
439        panic("Local APIC Arbitration Priority register unimplemented.\n");
440        break;
441      case APIC_PROCESSOR_PRIORITY:
442        panic("Local APIC Processor Priority register unimplemented.\n");
443        break;
444      case APIC_EOI:
445        // Remove the interrupt that just completed from the local apic state.
446        clearRegArrayBit(APIC_IN_SERVICE_BASE, ISRV);
447        updateISRV();
448        return;
449      case APIC_LOGICAL_DESTINATION:
450        newVal = val & 0xFF000000;
451        break;
452      case APIC_DESTINATION_FORMAT:
453        newVal = val | 0x0FFFFFFF;
454        break;
455      case APIC_SPURIOUS_INTERRUPT_VECTOR:
456        regs[APIC_INTERNAL_STATE] &= ~ULL(1 << 1);
457        regs[APIC_INTERNAL_STATE] |= val & (1 << 8);
458        if (val & (1 << 9))
459            warn("Focus processor checking not implemented.\n");
460        break;
461      case APIC_ERROR_STATUS:
462        {
463            if (regs[APIC_INTERNAL_STATE] & 0x1) {
464                regs[APIC_INTERNAL_STATE] &= ~ULL(0x1);
465                newVal = 0;
466            } else {
467                regs[APIC_INTERNAL_STATE] |= ULL(0x1);
468                return;
469            }
470
471        }
472        break;
473      case APIC_INTERRUPT_COMMAND_LOW:
474        {
475            InterruptCommandRegLow low = regs[APIC_INTERRUPT_COMMAND_LOW];
476            // Check if we're already sending an IPI.
477            if (low.deliveryStatus) {
478                newVal = low;
479                break;
480            }
481            low = val;
482            InterruptCommandRegHigh high = regs[APIC_INTERRUPT_COMMAND_HIGH];
483            // Record that an IPI is being sent.
484            low.deliveryStatus = 1;
485            TriggerIntMessage message = 0;
486            message.destination = high.destination;
487            message.vector = low.vector;
488            message.deliveryMode = low.deliveryMode;
489            message.destMode = low.destMode;
490            message.level = low.level;
491            message.trigger = low.trigger;
492            bool timing = sys->getMemoryMode() == Enums::timing;
493            // Be careful no updates of the delivery status bit get lost.
494            regs[APIC_INTERRUPT_COMMAND_LOW] = low;
495            ApicList apics;
496            int numContexts = sys->numContexts();
497            switch (low.destShorthand) {
498              case 0:
499                if (message.deliveryMode == DeliveryMode::LowestPriority) {
500                    panic("Lowest priority delivery mode "
501                            "IPIs aren't implemented.\n");
502                }
503                if (message.destMode == 1) {
504                    int dest = message.destination;
505                    hack_once("Assuming logical destinations are 1 << id.\n");
506                    for (int i = 0; i < numContexts; i++) {
507                        if (dest & 0x1)
508                            apics.push_back(i);
509                        dest = dest >> 1;
510                    }
511                } else {
512                    if (message.destination == 0xFF) {
513                        for (int i = 0; i < numContexts; i++) {
514                            if (i == initialApicId) {
515                                requestInterrupt(message.vector,
516                                        message.deliveryMode, message.trigger);
517                            } else {
518                                apics.push_back(i);
519                            }
520                        }
521                    } else {
522                        if (message.destination == initialApicId) {
523                            requestInterrupt(message.vector,
524                                    message.deliveryMode, message.trigger);
525                        } else {
526                            apics.push_back(message.destination);
527                        }
528                    }
529                }
530                break;
531              case 1:
532                newVal = val;
533                requestInterrupt(message.vector,
534                        message.deliveryMode, message.trigger);
535                break;
536              case 2:
537                requestInterrupt(message.vector,
538                        message.deliveryMode, message.trigger);
539                // Fall through
540              case 3:
541                {
542                    for (int i = 0; i < numContexts; i++) {
543                        if (i != initialApicId) {
544                            apics.push_back(i);
545                        }
546                    }
547                }
548                break;
549            }
550            pendingIPIs += apics.size();
551            intPort->sendMessage(apics, message, timing);
552            newVal = regs[APIC_INTERRUPT_COMMAND_LOW];
553        }
554        break;
555      case APIC_LVT_TIMER:
556      case APIC_LVT_THERMAL_SENSOR:
557      case APIC_LVT_PERFORMANCE_MONITORING_COUNTERS:
558      case APIC_LVT_LINT0:
559      case APIC_LVT_LINT1:
560      case APIC_LVT_ERROR:
561        {
562            uint64_t readOnlyMask = (1 << 12) | (1 << 14);
563            newVal = (val & ~readOnlyMask) |
564                     (regs[reg] & readOnlyMask);
565        }
566        break;
567      case APIC_INITIAL_COUNT:
568        {
569            assert(clock);
570            newVal = bits(val, 31, 0);
571            // Compute how many timer ticks we're being programmed for.
572            uint64_t newCount = newVal *
573                (divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]));
574            // Schedule on the edge of the next tick plus the new count.
575            Tick offset = curTick() % clock;
576            if (offset) {
577                reschedule(apicTimerEvent,
578                        curTick() + (newCount + 1) * clock - offset, true);
579            } else {
580                reschedule(apicTimerEvent,
581                        curTick() + newCount * clock, true);
582            }
583        }
584        break;
585      case APIC_CURRENT_COUNT:
586        //Local APIC Current Count register is read only.
587        return;
588      case APIC_DIVIDE_CONFIGURATION:
589        newVal = val & 0xB;
590        break;
591      default:
592        break;
593    }
594    regs[reg] = newVal;
595    return;
596}
597
598
599X86ISA::Interrupts::Interrupts(Params * p) :
600    BasicPioDevice(p), IntDev(this), latency(p->pio_latency), clock(0),
601    apicTimerEvent(this),
602    pendingSmi(false), smiVector(0),
603    pendingNmi(false), nmiVector(0),
604    pendingExtInt(false), extIntVector(0),
605    pendingInit(false), initVector(0),
606    pendingStartup(false), startupVector(0),
607    startedUp(false), pendingUnmaskableInt(false),
608    pendingIPIs(0), cpu(NULL)
609{
610    pioSize = PageBytes;
611    memset(regs, 0, sizeof(regs));
612    //Set the local apic DFR to the flat model.
613    regs[APIC_DESTINATION_FORMAT] = (uint32_t)(-1);
614    ISRV = 0;
615    IRRV = 0;
616}
617
618
619bool
620X86ISA::Interrupts::checkInterrupts(ThreadContext *tc) const
621{
622    RFLAGS rflags = tc->readMiscRegNoEffect(MISCREG_RFLAGS);
623    if (pendingUnmaskableInt) {
624        DPRINTF(LocalApic, "Reported pending unmaskable interrupt.\n");
625        return true;
626    }
627    if (rflags.intf) {
628        if (pendingExtInt) {
629            DPRINTF(LocalApic, "Reported pending external interrupt.\n");
630            return true;
631        }
632        if (IRRV > ISRV && bits(IRRV, 7, 4) >
633               bits(regs[APIC_TASK_PRIORITY], 7, 4)) {
634            DPRINTF(LocalApic, "Reported pending regular interrupt.\n");
635            return true;
636        }
637    }
638    return false;
639}
640
641Fault
642X86ISA::Interrupts::getInterrupt(ThreadContext *tc)
643{
644    assert(checkInterrupts(tc));
645    // These are all probably fairly uncommon, so we'll make them easier to
646    // check for.
647    if (pendingUnmaskableInt) {
648        if (pendingSmi) {
649            DPRINTF(LocalApic, "Generated SMI fault object.\n");
650            return new SystemManagementInterrupt();
651        } else if (pendingNmi) {
652            DPRINTF(LocalApic, "Generated NMI fault object.\n");
653            return new NonMaskableInterrupt(nmiVector);
654        } else if (pendingInit) {
655            DPRINTF(LocalApic, "Generated INIT fault object.\n");
656            return new InitInterrupt(initVector);
657        } else if (pendingStartup) {
658            DPRINTF(LocalApic, "Generating SIPI fault object.\n");
659            return new StartupInterrupt(startupVector);
660        } else {
661            panic("pendingUnmaskableInt set, but no unmaskable "
662                    "ints were pending.\n");
663            return NoFault;
664        }
665    } else if (pendingExtInt) {
666        DPRINTF(LocalApic, "Generated external interrupt fault object.\n");
667        return new ExternalInterrupt(extIntVector);
668    } else {
669        DPRINTF(LocalApic, "Generated regular interrupt fault object.\n");
670        // The only thing left are fixed and lowest priority interrupts.
671        return new ExternalInterrupt(IRRV);
672    }
673}
674
675void
676X86ISA::Interrupts::updateIntrInfo(ThreadContext *tc)
677{
678    assert(checkInterrupts(tc));
679    if (pendingUnmaskableInt) {
680        if (pendingSmi) {
681            DPRINTF(LocalApic, "SMI sent to core.\n");
682            pendingSmi = false;
683        } else if (pendingNmi) {
684            DPRINTF(LocalApic, "NMI sent to core.\n");
685            pendingNmi = false;
686        } else if (pendingInit) {
687            DPRINTF(LocalApic, "Init sent to core.\n");
688            pendingInit = false;
689            startedUp = false;
690        } else if (pendingStartup) {
691            DPRINTF(LocalApic, "SIPI sent to core.\n");
692            pendingStartup = false;
693            startedUp = true;
694        }
695        if (!(pendingSmi || pendingNmi || pendingInit || pendingStartup))
696            pendingUnmaskableInt = false;
697    } else if (pendingExtInt) {
698        pendingExtInt = false;
699    } else {
700        DPRINTF(LocalApic, "Interrupt %d sent to core.\n", IRRV);
701        // Mark the interrupt as "in service".
702        ISRV = IRRV;
703        setRegArrayBit(APIC_IN_SERVICE_BASE, ISRV);
704        // Clear it out of the IRR.
705        clearRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, IRRV);
706        updateIRRV();
707    }
708}
709
710X86ISA::Interrupts *
711X86LocalApicParams::create()
712{
713    return new X86ISA::Interrupts(this);
714}
715