interrupts.cc revision 5654
1955SN/A/*
2955SN/A * Copyright (c) 2008 The Hewlett-Packard Development Company
31762SN/A * All rights reserved.
4955SN/A *
5955SN/A * Redistribution and use of this software in source and binary forms,
6955SN/A * with or without modification, are permitted provided that the
7955SN/A * following conditions are met:
8955SN/A *
9955SN/A * The software must be used only for Non-Commercial Use which means any
10955SN/A * use which is NOT directed to receiving any direct monetary
11955SN/A * compensation for, or commercial advantage from such use.  Illustrative
12955SN/A * examples of non-commercial use are academic research, personal study,
13955SN/A * teaching, education and corporate research & development.
14955SN/A * Illustrative examples of commercial use are distributing products for
15955SN/A * commercial advantage and providing services using the software for
16955SN/A * commercial advantage.
17955SN/A *
18955SN/A * If you wish to use this software or functionality therein that may be
19955SN/A * covered by patents for commercial use, please contact:
20955SN/A *     Director of Intellectual Property Licensing
21955SN/A *     Office of Strategy and Technology
22955SN/A *     Hewlett-Packard Company
23955SN/A *     1501 Page Mill Road
24955SN/A *     Palo Alto, California  94304
25955SN/A *
26955SN/A * Redistributions of source code must retain the above copyright notice,
27955SN/A * this list of conditions and the following disclaimer.  Redistributions
282665Ssaidi@eecs.umich.edu * in binary form must reproduce the above copyright notice, this list of
294762Snate@binkert.org * conditions and the following disclaimer in the documentation and/or
30955SN/A * other materials provided with the distribution.  Neither the name of
315522Snate@binkert.org * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
326143Snate@binkert.org * contributors may be used to endorse or promote products derived from
334762Snate@binkert.org * this software without specific prior written permission.  No right of
345522Snate@binkert.org * sublicense is granted herewith.  Derivatives of the software and
35955SN/A * output created using the software may be prepared, but only for
365522Snate@binkert.org * Non-Commercial Uses.  Derivatives of the software may be shared with
3711974Sgabeblack@google.com * others provided: (i) the others agree to abide by the list of
38955SN/A * conditions herein which includes the Non-Commercial Use restrictions;
395522Snate@binkert.org * and (ii) such Derivatives of the software include the above copyright
404202Sbinkertn@umich.edu * notice to acknowledge the contribution from this software where
415742Snate@binkert.org * applicable, this list of conditions and the disclaimer below.
42955SN/A *
434381Sbinkertn@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
444381Sbinkertn@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
458334Snate@binkert.org * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
46955SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
47955SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
484202Sbinkertn@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
49955SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
504382Sbinkertn@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
514382Sbinkertn@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
524382Sbinkertn@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
536654Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
545517Snate@binkert.org *
558614Sgblack@eecs.umich.edu * Authors: Gabe Black
567674Snate@binkert.org */
576143Snate@binkert.org
586143Snate@binkert.org#include "arch/x86/apicregs.hh"
596143Snate@binkert.org#include "arch/x86/interrupts.hh"
608233Snate@binkert.org#include "arch/x86/intmessage.hh"
618233Snate@binkert.org#include "cpu/base.hh"
628233Snate@binkert.org#include "mem/packet_access.hh"
638233Snate@binkert.org
648233Snate@binkert.orgint
658334Snate@binkert.orgdivideFromConf(uint32_t conf)
668334Snate@binkert.org{
6710453SAndrew.Bardsley@arm.com    // This figures out what division we want from the division configuration
6810453SAndrew.Bardsley@arm.com    // register in the local APIC. The encoding is a little odd but it can
698233Snate@binkert.org    // be deciphered fairly easily.
708233Snate@binkert.org    int shift = ((conf & 0x8) >> 1) | (conf & 0x3);
718233Snate@binkert.org    shift = (shift + 1) % 8;
728233Snate@binkert.org    return 1 << shift;
738233Snate@binkert.org}
748233Snate@binkert.org
7511983Sgabeblack@google.comnamespace X86ISA
7611983Sgabeblack@google.com{
7711983Sgabeblack@google.com
7811983Sgabeblack@google.comApicRegIndex
7911983Sgabeblack@google.comdecodeAddr(Addr paddr)
8011983Sgabeblack@google.com{
8111983Sgabeblack@google.com    ApicRegIndex regNum;
8211983Sgabeblack@google.com    paddr &= ~mask(3);
8311983Sgabeblack@google.com    switch (paddr)
8411983Sgabeblack@google.com    {
8511983Sgabeblack@google.com      case 0x20:
866143Snate@binkert.org        regNum = APIC_ID;
878233Snate@binkert.org        break;
888233Snate@binkert.org      case 0x30:
898233Snate@binkert.org        regNum = APIC_VERSION;
906143Snate@binkert.org        break;
916143Snate@binkert.org      case 0x80:
926143Snate@binkert.org        regNum = APIC_TASK_PRIORITY;
9311308Santhony.gutierrez@amd.com        break;
948233Snate@binkert.org      case 0x90:
958233Snate@binkert.org        regNum = APIC_ARBITRATION_PRIORITY;
968233Snate@binkert.org        break;
9711983Sgabeblack@google.com      case 0xA0:
9811983Sgabeblack@google.com        regNum = APIC_PROCESSOR_PRIORITY;
994762Snate@binkert.org        break;
1006143Snate@binkert.org      case 0xB0:
1018233Snate@binkert.org        regNum = APIC_EOI;
1028233Snate@binkert.org        break;
1038233Snate@binkert.org      case 0xD0:
1048233Snate@binkert.org        regNum = APIC_LOGICAL_DESTINATION;
1058233Snate@binkert.org        break;
1066143Snate@binkert.org      case 0xE0:
1078233Snate@binkert.org        regNum = APIC_DESTINATION_FORMAT;
1088233Snate@binkert.org        break;
1098233Snate@binkert.org      case 0xF0:
1108233Snate@binkert.org        regNum = APIC_SPURIOUS_INTERRUPT_VECTOR;
1116143Snate@binkert.org        break;
1126143Snate@binkert.org      case 0x100:
1136143Snate@binkert.org      case 0x108:
1146143Snate@binkert.org      case 0x110:
1156143Snate@binkert.org      case 0x118:
1166143Snate@binkert.org      case 0x120:
1176143Snate@binkert.org      case 0x128:
1186143Snate@binkert.org      case 0x130:
1196143Snate@binkert.org      case 0x138:
1207065Snate@binkert.org      case 0x140:
1216143Snate@binkert.org      case 0x148:
1228233Snate@binkert.org      case 0x150:
1238233Snate@binkert.org      case 0x158:
1248233Snate@binkert.org      case 0x160:
1258233Snate@binkert.org      case 0x168:
1268233Snate@binkert.org      case 0x170:
1278233Snate@binkert.org      case 0x178:
1288233Snate@binkert.org        regNum = APIC_IN_SERVICE((paddr - 0x100) / 0x8);
1298233Snate@binkert.org        break;
1308233Snate@binkert.org      case 0x180:
1318233Snate@binkert.org      case 0x188:
1328233Snate@binkert.org      case 0x190:
1338233Snate@binkert.org      case 0x198:
1348233Snate@binkert.org      case 0x1A0:
1358233Snate@binkert.org      case 0x1A8:
1368233Snate@binkert.org      case 0x1B0:
1378233Snate@binkert.org      case 0x1B8:
1388233Snate@binkert.org      case 0x1C0:
1398233Snate@binkert.org      case 0x1C8:
1408233Snate@binkert.org      case 0x1D0:
1418233Snate@binkert.org      case 0x1D8:
1428233Snate@binkert.org      case 0x1E0:
1438233Snate@binkert.org      case 0x1E8:
1448233Snate@binkert.org      case 0x1F0:
1458233Snate@binkert.org      case 0x1F8:
1468233Snate@binkert.org        regNum = APIC_TRIGGER_MODE((paddr - 0x180) / 0x8);
1478233Snate@binkert.org        break;
1488233Snate@binkert.org      case 0x200:
1498233Snate@binkert.org      case 0x208:
1508233Snate@binkert.org      case 0x210:
1518233Snate@binkert.org      case 0x218:
1528233Snate@binkert.org      case 0x220:
1536143Snate@binkert.org      case 0x228:
1546143Snate@binkert.org      case 0x230:
1556143Snate@binkert.org      case 0x238:
1566143Snate@binkert.org      case 0x240:
1576143Snate@binkert.org      case 0x248:
1586143Snate@binkert.org      case 0x250:
1599982Satgutier@umich.edu      case 0x258:
16010196SCurtis.Dunham@arm.com      case 0x260:
16110196SCurtis.Dunham@arm.com      case 0x268:
16210196SCurtis.Dunham@arm.com      case 0x270:
16310196SCurtis.Dunham@arm.com      case 0x278:
16410196SCurtis.Dunham@arm.com        regNum = APIC_INTERRUPT_REQUEST((paddr - 0x200) / 0x8);
16510196SCurtis.Dunham@arm.com        break;
16610196SCurtis.Dunham@arm.com      case 0x280:
16710196SCurtis.Dunham@arm.com        regNum = APIC_ERROR_STATUS;
1686143Snate@binkert.org        break;
16911983Sgabeblack@google.com      case 0x300:
17011983Sgabeblack@google.com        regNum = APIC_INTERRUPT_COMMAND_LOW;
17111983Sgabeblack@google.com        break;
17211983Sgabeblack@google.com      case 0x310:
17311983Sgabeblack@google.com        regNum = APIC_INTERRUPT_COMMAND_HIGH;
17411983Sgabeblack@google.com        break;
17511983Sgabeblack@google.com      case 0x320:
17611983Sgabeblack@google.com        regNum = APIC_LVT_TIMER;
17711983Sgabeblack@google.com        break;
1786143Snate@binkert.org      case 0x330:
17911988Sandreas.sandberg@arm.com        regNum = APIC_LVT_THERMAL_SENSOR;
1808233Snate@binkert.org        break;
1818233Snate@binkert.org      case 0x340:
1826143Snate@binkert.org        regNum = APIC_LVT_PERFORMANCE_MONITORING_COUNTERS;
1838945Ssteve.reinhardt@amd.com        break;
1846143Snate@binkert.org      case 0x350:
18511983Sgabeblack@google.com        regNum = APIC_LVT_LINT0;
18611983Sgabeblack@google.com        break;
1876143Snate@binkert.org      case 0x360:
1886143Snate@binkert.org        regNum = APIC_LVT_LINT1;
1895522Snate@binkert.org        break;
1906143Snate@binkert.org      case 0x370:
1916143Snate@binkert.org        regNum = APIC_LVT_ERROR;
1926143Snate@binkert.org        break;
1939982Satgutier@umich.edu      case 0x380:
1948233Snate@binkert.org        regNum = APIC_INITIAL_COUNT;
1958233Snate@binkert.org        break;
1968233Snate@binkert.org      case 0x390:
1976143Snate@binkert.org        regNum = APIC_CURRENT_COUNT;
1986143Snate@binkert.org        break;
1996143Snate@binkert.org      case 0x3E0:
2006143Snate@binkert.org        regNum = APIC_DIVIDE_CONFIGURATION;
2015522Snate@binkert.org        break;
2025522Snate@binkert.org      default:
2035522Snate@binkert.org        // A reserved register field.
2045522Snate@binkert.org        panic("Accessed reserved register field %#x.\n", paddr);
2055604Snate@binkert.org        break;
2065604Snate@binkert.org    }
2076143Snate@binkert.org    return regNum;
2086143Snate@binkert.org}
2094762Snate@binkert.org}
2104762Snate@binkert.org
2116143Snate@binkert.orgTick
2126727Ssteve.reinhardt@amd.comX86ISA::Interrupts::read(PacketPtr pkt)
2136727Ssteve.reinhardt@amd.com{
2146727Ssteve.reinhardt@amd.com    Addr offset = pkt->getAddr() - pioAddr;
2154762Snate@binkert.org    //Make sure we're at least only accessing one register.
2166143Snate@binkert.org    if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3)))
2176143Snate@binkert.org        panic("Accessed more than one register at a time in the APIC!\n");
2186143Snate@binkert.org    ApicRegIndex reg = decodeAddr(offset);
2196143Snate@binkert.org    uint32_t val = htog(readReg(reg));
2206727Ssteve.reinhardt@amd.com    DPRINTF(LocalApic,
2216143Snate@binkert.org            "Reading Local APIC register %d at offset %#x as %#x.\n",
2227674Snate@binkert.org            reg, offset, val);
2237674Snate@binkert.org    pkt->setData(((uint8_t *)&val) + (offset & mask(3)));
2245604Snate@binkert.org    return latency;
2256143Snate@binkert.org}
2266143Snate@binkert.org
2276143Snate@binkert.orgTick
2284762Snate@binkert.orgX86ISA::Interrupts::write(PacketPtr pkt)
2296143Snate@binkert.org{
2304762Snate@binkert.org    Addr offset = pkt->getAddr() - pioAddr;
2314762Snate@binkert.org    //Make sure we're at least only accessing one register.
2324762Snate@binkert.org    if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3)))
2336143Snate@binkert.org        panic("Accessed more than one register at a time in the APIC!\n");
2346143Snate@binkert.org    ApicRegIndex reg = decodeAddr(offset);
2354762Snate@binkert.org    uint32_t val = regs[reg];
2368233Snate@binkert.org    pkt->writeData(((uint8_t *)&val) + (offset & mask(3)));
2378233Snate@binkert.org    DPRINTF(LocalApic,
2388233Snate@binkert.org            "Writing Local APIC register %d at offset %#x as %#x.\n",
2398233Snate@binkert.org            reg, offset, gtoh(val));
2406143Snate@binkert.org    setReg(reg, gtoh(val));
2416143Snate@binkert.org    return latency;
2424762Snate@binkert.org}
2436143Snate@binkert.org
2444762Snate@binkert.orgTick
2459396Sandreas.hansson@arm.comX86ISA::Interrupts::recvMessage(PacketPtr pkt)
2469396Sandreas.hansson@arm.com{
2479396Sandreas.hansson@arm.com    uint8_t id = 0;
2489396Sandreas.hansson@arm.com    Addr offset = pkt->getAddr() - x86InterruptAddress(id, 0);
2499396Sandreas.hansson@arm.com    assert(pkt->cmd == MemCmd::MessageReq);
2509396Sandreas.hansson@arm.com    switch(offset)
2519396Sandreas.hansson@arm.com    {
2529396Sandreas.hansson@arm.com      case 0:
2539396Sandreas.hansson@arm.com        {
2549396Sandreas.hansson@arm.com            TriggerIntMessage message = pkt->get<TriggerIntMessage>();
2559396Sandreas.hansson@arm.com            uint8_t vector = message.vector;
2569396Sandreas.hansson@arm.com            DPRINTF(LocalApic,
2579396Sandreas.hansson@arm.com                    "Got Trigger Interrupt message with vector %#x.\n",
2589930Sandreas.hansson@arm.com                    vector);
2599930Sandreas.hansson@arm.com            // Make sure we're really supposed to get this.
2609396Sandreas.hansson@arm.com            assert((message.destMode == 0 && message.destination == id) ||
2618235Snate@binkert.org                   (bits((int)message.destination, id)));
2628235Snate@binkert.org            if (DeliveryMode::isUnmaskable(message.deliveryMode)) {
2636143Snate@binkert.org                DPRINTF(LocalApic, "Interrupt is an %s and unmaskable.\n",
2648235Snate@binkert.org                        DeliveryMode::names[message.deliveryMode]);
2659003SAli.Saidi@ARM.com                panic("Unmaskable interrupts aren't implemented.\n");
2668235Snate@binkert.org            } else if (DeliveryMode::isMaskable(message.deliveryMode)) {
2678235Snate@binkert.org                DPRINTF(LocalApic, "Interrupt is an %s and maskable.\n",
2688235Snate@binkert.org                        DeliveryMode::names[message.deliveryMode]);
2698235Snate@binkert.org                // Queue up the interrupt in the IRR.
2708235Snate@binkert.org                if (vector > IRRV)
2718235Snate@binkert.org                    IRRV = vector;
2728235Snate@binkert.org                if (!getRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, vector)) {
2738235Snate@binkert.org                    setRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, vector);
2748235Snate@binkert.org                    if (message.trigger) {
2758235Snate@binkert.org                        // Level triggered.
2768235Snate@binkert.org                        setRegArrayBit(APIC_TRIGGER_MODE_BASE, vector);
2778235Snate@binkert.org                    } else {
2788235Snate@binkert.org                        // Edge triggered.
2798235Snate@binkert.org                        clearRegArrayBit(APIC_TRIGGER_MODE_BASE, vector);
2809003SAli.Saidi@ARM.com                    }
2818235Snate@binkert.org                }
2825584Snate@binkert.org            }
2834382Sbinkertn@umich.edu        }
2844202Sbinkertn@umich.edu        break;
2854382Sbinkertn@umich.edu      default:
2864382Sbinkertn@umich.edu        panic("Local apic got unknown interrupt message at offset %#x.\n",
2879396Sandreas.hansson@arm.com                offset);
2885584Snate@binkert.org        break;
2894382Sbinkertn@umich.edu    }
2904382Sbinkertn@umich.edu    delete pkt->req;
2914382Sbinkertn@umich.edu    delete pkt;
2928232Snate@binkert.org    return latency;
2935192Ssaidi@eecs.umich.edu}
2948232Snate@binkert.org
2958232Snate@binkert.org
2968232Snate@binkert.orguint32_t
2975192Ssaidi@eecs.umich.eduX86ISA::Interrupts::readReg(ApicRegIndex reg)
2988232Snate@binkert.org{
2995192Ssaidi@eecs.umich.edu    if (reg >= APIC_TRIGGER_MODE(0) &&
3005799Snate@binkert.org            reg <= APIC_TRIGGER_MODE(15)) {
3018232Snate@binkert.org        panic("Local APIC Trigger Mode registers are unimplemented.\n");
3025192Ssaidi@eecs.umich.edu    }
3035192Ssaidi@eecs.umich.edu    switch (reg) {
3045192Ssaidi@eecs.umich.edu      case APIC_ARBITRATION_PRIORITY:
3058232Snate@binkert.org        panic("Local APIC Arbitration Priority register unimplemented.\n");
3065192Ssaidi@eecs.umich.edu        break;
3078232Snate@binkert.org      case APIC_PROCESSOR_PRIORITY:
3085192Ssaidi@eecs.umich.edu        panic("Local APIC Processor Priority register unimplemented.\n");
3095192Ssaidi@eecs.umich.edu        break;
3105192Ssaidi@eecs.umich.edu      case APIC_EOI:
3115192Ssaidi@eecs.umich.edu        panic("Local APIC EOI register unimplemented.\n");
3124382Sbinkertn@umich.edu        break;
3134382Sbinkertn@umich.edu      case APIC_ERROR_STATUS:
3144382Sbinkertn@umich.edu        regs[APIC_INTERNAL_STATE] &= ~ULL(0x1);
3152667Sstever@eecs.umich.edu        break;
3162667Sstever@eecs.umich.edu      case APIC_INTERRUPT_COMMAND_LOW:
3172667Sstever@eecs.umich.edu        panic("Local APIC Interrupt Command low"
3182667Sstever@eecs.umich.edu                " register unimplemented.\n");
3192667Sstever@eecs.umich.edu        break;
3202667Sstever@eecs.umich.edu      case APIC_INTERRUPT_COMMAND_HIGH:
3215742Snate@binkert.org        panic("Local APIC Interrupt Command high"
3225742Snate@binkert.org                " register unimplemented.\n");
3235742Snate@binkert.org        break;
3245793Snate@binkert.org      case APIC_CURRENT_COUNT:
3258334Snate@binkert.org        {
3265793Snate@binkert.org            assert(clock);
3275793Snate@binkert.org            uint32_t val = regs[reg] - curTick / clock;
3285793Snate@binkert.org            val /= (16 * divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]));
3294382Sbinkertn@umich.edu            return val;
3304762Snate@binkert.org        }
3315344Sstever@gmail.com      default:
3324382Sbinkertn@umich.edu        break;
3335341Sstever@gmail.com    }
3345742Snate@binkert.org    return regs[reg];
3355742Snate@binkert.org}
3365742Snate@binkert.org
3375742Snate@binkert.orgvoid
3385742Snate@binkert.orgX86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val)
3394762Snate@binkert.org{
3405742Snate@binkert.org    uint32_t newVal = val;
3415742Snate@binkert.org    if (reg >= APIC_IN_SERVICE(0) &&
34211984Sgabeblack@google.com            reg <= APIC_IN_SERVICE(15)) {
3437722Sgblack@eecs.umich.edu        panic("Local APIC In-Service registers are unimplemented.\n");
3445742Snate@binkert.org    }
3455742Snate@binkert.org    if (reg >= APIC_TRIGGER_MODE(0) &&
3465742Snate@binkert.org            reg <= APIC_TRIGGER_MODE(15)) {
3479930Sandreas.hansson@arm.com        panic("Local APIC Trigger Mode registers are unimplemented.\n");
3489930Sandreas.hansson@arm.com    }
3499930Sandreas.hansson@arm.com    if (reg >= APIC_INTERRUPT_REQUEST(0) &&
3509930Sandreas.hansson@arm.com            reg <= APIC_INTERRUPT_REQUEST(15)) {
3519930Sandreas.hansson@arm.com        panic("Local APIC Interrupt Request registers "
3525742Snate@binkert.org                "are unimplemented.\n");
3538242Sbradley.danofsky@amd.com    }
3548242Sbradley.danofsky@amd.com    switch (reg) {
3558242Sbradley.danofsky@amd.com      case APIC_ID:
3568242Sbradley.danofsky@amd.com        newVal = val & 0xFF;
3575341Sstever@gmail.com        break;
3585742Snate@binkert.org      case APIC_VERSION:
3597722Sgblack@eecs.umich.edu        // The Local APIC Version register is read only.
3604773Snate@binkert.org        return;
3616108Snate@binkert.org      case APIC_TASK_PRIORITY:
3621858SN/A        newVal = val & 0xFF;
3631085SN/A        break;
3646658Snate@binkert.org      case APIC_ARBITRATION_PRIORITY:
3656658Snate@binkert.org        panic("Local APIC Arbitration Priority register unimplemented.\n");
3667673Snate@binkert.org        break;
3676658Snate@binkert.org      case APIC_PROCESSOR_PRIORITY:
3686658Snate@binkert.org        panic("Local APIC Processor Priority register unimplemented.\n");
36911308Santhony.gutierrez@amd.com        break;
3706658Snate@binkert.org      case APIC_EOI:
37111308Santhony.gutierrez@amd.com        panic("Local APIC EOI register unimplemented.\n");
3726658Snate@binkert.org        break;
3736658Snate@binkert.org      case APIC_LOGICAL_DESTINATION:
3747673Snate@binkert.org        newVal = val & 0xFF000000;
3757673Snate@binkert.org        break;
3767673Snate@binkert.org      case APIC_DESTINATION_FORMAT:
3777673Snate@binkert.org        newVal = val | 0x0FFFFFFF;
3787673Snate@binkert.org        break;
3797673Snate@binkert.org      case APIC_SPURIOUS_INTERRUPT_VECTOR:
3807673Snate@binkert.org        regs[APIC_INTERNAL_STATE] &= ~ULL(1 << 1);
38110467Sandreas.hansson@arm.com        regs[APIC_INTERNAL_STATE] |= val & (1 << 8);
3826658Snate@binkert.org        if (val & (1 << 9))
3837673Snate@binkert.org            warn("Focus processor checking not implemented.\n");
38410467Sandreas.hansson@arm.com        break;
38510467Sandreas.hansson@arm.com      case APIC_ERROR_STATUS:
38610467Sandreas.hansson@arm.com        {
38710467Sandreas.hansson@arm.com            if (regs[APIC_INTERNAL_STATE] & 0x1) {
38810467Sandreas.hansson@arm.com                regs[APIC_INTERNAL_STATE] &= ~ULL(0x1);
38910467Sandreas.hansson@arm.com                newVal = 0;
39010467Sandreas.hansson@arm.com            } else {
39110467Sandreas.hansson@arm.com                regs[APIC_INTERNAL_STATE] |= ULL(0x1);
39210467Sandreas.hansson@arm.com                return;
39310467Sandreas.hansson@arm.com            }
39410467Sandreas.hansson@arm.com
3957673Snate@binkert.org        }
3967673Snate@binkert.org        break;
3977673Snate@binkert.org      case APIC_INTERRUPT_COMMAND_LOW:
3987673Snate@binkert.org        panic("Local APIC Interrupt Command low"
3997673Snate@binkert.org                " register unimplemented.\n");
4009048SAli.Saidi@ARM.com        break;
4017673Snate@binkert.org      case APIC_INTERRUPT_COMMAND_HIGH:
4027673Snate@binkert.org        panic("Local APIC Interrupt Command high"
4037673Snate@binkert.org                " register unimplemented.\n");
4047673Snate@binkert.org        break;
4056658Snate@binkert.org      case APIC_LVT_TIMER:
4067756SAli.Saidi@ARM.com      case APIC_LVT_THERMAL_SENSOR:
4077816Ssteve.reinhardt@amd.com      case APIC_LVT_PERFORMANCE_MONITORING_COUNTERS:
4086658Snate@binkert.org      case APIC_LVT_LINT0:
40911308Santhony.gutierrez@amd.com      case APIC_LVT_LINT1:
41011308Santhony.gutierrez@amd.com      case APIC_LVT_ERROR:
41111308Santhony.gutierrez@amd.com        {
41211308Santhony.gutierrez@amd.com            uint64_t readOnlyMask = (1 << 12) | (1 << 14);
41311308Santhony.gutierrez@amd.com            newVal = (val & ~readOnlyMask) |
41411308Santhony.gutierrez@amd.com                     (regs[reg] & readOnlyMask);
41511308Santhony.gutierrez@amd.com        }
41611308Santhony.gutierrez@amd.com        break;
41711308Santhony.gutierrez@amd.com      case APIC_INITIAL_COUNT:
41811308Santhony.gutierrez@amd.com        {
41911308Santhony.gutierrez@amd.com            assert(clock);
42011308Santhony.gutierrez@amd.com            newVal = bits(val, 31, 0);
42111308Santhony.gutierrez@amd.com            uint32_t newCount = newVal *
42211308Santhony.gutierrez@amd.com                (divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]) * 16);
42311308Santhony.gutierrez@amd.com            regs[APIC_CURRENT_COUNT] = newCount + curTick / clock;
42411308Santhony.gutierrez@amd.com            // Find out how long a "tick" of the timer should take.
42511308Santhony.gutierrez@amd.com            Tick timerTick = 16 * clock;
42611308Santhony.gutierrez@amd.com            // Schedule on the edge of the next tick plus the new count.
42711308Santhony.gutierrez@amd.com            Tick offset = curTick % timerTick;
42811308Santhony.gutierrez@amd.com            if (offset) {
42911308Santhony.gutierrez@amd.com                reschedule(apicTimerEvent,
43011308Santhony.gutierrez@amd.com                        curTick + (newCount + 1) * timerTick - offset, true);
43111308Santhony.gutierrez@amd.com            } else {
43211308Santhony.gutierrez@amd.com                reschedule(apicTimerEvent,
43311308Santhony.gutierrez@amd.com                        curTick + newCount * timerTick, true);
43411308Santhony.gutierrez@amd.com            }
43511308Santhony.gutierrez@amd.com        }
43611308Santhony.gutierrez@amd.com        break;
43711308Santhony.gutierrez@amd.com      case APIC_CURRENT_COUNT:
43811308Santhony.gutierrez@amd.com        //Local APIC Current Count register is read only.
43911308Santhony.gutierrez@amd.com        return;
44011308Santhony.gutierrez@amd.com      case APIC_DIVIDE_CONFIGURATION:
44111308Santhony.gutierrez@amd.com        newVal = val & 0xB;
44211308Santhony.gutierrez@amd.com        break;
44311308Santhony.gutierrez@amd.com      default:
44411308Santhony.gutierrez@amd.com        break;
44511308Santhony.gutierrez@amd.com    }
44611308Santhony.gutierrez@amd.com    regs[reg] = newVal;
44711308Santhony.gutierrez@amd.com    return;
44811308Santhony.gutierrez@amd.com}
44911308Santhony.gutierrez@amd.com
45011308Santhony.gutierrez@amd.combool
45111308Santhony.gutierrez@amd.comX86ISA::Interrupts::check_interrupts(ThreadContext * tc) const
45211308Santhony.gutierrez@amd.com{
45311308Santhony.gutierrez@amd.com    RFLAGS rflags = tc->readMiscRegNoEffect(MISCREG_RFLAGS);
4544382Sbinkertn@umich.edu    if (IRRV > ISRV && rflags.intf &&
4554382Sbinkertn@umich.edu            bits(IRRV, 7, 4) > bits(regs[APIC_TASK_PRIORITY], 7, 4)) {
4564762Snate@binkert.org        return true;
4574762Snate@binkert.org    }
4584762Snate@binkert.org    return false;
4596654Snate@binkert.org}
4606654Snate@binkert.org
4615517Snate@binkert.orgFault
4625517Snate@binkert.orgX86ISA::Interrupts::getInterrupt(ThreadContext * tc)
4635517Snate@binkert.org{
4645517Snate@binkert.org    assert(check_interrupts(tc));
4655517Snate@binkert.org    return new ExternalInterrupt(IRRV);
4665517Snate@binkert.org}
4675517Snate@binkert.org
4685517Snate@binkert.orgvoid
4695517Snate@binkert.orgX86ISA::Interrupts::updateIntrInfo(ThreadContext * tc)
4705517Snate@binkert.org{
4715517Snate@binkert.org    assert(check_interrupts(tc));
4725517Snate@binkert.org    // Mark the interrupt as "in service".
4735517Snate@binkert.org    ISRV = IRRV;
4745517Snate@binkert.org    setRegArrayBit(APIC_IN_SERVICE_BASE, ISRV);
4755517Snate@binkert.org    // Clear it out of the IRR.
4765517Snate@binkert.org    clearRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, IRRV);
4775517Snate@binkert.org    updateIRRV();
4786654Snate@binkert.org}
4795517Snate@binkert.org
4805517Snate@binkert.orgX86ISA::Interrupts *
4815517Snate@binkert.orgX86LocalApicParams::create()
4825517Snate@binkert.org{
4835517Snate@binkert.org    return new X86ISA::Interrupts(this);
48411802Sandreas.sandberg@arm.com}
4855517Snate@binkert.org