interrupts.cc revision 10542:7be879ff600c
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) 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 §ion) 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} 793