interrupts.cc (10542:7be879ff600c) interrupts.cc (10905:a6ca6831e775)
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 0x108:
116 case 0x110:
117 case 0x118:
118 case 0x120:
119 case 0x128:
120 case 0x130:
121 case 0x138:
122 case 0x140:
123 case 0x148:
124 case 0x150:
125 case 0x158:
126 case 0x160:
127 case 0x168:
128 case 0x170:
129 case 0x178:
130 regNum = APIC_IN_SERVICE((paddr - 0x100) / 0x8);
131 break;
132 case 0x180:
133 case 0x188:
134 case 0x190:
135 case 0x198:
136 case 0x1A0:
137 case 0x1A8:
138 case 0x1B0:
139 case 0x1B8:
140 case 0x1C0:
141 case 0x1C8:
142 case 0x1D0:
143 case 0x1D8:
144 case 0x1E0:
145 case 0x1E8:
146 case 0x1F0:
147 case 0x1F8:
148 regNum = APIC_TRIGGER_MODE((paddr - 0x180) / 0x8);
149 break;
150 case 0x200:
151 case 0x208:
152 case 0x210:
153 case 0x218:
154 case 0x220:
155 case 0x228:
156 case 0x230:
157 case 0x238:
158 case 0x240:
159 case 0x248:
160 case 0x250:
161 case 0x258:
162 case 0x260:
163 case 0x268:
164 case 0x270:
165 case 0x278:
166 regNum = APIC_INTERRUPT_REQUEST((paddr - 0x200) / 0x8);
167 break;
168 case 0x280:
169 regNum = APIC_ERROR_STATUS;
170 break;
171 case 0x300:
172 regNum = APIC_INTERRUPT_COMMAND_LOW;
173 break;
174 case 0x310:
175 regNum = APIC_INTERRUPT_COMMAND_HIGH;
176 break;
177 case 0x320:
178 regNum = APIC_LVT_TIMER;
179 break;
180 case 0x330:
181 regNum = APIC_LVT_THERMAL_SENSOR;
182 break;
183 case 0x340:
184 regNum = APIC_LVT_PERFORMANCE_MONITORING_COUNTERS;
185 break;
186 case 0x350:
187 regNum = APIC_LVT_LINT0;
188 break;
189 case 0x360:
190 regNum = APIC_LVT_LINT1;
191 break;
192 case 0x370:
193 regNum = APIC_LVT_ERROR;
194 break;
195 case 0x380:
196 regNum = APIC_INITIAL_COUNT;
197 break;
198 case 0x390:
199 regNum = APIC_CURRENT_COUNT;
200 break;
201 case 0x3E0:
202 regNum = APIC_DIVIDE_CONFIGURATION;
203 break;
204 default:
205 // A reserved register field.
206 panic("Accessed reserved register field %#x.\n", paddr);
207 break;
208 }
209 return regNum;
210}
211}
212
213Tick
214X86ISA::Interrupts::read(PacketPtr pkt)
215{
216 Addr offset = pkt->getAddr() - pioAddr;
217 //Make sure we're at least only accessing one register.
218 if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3)))
219 panic("Accessed more than one register at a time in the APIC!\n");
220 ApicRegIndex reg = decodeAddr(offset);
221 uint32_t val = htog(readReg(reg));
222 DPRINTF(LocalApic,
223 "Reading Local APIC register %d at offset %#x as %#x.\n",
224 reg, offset, val);
225 pkt->setData(((uint8_t *)&val) + (offset & mask(3)));
226 pkt->makeAtomicResponse();
227 return pioDelay;
228}
229
230Tick
231X86ISA::Interrupts::write(PacketPtr pkt)
232{
233 Addr offset = pkt->getAddr() - pioAddr;
234 //Make sure we're at least only accessing one register.
235 if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3)))
236 panic("Accessed more than one register at a time in the APIC!\n");
237 ApicRegIndex reg = decodeAddr(offset);
238 uint32_t val = regs[reg];
239 pkt->writeData(((uint8_t *)&val) + (offset & mask(3)));
240 DPRINTF(LocalApic,
241 "Writing Local APIC register %d at offset %#x as %#x.\n",
242 reg, offset, gtoh(val));
243 setReg(reg, gtoh(val));
244 pkt->makeAtomicResponse();
245 return pioDelay;
246}
247void
248X86ISA::Interrupts::requestInterrupt(uint8_t vector,
249 uint8_t deliveryMode, bool level)
250{
251 /*
252 * Fixed and lowest-priority delivery mode interrupts are handled
253 * using the IRR/ISR registers, checking against the TPR, etc.
254 * The SMI, NMI, ExtInt, INIT, etc interrupts go straight through.
255 */
256 if (deliveryMode == DeliveryMode::Fixed ||
257 deliveryMode == DeliveryMode::LowestPriority) {
258 DPRINTF(LocalApic, "Interrupt is an %s.\n",
259 DeliveryMode::names[deliveryMode]);
260 // Queue up the interrupt in the IRR.
261 if (vector > IRRV)
262 IRRV = vector;
263 if (!getRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, vector)) {
264 setRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, vector);
265 if (level) {
266 setRegArrayBit(APIC_TRIGGER_MODE_BASE, vector);
267 } else {
268 clearRegArrayBit(APIC_TRIGGER_MODE_BASE, vector);
269 }
270 }
271 } else if (!DeliveryMode::isReserved(deliveryMode)) {
272 DPRINTF(LocalApic, "Interrupt is an %s.\n",
273 DeliveryMode::names[deliveryMode]);
274 if (deliveryMode == DeliveryMode::SMI && !pendingSmi) {
275 pendingUnmaskableInt = pendingSmi = true;
276 smiVector = vector;
277 } else if (deliveryMode == DeliveryMode::NMI && !pendingNmi) {
278 pendingUnmaskableInt = pendingNmi = true;
279 nmiVector = vector;
280 } else if (deliveryMode == DeliveryMode::ExtInt && !pendingExtInt) {
281 pendingExtInt = true;
282 extIntVector = vector;
283 } else if (deliveryMode == DeliveryMode::INIT && !pendingInit) {
284 pendingUnmaskableInt = pendingInit = true;
285 initVector = vector;
286 } else if (deliveryMode == DeliveryMode::SIPI &&
287 !pendingStartup && !startedUp) {
288 pendingUnmaskableInt = pendingStartup = true;
289 startupVector = vector;
290 }
291 }
292 if (FullSystem)
293 cpu->wakeup();
294}
295
296
297void
298X86ISA::Interrupts::setCPU(BaseCPU * newCPU)
299{
300 assert(newCPU);
301 if (cpu != NULL && cpu->cpuId() != newCPU->cpuId()) {
302 panic("Local APICs can't be moved between CPUs"
303 " with different IDs.\n");
304 }
305 cpu = newCPU;
306 initialApicId = cpu->cpuId();
307 regs[APIC_ID] = (initialApicId << 24);
308 pioAddr = x86LocalAPICAddress(initialApicId, 0);
309}
310
311
312void
313X86ISA::Interrupts::init()
314{
315 //
316 // The local apic must register its address ranges on both its pio
317 // port via the basicpiodevice(piodevice) init() function and its
318 // int port that it inherited from IntDevice. Note IntDevice is
319 // not a SimObject itself.
320 //
321 BasicPioDevice::init();
322 IntDevice::init();
323
324 // the slave port has a range so inform the connected master
325 intSlavePort.sendRangeChange();
326}
327
328
329Tick
330X86ISA::Interrupts::recvMessage(PacketPtr pkt)
331{
332 Addr offset = pkt->getAddr() - x86InterruptAddress(initialApicId, 0);
333 assert(pkt->cmd == MemCmd::MessageReq);
334 switch(offset)
335 {
336 case 0:
337 {
338 TriggerIntMessage message = pkt->get<TriggerIntMessage>();
339 DPRINTF(LocalApic,
340 "Got Trigger Interrupt message with vector %#x.\n",
341 message.vector);
342
343 requestInterrupt(message.vector,
344 message.deliveryMode, message.trigger);
345 }
346 break;
347 default:
348 panic("Local apic got unknown interrupt message at offset %#x.\n",
349 offset);
350 break;
351 }
352 pkt->makeAtomicResponse();
353 return pioDelay;
354}
355
356
357Tick
358X86ISA::Interrupts::recvResponse(PacketPtr pkt)
359{
360 assert(!pkt->isError());
361 assert(pkt->cmd == MemCmd::MessageResp);
362 if (--pendingIPIs == 0) {
363 InterruptCommandRegLow low = regs[APIC_INTERRUPT_COMMAND_LOW];
364 // Record that the ICR is now idle.
365 low.deliveryStatus = 0;
366 regs[APIC_INTERRUPT_COMMAND_LOW] = low;
367 }
368 DPRINTF(LocalApic, "ICR is now idle.\n");
369 return 0;
370}
371
372
373AddrRangeList
374X86ISA::Interrupts::getIntAddrRange() const
375{
376 AddrRangeList ranges;
377 ranges.push_back(RangeEx(x86InterruptAddress(initialApicId, 0),
378 x86InterruptAddress(initialApicId, 0) +
379 PhysAddrAPICRangeSize));
380 return ranges;
381}
382
383
384uint32_t
385X86ISA::Interrupts::readReg(ApicRegIndex reg)
386{
387 if (reg >= APIC_TRIGGER_MODE(0) &&
388 reg <= APIC_TRIGGER_MODE(15)) {
389 panic("Local APIC Trigger Mode registers are unimplemented.\n");
390 }
391 switch (reg) {
392 case APIC_ARBITRATION_PRIORITY:
393 panic("Local APIC Arbitration Priority register unimplemented.\n");
394 break;
395 case APIC_PROCESSOR_PRIORITY:
396 panic("Local APIC Processor Priority register unimplemented.\n");
397 break;
398 case APIC_ERROR_STATUS:
399 regs[APIC_INTERNAL_STATE] &= ~ULL(0x1);
400 break;
401 case APIC_CURRENT_COUNT:
402 {
403 if (apicTimerEvent.scheduled()) {
404 // Compute how many m5 ticks happen per count.
405 uint64_t ticksPerCount = clockPeriod() *
406 divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]);
407 // Compute how many m5 ticks are left.
408 uint64_t val = apicTimerEvent.when() - curTick();
409 // Turn that into a count.
410 val = (val + ticksPerCount - 1) / ticksPerCount;
411 return val;
412 } else {
413 return 0;
414 }
415 }
416 default:
417 break;
418 }
419 return regs[reg];
420}
421
422void
423X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val)
424{
425 uint32_t newVal = val;
426 if (reg >= APIC_IN_SERVICE(0) &&
427 reg <= APIC_IN_SERVICE(15)) {
428 panic("Local APIC In-Service registers are unimplemented.\n");
429 }
430 if (reg >= APIC_TRIGGER_MODE(0) &&
431 reg <= APIC_TRIGGER_MODE(15)) {
432 panic("Local APIC Trigger Mode registers are unimplemented.\n");
433 }
434 if (reg >= APIC_INTERRUPT_REQUEST(0) &&
435 reg <= APIC_INTERRUPT_REQUEST(15)) {
436 panic("Local APIC Interrupt Request registers "
437 "are unimplemented.\n");
438 }
439 switch (reg) {
440 case APIC_ID:
441 newVal = val & 0xFF;
442 break;
443 case APIC_VERSION:
444 // The Local APIC Version register is read only.
445 return;
446 case APIC_TASK_PRIORITY:
447 newVal = val & 0xFF;
448 break;
449 case APIC_ARBITRATION_PRIORITY:
450 panic("Local APIC Arbitration Priority register unimplemented.\n");
451 break;
452 case APIC_PROCESSOR_PRIORITY:
453 panic("Local APIC Processor Priority register unimplemented.\n");
454 break;
455 case APIC_EOI:
456 // Remove the interrupt that just completed from the local apic state.
457 clearRegArrayBit(APIC_IN_SERVICE_BASE, ISRV);
458 updateISRV();
459 return;
460 case APIC_LOGICAL_DESTINATION:
461 newVal = val & 0xFF000000;
462 break;
463 case APIC_DESTINATION_FORMAT:
464 newVal = val | 0x0FFFFFFF;
465 break;
466 case APIC_SPURIOUS_INTERRUPT_VECTOR:
467 regs[APIC_INTERNAL_STATE] &= ~ULL(1 << 1);
468 regs[APIC_INTERNAL_STATE] |= val & (1 << 8);
469 if (val & (1 << 9))
470 warn("Focus processor checking not implemented.\n");
471 break;
472 case APIC_ERROR_STATUS:
473 {
474 if (regs[APIC_INTERNAL_STATE] & 0x1) {
475 regs[APIC_INTERNAL_STATE] &= ~ULL(0x1);
476 newVal = 0;
477 } else {
478 regs[APIC_INTERNAL_STATE] |= ULL(0x1);
479 return;
480 }
481
482 }
483 break;
484 case APIC_INTERRUPT_COMMAND_LOW:
485 {
486 InterruptCommandRegLow low = regs[APIC_INTERRUPT_COMMAND_LOW];
487 // Check if we're already sending an IPI.
488 if (low.deliveryStatus) {
489 newVal = low;
490 break;
491 }
492 low = val;
493 InterruptCommandRegHigh high = regs[APIC_INTERRUPT_COMMAND_HIGH];
494 TriggerIntMessage message = 0;
495 message.destination = high.destination;
496 message.vector = low.vector;
497 message.deliveryMode = low.deliveryMode;
498 message.destMode = low.destMode;
499 message.level = low.level;
500 message.trigger = low.trigger;
501 ApicList apics;
502 int numContexts = sys->numContexts();
503 switch (low.destShorthand) {
504 case 0:
505 if (message.deliveryMode == DeliveryMode::LowestPriority) {
506 panic("Lowest priority delivery mode "
507 "IPIs aren't implemented.\n");
508 }
509 if (message.destMode == 1) {
510 int dest = message.destination;
511 hack_once("Assuming logical destinations are 1 << id.\n");
512 for (int i = 0; i < numContexts; i++) {
513 if (dest & 0x1)
514 apics.push_back(i);
515 dest = dest >> 1;
516 }
517 } else {
518 if (message.destination == 0xFF) {
519 for (int i = 0; i < numContexts; i++) {
520 if (i == initialApicId) {
521 requestInterrupt(message.vector,
522 message.deliveryMode, message.trigger);
523 } else {
524 apics.push_back(i);
525 }
526 }
527 } else {
528 if (message.destination == initialApicId) {
529 requestInterrupt(message.vector,
530 message.deliveryMode, message.trigger);
531 } else {
532 apics.push_back(message.destination);
533 }
534 }
535 }
536 break;
537 case 1:
538 newVal = val;
539 requestInterrupt(message.vector,
540 message.deliveryMode, message.trigger);
541 break;
542 case 2:
543 requestInterrupt(message.vector,
544 message.deliveryMode, message.trigger);
545 // Fall through
546 case 3:
547 {
548 for (int i = 0; i < numContexts; i++) {
549 if (i != initialApicId) {
550 apics.push_back(i);
551 }
552 }
553 }
554 break;
555 }
556 // Record that an IPI is being sent if one actually is.
557 if (apics.size()) {
558 low.deliveryStatus = 1;
559 pendingIPIs += apics.size();
560 }
561 regs[APIC_INTERRUPT_COMMAND_LOW] = low;
562 intMasterPort.sendMessage(apics, message, sys->isTimingMode());
563 newVal = regs[APIC_INTERRUPT_COMMAND_LOW];
564 }
565 break;
566 case APIC_LVT_TIMER:
567 case APIC_LVT_THERMAL_SENSOR:
568 case APIC_LVT_PERFORMANCE_MONITORING_COUNTERS:
569 case APIC_LVT_LINT0:
570 case APIC_LVT_LINT1:
571 case APIC_LVT_ERROR:
572 {
573 uint64_t readOnlyMask = (1 << 12) | (1 << 14);
574 newVal = (val & ~readOnlyMask) |
575 (regs[reg] & readOnlyMask);
576 }
577 break;
578 case APIC_INITIAL_COUNT:
579 {
580 newVal = bits(val, 31, 0);
581 // Compute how many timer ticks we're being programmed for.
582 uint64_t newCount = newVal *
583 (divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]));
584 // Schedule on the edge of the next tick plus the new count.
585 Tick offset = curTick() % clockPeriod();
586 if (offset) {
587 reschedule(apicTimerEvent,
588 curTick() + (newCount + 1) *
589 clockPeriod() - offset, true);
590 } else {
591 if (newCount)
592 reschedule(apicTimerEvent,
593 curTick() + newCount *
594 clockPeriod(), true);
595 }
596 }
597 break;
598 case APIC_CURRENT_COUNT:
599 //Local APIC Current Count register is read only.
600 return;
601 case APIC_DIVIDE_CONFIGURATION:
602 newVal = val & 0xB;
603 break;
604 default:
605 break;
606 }
607 regs[reg] = newVal;
608 return;
609}
610
611
612X86ISA::Interrupts::Interrupts(Params * p)
613 : BasicPioDevice(p, PageBytes), IntDevice(this, p->int_latency),
614 apicTimerEvent(this),
615 pendingSmi(false), smiVector(0),
616 pendingNmi(false), nmiVector(0),
617 pendingExtInt(false), extIntVector(0),
618 pendingInit(false), initVector(0),
619 pendingStartup(false), startupVector(0),
620 startedUp(false), pendingUnmaskableInt(false),
621 pendingIPIs(0), cpu(NULL),
622 intSlavePort(name() + ".int_slave", this, this)
623{
624 memset(regs, 0, sizeof(regs));
625 //Set the local apic DFR to the flat model.
626 regs[APIC_DESTINATION_FORMAT] = (uint32_t)(-1);
627 ISRV = 0;
628 IRRV = 0;
629}
630
631
632bool
633X86ISA::Interrupts::checkInterrupts(ThreadContext *tc) const
634{
635 RFLAGS rflags = tc->readMiscRegNoEffect(MISCREG_RFLAGS);
636 if (pendingUnmaskableInt) {
637 DPRINTF(LocalApic, "Reported pending unmaskable interrupt.\n");
638 return true;
639 }
640 if (rflags.intf) {
641 if (pendingExtInt) {
642 DPRINTF(LocalApic, "Reported pending external interrupt.\n");
643 return true;
644 }
645 if (IRRV > ISRV && bits(IRRV, 7, 4) >
646 bits(regs[APIC_TASK_PRIORITY], 7, 4)) {
647 DPRINTF(LocalApic, "Reported pending regular interrupt.\n");
648 return true;
649 }
650 }
651 return false;
652}
653
654bool
655X86ISA::Interrupts::checkInterruptsRaw() const
656{
657 return pendingUnmaskableInt || pendingExtInt ||
658 (IRRV > ISRV && bits(IRRV, 7, 4) >
659 bits(regs[APIC_TASK_PRIORITY], 7, 4));
660}
661
662Fault
663X86ISA::Interrupts::getInterrupt(ThreadContext *tc)
664{
665 assert(checkInterrupts(tc));
666 // These are all probably fairly uncommon, so we'll make them easier to
667 // check for.
668 if (pendingUnmaskableInt) {
669 if (pendingSmi) {
670 DPRINTF(LocalApic, "Generated SMI fault object.\n");
671 return std::make_shared<SystemManagementInterrupt>();
672 } else if (pendingNmi) {
673 DPRINTF(LocalApic, "Generated NMI fault object.\n");
674 return std::make_shared<NonMaskableInterrupt>(nmiVector);
675 } else if (pendingInit) {
676 DPRINTF(LocalApic, "Generated INIT fault object.\n");
677 return std::make_shared<InitInterrupt>(initVector);
678 } else if (pendingStartup) {
679 DPRINTF(LocalApic, "Generating SIPI fault object.\n");
680 return std::make_shared<StartupInterrupt>(startupVector);
681 } else {
682 panic("pendingUnmaskableInt set, but no unmaskable "
683 "ints were pending.\n");
684 return NoFault;
685 }
686 } else if (pendingExtInt) {
687 DPRINTF(LocalApic, "Generated external interrupt fault object.\n");
688 return std::make_shared<ExternalInterrupt>(extIntVector);
689 } else {
690 DPRINTF(LocalApic, "Generated regular interrupt fault object.\n");
691 // The only thing left are fixed and lowest priority interrupts.
692 return std::make_shared<ExternalInterrupt>(IRRV);
693 }
694}
695
696void
697X86ISA::Interrupts::updateIntrInfo(ThreadContext *tc)
698{
699 assert(checkInterrupts(tc));
700 if (pendingUnmaskableInt) {
701 if (pendingSmi) {
702 DPRINTF(LocalApic, "SMI sent to core.\n");
703 pendingSmi = false;
704 } else if (pendingNmi) {
705 DPRINTF(LocalApic, "NMI sent to core.\n");
706 pendingNmi = false;
707 } else if (pendingInit) {
708 DPRINTF(LocalApic, "Init sent to core.\n");
709 pendingInit = false;
710 startedUp = false;
711 } else if (pendingStartup) {
712 DPRINTF(LocalApic, "SIPI sent to core.\n");
713 pendingStartup = false;
714 startedUp = true;
715 }
716 if (!(pendingSmi || pendingNmi || pendingInit || pendingStartup))
717 pendingUnmaskableInt = false;
718 } else if (pendingExtInt) {
719 pendingExtInt = false;
720 } else {
721 DPRINTF(LocalApic, "Interrupt %d sent to core.\n", IRRV);
722 // Mark the interrupt as "in service".
723 ISRV = IRRV;
724 setRegArrayBit(APIC_IN_SERVICE_BASE, ISRV);
725 // Clear it out of the IRR.
726 clearRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, IRRV);
727 updateIRRV();
728 }
729}
730
731void
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 0x108:
116 case 0x110:
117 case 0x118:
118 case 0x120:
119 case 0x128:
120 case 0x130:
121 case 0x138:
122 case 0x140:
123 case 0x148:
124 case 0x150:
125 case 0x158:
126 case 0x160:
127 case 0x168:
128 case 0x170:
129 case 0x178:
130 regNum = APIC_IN_SERVICE((paddr - 0x100) / 0x8);
131 break;
132 case 0x180:
133 case 0x188:
134 case 0x190:
135 case 0x198:
136 case 0x1A0:
137 case 0x1A8:
138 case 0x1B0:
139 case 0x1B8:
140 case 0x1C0:
141 case 0x1C8:
142 case 0x1D0:
143 case 0x1D8:
144 case 0x1E0:
145 case 0x1E8:
146 case 0x1F0:
147 case 0x1F8:
148 regNum = APIC_TRIGGER_MODE((paddr - 0x180) / 0x8);
149 break;
150 case 0x200:
151 case 0x208:
152 case 0x210:
153 case 0x218:
154 case 0x220:
155 case 0x228:
156 case 0x230:
157 case 0x238:
158 case 0x240:
159 case 0x248:
160 case 0x250:
161 case 0x258:
162 case 0x260:
163 case 0x268:
164 case 0x270:
165 case 0x278:
166 regNum = APIC_INTERRUPT_REQUEST((paddr - 0x200) / 0x8);
167 break;
168 case 0x280:
169 regNum = APIC_ERROR_STATUS;
170 break;
171 case 0x300:
172 regNum = APIC_INTERRUPT_COMMAND_LOW;
173 break;
174 case 0x310:
175 regNum = APIC_INTERRUPT_COMMAND_HIGH;
176 break;
177 case 0x320:
178 regNum = APIC_LVT_TIMER;
179 break;
180 case 0x330:
181 regNum = APIC_LVT_THERMAL_SENSOR;
182 break;
183 case 0x340:
184 regNum = APIC_LVT_PERFORMANCE_MONITORING_COUNTERS;
185 break;
186 case 0x350:
187 regNum = APIC_LVT_LINT0;
188 break;
189 case 0x360:
190 regNum = APIC_LVT_LINT1;
191 break;
192 case 0x370:
193 regNum = APIC_LVT_ERROR;
194 break;
195 case 0x380:
196 regNum = APIC_INITIAL_COUNT;
197 break;
198 case 0x390:
199 regNum = APIC_CURRENT_COUNT;
200 break;
201 case 0x3E0:
202 regNum = APIC_DIVIDE_CONFIGURATION;
203 break;
204 default:
205 // A reserved register field.
206 panic("Accessed reserved register field %#x.\n", paddr);
207 break;
208 }
209 return regNum;
210}
211}
212
213Tick
214X86ISA::Interrupts::read(PacketPtr pkt)
215{
216 Addr offset = pkt->getAddr() - pioAddr;
217 //Make sure we're at least only accessing one register.
218 if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3)))
219 panic("Accessed more than one register at a time in the APIC!\n");
220 ApicRegIndex reg = decodeAddr(offset);
221 uint32_t val = htog(readReg(reg));
222 DPRINTF(LocalApic,
223 "Reading Local APIC register %d at offset %#x as %#x.\n",
224 reg, offset, val);
225 pkt->setData(((uint8_t *)&val) + (offset & mask(3)));
226 pkt->makeAtomicResponse();
227 return pioDelay;
228}
229
230Tick
231X86ISA::Interrupts::write(PacketPtr pkt)
232{
233 Addr offset = pkt->getAddr() - pioAddr;
234 //Make sure we're at least only accessing one register.
235 if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3)))
236 panic("Accessed more than one register at a time in the APIC!\n");
237 ApicRegIndex reg = decodeAddr(offset);
238 uint32_t val = regs[reg];
239 pkt->writeData(((uint8_t *)&val) + (offset & mask(3)));
240 DPRINTF(LocalApic,
241 "Writing Local APIC register %d at offset %#x as %#x.\n",
242 reg, offset, gtoh(val));
243 setReg(reg, gtoh(val));
244 pkt->makeAtomicResponse();
245 return pioDelay;
246}
247void
248X86ISA::Interrupts::requestInterrupt(uint8_t vector,
249 uint8_t deliveryMode, bool level)
250{
251 /*
252 * Fixed and lowest-priority delivery mode interrupts are handled
253 * using the IRR/ISR registers, checking against the TPR, etc.
254 * The SMI, NMI, ExtInt, INIT, etc interrupts go straight through.
255 */
256 if (deliveryMode == DeliveryMode::Fixed ||
257 deliveryMode == DeliveryMode::LowestPriority) {
258 DPRINTF(LocalApic, "Interrupt is an %s.\n",
259 DeliveryMode::names[deliveryMode]);
260 // Queue up the interrupt in the IRR.
261 if (vector > IRRV)
262 IRRV = vector;
263 if (!getRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, vector)) {
264 setRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, vector);
265 if (level) {
266 setRegArrayBit(APIC_TRIGGER_MODE_BASE, vector);
267 } else {
268 clearRegArrayBit(APIC_TRIGGER_MODE_BASE, vector);
269 }
270 }
271 } else if (!DeliveryMode::isReserved(deliveryMode)) {
272 DPRINTF(LocalApic, "Interrupt is an %s.\n",
273 DeliveryMode::names[deliveryMode]);
274 if (deliveryMode == DeliveryMode::SMI && !pendingSmi) {
275 pendingUnmaskableInt = pendingSmi = true;
276 smiVector = vector;
277 } else if (deliveryMode == DeliveryMode::NMI && !pendingNmi) {
278 pendingUnmaskableInt = pendingNmi = true;
279 nmiVector = vector;
280 } else if (deliveryMode == DeliveryMode::ExtInt && !pendingExtInt) {
281 pendingExtInt = true;
282 extIntVector = vector;
283 } else if (deliveryMode == DeliveryMode::INIT && !pendingInit) {
284 pendingUnmaskableInt = pendingInit = true;
285 initVector = vector;
286 } else if (deliveryMode == DeliveryMode::SIPI &&
287 !pendingStartup && !startedUp) {
288 pendingUnmaskableInt = pendingStartup = true;
289 startupVector = vector;
290 }
291 }
292 if (FullSystem)
293 cpu->wakeup();
294}
295
296
297void
298X86ISA::Interrupts::setCPU(BaseCPU * newCPU)
299{
300 assert(newCPU);
301 if (cpu != NULL && cpu->cpuId() != newCPU->cpuId()) {
302 panic("Local APICs can't be moved between CPUs"
303 " with different IDs.\n");
304 }
305 cpu = newCPU;
306 initialApicId = cpu->cpuId();
307 regs[APIC_ID] = (initialApicId << 24);
308 pioAddr = x86LocalAPICAddress(initialApicId, 0);
309}
310
311
312void
313X86ISA::Interrupts::init()
314{
315 //
316 // The local apic must register its address ranges on both its pio
317 // port via the basicpiodevice(piodevice) init() function and its
318 // int port that it inherited from IntDevice. Note IntDevice is
319 // not a SimObject itself.
320 //
321 BasicPioDevice::init();
322 IntDevice::init();
323
324 // the slave port has a range so inform the connected master
325 intSlavePort.sendRangeChange();
326}
327
328
329Tick
330X86ISA::Interrupts::recvMessage(PacketPtr pkt)
331{
332 Addr offset = pkt->getAddr() - x86InterruptAddress(initialApicId, 0);
333 assert(pkt->cmd == MemCmd::MessageReq);
334 switch(offset)
335 {
336 case 0:
337 {
338 TriggerIntMessage message = pkt->get<TriggerIntMessage>();
339 DPRINTF(LocalApic,
340 "Got Trigger Interrupt message with vector %#x.\n",
341 message.vector);
342
343 requestInterrupt(message.vector,
344 message.deliveryMode, message.trigger);
345 }
346 break;
347 default:
348 panic("Local apic got unknown interrupt message at offset %#x.\n",
349 offset);
350 break;
351 }
352 pkt->makeAtomicResponse();
353 return pioDelay;
354}
355
356
357Tick
358X86ISA::Interrupts::recvResponse(PacketPtr pkt)
359{
360 assert(!pkt->isError());
361 assert(pkt->cmd == MemCmd::MessageResp);
362 if (--pendingIPIs == 0) {
363 InterruptCommandRegLow low = regs[APIC_INTERRUPT_COMMAND_LOW];
364 // Record that the ICR is now idle.
365 low.deliveryStatus = 0;
366 regs[APIC_INTERRUPT_COMMAND_LOW] = low;
367 }
368 DPRINTF(LocalApic, "ICR is now idle.\n");
369 return 0;
370}
371
372
373AddrRangeList
374X86ISA::Interrupts::getIntAddrRange() const
375{
376 AddrRangeList ranges;
377 ranges.push_back(RangeEx(x86InterruptAddress(initialApicId, 0),
378 x86InterruptAddress(initialApicId, 0) +
379 PhysAddrAPICRangeSize));
380 return ranges;
381}
382
383
384uint32_t
385X86ISA::Interrupts::readReg(ApicRegIndex reg)
386{
387 if (reg >= APIC_TRIGGER_MODE(0) &&
388 reg <= APIC_TRIGGER_MODE(15)) {
389 panic("Local APIC Trigger Mode registers are unimplemented.\n");
390 }
391 switch (reg) {
392 case APIC_ARBITRATION_PRIORITY:
393 panic("Local APIC Arbitration Priority register unimplemented.\n");
394 break;
395 case APIC_PROCESSOR_PRIORITY:
396 panic("Local APIC Processor Priority register unimplemented.\n");
397 break;
398 case APIC_ERROR_STATUS:
399 regs[APIC_INTERNAL_STATE] &= ~ULL(0x1);
400 break;
401 case APIC_CURRENT_COUNT:
402 {
403 if (apicTimerEvent.scheduled()) {
404 // Compute how many m5 ticks happen per count.
405 uint64_t ticksPerCount = clockPeriod() *
406 divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]);
407 // Compute how many m5 ticks are left.
408 uint64_t val = apicTimerEvent.when() - curTick();
409 // Turn that into a count.
410 val = (val + ticksPerCount - 1) / ticksPerCount;
411 return val;
412 } else {
413 return 0;
414 }
415 }
416 default:
417 break;
418 }
419 return regs[reg];
420}
421
422void
423X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val)
424{
425 uint32_t newVal = val;
426 if (reg >= APIC_IN_SERVICE(0) &&
427 reg <= APIC_IN_SERVICE(15)) {
428 panic("Local APIC In-Service registers are unimplemented.\n");
429 }
430 if (reg >= APIC_TRIGGER_MODE(0) &&
431 reg <= APIC_TRIGGER_MODE(15)) {
432 panic("Local APIC Trigger Mode registers are unimplemented.\n");
433 }
434 if (reg >= APIC_INTERRUPT_REQUEST(0) &&
435 reg <= APIC_INTERRUPT_REQUEST(15)) {
436 panic("Local APIC Interrupt Request registers "
437 "are unimplemented.\n");
438 }
439 switch (reg) {
440 case APIC_ID:
441 newVal = val & 0xFF;
442 break;
443 case APIC_VERSION:
444 // The Local APIC Version register is read only.
445 return;
446 case APIC_TASK_PRIORITY:
447 newVal = val & 0xFF;
448 break;
449 case APIC_ARBITRATION_PRIORITY:
450 panic("Local APIC Arbitration Priority register unimplemented.\n");
451 break;
452 case APIC_PROCESSOR_PRIORITY:
453 panic("Local APIC Processor Priority register unimplemented.\n");
454 break;
455 case APIC_EOI:
456 // Remove the interrupt that just completed from the local apic state.
457 clearRegArrayBit(APIC_IN_SERVICE_BASE, ISRV);
458 updateISRV();
459 return;
460 case APIC_LOGICAL_DESTINATION:
461 newVal = val & 0xFF000000;
462 break;
463 case APIC_DESTINATION_FORMAT:
464 newVal = val | 0x0FFFFFFF;
465 break;
466 case APIC_SPURIOUS_INTERRUPT_VECTOR:
467 regs[APIC_INTERNAL_STATE] &= ~ULL(1 << 1);
468 regs[APIC_INTERNAL_STATE] |= val & (1 << 8);
469 if (val & (1 << 9))
470 warn("Focus processor checking not implemented.\n");
471 break;
472 case APIC_ERROR_STATUS:
473 {
474 if (regs[APIC_INTERNAL_STATE] & 0x1) {
475 regs[APIC_INTERNAL_STATE] &= ~ULL(0x1);
476 newVal = 0;
477 } else {
478 regs[APIC_INTERNAL_STATE] |= ULL(0x1);
479 return;
480 }
481
482 }
483 break;
484 case APIC_INTERRUPT_COMMAND_LOW:
485 {
486 InterruptCommandRegLow low = regs[APIC_INTERRUPT_COMMAND_LOW];
487 // Check if we're already sending an IPI.
488 if (low.deliveryStatus) {
489 newVal = low;
490 break;
491 }
492 low = val;
493 InterruptCommandRegHigh high = regs[APIC_INTERRUPT_COMMAND_HIGH];
494 TriggerIntMessage message = 0;
495 message.destination = high.destination;
496 message.vector = low.vector;
497 message.deliveryMode = low.deliveryMode;
498 message.destMode = low.destMode;
499 message.level = low.level;
500 message.trigger = low.trigger;
501 ApicList apics;
502 int numContexts = sys->numContexts();
503 switch (low.destShorthand) {
504 case 0:
505 if (message.deliveryMode == DeliveryMode::LowestPriority) {
506 panic("Lowest priority delivery mode "
507 "IPIs aren't implemented.\n");
508 }
509 if (message.destMode == 1) {
510 int dest = message.destination;
511 hack_once("Assuming logical destinations are 1 << id.\n");
512 for (int i = 0; i < numContexts; i++) {
513 if (dest & 0x1)
514 apics.push_back(i);
515 dest = dest >> 1;
516 }
517 } else {
518 if (message.destination == 0xFF) {
519 for (int i = 0; i < numContexts; i++) {
520 if (i == initialApicId) {
521 requestInterrupt(message.vector,
522 message.deliveryMode, message.trigger);
523 } else {
524 apics.push_back(i);
525 }
526 }
527 } else {
528 if (message.destination == initialApicId) {
529 requestInterrupt(message.vector,
530 message.deliveryMode, message.trigger);
531 } else {
532 apics.push_back(message.destination);
533 }
534 }
535 }
536 break;
537 case 1:
538 newVal = val;
539 requestInterrupt(message.vector,
540 message.deliveryMode, message.trigger);
541 break;
542 case 2:
543 requestInterrupt(message.vector,
544 message.deliveryMode, message.trigger);
545 // Fall through
546 case 3:
547 {
548 for (int i = 0; i < numContexts; i++) {
549 if (i != initialApicId) {
550 apics.push_back(i);
551 }
552 }
553 }
554 break;
555 }
556 // Record that an IPI is being sent if one actually is.
557 if (apics.size()) {
558 low.deliveryStatus = 1;
559 pendingIPIs += apics.size();
560 }
561 regs[APIC_INTERRUPT_COMMAND_LOW] = low;
562 intMasterPort.sendMessage(apics, message, sys->isTimingMode());
563 newVal = regs[APIC_INTERRUPT_COMMAND_LOW];
564 }
565 break;
566 case APIC_LVT_TIMER:
567 case APIC_LVT_THERMAL_SENSOR:
568 case APIC_LVT_PERFORMANCE_MONITORING_COUNTERS:
569 case APIC_LVT_LINT0:
570 case APIC_LVT_LINT1:
571 case APIC_LVT_ERROR:
572 {
573 uint64_t readOnlyMask = (1 << 12) | (1 << 14);
574 newVal = (val & ~readOnlyMask) |
575 (regs[reg] & readOnlyMask);
576 }
577 break;
578 case APIC_INITIAL_COUNT:
579 {
580 newVal = bits(val, 31, 0);
581 // Compute how many timer ticks we're being programmed for.
582 uint64_t newCount = newVal *
583 (divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]));
584 // Schedule on the edge of the next tick plus the new count.
585 Tick offset = curTick() % clockPeriod();
586 if (offset) {
587 reschedule(apicTimerEvent,
588 curTick() + (newCount + 1) *
589 clockPeriod() - offset, true);
590 } else {
591 if (newCount)
592 reschedule(apicTimerEvent,
593 curTick() + newCount *
594 clockPeriod(), true);
595 }
596 }
597 break;
598 case APIC_CURRENT_COUNT:
599 //Local APIC Current Count register is read only.
600 return;
601 case APIC_DIVIDE_CONFIGURATION:
602 newVal = val & 0xB;
603 break;
604 default:
605 break;
606 }
607 regs[reg] = newVal;
608 return;
609}
610
611
612X86ISA::Interrupts::Interrupts(Params * p)
613 : BasicPioDevice(p, PageBytes), IntDevice(this, p->int_latency),
614 apicTimerEvent(this),
615 pendingSmi(false), smiVector(0),
616 pendingNmi(false), nmiVector(0),
617 pendingExtInt(false), extIntVector(0),
618 pendingInit(false), initVector(0),
619 pendingStartup(false), startupVector(0),
620 startedUp(false), pendingUnmaskableInt(false),
621 pendingIPIs(0), cpu(NULL),
622 intSlavePort(name() + ".int_slave", this, this)
623{
624 memset(regs, 0, sizeof(regs));
625 //Set the local apic DFR to the flat model.
626 regs[APIC_DESTINATION_FORMAT] = (uint32_t)(-1);
627 ISRV = 0;
628 IRRV = 0;
629}
630
631
632bool
633X86ISA::Interrupts::checkInterrupts(ThreadContext *tc) const
634{
635 RFLAGS rflags = tc->readMiscRegNoEffect(MISCREG_RFLAGS);
636 if (pendingUnmaskableInt) {
637 DPRINTF(LocalApic, "Reported pending unmaskable interrupt.\n");
638 return true;
639 }
640 if (rflags.intf) {
641 if (pendingExtInt) {
642 DPRINTF(LocalApic, "Reported pending external interrupt.\n");
643 return true;
644 }
645 if (IRRV > ISRV && bits(IRRV, 7, 4) >
646 bits(regs[APIC_TASK_PRIORITY], 7, 4)) {
647 DPRINTF(LocalApic, "Reported pending regular interrupt.\n");
648 return true;
649 }
650 }
651 return false;
652}
653
654bool
655X86ISA::Interrupts::checkInterruptsRaw() const
656{
657 return pendingUnmaskableInt || pendingExtInt ||
658 (IRRV > ISRV && bits(IRRV, 7, 4) >
659 bits(regs[APIC_TASK_PRIORITY], 7, 4));
660}
661
662Fault
663X86ISA::Interrupts::getInterrupt(ThreadContext *tc)
664{
665 assert(checkInterrupts(tc));
666 // These are all probably fairly uncommon, so we'll make them easier to
667 // check for.
668 if (pendingUnmaskableInt) {
669 if (pendingSmi) {
670 DPRINTF(LocalApic, "Generated SMI fault object.\n");
671 return std::make_shared<SystemManagementInterrupt>();
672 } else if (pendingNmi) {
673 DPRINTF(LocalApic, "Generated NMI fault object.\n");
674 return std::make_shared<NonMaskableInterrupt>(nmiVector);
675 } else if (pendingInit) {
676 DPRINTF(LocalApic, "Generated INIT fault object.\n");
677 return std::make_shared<InitInterrupt>(initVector);
678 } else if (pendingStartup) {
679 DPRINTF(LocalApic, "Generating SIPI fault object.\n");
680 return std::make_shared<StartupInterrupt>(startupVector);
681 } else {
682 panic("pendingUnmaskableInt set, but no unmaskable "
683 "ints were pending.\n");
684 return NoFault;
685 }
686 } else if (pendingExtInt) {
687 DPRINTF(LocalApic, "Generated external interrupt fault object.\n");
688 return std::make_shared<ExternalInterrupt>(extIntVector);
689 } else {
690 DPRINTF(LocalApic, "Generated regular interrupt fault object.\n");
691 // The only thing left are fixed and lowest priority interrupts.
692 return std::make_shared<ExternalInterrupt>(IRRV);
693 }
694}
695
696void
697X86ISA::Interrupts::updateIntrInfo(ThreadContext *tc)
698{
699 assert(checkInterrupts(tc));
700 if (pendingUnmaskableInt) {
701 if (pendingSmi) {
702 DPRINTF(LocalApic, "SMI sent to core.\n");
703 pendingSmi = false;
704 } else if (pendingNmi) {
705 DPRINTF(LocalApic, "NMI sent to core.\n");
706 pendingNmi = false;
707 } else if (pendingInit) {
708 DPRINTF(LocalApic, "Init sent to core.\n");
709 pendingInit = false;
710 startedUp = false;
711 } else if (pendingStartup) {
712 DPRINTF(LocalApic, "SIPI sent to core.\n");
713 pendingStartup = false;
714 startedUp = true;
715 }
716 if (!(pendingSmi || pendingNmi || pendingInit || pendingStartup))
717 pendingUnmaskableInt = false;
718 } else if (pendingExtInt) {
719 pendingExtInt = false;
720 } else {
721 DPRINTF(LocalApic, "Interrupt %d sent to core.\n", IRRV);
722 // Mark the interrupt as "in service".
723 ISRV = IRRV;
724 setRegArrayBit(APIC_IN_SERVICE_BASE, ISRV);
725 // Clear it out of the IRR.
726 clearRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, IRRV);
727 updateIRRV();
728 }
729}
730
731void
732X86ISA::Interrupts::serialize(std::ostream &os)
732X86ISA::Interrupts::serialize(CheckpointOut &cp) const
733{
734 SERIALIZE_ARRAY(regs, NUM_APIC_REGS);
735 SERIALIZE_SCALAR(pendingSmi);
736 SERIALIZE_SCALAR(smiVector);
737 SERIALIZE_SCALAR(pendingNmi);
738 SERIALIZE_SCALAR(nmiVector);
739 SERIALIZE_SCALAR(pendingExtInt);
740 SERIALIZE_SCALAR(extIntVector);
741 SERIALIZE_SCALAR(pendingInit);
742 SERIALIZE_SCALAR(initVector);
743 SERIALIZE_SCALAR(pendingStartup);
744 SERIALIZE_SCALAR(startupVector);
745 SERIALIZE_SCALAR(startedUp);
746 SERIALIZE_SCALAR(pendingUnmaskableInt);
747 SERIALIZE_SCALAR(pendingIPIs);
748 SERIALIZE_SCALAR(IRRV);
749 SERIALIZE_SCALAR(ISRV);
750 bool apicTimerEventScheduled = apicTimerEvent.scheduled();
751 SERIALIZE_SCALAR(apicTimerEventScheduled);
752 Tick apicTimerEventTick = apicTimerEvent.when();
753 SERIALIZE_SCALAR(apicTimerEventTick);
754}
755
756void
733{
734 SERIALIZE_ARRAY(regs, NUM_APIC_REGS);
735 SERIALIZE_SCALAR(pendingSmi);
736 SERIALIZE_SCALAR(smiVector);
737 SERIALIZE_SCALAR(pendingNmi);
738 SERIALIZE_SCALAR(nmiVector);
739 SERIALIZE_SCALAR(pendingExtInt);
740 SERIALIZE_SCALAR(extIntVector);
741 SERIALIZE_SCALAR(pendingInit);
742 SERIALIZE_SCALAR(initVector);
743 SERIALIZE_SCALAR(pendingStartup);
744 SERIALIZE_SCALAR(startupVector);
745 SERIALIZE_SCALAR(startedUp);
746 SERIALIZE_SCALAR(pendingUnmaskableInt);
747 SERIALIZE_SCALAR(pendingIPIs);
748 SERIALIZE_SCALAR(IRRV);
749 SERIALIZE_SCALAR(ISRV);
750 bool apicTimerEventScheduled = apicTimerEvent.scheduled();
751 SERIALIZE_SCALAR(apicTimerEventScheduled);
752 Tick apicTimerEventTick = apicTimerEvent.when();
753 SERIALIZE_SCALAR(apicTimerEventTick);
754}
755
756void
757X86ISA::Interrupts::unserialize(Checkpoint *cp, const std::string &section)
757X86ISA::Interrupts::unserialize(CheckpointIn &cp)
758{
759 UNSERIALIZE_ARRAY(regs, NUM_APIC_REGS);
760 UNSERIALIZE_SCALAR(pendingSmi);
761 UNSERIALIZE_SCALAR(smiVector);
762 UNSERIALIZE_SCALAR(pendingNmi);
763 UNSERIALIZE_SCALAR(nmiVector);
764 UNSERIALIZE_SCALAR(pendingExtInt);
765 UNSERIALIZE_SCALAR(extIntVector);
766 UNSERIALIZE_SCALAR(pendingInit);
767 UNSERIALIZE_SCALAR(initVector);
768 UNSERIALIZE_SCALAR(pendingStartup);
769 UNSERIALIZE_SCALAR(startupVector);
770 UNSERIALIZE_SCALAR(startedUp);
771 UNSERIALIZE_SCALAR(pendingUnmaskableInt);
772 UNSERIALIZE_SCALAR(pendingIPIs);
773 UNSERIALIZE_SCALAR(IRRV);
774 UNSERIALIZE_SCALAR(ISRV);
775 bool apicTimerEventScheduled;
776 UNSERIALIZE_SCALAR(apicTimerEventScheduled);
777 if (apicTimerEventScheduled) {
778 Tick apicTimerEventTick;
779 UNSERIALIZE_SCALAR(apicTimerEventTick);
780 if (apicTimerEvent.scheduled()) {
781 reschedule(apicTimerEvent, apicTimerEventTick, true);
782 } else {
783 schedule(apicTimerEvent, apicTimerEventTick);
784 }
785 }
786}
787
788X86ISA::Interrupts *
789X86LocalApicParams::create()
790{
791 return new X86ISA::Interrupts(this);
792}
758{
759 UNSERIALIZE_ARRAY(regs, NUM_APIC_REGS);
760 UNSERIALIZE_SCALAR(pendingSmi);
761 UNSERIALIZE_SCALAR(smiVector);
762 UNSERIALIZE_SCALAR(pendingNmi);
763 UNSERIALIZE_SCALAR(nmiVector);
764 UNSERIALIZE_SCALAR(pendingExtInt);
765 UNSERIALIZE_SCALAR(extIntVector);
766 UNSERIALIZE_SCALAR(pendingInit);
767 UNSERIALIZE_SCALAR(initVector);
768 UNSERIALIZE_SCALAR(pendingStartup);
769 UNSERIALIZE_SCALAR(startupVector);
770 UNSERIALIZE_SCALAR(startedUp);
771 UNSERIALIZE_SCALAR(pendingUnmaskableInt);
772 UNSERIALIZE_SCALAR(pendingIPIs);
773 UNSERIALIZE_SCALAR(IRRV);
774 UNSERIALIZE_SCALAR(ISRV);
775 bool apicTimerEventScheduled;
776 UNSERIALIZE_SCALAR(apicTimerEventScheduled);
777 if (apicTimerEventScheduled) {
778 Tick apicTimerEventTick;
779 UNSERIALIZE_SCALAR(apicTimerEventTick);
780 if (apicTimerEvent.scheduled()) {
781 reschedule(apicTimerEvent, apicTimerEventTick, true);
782 } else {
783 schedule(apicTimerEvent, apicTimerEventTick);
784 }
785 }
786}
787
788X86ISA::Interrupts *
789X86LocalApicParams::create()
790{
791 return new X86ISA::Interrupts(this);
792}