i82094aa.cc revision 8746
11689SN/A/*
28733Sgeoffrey.blake@arm.com * Copyright (c) 2008 The Regents of The University of Michigan
37783SGiacomo.Gabrielli@arm.com * All rights reserved.
47783SGiacomo.Gabrielli@arm.com *
57783SGiacomo.Gabrielli@arm.com * Redistribution and use in source and binary forms, with or without
67783SGiacomo.Gabrielli@arm.com * modification, are permitted provided that the following conditions are
77783SGiacomo.Gabrielli@arm.com * met: redistributions of source code must retain the above copyright
87783SGiacomo.Gabrielli@arm.com * notice, this list of conditions and the following disclaimer;
97783SGiacomo.Gabrielli@arm.com * redistributions in binary form must reproduce the above copyright
107783SGiacomo.Gabrielli@arm.com * notice, this list of conditions and the following disclaimer in the
117783SGiacomo.Gabrielli@arm.com * documentation and/or other materials provided with the distribution;
127783SGiacomo.Gabrielli@arm.com * neither the name of the copyright holders nor the names of its
137783SGiacomo.Gabrielli@arm.com * contributors may be used to endorse or promote products derived from
142316SN/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.
271689SN/A *
281689SN/A * Authors: Gabe Black
291689SN/A */
301689SN/A
311689SN/A#include "config/full_system.hh"
321689SN/A
331689SN/A#include "arch/x86/interrupts.hh"
341689SN/A#include "arch/x86/intmessage.hh"
351689SN/A#include "cpu/base.hh"
361689SN/A#include "debug/I82094AA.hh"
371689SN/A#include "dev/x86/i82094aa.hh"
381689SN/A#include "dev/x86/i8259.hh"
392665SN/A#include "mem/packet.hh"
402665SN/A#include "mem/packet_access.hh"
411689SN/A#include "sim/system.hh"
421061SN/A
439944Smatt.horsnell@ARM.comX86ISA::I82094AA::I82094AA(Params *p) : PioDevice(p),
449944Smatt.horsnell@ARM.com    IntDev(this, p->int_latency),
459944Smatt.horsnell@ARM.com    latency(p->pio_latency), pioAddr(p->pio_addr),
465953Ssaidi@eecs.umich.edu    extIntPic(p->external_int_pic), lowestPriorityOffset(0)
475596Sgblack@eecs.umich.edu{
488779Sgblack@eecs.umich.edu    // This assumes there's only one I/O APIC in the system and since the apic
499252Sdjordje.kovacevic@arm.com    // id is stored in a 8-bit field with 0xff meaning broadcast, the id must
501061SN/A    // be less than 0xff
511061SN/A
5210417Sandreas.hansson@arm.com    assert(p->apic_id < 0xff);
5310417Sandreas.hansson@arm.com    initialApicId = id = p->apic_id;
547720Sgblack@eecs.umich.edu    arbId = id;
555596Sgblack@eecs.umich.edu    regSel = 0;
568502Sgblack@eecs.umich.edu    RedirTableEntry entry = 0;
574637SN/A    entry.mask = 1;
584637SN/A    for (int i = 0; i < TableSize; i++) {
594637SN/A        redirTable[i] = entry;
604637SN/A        pinStates[i] = false;
614637SN/A    }
6210417Sandreas.hansson@arm.com}
6310417Sandreas.hansson@arm.com
648502Sgblack@eecs.umich.eduvoid
651061SN/AX86ISA::I82094AA::init()
662292SN/A{
672292SN/A    // The io apic must register its address ranges on both its pio port
682292SN/A    // via the piodevice init() function and its int port that it inherited
699252Sdjordje.kovacevic@arm.com    // from IntDev.  Note IntDev is not a SimObject itself.
709252Sdjordje.kovacevic@arm.com
719252Sdjordje.kovacevic@arm.com    PioDevice::init();
729527SMatt.Horsnell@arm.com    IntDev::init();
739527SMatt.Horsnell@arm.com}
749527SMatt.Horsnell@arm.com
759527SMatt.Horsnell@arm.comTick
769527SMatt.Horsnell@arm.comX86ISA::I82094AA::read(PacketPtr pkt)
779527SMatt.Horsnell@arm.com{
789527SMatt.Horsnell@arm.com    assert(pkt->getSize() == 4);
799527SMatt.Horsnell@arm.com    Addr offset = pkt->getAddr() - pioAddr;
809527SMatt.Horsnell@arm.com    switch(offset) {
819527SMatt.Horsnell@arm.com      case 0:
829527SMatt.Horsnell@arm.com        pkt->set<uint32_t>(regSel);
839527SMatt.Horsnell@arm.com        break;
849527SMatt.Horsnell@arm.com      case 16:
859527SMatt.Horsnell@arm.com        pkt->set<uint32_t>(readReg(regSel));
869527SMatt.Horsnell@arm.com        break;
879527SMatt.Horsnell@arm.com      default:
889527SMatt.Horsnell@arm.com        panic("Illegal read from I/O APIC.\n");
899527SMatt.Horsnell@arm.com    }
909527SMatt.Horsnell@arm.com    pkt->makeAtomicResponse();
919527SMatt.Horsnell@arm.com    return latency;
929527SMatt.Horsnell@arm.com}
939527SMatt.Horsnell@arm.com
949527SMatt.Horsnell@arm.comTick
959527SMatt.Horsnell@arm.comX86ISA::I82094AA::write(PacketPtr pkt)
969527SMatt.Horsnell@arm.com{
979527SMatt.Horsnell@arm.com    assert(pkt->getSize() == 4);
989527SMatt.Horsnell@arm.com    Addr offset = pkt->getAddr() - pioAddr;
999527SMatt.Horsnell@arm.com    switch(offset) {
1009527SMatt.Horsnell@arm.com      case 0:
1019252Sdjordje.kovacevic@arm.com        regSel = pkt->get<uint32_t>();
1029252Sdjordje.kovacevic@arm.com        break;
1039252Sdjordje.kovacevic@arm.com      case 16:
1049252Sdjordje.kovacevic@arm.com        writeReg(regSel, pkt->get<uint32_t>());
1052292SN/A        break;
1062292SN/A      default:
1075596Sgblack@eecs.umich.edu        panic("Illegal write to I/O APIC.\n");
1082292SN/A    }
1091464SN/A    pkt->makeAtomicResponse();
1101464SN/A    return latency;
1111464SN/A}
1122292SN/A
1133782SN/Avoid
1141464SN/AX86ISA::I82094AA::writeReg(uint8_t offset, uint32_t value)
1151464SN/A{
1162292SN/A    if (offset == 0x0) {
1173782SN/A        id = bits(value, 31, 24);
1181464SN/A    } else if (offset == 0x1) {
1197783SGiacomo.Gabrielli@arm.com        // The IOAPICVER register is read only.
1209046SAli.Saidi@ARM.com    } else if (offset == 0x2) {
1219046SAli.Saidi@ARM.com        arbId = bits(value, 31, 24);
1227783SGiacomo.Gabrielli@arm.com    } else if (offset >= 0x10 && offset <= (0x10 + TableSize * 2)) {
1238471SGiacomo.Gabrielli@arm.com        int index = (offset - 0x10) / 2;
1248471SGiacomo.Gabrielli@arm.com        if (offset % 2) {
1259252Sdjordje.kovacevic@arm.com            redirTable[index].topDW = value;
1269252Sdjordje.kovacevic@arm.com            redirTable[index].topReserved = 0;
1279252Sdjordje.kovacevic@arm.com        } else {
1289252Sdjordje.kovacevic@arm.com            redirTable[index].bottomDW = value;
1299252Sdjordje.kovacevic@arm.com            redirTable[index].bottomReserved = 0;
1309252Sdjordje.kovacevic@arm.com        }
1319252Sdjordje.kovacevic@arm.com    } else {
1329252Sdjordje.kovacevic@arm.com        warn("Access to undefined I/O APIC register %#x.\n", offset);
1339252Sdjordje.kovacevic@arm.com    }
1349527SMatt.Horsnell@arm.com    DPRINTF(I82094AA,
1358471SGiacomo.Gabrielli@arm.com            "Wrote %#x to I/O APIC register %#x .\n", value, offset);
1361061SN/A}
1371061SN/A
1382292SN/Auint32_t
1392292SN/AX86ISA::I82094AA::readReg(uint8_t offset)
1405596Sgblack@eecs.umich.edu{
1412292SN/A    uint32_t result = 0;
1422348SN/A    if (offset == 0x0) {
1432680SN/A        result = id << 24;
1442348SN/A    } else if (offset == 0x1) {
1452680SN/A        result = ((TableSize - 1) << 16) | APICVersion;
1469382SAli.Saidi@ARM.com    } else if (offset == 0x2) {
1479382SAli.Saidi@ARM.com        result = arbId << 24;
1482292SN/A    } else if (offset >= 0x10 && offset <= (0x10 + TableSize * 2)) {
1492292SN/A        int index = (offset - 0x10) / 2;
1502292SN/A        if (offset % 2) {
1519382SAli.Saidi@ARM.com            result = redirTable[index].topDW;
1522292SN/A        } else {
1532292SN/A            result = redirTable[index].bottomDW;
1542292SN/A        }
1552292SN/A    } else {
1562292SN/A        warn("Access to undefined I/O APIC register %#x.\n", offset);
1572292SN/A    }
1585596Sgblack@eecs.umich.edu    DPRINTF(I82094AA,
1592292SN/A            "Read %#x from I/O APIC register %#x.\n", result, offset);
1602348SN/A    return result;
1612680SN/A}
1622348SN/A
1632680SN/Avoid
1649382SAli.Saidi@ARM.comX86ISA::I82094AA::signalInterrupt(int line)
1659382SAli.Saidi@ARM.com{
1662292SN/A    DPRINTF(I82094AA, "Received interrupt %d.\n", line);
1672292SN/A    assert(line < TableSize);
1682292SN/A    RedirTableEntry entry = redirTable[line];
1699382SAli.Saidi@ARM.com    if (entry.mask) {
1702292SN/A        DPRINTF(I82094AA, "Entry was masked.\n");
1712292SN/A        return;
1722292SN/A    } else {
1732292SN/A        TriggerIntMessage message = 0;
1742292SN/A        message.destination = entry.dest;
1752292SN/A        if (entry.deliveryMode == DeliveryMode::ExtInt) {
1765596Sgblack@eecs.umich.edu            assert(extIntPic);
1772292SN/A            message.vector = extIntPic->getVector();
1787758Sminkyu.jeong@arm.com        } else {
1797758Sminkyu.jeong@arm.com            message.vector = entry.vector;
1807758Sminkyu.jeong@arm.com        }
1817758Sminkyu.jeong@arm.com        message.deliveryMode = entry.deliveryMode;
1829382SAli.Saidi@ARM.com        message.destMode = entry.destMode;
1839382SAli.Saidi@ARM.com        message.level = entry.polarity;
1847758Sminkyu.jeong@arm.com        message.trigger = entry.trigger;
1858887Sgeoffrey.blake@arm.com        ApicList apics;
1868887Sgeoffrey.blake@arm.com        int numContexts = sys->numContexts();
1878887Sgeoffrey.blake@arm.com        if (message.destMode == 0) {
1888887Sgeoffrey.blake@arm.com            if (message.deliveryMode == DeliveryMode::LowestPriority) {
1898733Sgeoffrey.blake@arm.com                panic("Lowest priority delivery mode from the "
1908887Sgeoffrey.blake@arm.com                        "IO APIC aren't supported in physical "
1912790SN/A                        "destination mode.\n");
1922292SN/A            }
1939382SAli.Saidi@ARM.com            if (message.destination == 0xFF) {
1947758Sminkyu.jeong@arm.com                for (int i = 0; i < numContexts; i++) {
1952292SN/A                    apics.push_back(i);
1962292SN/A                }
1972292SN/A            } else {
1981061SN/A                apics.push_back(message.destination);
1995702Ssaidi@eecs.umich.edu            }
2005702Ssaidi@eecs.umich.edu        } else {
2015702Ssaidi@eecs.umich.edu            for (int i = 0; i < numContexts; i++) {
2025702Ssaidi@eecs.umich.edu                Interrupts *localApic = sys->getThreadContext(i)->
2035702Ssaidi@eecs.umich.edu                    getCpuPtr()->getInterruptController();
2047720Sgblack@eecs.umich.edu                if ((localApic->readReg(APIC_LOGICAL_DESTINATION) >> 24) &
20510474Sandreas.hansson@arm.com                        message.destination) {
2065702Ssaidi@eecs.umich.edu                    apics.push_back(localApic->getInitialApicId());
2075702Ssaidi@eecs.umich.edu                }
2087720Sgblack@eecs.umich.edu            }
2097720Sgblack@eecs.umich.edu            if (message.deliveryMode == DeliveryMode::LowestPriority &&
2107720Sgblack@eecs.umich.edu                    apics.size()) {
2117720Sgblack@eecs.umich.edu                // The manual seems to suggest that the chipset just does
2125953Ssaidi@eecs.umich.edu                // something reasonable for these instead of actually using
2135953Ssaidi@eecs.umich.edu                // state from the local APIC. We'll just rotate an offset
2147720Sgblack@eecs.umich.edu                // through the set of APICs selected above.
2155953Ssaidi@eecs.umich.edu                uint64_t modOffset = lowestPriorityOffset % apics.size();
2165702Ssaidi@eecs.umich.edu                lowestPriorityOffset++;
2175702Ssaidi@eecs.umich.edu                ApicList::iterator apicIt = apics.begin();
2185702Ssaidi@eecs.umich.edu                while (modOffset--) {
2195702Ssaidi@eecs.umich.edu                    apicIt++;
2205702Ssaidi@eecs.umich.edu                    assert(apicIt != apics.end());
2215702Ssaidi@eecs.umich.edu                }
2225702Ssaidi@eecs.umich.edu                int selected = *apicIt;
2235702Ssaidi@eecs.umich.edu                apics.clear();
2245702Ssaidi@eecs.umich.edu                apics.push_back(selected);
2255702Ssaidi@eecs.umich.edu            }
2265702Ssaidi@eecs.umich.edu        }
2271061SN/A        intPort->sendMessage(apics, message,
22810379Sandreas.hansson@arm.com                sys->getMemoryMode() == Enums::timing);
2291061SN/A    }
2307684Sgblack@eecs.umich.edu}
2311061SN/A
2325702Ssaidi@eecs.umich.eduvoid
2335702Ssaidi@eecs.umich.eduX86ISA::I82094AA::raiseInterruptPin(int number)
2345702Ssaidi@eecs.umich.edu{
2355702Ssaidi@eecs.umich.edu    assert(number < TableSize);
2365702Ssaidi@eecs.umich.edu    if (!pinStates[number])
2375702Ssaidi@eecs.umich.edu        signalInterrupt(number);
2385702Ssaidi@eecs.umich.edu    pinStates[number] = true;
2395702Ssaidi@eecs.umich.edu}
2405702Ssaidi@eecs.umich.edu
2415702Ssaidi@eecs.umich.eduvoid
2428557Sgblack@eecs.umich.eduX86ISA::I82094AA::lowerInterruptPin(int number)
2431061SN/A{
2441061SN/A    assert(number < TableSize);
2455596Sgblack@eecs.umich.edu    pinStates[number] = false;
2461061SN/A}
2478806Sgblack@eecs.umich.edu
2488779Sgblack@eecs.umich.eduvoid
2498806Sgblack@eecs.umich.eduX86ISA::I82094AA::serialize(std::ostream &os)
2505556SN/A{
2515556SN/A    uint64_t* redirTableArray = (uint64_t*)redirTable;
2525556SN/A    SERIALIZE_SCALAR(regSel);
2537720Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(initialApicId);
2542669SN/A    SERIALIZE_SCALAR(id);
2557720Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(arbId);
2567720Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(lowestPriorityOffset);
2577720Sgblack@eecs.umich.edu    SERIALIZE_ARRAY(redirTableArray, TableSize);
2585556SN/A    SERIALIZE_ARRAY(pinStates, TableSize);
2591061SN/A}
2601061SN/A
2619944Smatt.horsnell@ARM.comvoid
262X86ISA::I82094AA::unserialize(Checkpoint *cp, const std::string &section)
263{
264    uint64_t redirTableArray[TableSize];
265    UNSERIALIZE_SCALAR(regSel);
266    UNSERIALIZE_SCALAR(initialApicId);
267    UNSERIALIZE_SCALAR(id);
268    UNSERIALIZE_SCALAR(arbId);
269    UNSERIALIZE_SCALAR(lowestPriorityOffset);
270    UNSERIALIZE_ARRAY(redirTableArray, TableSize);
271    UNSERIALIZE_ARRAY(pinStates, TableSize);
272    for (int i = 0; i < TableSize; i++) {
273        redirTable[i] = (RedirTableEntry)redirTableArray[i];
274    }
275}
276
277X86ISA::I82094AA *
278I82094AAParams::create()
279{
280    return new X86ISA::I82094AA(this);
281}
282