Deleted Added
sdiff udiff text old ( 11479:8b23edf06cd3 ) new ( 11793:ef606668d247 )
full compact
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}