interrupts.cc revision 5691
112855Sgabeblack@google.com/* 212855Sgabeblack@google.com * Copyright (c) 2008 The Hewlett-Packard Development Company 312855Sgabeblack@google.com * All rights reserved. 412855Sgabeblack@google.com * 512855Sgabeblack@google.com * Redistribution and use of this software in source and binary forms, 612855Sgabeblack@google.com * with or without modification, are permitted provided that the 712855Sgabeblack@google.com * following conditions are met: 812855Sgabeblack@google.com * 912855Sgabeblack@google.com * The software must be used only for Non-Commercial Use which means any 1012855Sgabeblack@google.com * use which is NOT directed to receiving any direct monetary 1112855Sgabeblack@google.com * compensation for, or commercial advantage from such use. Illustrative 1212855Sgabeblack@google.com * examples of non-commercial use are academic research, personal study, 1312855Sgabeblack@google.com * teaching, education and corporate research & development. 1412855Sgabeblack@google.com * Illustrative examples of commercial use are distributing products for 1512855Sgabeblack@google.com * commercial advantage and providing services using the software for 1612855Sgabeblack@google.com * commercial advantage. 1712855Sgabeblack@google.com * 1812855Sgabeblack@google.com * If you wish to use this software or functionality therein that may be 1912855Sgabeblack@google.com * covered by patents for commercial use, please contact: 2012855Sgabeblack@google.com * Director of Intellectual Property Licensing 2112855Sgabeblack@google.com * Office of Strategy and Technology 2212855Sgabeblack@google.com * Hewlett-Packard Company 2312855Sgabeblack@google.com * 1501 Page Mill Road 2412855Sgabeblack@google.com * Palo Alto, California 94304 2512855Sgabeblack@google.com * 2612855Sgabeblack@google.com * Redistributions of source code must retain the above copyright notice, 2712855Sgabeblack@google.com * this list of conditions and the following disclaimer. Redistributions 2812855Sgabeblack@google.com * in binary form must reproduce the above copyright notice, this list of 2912855Sgabeblack@google.com * conditions and the following disclaimer in the documentation and/or 3012855Sgabeblack@google.com * other materials provided with the distribution. Neither the name of 3112855Sgabeblack@google.com * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its 3212855Sgabeblack@google.com * contributors may be used to endorse or promote products derived from 3312855Sgabeblack@google.com * this software without specific prior written permission. No right of 3412855Sgabeblack@google.com * sublicense is granted herewith. Derivatives of the software and 3512855Sgabeblack@google.com * output created using the software may be prepared, but only for 3612855Sgabeblack@google.com * Non-Commercial Uses. Derivatives of the software may be shared with 3712855Sgabeblack@google.com * others provided: (i) the others agree to abide by the list of 3812855Sgabeblack@google.com * conditions herein which includes the Non-Commercial Use restrictions; 3912855Sgabeblack@google.com * and (ii) such Derivatives of the software include the above copyright 4012855Sgabeblack@google.com * notice to acknowledge the contribution from this software where 4112855Sgabeblack@google.com * applicable, this list of conditions and the disclaimer below. 4212855Sgabeblack@google.com * 4312855Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 4412855Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 4512855Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 4612855Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 4712855Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 4812855Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 4912855Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 5012855Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 5112855Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 5212855Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 5312855Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 5412855Sgabeblack@google.com * 5512855Sgabeblack@google.com * Authors: Gabe Black 5612855Sgabeblack@google.com */ 5712855Sgabeblack@google.com 5812855Sgabeblack@google.com#include "arch/x86/apicregs.hh" 5912855Sgabeblack@google.com#include "arch/x86/interrupts.hh" 6012855Sgabeblack@google.com#include "arch/x86/intmessage.hh" 6112855Sgabeblack@google.com#include "cpu/base.hh" 6212855Sgabeblack@google.com#include "mem/packet_access.hh" 6312855Sgabeblack@google.com 6412855Sgabeblack@google.comint 6512855Sgabeblack@google.comdivideFromConf(uint32_t conf) 6612855Sgabeblack@google.com{ 6712855Sgabeblack@google.com // This figures out what division we want from the division configuration 6812855Sgabeblack@google.com // register in the local APIC. The encoding is a little odd but it can 6912855Sgabeblack@google.com // be deciphered fairly easily. 7012855Sgabeblack@google.com int shift = ((conf & 0x8) >> 1) | (conf & 0x3); 7112855Sgabeblack@google.com shift = (shift + 1) % 8; 7212855Sgabeblack@google.com return 1 << shift; 7312855Sgabeblack@google.com} 7412855Sgabeblack@google.com 7512855Sgabeblack@google.comnamespace X86ISA 7612855Sgabeblack@google.com{ 7712855Sgabeblack@google.com 7812855Sgabeblack@google.comApicRegIndex 7912855Sgabeblack@google.comdecodeAddr(Addr paddr) 8012855Sgabeblack@google.com{ 8112855Sgabeblack@google.com ApicRegIndex regNum; 8212855Sgabeblack@google.com paddr &= ~mask(3); 8312855Sgabeblack@google.com switch (paddr) 8412855Sgabeblack@google.com { 8512855Sgabeblack@google.com case 0x20: 8612855Sgabeblack@google.com regNum = APIC_ID; 8712855Sgabeblack@google.com break; 8812855Sgabeblack@google.com case 0x30: 8912855Sgabeblack@google.com regNum = APIC_VERSION; 9012855Sgabeblack@google.com break; 9112855Sgabeblack@google.com case 0x80: 9212855Sgabeblack@google.com regNum = APIC_TASK_PRIORITY; 9312855Sgabeblack@google.com break; 9412855Sgabeblack@google.com case 0x90: 9512855Sgabeblack@google.com regNum = APIC_ARBITRATION_PRIORITY; 9612855Sgabeblack@google.com break; 9712855Sgabeblack@google.com case 0xA0: 9812855Sgabeblack@google.com regNum = APIC_PROCESSOR_PRIORITY; 9912855Sgabeblack@google.com break; 10012855Sgabeblack@google.com case 0xB0: 10112855Sgabeblack@google.com regNum = APIC_EOI; 10212855Sgabeblack@google.com break; 10312855Sgabeblack@google.com case 0xD0: 10412855Sgabeblack@google.com regNum = APIC_LOGICAL_DESTINATION; 10512855Sgabeblack@google.com break; 10612855Sgabeblack@google.com case 0xE0: 10712855Sgabeblack@google.com regNum = APIC_DESTINATION_FORMAT; 10812855Sgabeblack@google.com break; 10912855Sgabeblack@google.com case 0xF0: 11012855Sgabeblack@google.com regNum = APIC_SPURIOUS_INTERRUPT_VECTOR; 11112855Sgabeblack@google.com break; 11212855Sgabeblack@google.com case 0x100: 11312855Sgabeblack@google.com case 0x108: 11412855Sgabeblack@google.com case 0x110: 11512855Sgabeblack@google.com case 0x118: 11612855Sgabeblack@google.com case 0x120: 11712855Sgabeblack@google.com case 0x128: 11812855Sgabeblack@google.com case 0x130: 11912855Sgabeblack@google.com case 0x138: 12012855Sgabeblack@google.com case 0x140: 12112855Sgabeblack@google.com case 0x148: 12212855Sgabeblack@google.com case 0x150: 12312855Sgabeblack@google.com case 0x158: 12412855Sgabeblack@google.com case 0x160: 12512855Sgabeblack@google.com case 0x168: 12612855Sgabeblack@google.com case 0x170: 12712855Sgabeblack@google.com case 0x178: 12812855Sgabeblack@google.com regNum = APIC_IN_SERVICE((paddr - 0x100) / 0x8); 12912855Sgabeblack@google.com break; 13012855Sgabeblack@google.com case 0x180: 13112855Sgabeblack@google.com case 0x188: 13212855Sgabeblack@google.com case 0x190: 13312855Sgabeblack@google.com case 0x198: 13412855Sgabeblack@google.com case 0x1A0: 13512855Sgabeblack@google.com case 0x1A8: 13612855Sgabeblack@google.com case 0x1B0: 13712855Sgabeblack@google.com case 0x1B8: 13812855Sgabeblack@google.com case 0x1C0: 13912855Sgabeblack@google.com case 0x1C8: 14012855Sgabeblack@google.com case 0x1D0: 14112855Sgabeblack@google.com case 0x1D8: 14212855Sgabeblack@google.com case 0x1E0: 14312855Sgabeblack@google.com case 0x1E8: 14412855Sgabeblack@google.com case 0x1F0: 14512855Sgabeblack@google.com case 0x1F8: 14612855Sgabeblack@google.com regNum = APIC_TRIGGER_MODE((paddr - 0x180) / 0x8); 14712855Sgabeblack@google.com break; 14812855Sgabeblack@google.com case 0x200: 14912855Sgabeblack@google.com case 0x208: 15012855Sgabeblack@google.com case 0x210: 15112855Sgabeblack@google.com case 0x218: 15212855Sgabeblack@google.com case 0x220: 15312855Sgabeblack@google.com case 0x228: 15412855Sgabeblack@google.com case 0x230: 15512855Sgabeblack@google.com case 0x238: 15612855Sgabeblack@google.com case 0x240: 15712855Sgabeblack@google.com case 0x248: 15812855Sgabeblack@google.com case 0x250: 15912855Sgabeblack@google.com case 0x258: 16012855Sgabeblack@google.com case 0x260: 16112855Sgabeblack@google.com case 0x268: 16212855Sgabeblack@google.com case 0x270: 16312855Sgabeblack@google.com case 0x278: 16412855Sgabeblack@google.com regNum = APIC_INTERRUPT_REQUEST((paddr - 0x200) / 0x8); 16512855Sgabeblack@google.com break; 16612855Sgabeblack@google.com case 0x280: 16712855Sgabeblack@google.com regNum = APIC_ERROR_STATUS; 16812855Sgabeblack@google.com break; 16912855Sgabeblack@google.com case 0x300: 17012855Sgabeblack@google.com regNum = APIC_INTERRUPT_COMMAND_LOW; 17112855Sgabeblack@google.com break; 17212855Sgabeblack@google.com case 0x310: 17312855Sgabeblack@google.com regNum = APIC_INTERRUPT_COMMAND_HIGH; 17412855Sgabeblack@google.com break; 17512855Sgabeblack@google.com case 0x320: 17612855Sgabeblack@google.com regNum = APIC_LVT_TIMER; 17712855Sgabeblack@google.com break; 17812855Sgabeblack@google.com case 0x330: 17912855Sgabeblack@google.com regNum = APIC_LVT_THERMAL_SENSOR; 18012855Sgabeblack@google.com break; 18112855Sgabeblack@google.com case 0x340: 18212855Sgabeblack@google.com regNum = APIC_LVT_PERFORMANCE_MONITORING_COUNTERS; 18312855Sgabeblack@google.com break; 18412855Sgabeblack@google.com case 0x350: 18512855Sgabeblack@google.com regNum = APIC_LVT_LINT0; 18612855Sgabeblack@google.com break; 18712855Sgabeblack@google.com case 0x360: 18812855Sgabeblack@google.com regNum = APIC_LVT_LINT1; 18912855Sgabeblack@google.com break; 19012855Sgabeblack@google.com case 0x370: 19112855Sgabeblack@google.com regNum = APIC_LVT_ERROR; 19212855Sgabeblack@google.com break; 19312855Sgabeblack@google.com case 0x380: 19412855Sgabeblack@google.com regNum = APIC_INITIAL_COUNT; 19512855Sgabeblack@google.com break; 19612855Sgabeblack@google.com case 0x390: 19712855Sgabeblack@google.com regNum = APIC_CURRENT_COUNT; 19812855Sgabeblack@google.com break; 19912855Sgabeblack@google.com case 0x3E0: 20012855Sgabeblack@google.com regNum = APIC_DIVIDE_CONFIGURATION; 20112855Sgabeblack@google.com break; 20212855Sgabeblack@google.com default: 20312855Sgabeblack@google.com // A reserved register field. 20412855Sgabeblack@google.com panic("Accessed reserved register field %#x.\n", paddr); 20512855Sgabeblack@google.com break; 20612855Sgabeblack@google.com } 20712855Sgabeblack@google.com return regNum; 20812855Sgabeblack@google.com} 20912855Sgabeblack@google.com} 21012855Sgabeblack@google.com 21112855Sgabeblack@google.comTick 21212855Sgabeblack@google.comX86ISA::Interrupts::read(PacketPtr pkt) 21312855Sgabeblack@google.com{ 21412855Sgabeblack@google.com Addr offset = pkt->getAddr() - pioAddr; 21512855Sgabeblack@google.com //Make sure we're at least only accessing one register. 21612855Sgabeblack@google.com if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3))) 21712855Sgabeblack@google.com panic("Accessed more than one register at a time in the APIC!\n"); 21812855Sgabeblack@google.com ApicRegIndex reg = decodeAddr(offset); 21912855Sgabeblack@google.com uint32_t val = htog(readReg(reg)); 22012855Sgabeblack@google.com DPRINTF(LocalApic, 22112855Sgabeblack@google.com "Reading Local APIC register %d at offset %#x as %#x.\n", 22212855Sgabeblack@google.com reg, offset, val); 22312855Sgabeblack@google.com pkt->setData(((uint8_t *)&val) + (offset & mask(3))); 22412855Sgabeblack@google.com return latency; 22512855Sgabeblack@google.com} 22612855Sgabeblack@google.com 22712855Sgabeblack@google.comTick 22812855Sgabeblack@google.comX86ISA::Interrupts::write(PacketPtr pkt) 22912855Sgabeblack@google.com{ 23012855Sgabeblack@google.com Addr offset = pkt->getAddr() - pioAddr; 23112855Sgabeblack@google.com //Make sure we're at least only accessing one register. 23212855Sgabeblack@google.com if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3))) 23312855Sgabeblack@google.com panic("Accessed more than one register at a time in the APIC!\n"); 23412855Sgabeblack@google.com ApicRegIndex reg = decodeAddr(offset); 23512855Sgabeblack@google.com uint32_t val = regs[reg]; 23612855Sgabeblack@google.com pkt->writeData(((uint8_t *)&val) + (offset & mask(3))); 23712855Sgabeblack@google.com DPRINTF(LocalApic, 23812855Sgabeblack@google.com "Writing Local APIC register %d at offset %#x as %#x.\n", 23912855Sgabeblack@google.com reg, offset, gtoh(val)); 24012855Sgabeblack@google.com setReg(reg, gtoh(val)); 24112855Sgabeblack@google.com return latency; 24212855Sgabeblack@google.com} 24312855Sgabeblack@google.comvoid 24412855Sgabeblack@google.comX86ISA::Interrupts::requestInterrupt(uint8_t vector, 24512855Sgabeblack@google.com uint8_t deliveryMode, bool level) 24612855Sgabeblack@google.com{ 24712855Sgabeblack@google.com /* 24812855Sgabeblack@google.com * Fixed and lowest-priority delivery mode interrupts are handled 24912855Sgabeblack@google.com * using the IRR/ISR registers, checking against the TPR, etc. 25012855Sgabeblack@google.com * The SMI, NMI, ExtInt, INIT, etc interrupts go straight through. 25112855Sgabeblack@google.com */ 25212855Sgabeblack@google.com if (deliveryMode == DeliveryMode::Fixed || 25312855Sgabeblack@google.com deliveryMode == DeliveryMode::LowestPriority) { 25412855Sgabeblack@google.com DPRINTF(LocalApic, "Interrupt is an %s.\n", 25512855Sgabeblack@google.com DeliveryMode::names[deliveryMode]); 25612855Sgabeblack@google.com // Queue up the interrupt in the IRR. 25712855Sgabeblack@google.com if (vector > IRRV) 25812855Sgabeblack@google.com IRRV = vector; 25912855Sgabeblack@google.com if (!getRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, vector)) { 26012855Sgabeblack@google.com setRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, vector); 26112855Sgabeblack@google.com if (level) { 26212855Sgabeblack@google.com setRegArrayBit(APIC_TRIGGER_MODE_BASE, vector); 26312855Sgabeblack@google.com } else { 26412855Sgabeblack@google.com clearRegArrayBit(APIC_TRIGGER_MODE_BASE, vector); 26512855Sgabeblack@google.com } 26612855Sgabeblack@google.com } 26712855Sgabeblack@google.com } else if (!DeliveryMode::isReserved(deliveryMode)) { 26812855Sgabeblack@google.com DPRINTF(LocalApic, "Interrupt is an %s.\n", 26912855Sgabeblack@google.com DeliveryMode::names[deliveryMode]); 27012855Sgabeblack@google.com if (deliveryMode == DeliveryMode::SMI && !pendingSmi) { 27112855Sgabeblack@google.com pendingUnmaskableInt = pendingSmi = true; 27212855Sgabeblack@google.com smiVector = vector; 27312855Sgabeblack@google.com } else if (deliveryMode == DeliveryMode::NMI && !pendingNmi) { 27412855Sgabeblack@google.com pendingUnmaskableInt = pendingNmi = true; 27512855Sgabeblack@google.com nmiVector = vector; 27612855Sgabeblack@google.com } else if (deliveryMode == DeliveryMode::ExtInt && !pendingExtInt) { 27712855Sgabeblack@google.com pendingExtInt = true; 27812855Sgabeblack@google.com extIntVector = vector; 27912855Sgabeblack@google.com } else if (deliveryMode == DeliveryMode::INIT && !pendingInit) { 28012855Sgabeblack@google.com pendingUnmaskableInt = pendingInit = true; 28112855Sgabeblack@google.com initVector = vector; 28212855Sgabeblack@google.com } 28312855Sgabeblack@google.com } 28412855Sgabeblack@google.com} 28512855Sgabeblack@google.com 28612855Sgabeblack@google.comTick 28712855Sgabeblack@google.comX86ISA::Interrupts::recvMessage(PacketPtr pkt) 28812855Sgabeblack@google.com{ 28912855Sgabeblack@google.com uint8_t id = 0; 29012855Sgabeblack@google.com Addr offset = pkt->getAddr() - x86InterruptAddress(id, 0); 29112855Sgabeblack@google.com assert(pkt->cmd == MemCmd::MessageReq); 29212855Sgabeblack@google.com switch(offset) 29312855Sgabeblack@google.com { 29412855Sgabeblack@google.com case 0: 29512855Sgabeblack@google.com { 29612855Sgabeblack@google.com TriggerIntMessage message = pkt->get<TriggerIntMessage>(); 29712855Sgabeblack@google.com uint8_t vector = message.vector; 29812855Sgabeblack@google.com DPRINTF(LocalApic, 29912855Sgabeblack@google.com "Got Trigger Interrupt message with vector %#x.\n", 30012855Sgabeblack@google.com vector); 30112855Sgabeblack@google.com // Make sure we're really supposed to get this. 30212855Sgabeblack@google.com assert((message.destMode == 0 && message.destination == id) || 30312855Sgabeblack@google.com (bits((int)message.destination, id))); 30412855Sgabeblack@google.com 30512855Sgabeblack@google.com requestInterrupt(message.vector, 30612855Sgabeblack@google.com message.deliveryMode, message.trigger); 30712855Sgabeblack@google.com } 30812855Sgabeblack@google.com break; 30912855Sgabeblack@google.com default: 31012855Sgabeblack@google.com panic("Local apic got unknown interrupt message at offset %#x.\n", 31112855Sgabeblack@google.com offset); 31212855Sgabeblack@google.com break; 31312855Sgabeblack@google.com } 31412855Sgabeblack@google.com delete pkt->req; 31512855Sgabeblack@google.com delete pkt; 31612855Sgabeblack@google.com return latency; 31712855Sgabeblack@google.com} 31812855Sgabeblack@google.com 31912855Sgabeblack@google.com 32012855Sgabeblack@google.comuint32_t 32112855Sgabeblack@google.comX86ISA::Interrupts::readReg(ApicRegIndex reg) 32212855Sgabeblack@google.com{ 32312855Sgabeblack@google.com if (reg >= APIC_TRIGGER_MODE(0) && 32412855Sgabeblack@google.com reg <= APIC_TRIGGER_MODE(15)) { 32512855Sgabeblack@google.com panic("Local APIC Trigger Mode registers are unimplemented.\n"); 32612855Sgabeblack@google.com } 32712855Sgabeblack@google.com switch (reg) { 32812855Sgabeblack@google.com case APIC_ARBITRATION_PRIORITY: 32912855Sgabeblack@google.com panic("Local APIC Arbitration Priority register unimplemented.\n"); 33012855Sgabeblack@google.com break; 33112855Sgabeblack@google.com case APIC_PROCESSOR_PRIORITY: 33212855Sgabeblack@google.com panic("Local APIC Processor Priority register unimplemented.\n"); 33312855Sgabeblack@google.com break; 33412855Sgabeblack@google.com case APIC_ERROR_STATUS: 33512855Sgabeblack@google.com regs[APIC_INTERNAL_STATE] &= ~ULL(0x1); 33612855Sgabeblack@google.com break; 33712855Sgabeblack@google.com case APIC_INTERRUPT_COMMAND_LOW: 33812855Sgabeblack@google.com panic("Local APIC Interrupt Command low" 33912855Sgabeblack@google.com " register unimplemented.\n"); 34012855Sgabeblack@google.com break; 34112855Sgabeblack@google.com case APIC_INTERRUPT_COMMAND_HIGH: 34212855Sgabeblack@google.com panic("Local APIC Interrupt Command high" 34312855Sgabeblack@google.com " register unimplemented.\n"); 34412855Sgabeblack@google.com break; 34512855Sgabeblack@google.com case APIC_CURRENT_COUNT: 34612855Sgabeblack@google.com { 34712855Sgabeblack@google.com assert(clock); 34812855Sgabeblack@google.com uint32_t val = regs[reg] - curTick / clock; 34912855Sgabeblack@google.com val /= (16 * divideFromConf(regs[APIC_DIVIDE_CONFIGURATION])); 35012855Sgabeblack@google.com return val; 35112855Sgabeblack@google.com } 35212855Sgabeblack@google.com default: 35312855Sgabeblack@google.com break; 35412855Sgabeblack@google.com } 35512855Sgabeblack@google.com return regs[reg]; 35612855Sgabeblack@google.com} 35712855Sgabeblack@google.com 35812855Sgabeblack@google.comvoid 35912855Sgabeblack@google.comX86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val) 36012855Sgabeblack@google.com{ 36112855Sgabeblack@google.com uint32_t newVal = val; 36212855Sgabeblack@google.com if (reg >= APIC_IN_SERVICE(0) && 36312855Sgabeblack@google.com reg <= APIC_IN_SERVICE(15)) { 36412855Sgabeblack@google.com panic("Local APIC In-Service registers are unimplemented.\n"); 36512855Sgabeblack@google.com } 36612855Sgabeblack@google.com if (reg >= APIC_TRIGGER_MODE(0) && 36712855Sgabeblack@google.com reg <= APIC_TRIGGER_MODE(15)) { 36812855Sgabeblack@google.com panic("Local APIC Trigger Mode registers are unimplemented.\n"); 36912855Sgabeblack@google.com } 37012855Sgabeblack@google.com if (reg >= APIC_INTERRUPT_REQUEST(0) && 37112855Sgabeblack@google.com reg <= APIC_INTERRUPT_REQUEST(15)) { 37212855Sgabeblack@google.com panic("Local APIC Interrupt Request registers " 37312855Sgabeblack@google.com "are unimplemented.\n"); 37412855Sgabeblack@google.com } 37512855Sgabeblack@google.com switch (reg) { 37612855Sgabeblack@google.com case APIC_ID: 37712855Sgabeblack@google.com newVal = val & 0xFF; 37812855Sgabeblack@google.com break; 37912855Sgabeblack@google.com case APIC_VERSION: 38012855Sgabeblack@google.com // The Local APIC Version register is read only. 38112855Sgabeblack@google.com return; 38212855Sgabeblack@google.com case APIC_TASK_PRIORITY: 38312855Sgabeblack@google.com newVal = val & 0xFF; 38412855Sgabeblack@google.com break; 38512855Sgabeblack@google.com case APIC_ARBITRATION_PRIORITY: 38612855Sgabeblack@google.com panic("Local APIC Arbitration Priority register unimplemented.\n"); 38712855Sgabeblack@google.com break; 38812855Sgabeblack@google.com case APIC_PROCESSOR_PRIORITY: 38912855Sgabeblack@google.com panic("Local APIC Processor Priority register unimplemented.\n"); 39012855Sgabeblack@google.com break; 39112855Sgabeblack@google.com case APIC_EOI: 39212855Sgabeblack@google.com // Remove the interrupt that just completed from the local apic state. 39312855Sgabeblack@google.com clearRegArrayBit(APIC_IN_SERVICE_BASE, ISRV); 39412855Sgabeblack@google.com updateISRV(); 39512855Sgabeblack@google.com return; 39612855Sgabeblack@google.com case APIC_LOGICAL_DESTINATION: 39712855Sgabeblack@google.com newVal = val & 0xFF000000; 39812855Sgabeblack@google.com break; 39912855Sgabeblack@google.com case APIC_DESTINATION_FORMAT: 40012855Sgabeblack@google.com newVal = val | 0x0FFFFFFF; 40112855Sgabeblack@google.com break; 40212855Sgabeblack@google.com case APIC_SPURIOUS_INTERRUPT_VECTOR: 40312855Sgabeblack@google.com regs[APIC_INTERNAL_STATE] &= ~ULL(1 << 1); 40412855Sgabeblack@google.com regs[APIC_INTERNAL_STATE] |= val & (1 << 8); 40512855Sgabeblack@google.com if (val & (1 << 9)) 40612855Sgabeblack@google.com warn("Focus processor checking not implemented.\n"); 40712855Sgabeblack@google.com break; 40812855Sgabeblack@google.com case APIC_ERROR_STATUS: 40912855Sgabeblack@google.com { 41012855Sgabeblack@google.com if (regs[APIC_INTERNAL_STATE] & 0x1) { 41112855Sgabeblack@google.com regs[APIC_INTERNAL_STATE] &= ~ULL(0x1); 41212855Sgabeblack@google.com newVal = 0; 41312855Sgabeblack@google.com } else { 41412855Sgabeblack@google.com regs[APIC_INTERNAL_STATE] |= ULL(0x1); 41512855Sgabeblack@google.com return; 41612855Sgabeblack@google.com } 41712855Sgabeblack@google.com 41812855Sgabeblack@google.com } 41912855Sgabeblack@google.com break; 42012855Sgabeblack@google.com case APIC_INTERRUPT_COMMAND_LOW: 42112855Sgabeblack@google.com panic("Local APIC Interrupt Command low" 42212855Sgabeblack@google.com " register unimplemented.\n"); 42312855Sgabeblack@google.com break; 42412855Sgabeblack@google.com case APIC_INTERRUPT_COMMAND_HIGH: 42512855Sgabeblack@google.com panic("Local APIC Interrupt Command high" 42612855Sgabeblack@google.com " register unimplemented.\n"); 42712855Sgabeblack@google.com break; 42812855Sgabeblack@google.com case APIC_LVT_TIMER: 42912855Sgabeblack@google.com case APIC_LVT_THERMAL_SENSOR: 43012855Sgabeblack@google.com case APIC_LVT_PERFORMANCE_MONITORING_COUNTERS: 43112855Sgabeblack@google.com case APIC_LVT_LINT0: 43212855Sgabeblack@google.com case APIC_LVT_LINT1: 43312855Sgabeblack@google.com case APIC_LVT_ERROR: 43412855Sgabeblack@google.com { 43512855Sgabeblack@google.com uint64_t readOnlyMask = (1 << 12) | (1 << 14); 43612855Sgabeblack@google.com newVal = (val & ~readOnlyMask) | 43712855Sgabeblack@google.com (regs[reg] & readOnlyMask); 43812855Sgabeblack@google.com } 43912855Sgabeblack@google.com break; 44012855Sgabeblack@google.com case APIC_INITIAL_COUNT: 44112855Sgabeblack@google.com { 44212855Sgabeblack@google.com assert(clock); 44312855Sgabeblack@google.com newVal = bits(val, 31, 0); 44412855Sgabeblack@google.com uint32_t newCount = newVal * 44512855Sgabeblack@google.com (divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]) * 16); 44612855Sgabeblack@google.com regs[APIC_CURRENT_COUNT] = newCount + curTick / clock; 44712855Sgabeblack@google.com // Find out how long a "tick" of the timer should take. 44812855Sgabeblack@google.com Tick timerTick = 16 * clock; 44912855Sgabeblack@google.com // Schedule on the edge of the next tick plus the new count. 45012855Sgabeblack@google.com Tick offset = curTick % timerTick; 45112855Sgabeblack@google.com if (offset) { 45212855Sgabeblack@google.com reschedule(apicTimerEvent, 45312855Sgabeblack@google.com curTick + (newCount + 1) * timerTick - offset, true); 45412855Sgabeblack@google.com } else { 45512855Sgabeblack@google.com reschedule(apicTimerEvent, 45612855Sgabeblack@google.com curTick + newCount * timerTick, true); 45712855Sgabeblack@google.com } 45812855Sgabeblack@google.com } 45912855Sgabeblack@google.com break; 46012855Sgabeblack@google.com case APIC_CURRENT_COUNT: 46112855Sgabeblack@google.com //Local APIC Current Count register is read only. 46212855Sgabeblack@google.com return; 46312855Sgabeblack@google.com case APIC_DIVIDE_CONFIGURATION: 46412855Sgabeblack@google.com newVal = val & 0xB; 46512855Sgabeblack@google.com break; 46612855Sgabeblack@google.com default: 46712855Sgabeblack@google.com break; 46812855Sgabeblack@google.com } 46912855Sgabeblack@google.com regs[reg] = newVal; 47012855Sgabeblack@google.com return; 47112855Sgabeblack@google.com} 47212855Sgabeblack@google.com 47312855Sgabeblack@google.combool 47412855Sgabeblack@google.comX86ISA::Interrupts::check_interrupts(ThreadContext * tc) const 47512855Sgabeblack@google.com{ 47612855Sgabeblack@google.com RFLAGS rflags = tc->readMiscRegNoEffect(MISCREG_RFLAGS); 47712855Sgabeblack@google.com if (pendingUnmaskableInt) { 47812855Sgabeblack@google.com DPRINTF(LocalApic, "Reported pending unmaskable interrupt.\n"); 47912855Sgabeblack@google.com return true; 48012855Sgabeblack@google.com } 48112855Sgabeblack@google.com if (rflags.intf) { 48212855Sgabeblack@google.com if (pendingExtInt) { 48312855Sgabeblack@google.com DPRINTF(LocalApic, "Reported pending external interrupt.\n"); 48412855Sgabeblack@google.com return true; 48512855Sgabeblack@google.com } 48612855Sgabeblack@google.com if (IRRV > ISRV && bits(IRRV, 7, 4) > 48712855Sgabeblack@google.com bits(regs[APIC_TASK_PRIORITY], 7, 4)) { 48812855Sgabeblack@google.com DPRINTF(LocalApic, "Reported pending regular interrupt.\n"); 48912855Sgabeblack@google.com return true; 49012855Sgabeblack@google.com } 49112855Sgabeblack@google.com } 49212855Sgabeblack@google.com return false; 49312855Sgabeblack@google.com} 49412855Sgabeblack@google.com 49512855Sgabeblack@google.comFault 49612855Sgabeblack@google.comX86ISA::Interrupts::getInterrupt(ThreadContext * tc) 49712855Sgabeblack@google.com{ 49812855Sgabeblack@google.com assert(check_interrupts(tc)); 49912855Sgabeblack@google.com // These are all probably fairly uncommon, so we'll make them easier to 50012855Sgabeblack@google.com // check for. 50112855Sgabeblack@google.com if (pendingUnmaskableInt) { 50212855Sgabeblack@google.com if (pendingSmi) { 50312855Sgabeblack@google.com DPRINTF(LocalApic, "Generated SMI fault object.\n"); 50412855Sgabeblack@google.com return new SystemManagementInterrupt(); 50512855Sgabeblack@google.com } else if (pendingNmi) { 50612855Sgabeblack@google.com DPRINTF(LocalApic, "Generated NMI fault object.\n"); 50712855Sgabeblack@google.com return new NonMaskableInterrupt(nmiVector); 50812855Sgabeblack@google.com } else if (pendingInit) { 50912855Sgabeblack@google.com DPRINTF(LocalApic, "Generated INIT fault object.\n"); 51012855Sgabeblack@google.com return new InitInterrupt(initVector); 51112855Sgabeblack@google.com } else { 51212855Sgabeblack@google.com panic("pendingUnmaskableInt set, but no unmaskable " 51312855Sgabeblack@google.com "ints were pending.\n"); 51412855Sgabeblack@google.com return NoFault; 51512855Sgabeblack@google.com } 51612855Sgabeblack@google.com } else if (pendingExtInt) { 51712855Sgabeblack@google.com DPRINTF(LocalApic, "Generated external interrupt fault object.\n"); 51812855Sgabeblack@google.com return new ExternalInterrupt(extIntVector); 51912855Sgabeblack@google.com } else { 52012855Sgabeblack@google.com DPRINTF(LocalApic, "Generated regular interrupt fault object.\n"); 52112855Sgabeblack@google.com // The only thing left are fixed and lowest priority interrupts. 52212855Sgabeblack@google.com return new ExternalInterrupt(IRRV); 52312855Sgabeblack@google.com } 52412855Sgabeblack@google.com} 52512855Sgabeblack@google.com 52612855Sgabeblack@google.comvoid 52712855Sgabeblack@google.comX86ISA::Interrupts::updateIntrInfo(ThreadContext * tc) 52812855Sgabeblack@google.com{ 52912855Sgabeblack@google.com assert(check_interrupts(tc)); 53012855Sgabeblack@google.com if (pendingUnmaskableInt) { 53112855Sgabeblack@google.com if (pendingSmi) { 53212855Sgabeblack@google.com DPRINTF(LocalApic, "SMI sent to core.\n"); 53312855Sgabeblack@google.com pendingSmi = false; 53412855Sgabeblack@google.com } else if (pendingNmi) { 53512855Sgabeblack@google.com DPRINTF(LocalApic, "NMI sent to core.\n"); 53612855Sgabeblack@google.com pendingNmi = false; 53712855Sgabeblack@google.com } else if (pendingInit) { 53812855Sgabeblack@google.com DPRINTF(LocalApic, "Init sent to core.\n"); 53912855Sgabeblack@google.com pendingInit = false; 54012855Sgabeblack@google.com } 54112855Sgabeblack@google.com if (!(pendingSmi || pendingNmi || pendingInit)) 54212855Sgabeblack@google.com pendingUnmaskableInt = false; 54312855Sgabeblack@google.com } else if (pendingExtInt) { 54412855Sgabeblack@google.com pendingExtInt = false; 54512855Sgabeblack@google.com } else { 54612855Sgabeblack@google.com DPRINTF(LocalApic, "Interrupt %d sent to core.\n", IRRV); 54712855Sgabeblack@google.com // Mark the interrupt as "in service". 54812855Sgabeblack@google.com ISRV = IRRV; 54912855Sgabeblack@google.com setRegArrayBit(APIC_IN_SERVICE_BASE, ISRV); 55012855Sgabeblack@google.com // Clear it out of the IRR. 55112855Sgabeblack@google.com clearRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, IRRV); 55212855Sgabeblack@google.com updateIRRV(); 55312855Sgabeblack@google.com } 55412855Sgabeblack@google.com} 55512855Sgabeblack@google.com 55612855Sgabeblack@google.comX86ISA::Interrupts * 55712855Sgabeblack@google.comX86LocalApicParams::create() 55812855Sgabeblack@google.com{ 55912855Sgabeblack@google.com return new X86ISA::Interrupts(this); 56012855Sgabeblack@google.com} 56112855Sgabeblack@google.com