i82094aa.cc revision 13784
12SN/A/*
21762SN/A * Copyright (c) 2008 The Regents of The University of Michigan
35502Snate@binkert.org * All rights reserved.
49983Sstever@gmail.com *
52SN/A * Redistribution and use in source and binary forms, with or without
62SN/A * modification, are permitted provided that the following conditions are
72SN/A * met: redistributions of source code must retain the above copyright
82SN/A * notice, this list of conditions and the following disclaimer;
92SN/A * redistributions in binary form must reproduce the above copyright
102SN/A * notice, this list of conditions and the following disclaimer in the
112SN/A * documentation and/or other materials provided with the distribution;
122SN/A * neither the name of the copyright holders nor the names of its
132SN/A * contributors may be used to endorse or promote products derived from
142SN/A * this software without specific prior written permission.
152SN/A *
162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272SN/A *
282SN/A * Authors: Gabe Black
292665Ssaidi@eecs.umich.edu */
302665Ssaidi@eecs.umich.edu
312665Ssaidi@eecs.umich.edu#include "dev/x86/i82094aa.hh"
322665Ssaidi@eecs.umich.edu
332SN/A#include "arch/x86/interrupts.hh"
342SN/A#include "arch/x86/intmessage.hh"
355501Snate@binkert.org#include "cpu/base.hh"
362SN/A#include "debug/I82094AA.hh"
372SN/A#include "dev/x86/i8259.hh"
382SN/A#include "mem/packet.hh"
392SN/A#include "mem/packet_access.hh"
405502Snate@binkert.org#include "sim/system.hh"
415501Snate@binkert.org
425501Snate@binkert.orgX86ISA::I82094AA::I82094AA(Params *p)
431717SN/A    : BasicPioDevice(p, 20), IntDevice(this, p->int_latency),
4410906Sandreas.sandberg@arm.com      extIntPic(p->external_int_pic), lowestPriorityOffset(0)
455501Snate@binkert.org{
469356Snilay@cs.wisc.edu    // This assumes there's only one I/O APIC in the system and since the apic
472SN/A    // id is stored in a 8-bit field with 0xff meaning broadcast, the id must
482SN/A    // be less than 0xff
492SN/A
509983Sstever@gmail.com    assert(p->apic_id < 0xff);
519983Sstever@gmail.com    initialApicId = id = p->apic_id;
522SN/A    arbId = id;
539983Sstever@gmail.com    regSel = 0;
542SN/A    RedirTableEntry entry = 0;
559983Sstever@gmail.com    entry.mask = 1;
562SN/A    for (int i = 0; i < TableSize; i++) {
572SN/A        redirTable[i] = entry;
589983Sstever@gmail.com        pinStates[i] = false;
599983Sstever@gmail.com    }
609983Sstever@gmail.com}
619983Sstever@gmail.com
629983Sstever@gmail.comvoid
639983Sstever@gmail.comX86ISA::I82094AA::init()
649983Sstever@gmail.com{
659983Sstever@gmail.com    // The io apic must register its address ranges on both its pio port
669983Sstever@gmail.com    // via the piodevice init() function and its int port that it inherited
679983Sstever@gmail.com    // from IntDevice.  Note IntDevice is not a SimObject itself.
689983Sstever@gmail.com
699983Sstever@gmail.com    BasicPioDevice::init();
709983Sstever@gmail.com    IntDevice::init();
719983Sstever@gmail.com}
729983Sstever@gmail.com
739983Sstever@gmail.comPort &
742SN/AX86ISA::I82094AA::getPort(const std::string &if_name, PortID idx)
754017Sstever@eecs.umich.edu{
764016Sstever@eecs.umich.edu    if (if_name == "int_master")
774017Sstever@eecs.umich.edu        return intMasterPort;
784016Sstever@eecs.umich.edu    return BasicPioDevice::getPort(if_name, idx);
795768Snate@binkert.org}
805768Snate@binkert.org
815774Snate@binkert.orgAddrRangeList
827059Snate@binkert.orgX86ISA::I82094AA::getIntAddrRange() const
835768Snate@binkert.org{
845768Snate@binkert.org    AddrRangeList ranges;
855768Snate@binkert.org    ranges.push_back(RangeEx(x86InterruptAddress(initialApicId, 0),
865768Snate@binkert.org                             x86InterruptAddress(initialApicId, 0) +
875768Snate@binkert.org                             PhysAddrAPICRangeSize));
885768Snate@binkert.org    return ranges;
895768Snate@binkert.org}
905768Snate@binkert.org
915768Snate@binkert.orgTick
925768Snate@binkert.orgX86ISA::I82094AA::recvResponse(PacketPtr pkt)
935768Snate@binkert.org{
945768Snate@binkert.org    // Packet instantiated calling sendMessage() in signalInterrupt()
955768Snate@binkert.org    delete pkt;
965602Snate@binkert.org    return 0;
975602Snate@binkert.org}
985502Snate@binkert.org
995503Snate@binkert.orgTick
1005502Snate@binkert.orgX86ISA::I82094AA::read(PacketPtr pkt)
1015502Snate@binkert.org{
1025502Snate@binkert.org    assert(pkt->getSize() == 4);
1035502Snate@binkert.org    Addr offset = pkt->getAddr() - pioAddr;
1045502Snate@binkert.org    switch(offset) {
1055503Snate@binkert.org      case 0:
1065502Snate@binkert.org        pkt->setLE<uint32_t>(regSel);
1075502Snate@binkert.org        break;
1085502Snate@binkert.org      case 16:
1095502Snate@binkert.org        pkt->setLE<uint32_t>(readReg(regSel));
1105503Snate@binkert.org        break;
1115503Snate@binkert.org      default:
1125503Snate@binkert.org        panic("Illegal read from I/O APIC.\n");
1135502Snate@binkert.org    }
1145503Snate@binkert.org    pkt->makeAtomicResponse();
1155502Snate@binkert.org    return pioDelay;
1165502Snate@binkert.org}
1172SN/A
1182SN/ATick
1192SN/AX86ISA::I82094AA::write(PacketPtr pkt)
1205502Snate@binkert.org{
1215502Snate@binkert.org    assert(pkt->getSize() == 4);
1225602Snate@binkert.org    Addr offset = pkt->getAddr() - pioAddr;
1235502Snate@binkert.org    switch(offset) {
1245502Snate@binkert.org      case 0:
1252SN/A        regSel = pkt->getLE<uint32_t>();
1265502Snate@binkert.org        break;
1275502Snate@binkert.org      case 16:
1285503Snate@binkert.org        writeReg(regSel, pkt->getLE<uint32_t>());
1295503Snate@binkert.org        break;
1305503Snate@binkert.org      default:
1315503Snate@binkert.org        panic("Illegal write to I/O APIC.\n");
1325503Snate@binkert.org    }
1335502Snate@binkert.org    pkt->makeAtomicResponse();
1342SN/A    return pioDelay;
1355503Snate@binkert.org}
1365503Snate@binkert.org
1375602Snate@binkert.orgvoid
1385502Snate@binkert.orgX86ISA::I82094AA::writeReg(uint8_t offset, uint32_t value)
1392SN/A{
1405602Snate@binkert.org    if (offset == 0x0) {
1415602Snate@binkert.org        id = bits(value, 31, 24);
1425502Snate@binkert.org    } else if (offset == 0x1) {
1435503Snate@binkert.org        // The IOAPICVER register is read only.
1445503Snate@binkert.org    } else if (offset == 0x2) {
1455502Snate@binkert.org        arbId = bits(value, 31, 24);
1465503Snate@binkert.org    } else if (offset >= 0x10 && offset <= (0x10 + TableSize * 2)) {
1475503Snate@binkert.org        int index = (offset - 0x10) / 2;
1485503Snate@binkert.org        if (offset % 2) {
1495503Snate@binkert.org            redirTable[index].topDW = value;
1505503Snate@binkert.org            redirTable[index].topReserved = 0;
1515503Snate@binkert.org        } else {
1525503Snate@binkert.org            redirTable[index].bottomDW = value;
1535503Snate@binkert.org            redirTable[index].bottomReserved = 0;
1545503Snate@binkert.org        }
1555503Snate@binkert.org    } else {
1565503Snate@binkert.org        warn("Access to undefined I/O APIC register %#x.\n", offset);
1575503Snate@binkert.org    }
1585503Snate@binkert.org    DPRINTF(I82094AA,
1595503Snate@binkert.org            "Wrote %#x to I/O APIC register %#x .\n", value, offset);
1605502Snate@binkert.org}
1615502Snate@binkert.org
1625503Snate@binkert.orguint32_t
1635503Snate@binkert.orgX86ISA::I82094AA::readReg(uint8_t offset)
1642SN/A{
1655502Snate@binkert.org    uint32_t result = 0;
1665503Snate@binkert.org    if (offset == 0x0) {
1675503Snate@binkert.org        result = id << 24;
1685503Snate@binkert.org    } else if (offset == 0x1) {
1692SN/A        result = ((TableSize - 1) << 16) | APICVersion;
1702SN/A    } else if (offset == 0x2) {
1712SN/A        result = arbId << 24;
1722SN/A    } else if (offset >= 0x10 && offset <= (0x10 + TableSize * 2)) {
1732SN/A        int index = (offset - 0x10) / 2;
1742SN/A        if (offset % 2) {
1755502Snate@binkert.org            result = redirTable[index].topDW;
1762SN/A        } else {
1779983Sstever@gmail.com            result = redirTable[index].bottomDW;
1789983Sstever@gmail.com        }
1795502Snate@binkert.org    } else {
1805502Snate@binkert.org        warn("Access to undefined I/O APIC register %#x.\n", offset);
1815502Snate@binkert.org    }
1825602Snate@binkert.org    DPRINTF(I82094AA,
1832SN/A            "Read %#x from I/O APIC register %#x.\n", result, offset);
1842SN/A    return result;
1852SN/A}
1865502Snate@binkert.org
1872SN/Avoid
1885502Snate@binkert.orgX86ISA::I82094AA::signalInterrupt(int line)
1895502Snate@binkert.org{
1902SN/A    DPRINTF(I82094AA, "Received interrupt %d.\n", line);
1915502Snate@binkert.org    assert(line < TableSize);
1922SN/A    RedirTableEntry entry = redirTable[line];
1932SN/A    if (entry.mask) {
1945502Snate@binkert.org        DPRINTF(I82094AA, "Entry was masked.\n");
1955502Snate@binkert.org        return;
1965502Snate@binkert.org    } else {
1975503Snate@binkert.org        TriggerIntMessage message = 0;
1985503Snate@binkert.org        message.destination = entry.dest;
1995502Snate@binkert.org        if (entry.deliveryMode == DeliveryMode::ExtInt) {
2005602Snate@binkert.org            assert(extIntPic);
2012SN/A            message.vector = extIntPic->getVector();
2022SN/A        } else {
2032667Sstever@eecs.umich.edu            message.vector = entry.vector;
2042SN/A        }
2052SN/A        message.deliveryMode = entry.deliveryMode;
20610153Sandreas@sandberg.pp.se        message.destMode = entry.destMode;
2075503Snate@binkert.org        message.level = entry.polarity;
2085503Snate@binkert.org        message.trigger = entry.trigger;
2095769Snate@binkert.org        ApicList apics;
2105502Snate@binkert.org        int numContexts = sys->numContexts();
2115503Snate@binkert.org        if (message.destMode == 0) {
2125503Snate@binkert.org            if (message.deliveryMode == DeliveryMode::LowestPriority) {
2135503Snate@binkert.org                panic("Lowest priority delivery mode from the "
2145503Snate@binkert.org                        "IO APIC aren't supported in physical "
2155503Snate@binkert.org                        "destination mode.\n");
2165503Snate@binkert.org            }
2175503Snate@binkert.org            if (message.destination == 0xFF) {
2185502Snate@binkert.org                for (int i = 0; i < numContexts; i++) {
2195502Snate@binkert.org                    apics.push_back(i);
2205503Snate@binkert.org                }
2215502Snate@binkert.org            } else {
2222SN/A                apics.push_back(message.destination);
2232SN/A            }
2242667Sstever@eecs.umich.edu        } else {
2259356Snilay@cs.wisc.edu            for (int i = 0; i < numContexts; i++) {
2269356Snilay@cs.wisc.edu                Interrupts *localApic = sys->getThreadContext(i)->
2279356Snilay@cs.wisc.edu                    getCpuPtr()->getInterruptController(0);
2282SN/A                if ((localApic->readReg(APIC_LOGICAL_DESTINATION) >> 24) &
2292667Sstever@eecs.umich.edu                        message.destination) {
2309328SAli.Saidi@ARM.com                    apics.push_back(localApic->getInitialApicId());
2319328SAli.Saidi@ARM.com                }
2322667Sstever@eecs.umich.edu            }
2332667Sstever@eecs.umich.edu            if (message.deliveryMode == DeliveryMode::LowestPriority &&
2342667Sstever@eecs.umich.edu                    apics.size()) {
2355769Snate@binkert.org                // The manual seems to suggest that the chipset just does
2362667Sstever@eecs.umich.edu                // something reasonable for these instead of actually using
2372SN/A                // state from the local APIC. We'll just rotate an offset
2385769Snate@binkert.org                // through the set of APICs selected above.
2392SN/A                uint64_t modOffset = lowestPriorityOffset % apics.size();
2402667Sstever@eecs.umich.edu                lowestPriorityOffset++;
2412667Sstever@eecs.umich.edu                ApicList::iterator apicIt = apics.begin();
2422SN/A                while (modOffset--) {
2432SN/A                    apicIt++;
244224SN/A                    assert(apicIt != apics.end());
24510905Sandreas.sandberg@arm.com                }
246224SN/A                int selected = *apicIt;
247224SN/A                apics.clear();
248224SN/A                apics.push_back(selected);
2495769Snate@binkert.org            }
2505769Snate@binkert.org        }
251224SN/A        intMasterPort.sendMessage(apics, message, sys->isTimingMode());
252224SN/A    }
253224SN/A}
25410905Sandreas.sandberg@arm.com
255224SN/Avoid
25610906Sandreas.sandberg@arm.comX86ISA::I82094AA::raiseInterruptPin(int number)
257224SN/A{
258224SN/A    assert(number < TableSize);
259224SN/A    if (!pinStates[number])
260224SN/A        signalInterrupt(number);
26110906Sandreas.sandberg@arm.com    pinStates[number] = true;
2625769Snate@binkert.org}
2637452SLisa.Hsu@amd.com
2647452SLisa.Hsu@amd.comvoid
2657452SLisa.Hsu@amd.comX86ISA::I82094AA::lowerInterruptPin(int number)
2667452SLisa.Hsu@amd.com{
2677452SLisa.Hsu@amd.com    assert(number < TableSize);
2687452SLisa.Hsu@amd.com    pinStates[number] = false;
2697452SLisa.Hsu@amd.com}
2707451SLisa.Hsu@amd.com
2715769Snate@binkert.orgvoid
2727451SLisa.Hsu@amd.comX86ISA::I82094AA::serialize(CheckpointOut &cp) const
2735769Snate@binkert.org{
2747452SLisa.Hsu@amd.com    uint64_t* redirTableArray = (uint64_t*)redirTable;
2757452SLisa.Hsu@amd.com    SERIALIZE_SCALAR(regSel);
2767452SLisa.Hsu@amd.com    SERIALIZE_SCALAR(initialApicId);
27710906Sandreas.sandberg@arm.com    SERIALIZE_SCALAR(id);
27810906Sandreas.sandberg@arm.com    SERIALIZE_SCALAR(arbId);
27910906Sandreas.sandberg@arm.com    SERIALIZE_SCALAR(lowestPriorityOffset);
28010906Sandreas.sandberg@arm.com    SERIALIZE_ARRAY(redirTableArray, TableSize);
28110906Sandreas.sandberg@arm.com    SERIALIZE_ARRAY(pinStates, TableSize);
282224SN/A}
283224SN/A
284224SN/Avoid
2852SN/AX86ISA::I82094AA::unserialize(CheckpointIn &cp)
28610905Sandreas.sandberg@arm.com{
2872SN/A    uint64_t redirTableArray[TableSize];
288265SN/A    UNSERIALIZE_SCALAR(regSel);
289237SN/A    UNSERIALIZE_SCALAR(initialApicId);
290237SN/A    UNSERIALIZE_SCALAR(id);
2915502Snate@binkert.org    UNSERIALIZE_SCALAR(arbId);
2925502Snate@binkert.org    UNSERIALIZE_SCALAR(lowestPriorityOffset);
2935503Snate@binkert.org    UNSERIALIZE_ARRAY(redirTableArray, TableSize);
2945502Snate@binkert.org    UNSERIALIZE_ARRAY(pinStates, TableSize);
2955503Snate@binkert.org    for (int i = 0; i < TableSize; i++) {
2965769Snate@binkert.org        redirTable[i] = (RedirTableEntry)redirTableArray[i];
2975502Snate@binkert.org    }
29810905Sandreas.sandberg@arm.com}
2995502Snate@binkert.org
3005502Snate@binkert.orgX86ISA::I82094AA *
3015502Snate@binkert.orgI82094AAParams::create()
3025503Snate@binkert.org{
3035502Snate@binkert.org    return new X86ISA::I82094AA(this);
3045502Snate@binkert.org}
3052SN/A