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