i82094aa.cc revision 13784
13005Sstever@eecs.umich.edu/*
23005Sstever@eecs.umich.edu * Copyright (c) 2008 The Regents of The University of Michigan
33005Sstever@eecs.umich.edu * All rights reserved.
43005Sstever@eecs.umich.edu *
53005Sstever@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
63005Sstever@eecs.umich.edu * modification, are permitted provided that the following conditions are
73005Sstever@eecs.umich.edu * met: redistributions of source code must retain the above copyright
83005Sstever@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
93005Sstever@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
103005Sstever@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
113005Sstever@eecs.umich.edu * documentation and/or other materials provided with the distribution;
123005Sstever@eecs.umich.edu * neither the name of the copyright holders nor the names of its
133005Sstever@eecs.umich.edu * contributors may be used to endorse or promote products derived from
143005Sstever@eecs.umich.edu * this software without specific prior written permission.
153005Sstever@eecs.umich.edu *
163005Sstever@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
173005Sstever@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
183005Sstever@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
193005Sstever@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
203005Sstever@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
213005Sstever@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
223005Sstever@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
233005Sstever@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
243005Sstever@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
253005Sstever@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
263005Sstever@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
273005Sstever@eecs.umich.edu *
283005Sstever@eecs.umich.edu * Authors: Gabe Black
292710SN/A */
302710SN/A
313005Sstever@eecs.umich.edu#include "dev/x86/i82094aa.hh"
322889SN/A
332667SN/A#include "arch/x86/interrupts.hh"
343005Sstever@eecs.umich.edu#include "arch/x86/intmessage.hh"
352856SN/A#include "cpu/base.hh"
362917SN/A#include "debug/I82094AA.hh"
372424SN/A#include "dev/x86/i8259.hh"
382957SN/A#include "mem/packet.hh"
392957SN/A#include "mem/packet_access.hh"
403323Shsul@eecs.umich.edu#include "sim/system.hh"
413005Sstever@eecs.umich.edu
423005Sstever@eecs.umich.eduX86ISA::I82094AA::I82094AA(Params *p)
432957SN/A    : BasicPioDevice(p, 20), IntDevice(this, p->int_latency),
442957SN/A      extIntPic(p->external_int_pic), lowestPriorityOffset(0)
452957SN/A{
462957SN/A    // This assumes there's only one I/O APIC in the system and since the apic
472957SN/A    // id is stored in a 8-bit field with 0xff meaning broadcast, the id must
482957SN/A    // be less than 0xff
493323Shsul@eecs.umich.edu
503323Shsul@eecs.umich.edu    assert(p->apic_id < 0xff);
512957SN/A    initialApicId = id = p->apic_id;
522957SN/A    arbId = id;
533323Shsul@eecs.umich.edu    regSel = 0;
543323Shsul@eecs.umich.edu    RedirTableEntry entry = 0;
553323Shsul@eecs.umich.edu    entry.mask = 1;
562957SN/A    for (int i = 0; i < TableSize; i++) {
573323Shsul@eecs.umich.edu        redirTable[i] = entry;
583323Shsul@eecs.umich.edu        pinStates[i] = false;
593323Shsul@eecs.umich.edu    }
603323Shsul@eecs.umich.edu}
613323Shsul@eecs.umich.edu
623323Shsul@eecs.umich.eduvoid
633323Shsul@eecs.umich.eduX86ISA::I82094AA::init()
643323Shsul@eecs.umich.edu{
653323Shsul@eecs.umich.edu    // The io apic must register its address ranges on both its pio port
663323Shsul@eecs.umich.edu    // via the piodevice init() function and its int port that it inherited
673323Shsul@eecs.umich.edu    // from IntDevice.  Note IntDevice is not a SimObject itself.
683323Shsul@eecs.umich.edu
693323Shsul@eecs.umich.edu    BasicPioDevice::init();
703323Shsul@eecs.umich.edu    IntDevice::init();
713323Shsul@eecs.umich.edu}
723323Shsul@eecs.umich.edu
733323Shsul@eecs.umich.eduPort &
743323Shsul@eecs.umich.eduX86ISA::I82094AA::getPort(const std::string &if_name, PortID idx)
753323Shsul@eecs.umich.edu{
763323Shsul@eecs.umich.edu    if (if_name == "int_master")
773323Shsul@eecs.umich.edu        return intMasterPort;
782957SN/A    return BasicPioDevice::getPort(if_name, idx);
792957SN/A}
802957SN/A
812957SN/AAddrRangeList
822957SN/AX86ISA::I82094AA::getIntAddrRange() const
832957SN/A{
842957SN/A    AddrRangeList ranges;
853323Shsul@eecs.umich.edu    ranges.push_back(RangeEx(x86InterruptAddress(initialApicId, 0),
863323Shsul@eecs.umich.edu                             x86InterruptAddress(initialApicId, 0) +
873323Shsul@eecs.umich.edu                             PhysAddrAPICRangeSize));
883323Shsul@eecs.umich.edu    return ranges;
893323Shsul@eecs.umich.edu}
903323Shsul@eecs.umich.edu
913323Shsul@eecs.umich.eduTick
922715SN/AX86ISA::I82094AA::recvResponse(PacketPtr pkt)
933005Sstever@eecs.umich.edu{
942801SN/A    // Packet instantiated calling sendMessage() in signalInterrupt()
952801SN/A    delete pkt;
962801SN/A    return 0;
972418SN/A}
982917SN/A
992833SN/ATick
1002833SN/AX86ISA::I82094AA::read(PacketPtr pkt)
1012833SN/A{
1022833SN/A    assert(pkt->getSize() == 4);
1032833SN/A    Addr offset = pkt->getAddr() - pioAddr;
1042833SN/A    switch(offset) {
1052833SN/A      case 0:
1062833SN/A        pkt->setLE<uint32_t>(regSel);
1072833SN/A        break;
1082833SN/A      case 16:
1092833SN/A        pkt->setLE<uint32_t>(readReg(regSel));
1102833SN/A        break;
1113005Sstever@eecs.umich.edu      default:
1122833SN/A        panic("Illegal read from I/O APIC.\n");
1132833SN/A    }
1142833SN/A    pkt->makeAtomicResponse();
1152833SN/A    return pioDelay;
1162833SN/A}
1172833SN/A
1182957SN/ATick
1192957SN/AX86ISA::I82094AA::write(PacketPtr pkt)
1202957SN/A{
1212957SN/A    assert(pkt->getSize() == 4);
1223223Sktlim@umich.edu    Addr offset = pkt->getAddr() - pioAddr;
1232957SN/A    switch(offset) {
1242957SN/A      case 0:
1252957SN/A        regSel = pkt->getLE<uint32_t>();
1263005Sstever@eecs.umich.edu        break;
1273180Sstever@eecs.umich.edu      case 16:
1283005Sstever@eecs.umich.edu        writeReg(regSel, pkt->getLE<uint32_t>());
1293005Sstever@eecs.umich.edu        break;
1303323Shsul@eecs.umich.edu      default:
1313005Sstever@eecs.umich.edu        panic("Illegal write to I/O APIC.\n");
1323005Sstever@eecs.umich.edu    }
1333005Sstever@eecs.umich.edu    pkt->makeAtomicResponse();
1343087Sstever@eecs.umich.edu    return pioDelay;
1353323Shsul@eecs.umich.edu}
1363323Shsul@eecs.umich.edu
1373323Shsul@eecs.umich.eduvoid
1383323Shsul@eecs.umich.eduX86ISA::I82094AA::writeReg(uint8_t offset, uint32_t value)
1393005Sstever@eecs.umich.edu{
1403005Sstever@eecs.umich.edu    if (offset == 0x0) {
1412902SN/A        id = bits(value, 31, 24);
1422902SN/A    } else if (offset == 0x1) {
1432925SN/A        // The IOAPICVER register is read only.
1442667SN/A    } else if (offset == 0x2) {
1453323Shsul@eecs.umich.edu        arbId = bits(value, 31, 24);
1463323Shsul@eecs.umich.edu    } else if (offset >= 0x10 && offset <= (0x10 + TableSize * 2)) {
1473323Shsul@eecs.umich.edu        int index = (offset - 0x10) / 2;
1483323Shsul@eecs.umich.edu        if (offset % 2) {
1493323Shsul@eecs.umich.edu            redirTable[index].topDW = value;
1503323Shsul@eecs.umich.edu            redirTable[index].topReserved = 0;
1513323Shsul@eecs.umich.edu        } else {
1523323Shsul@eecs.umich.edu            redirTable[index].bottomDW = value;
1533323Shsul@eecs.umich.edu            redirTable[index].bottomReserved = 0;
1543323Shsul@eecs.umich.edu        }
1553323Shsul@eecs.umich.edu    } else {
1563323Shsul@eecs.umich.edu        warn("Access to undefined I/O APIC register %#x.\n", offset);
1573323Shsul@eecs.umich.edu    }
1583323Shsul@eecs.umich.edu    DPRINTF(I82094AA,
1593323Shsul@eecs.umich.edu            "Wrote %#x to I/O APIC register %#x .\n", value, offset);
1603323Shsul@eecs.umich.edu}
1613323Shsul@eecs.umich.edu
1623323Shsul@eecs.umich.eduuint32_t
1633323Shsul@eecs.umich.eduX86ISA::I82094AA::readReg(uint8_t offset)
1643323Shsul@eecs.umich.edu{
1653323Shsul@eecs.umich.edu    uint32_t result = 0;
1662710SN/A    if (offset == 0x0) {
1672667SN/A        result = id << 24;
1682667SN/A    } else if (offset == 0x1) {
1693323Shsul@eecs.umich.edu        result = ((TableSize - 1) << 16) | APICVersion;
1703323Shsul@eecs.umich.edu    } else if (offset == 0x2) {
1713323Shsul@eecs.umich.edu        result = arbId << 24;
1723323Shsul@eecs.umich.edu    } else if (offset >= 0x10 && offset <= (0x10 + TableSize * 2)) {
1733323Shsul@eecs.umich.edu        int index = (offset - 0x10) / 2;
1743323Shsul@eecs.umich.edu        if (offset % 2) {
1753323Shsul@eecs.umich.edu            result = redirTable[index].topDW;
1763323Shsul@eecs.umich.edu        } else {
1773323Shsul@eecs.umich.edu            result = redirTable[index].bottomDW;
1783323Shsul@eecs.umich.edu        }
1793323Shsul@eecs.umich.edu    } else {
1803323Shsul@eecs.umich.edu        warn("Access to undefined I/O APIC register %#x.\n", offset);
1813323Shsul@eecs.umich.edu    }
1823323Shsul@eecs.umich.edu    DPRINTF(I82094AA,
1833323Shsul@eecs.umich.edu            "Read %#x from I/O APIC register %#x.\n", result, offset);
1843323Shsul@eecs.umich.edu    return result;
1853323Shsul@eecs.umich.edu}
1863323Shsul@eecs.umich.edu
1873323Shsul@eecs.umich.eduvoid
1883323Shsul@eecs.umich.eduX86ISA::I82094AA::signalInterrupt(int line)
1893323Shsul@eecs.umich.edu{
1903323Shsul@eecs.umich.edu    DPRINTF(I82094AA, "Received interrupt %d.\n", line);
1913323Shsul@eecs.umich.edu    assert(line < TableSize);
1923323Shsul@eecs.umich.edu    RedirTableEntry entry = redirTable[line];
1933323Shsul@eecs.umich.edu    if (entry.mask) {
1943323Shsul@eecs.umich.edu        DPRINTF(I82094AA, "Entry was masked.\n");
1953323Shsul@eecs.umich.edu        return;
1963323Shsul@eecs.umich.edu    } else {
1973323Shsul@eecs.umich.edu        TriggerIntMessage message = 0;
1983323Shsul@eecs.umich.edu        message.destination = entry.dest;
1993323Shsul@eecs.umich.edu        if (entry.deliveryMode == DeliveryMode::ExtInt) {
2003323Shsul@eecs.umich.edu            assert(extIntPic);
2013323Shsul@eecs.umich.edu            message.vector = extIntPic->getVector();
2023323Shsul@eecs.umich.edu        } else {
2033323Shsul@eecs.umich.edu            message.vector = entry.vector;
2043323Shsul@eecs.umich.edu        }
2053323Shsul@eecs.umich.edu        message.deliveryMode = entry.deliveryMode;
2063323Shsul@eecs.umich.edu        message.destMode = entry.destMode;
2073323Shsul@eecs.umich.edu        message.level = entry.polarity;
2083323Shsul@eecs.umich.edu        message.trigger = entry.trigger;
2093394Shsul@eecs.umich.edu        ApicList apics;
2103323Shsul@eecs.umich.edu        int numContexts = sys->numContexts();
2113323Shsul@eecs.umich.edu        if (message.destMode == 0) {
2122733SN/A            if (message.deliveryMode == DeliveryMode::LowestPriority) {
2133323Shsul@eecs.umich.edu                panic("Lowest priority delivery mode from the "
2143323Shsul@eecs.umich.edu                        "IO APIC aren't supported in physical "
2153323Shsul@eecs.umich.edu                        "destination mode.\n");
2163323Shsul@eecs.umich.edu            }
2173323Shsul@eecs.umich.edu            if (message.destination == 0xFF) {
2182733SN/A                for (int i = 0; i < numContexts; i++) {
2193323Shsul@eecs.umich.edu                    apics.push_back(i);
2202667SN/A                }
2213323Shsul@eecs.umich.edu            } else {
2222667SN/A                apics.push_back(message.destination);
2233323Shsul@eecs.umich.edu            }
2243323Shsul@eecs.umich.edu        } else {
2253323Shsul@eecs.umich.edu            for (int i = 0; i < numContexts; i++) {
2263323Shsul@eecs.umich.edu                Interrupts *localApic = sys->getThreadContext(i)->
2273323Shsul@eecs.umich.edu                    getCpuPtr()->getInterruptController(0);
2283323Shsul@eecs.umich.edu                if ((localApic->readReg(APIC_LOGICAL_DESTINATION) >> 24) &
2293323Shsul@eecs.umich.edu                        message.destination) {
2303323Shsul@eecs.umich.edu                    apics.push_back(localApic->getInitialApicId());
2313323Shsul@eecs.umich.edu                }
2323323Shsul@eecs.umich.edu            }
2333323Shsul@eecs.umich.edu            if (message.deliveryMode == DeliveryMode::LowestPriority &&
2343323Shsul@eecs.umich.edu                    apics.size()) {
2353323Shsul@eecs.umich.edu                // The manual seems to suggest that the chipset just does
2363323Shsul@eecs.umich.edu                // something reasonable for these instead of actually using
2373323Shsul@eecs.umich.edu                // state from the local APIC. We'll just rotate an offset
2383323Shsul@eecs.umich.edu                // through the set of APICs selected above.
2393323Shsul@eecs.umich.edu                uint64_t modOffset = lowestPriorityOffset % apics.size();
2403323Shsul@eecs.umich.edu                lowestPriorityOffset++;
2413323Shsul@eecs.umich.edu                ApicList::iterator apicIt = apics.begin();
2423323Shsul@eecs.umich.edu                while (modOffset--) {
2433323Shsul@eecs.umich.edu                    apicIt++;
2443323Shsul@eecs.umich.edu                    assert(apicIt != apics.end());
2453323Shsul@eecs.umich.edu                }
2463323Shsul@eecs.umich.edu                int selected = *apicIt;
2473323Shsul@eecs.umich.edu                apics.clear();
2483323Shsul@eecs.umich.edu                apics.push_back(selected);
2493323Shsul@eecs.umich.edu            }
2503323Shsul@eecs.umich.edu        }
2513323Shsul@eecs.umich.edu        intMasterPort.sendMessage(apics, message, sys->isTimingMode());
2523323Shsul@eecs.umich.edu    }
2533323Shsul@eecs.umich.edu}
2543323Shsul@eecs.umich.edu
2553323Shsul@eecs.umich.eduvoid
2563323Shsul@eecs.umich.eduX86ISA::I82094AA::raiseInterruptPin(int number)
2573323Shsul@eecs.umich.edu{
2583323Shsul@eecs.umich.edu    assert(number < TableSize);
2593323Shsul@eecs.umich.edu    if (!pinStates[number])
2603323Shsul@eecs.umich.edu        signalInterrupt(number);
2613323Shsul@eecs.umich.edu    pinStates[number] = true;
2623323Shsul@eecs.umich.edu}
2633323Shsul@eecs.umich.edu
2643323Shsul@eecs.umich.eduvoid
2653323Shsul@eecs.umich.eduX86ISA::I82094AA::lowerInterruptPin(int number)
2663323Shsul@eecs.umich.edu{
2673323Shsul@eecs.umich.edu    assert(number < TableSize);
2683323Shsul@eecs.umich.edu    pinStates[number] = false;
2693323Shsul@eecs.umich.edu}
2703323Shsul@eecs.umich.edu
2713323Shsul@eecs.umich.eduvoid
2723323Shsul@eecs.umich.eduX86ISA::I82094AA::serialize(CheckpointOut &cp) const
2733323Shsul@eecs.umich.edu{
2743323Shsul@eecs.umich.edu    uint64_t* redirTableArray = (uint64_t*)redirTable;
2753323Shsul@eecs.umich.edu    SERIALIZE_SCALAR(regSel);
276    SERIALIZE_SCALAR(initialApicId);
277    SERIALIZE_SCALAR(id);
278    SERIALIZE_SCALAR(arbId);
279    SERIALIZE_SCALAR(lowestPriorityOffset);
280    SERIALIZE_ARRAY(redirTableArray, TableSize);
281    SERIALIZE_ARRAY(pinStates, TableSize);
282}
283
284void
285X86ISA::I82094AA::unserialize(CheckpointIn &cp)
286{
287    uint64_t redirTableArray[TableSize];
288    UNSERIALIZE_SCALAR(regSel);
289    UNSERIALIZE_SCALAR(initialApicId);
290    UNSERIALIZE_SCALAR(id);
291    UNSERIALIZE_SCALAR(arbId);
292    UNSERIALIZE_SCALAR(lowestPriorityOffset);
293    UNSERIALIZE_ARRAY(redirTableArray, TableSize);
294    UNSERIALIZE_ARRAY(pinStates, TableSize);
295    for (int i = 0; i < TableSize; i++) {
296        redirTable[i] = (RedirTableEntry)redirTableArray[i];
297    }
298}
299
300X86ISA::I82094AA *
301I82094AAParams::create()
302{
303    return new X86ISA::I82094AA(this);
304}
305