interrupts.cc (11151:ca4ea9b5c052) interrupts.cc (11479:8b23edf06cd3)
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:
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:
115 case 0x110:
117 case 0x118:
118 case 0x120:
116 case 0x120:
119 case 0x128:
120 case 0x130:
117 case 0x130:
121 case 0x138:
122 case 0x140:
118 case 0x140:
123 case 0x148:
124 case 0x150:
119 case 0x150:
125 case 0x158:
126 case 0x160:
120 case 0x160:
127 case 0x168:
128 case 0x170:
121 case 0x170:
129 case 0x178:
130 regNum = APIC_IN_SERVICE((paddr - 0x100) / 0x8);
122 regNum = APIC_IN_SERVICE((paddr - 0x100) / 0x10);
131 break;
132 case 0x180:
123 break;
124 case 0x180:
133 case 0x188:
134 case 0x190:
125 case 0x190:
135 case 0x198:
136 case 0x1A0:
126 case 0x1A0:
137 case 0x1A8:
138 case 0x1B0:
127 case 0x1B0:
139 case 0x1B8:
140 case 0x1C0:
128 case 0x1C0:
141 case 0x1C8:
142 case 0x1D0:
129 case 0x1D0:
143 case 0x1D8:
144 case 0x1E0:
130 case 0x1E0:
145 case 0x1E8:
146 case 0x1F0:
131 case 0x1F0:
147 case 0x1F8:
148 regNum = APIC_TRIGGER_MODE((paddr - 0x180) / 0x8);
132 regNum = APIC_TRIGGER_MODE((paddr - 0x180) / 0x10);
149 break;
150 case 0x200:
133 break;
134 case 0x200:
151 case 0x208:
152 case 0x210:
135 case 0x210:
153 case 0x218:
154 case 0x220:
136 case 0x220:
155 case 0x228:
156 case 0x230:
137 case 0x230:
157 case 0x238:
158 case 0x240:
138 case 0x240:
159 case 0x248:
160 case 0x250:
139 case 0x250:
161 case 0x258:
162 case 0x260:
140 case 0x260:
163 case 0x268:
164 case 0x270:
141 case 0x270:
165 case 0x278:
166 regNum = APIC_INTERRUPT_REQUEST((paddr - 0x200) / 0x8);
142 regNum = APIC_INTERRUPT_REQUEST((paddr - 0x200) / 0x10);
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(0);
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(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
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}
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}