i82094aa.cc revision 14290:fa11f961ae4e
11689SN/A/*
21689SN/A * Copyright (c) 2008 The Regents of The University of Michigan
31689SN/A * All rights reserved.
41689SN/A *
51689SN/A * Redistribution and use in source and binary forms, with or without
61689SN/A * modification, are permitted provided that the following conditions are
71689SN/A * met: redistributions of source code must retain the above copyright
81689SN/A * notice, this list of conditions and the following disclaimer;
91689SN/A * redistributions in binary form must reproduce the above copyright
101689SN/A * notice, this list of conditions and the following disclaimer in the
111689SN/A * documentation and/or other materials provided with the distribution;
121689SN/A * neither the name of the copyright holders nor the names of its
131689SN/A * contributors may be used to endorse or promote products derived from
141689SN/A * this software without specific prior written permission.
151689SN/A *
161689SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
171689SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
181689SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
191689SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
201689SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
211689SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
221689SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
231689SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
241689SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
251689SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
261689SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665Ssaidi@eecs.umich.edu *
282665Ssaidi@eecs.umich.edu * Authors: Gabe Black
291689SN/A */
301689SN/A
311060SN/A#include "dev/x86/i82094aa.hh"
321060SN/A
331689SN/A#include "arch/x86/interrupts.hh"
341061SN/A#include "arch/x86/intmessage.hh"
351060SN/A#include "cpu/base.hh"
361060SN/A#include "debug/I82094AA.hh"
371060SN/A#include "dev/x86/i8259.hh"
381060SN/A#include "mem/packet.hh"
391717SN/A#include "mem/packet_access.hh"
401060SN/A#include "sim/system.hh"
411681SN/A
421681SN/AX86ISA::I82094AA::I82094AA(Params *p)
431681SN/A    : BasicPioDevice(p, 20), IntDevice(this, p->int_latency),
441681SN/A      extIntPic(p->external_int_pic), lowestPriorityOffset(0)
451681SN/A{
461681SN/A    // This assumes there's only one I/O APIC in the system and since the apic
471681SN/A    // id is stored in a 8-bit field with 0xff meaning broadcast, the id must
481681SN/A    // be less than 0xff
491681SN/A
501681SN/A    assert(p->apic_id < 0xff);
511681SN/A    initialApicId = id = p->apic_id;
521681SN/A    arbId = id;
531681SN/A    regSel = 0;
541681SN/A    RedirTableEntry entry = 0;
551681SN/A    entry.mask = 1;
561681SN/A    for (int i = 0; i < TableSize; i++) {
571681SN/A        redirTable[i] = entry;
581681SN/A        pinStates[i] = false;
591681SN/A    }
601681SN/A
611681SN/A    for (int i = 0; i < p->port_inputs_connection_count; i++)
621681SN/A        inputs.push_back(new ::IntSinkPin<I82094AA>(
631681SN/A                    csprintf("%s.inputs[%d]", name(), i), i, this));
641681SN/A}
651681SN/A
661681SN/Avoid
671681SN/AX86ISA::I82094AA::init()
681681SN/A{
691681SN/A    // The io apic must register its address ranges on both its pio port
701681SN/A    // via the piodevice init() function and its int port that it inherited
711060SN/A    // from IntDevice.  Note IntDevice is not a SimObject itself.
721061SN/A
731060SN/A    BasicPioDevice::init();
741061SN/A    IntDevice::init();
751060SN/A}
761060SN/A
771060SN/APort &
781060SN/AX86ISA::I82094AA::getPort(const std::string &if_name, PortID idx)
791060SN/A{
801060SN/A    if (if_name == "int_master")
811060SN/A        return intMasterPort;
821060SN/A    if (if_name == "inputs")
831060SN/A        return *inputs.at(idx);
841060SN/A    else
851060SN/A        return BasicPioDevice::getPort(if_name, idx);
861060SN/A}
871060SN/A
881060SN/AAddrRangeList
891060SN/AX86ISA::I82094AA::getIntAddrRange() const
901060SN/A{
911060SN/A    AddrRangeList ranges;
921060SN/A    ranges.push_back(RangeEx(x86InterruptAddress(initialApicId, 0),
931681SN/A                             x86InterruptAddress(initialApicId, 0) +
941681SN/A                             PhysAddrAPICRangeSize));
951060SN/A    return ranges;
961060SN/A}
971681SN/A
981062SN/ATick
991681SN/AX86ISA::I82094AA::recvResponse(PacketPtr pkt)
1001062SN/A{
1011062SN/A    // Packet instantiated calling sendMessage() in signalInterrupt()
1021062SN/A    delete pkt;
1031062SN/A    return 0;
1041062SN/A}
1051062SN/A
1061062SN/ATick
1071062SN/AX86ISA::I82094AA::read(PacketPtr pkt)
1081062SN/A{
1091062SN/A    assert(pkt->getSize() == 4);
1101062SN/A    Addr offset = pkt->getAddr() - pioAddr;
1111062SN/A    switch(offset) {
1121062SN/A      case 0:
1131062SN/A        pkt->setLE<uint32_t>(regSel);
1141062SN/A        break;
1151062SN/A      case 16:
1161062SN/A        pkt->setLE<uint32_t>(readReg(regSel));
1171062SN/A        break;
1181062SN/A      default:
1191062SN/A        panic("Illegal read from I/O APIC.\n");
1201062SN/A    }
1211062SN/A    pkt->makeAtomicResponse();
1221062SN/A    return pioDelay;
1231062SN/A}
1241062SN/A
1251062SN/ATick
1261062SN/AX86ISA::I82094AA::write(PacketPtr pkt)
1271062SN/A{
1281062SN/A    assert(pkt->getSize() == 4);
1291062SN/A    Addr offset = pkt->getAddr() - pioAddr;
1301062SN/A    switch(offset) {
1311062SN/A      case 0:
1321062SN/A        regSel = pkt->getLE<uint32_t>();
1331062SN/A        break;
1341062SN/A      case 16:
1351062SN/A        writeReg(regSel, pkt->getLE<uint32_t>());
1361062SN/A        break;
1371062SN/A      default:
1381062SN/A        panic("Illegal write to I/O APIC.\n");
1391062SN/A    }
1401062SN/A    pkt->makeAtomicResponse();
1411062SN/A    return pioDelay;
1421062SN/A}
1431062SN/A
1441062SN/Avoid
1451062SN/AX86ISA::I82094AA::writeReg(uint8_t offset, uint32_t value)
1461062SN/A{
1471062SN/A    if (offset == 0x0) {
1481062SN/A        id = bits(value, 31, 24);
1491062SN/A    } else if (offset == 0x1) {
1501062SN/A        // The IOAPICVER register is read only.
1511062SN/A    } else if (offset == 0x2) {
1521062SN/A        arbId = bits(value, 31, 24);
1531062SN/A    } else if (offset >= 0x10 && offset <= (0x10 + TableSize * 2)) {
1541062SN/A        int index = (offset - 0x10) / 2;
1551062SN/A        if (offset % 2) {
1561062SN/A            redirTable[index].topDW = value;
1571062SN/A            redirTable[index].topReserved = 0;
1581062SN/A        } else {
1591062SN/A            redirTable[index].bottomDW = value;
1601062SN/A            redirTable[index].bottomReserved = 0;
1611062SN/A        }
1621062SN/A    } else {
1631062SN/A        warn("Access to undefined I/O APIC register %#x.\n", offset);
1641062SN/A    }
1651062SN/A    DPRINTF(I82094AA,
1661062SN/A            "Wrote %#x to I/O APIC register %#x .\n", value, offset);
1671062SN/A}
1681062SN/A
1691062SN/Auint32_t
1701681SN/AX86ISA::I82094AA::readReg(uint8_t offset)
1711060SN/A{
1721681SN/A    uint32_t result = 0;
1731060SN/A    if (offset == 0x0) {
1741060SN/A        result = id << 24;
1751060SN/A    } else if (offset == 0x1) {
1761060SN/A        result = ((TableSize - 1) << 16) | APICVersion;
1771060SN/A    } else if (offset == 0x2) {
1781061SN/A        result = arbId << 24;
1791060SN/A    } else if (offset >= 0x10 && offset <= (0x10 + TableSize * 2)) {
1801060SN/A        int index = (offset - 0x10) / 2;
1811681SN/A        if (offset % 2) {
1821060SN/A            result = redirTable[index].topDW;
1831681SN/A        } else {
1841060SN/A            result = redirTable[index].bottomDW;
1851060SN/A        }
1861060SN/A    } else {
1871060SN/A        warn("Access to undefined I/O APIC register %#x.\n", offset);
1881060SN/A    }
1891060SN/A    DPRINTF(I82094AA,
1901060SN/A            "Read %#x from I/O APIC register %#x.\n", result, offset);
1911060SN/A    return result;
1921060SN/A}
1931060SN/A
1941060SN/Avoid
1951060SN/AX86ISA::I82094AA::signalInterrupt(int line)
1961060SN/A{
1971060SN/A    DPRINTF(I82094AA, "Received interrupt %d.\n", line);
1981681SN/A    assert(line < TableSize);
1991060SN/A    RedirTableEntry entry = redirTable[line];
2001681SN/A    if (entry.mask) {
2011060SN/A        DPRINTF(I82094AA, "Entry was masked.\n");
2021060SN/A        return;
2031060SN/A    } else {
2041060SN/A        TriggerIntMessage message = 0;
2051060SN/A        message.destination = entry.dest;
2061060SN/A        if (entry.deliveryMode == DeliveryMode::ExtInt) {
2071060SN/A            assert(extIntPic);
2081060SN/A            message.vector = extIntPic->getVector();
2091681SN/A        } else {
2101060SN/A            message.vector = entry.vector;
2111681SN/A        }
2121060SN/A        message.deliveryMode = entry.deliveryMode;
2131060SN/A        message.destMode = entry.destMode;
2141060SN/A        message.level = entry.polarity;
2151060SN/A        message.trigger = entry.trigger;
2161060SN/A        ApicList apics;
2171060SN/A        int numContexts = sys->numContexts();
2181060SN/A        if (message.destMode == 0) {
2191060SN/A            if (message.deliveryMode == DeliveryMode::LowestPriority) {
2201681SN/A                panic("Lowest priority delivery mode from the "
2211060SN/A                        "IO APIC aren't supported in physical "
2221681SN/A                        "destination mode.\n");
2231060SN/A            }
2241060SN/A            if (message.destination == 0xFF) {
2251060SN/A                for (int i = 0; i < numContexts; i++) {
2261060SN/A                    apics.push_back(i);
2271060SN/A                }
2281681SN/A            } else {
2291060SN/A                apics.push_back(message.destination);
2301681SN/A            }
2311060SN/A        } else {
2321681SN/A            for (int i = 0; i < numContexts; i++) {
2331681SN/A                Interrupts *localApic = sys->getThreadContext(i)->
2341681SN/A                    getCpuPtr()->getInterruptController(0);
2351681SN/A                if ((localApic->readReg(APIC_LOGICAL_DESTINATION) >> 24) &
2361681SN/A                        message.destination) {
2371681SN/A                    apics.push_back(localApic->getInitialApicId());
2381681SN/A                }
2391681SN/A            }
2401060SN/A            if (message.deliveryMode == DeliveryMode::LowestPriority &&
2411060SN/A                    apics.size()) {
2421681SN/A                // The manual seems to suggest that the chipset just does
2431060SN/A                // something reasonable for these instead of actually using
2441681SN/A                // state from the local APIC. We'll just rotate an offset
2451681SN/A                // through the set of APICs selected above.
2461681SN/A                uint64_t modOffset = lowestPriorityOffset % apics.size();
2471681SN/A                lowestPriorityOffset++;
2481681SN/A                ApicList::iterator apicIt = apics.begin();
2491681SN/A                while (modOffset--) {
2501681SN/A                    apicIt++;
2511681SN/A                    assert(apicIt != apics.end());
2521681SN/A                }
2531681SN/A                int selected = *apicIt;
2541681SN/A                apics.clear();
2551681SN/A                apics.push_back(selected);
2561681SN/A            }
2571681SN/A        }
2581681SN/A        intMasterPort.sendMessage(apics, message, sys->isTimingMode());
2591681SN/A    }
2601681SN/A}
2612107SN/A
2621681SN/Avoid
2631681SN/AX86ISA::I82094AA::raiseInterruptPin(int number)
2641681SN/A{
2651681SN/A    assert(number < TableSize);
2661681SN/A    if (!pinStates[number])
2671681SN/A        signalInterrupt(number);
2681681SN/A    pinStates[number] = true;
2691681SN/A}
2701681SN/A
2711681SN/Avoid
2721681SN/AX86ISA::I82094AA::lowerInterruptPin(int number)
2731681SN/A{
2741681SN/A    assert(number < TableSize);
2751681SN/A    pinStates[number] = false;
2761681SN/A}
2771681SN/A
2781681SN/Avoid
2791681SN/AX86ISA::I82094AA::serialize(CheckpointOut &cp) const
2801681SN/A{
2811681SN/A    uint64_t* redirTableArray = (uint64_t*)redirTable;
2821681SN/A    SERIALIZE_SCALAR(regSel);
2831681SN/A    SERIALIZE_SCALAR(initialApicId);
2841060SN/A    SERIALIZE_SCALAR(id);
2851060SN/A    SERIALIZE_SCALAR(arbId);
2861060SN/A    SERIALIZE_SCALAR(lowestPriorityOffset);
2871060SN/A    SERIALIZE_ARRAY(redirTableArray, TableSize);
2881060SN/A    SERIALIZE_ARRAY(pinStates, TableSize);
2891060SN/A}
2901060SN/A
2911060SN/Avoid
2921060SN/AX86ISA::I82094AA::unserialize(CheckpointIn &cp)
2931060SN/A{
2941060SN/A    uint64_t redirTableArray[TableSize];
2951060SN/A    UNSERIALIZE_SCALAR(regSel);
2961060SN/A    UNSERIALIZE_SCALAR(initialApicId);
2971060SN/A    UNSERIALIZE_SCALAR(id);
2981681SN/A    UNSERIALIZE_SCALAR(arbId);
2991060SN/A    UNSERIALIZE_SCALAR(lowestPriorityOffset);
3001681SN/A    UNSERIALIZE_ARRAY(redirTableArray, TableSize);
3011060SN/A    UNSERIALIZE_ARRAY(pinStates, TableSize);
3021060SN/A    for (int i = 0; i < TableSize; i++) {
3031060SN/A        redirTable[i] = (RedirTableEntry)redirTableArray[i];
3041060SN/A    }
3051060SN/A}
3061060SN/A
3071060SN/AX86ISA::I82094AA *
3081060SN/AI82094AAParams::create()
3091060SN/A{
3101060SN/A    return new X86ISA::I82094AA(this);
3111060SN/A}
3121060SN/A