i82094aa.cc revision 11793
111723Sar4jc@virginia.edu/*
211723Sar4jc@virginia.edu * Copyright (c) 2008 The Regents of The University of Michigan
311723Sar4jc@virginia.edu * All rights reserved.
412808Srobert.scheffel1@tu-dresden.de *
511723Sar4jc@virginia.edu * Redistribution and use in source and binary forms, with or without
611723Sar4jc@virginia.edu * modification, are permitted provided that the following conditions are
711723Sar4jc@virginia.edu * met: redistributions of source code must retain the above copyright
811723Sar4jc@virginia.edu * notice, this list of conditions and the following disclaimer;
911723Sar4jc@virginia.edu * redistributions in binary form must reproduce the above copyright
1011723Sar4jc@virginia.edu * notice, this list of conditions and the following disclaimer in the
1111723Sar4jc@virginia.edu * documentation and/or other materials provided with the distribution;
1211723Sar4jc@virginia.edu * neither the name of the copyright holders nor the names of its
1311723Sar4jc@virginia.edu * contributors may be used to endorse or promote products derived from
1411723Sar4jc@virginia.edu * this software without specific prior written permission.
1511723Sar4jc@virginia.edu *
1611723Sar4jc@virginia.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1711723Sar4jc@virginia.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1811723Sar4jc@virginia.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1911723Sar4jc@virginia.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2011723Sar4jc@virginia.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2111723Sar4jc@virginia.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2211723Sar4jc@virginia.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2311723Sar4jc@virginia.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2411723Sar4jc@virginia.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2511723Sar4jc@virginia.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2611723Sar4jc@virginia.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2711723Sar4jc@virginia.edu *
2811723Sar4jc@virginia.edu * Authors: Gabe Black
2911723Sar4jc@virginia.edu */
3011723Sar4jc@virginia.edu
3112808Srobert.scheffel1@tu-dresden.de#include "dev/x86/i82094aa.hh"
3211723Sar4jc@virginia.edu
3311723Sar4jc@virginia.edu#include "arch/x86/interrupts.hh"
3411723Sar4jc@virginia.edu#include "arch/x86/intmessage.hh"
3511723Sar4jc@virginia.edu#include "cpu/base.hh"
3611723Sar4jc@virginia.edu#include "debug/I82094AA.hh"
3711723Sar4jc@virginia.edu#include "dev/x86/i8259.hh"
3811723Sar4jc@virginia.edu#include "mem/packet.hh"
3912848Sar4jc@virginia.edu#include "mem/packet_access.hh"
4011723Sar4jc@virginia.edu#include "sim/system.hh"
4111723Sar4jc@virginia.edu
4211723Sar4jc@virginia.eduX86ISA::I82094AA::I82094AA(Params *p)
4311723Sar4jc@virginia.edu    : BasicPioDevice(p, 20), IntDevice(this, p->int_latency),
4411723Sar4jc@virginia.edu      extIntPic(p->external_int_pic), lowestPriorityOffset(0)
4511723Sar4jc@virginia.edu{
4612848Sar4jc@virginia.edu    // This assumes there's only one I/O APIC in the system and since the apic
4712848Sar4jc@virginia.edu    // id is stored in a 8-bit field with 0xff meaning broadcast, the id must
4812848Sar4jc@virginia.edu    // be less than 0xff
4912848Sar4jc@virginia.edu
5012848Sar4jc@virginia.edu    assert(p->apic_id < 0xff);
5112848Sar4jc@virginia.edu    initialApicId = id = p->apic_id;
5212848Sar4jc@virginia.edu    arbId = id;
5311725Sar4jc@virginia.edu    regSel = 0;
5412848Sar4jc@virginia.edu    RedirTableEntry entry = 0;
5511723Sar4jc@virginia.edu    entry.mask = 1;
5611723Sar4jc@virginia.edu    for (int i = 0; i < TableSize; i++) {
5711723Sar4jc@virginia.edu        redirTable[i] = entry;
5811723Sar4jc@virginia.edu        pinStates[i] = false;
5911723Sar4jc@virginia.edu    }
6011723Sar4jc@virginia.edu}
6111723Sar4jc@virginia.edu
6211723Sar4jc@virginia.eduvoid
6311723Sar4jc@virginia.eduX86ISA::I82094AA::init()
6411723Sar4jc@virginia.edu{
6511723Sar4jc@virginia.edu    // The io apic must register its address ranges on both its pio port
6611723Sar4jc@virginia.edu    // via the piodevice init() function and its int port that it inherited
6712848Sar4jc@virginia.edu    // from IntDevice.  Note IntDevice is not a SimObject itself.
6812848Sar4jc@virginia.edu
6912848Sar4jc@virginia.edu    BasicPioDevice::init();
7012848Sar4jc@virginia.edu    IntDevice::init();
7112848Sar4jc@virginia.edu}
7211723Sar4jc@virginia.edu
7311723Sar4jc@virginia.eduBaseMasterPort &
7412848Sar4jc@virginia.eduX86ISA::I82094AA::getMasterPort(const std::string &if_name, PortID idx)
7512848Sar4jc@virginia.edu{
7612848Sar4jc@virginia.edu    if (if_name == "int_master")
7712848Sar4jc@virginia.edu        return intMasterPort;
7812848Sar4jc@virginia.edu    return BasicPioDevice::getMasterPort(if_name, idx);
7912848Sar4jc@virginia.edu}
8012848Sar4jc@virginia.edu
8112848Sar4jc@virginia.eduAddrRangeList
8212848Sar4jc@virginia.eduX86ISA::I82094AA::getIntAddrRange() const
8312848Sar4jc@virginia.edu{
8412848Sar4jc@virginia.edu    AddrRangeList ranges;
8512848Sar4jc@virginia.edu    ranges.push_back(RangeEx(x86InterruptAddress(initialApicId, 0),
8612848Sar4jc@virginia.edu                             x86InterruptAddress(initialApicId, 0) +
8712848Sar4jc@virginia.edu                             PhysAddrAPICRangeSize));
8812848Sar4jc@virginia.edu    return ranges;
8912848Sar4jc@virginia.edu}
9012848Sar4jc@virginia.edu
9112848Sar4jc@virginia.eduTick
9212848Sar4jc@virginia.eduX86ISA::I82094AA::recvResponse(PacketPtr pkt)
9312848Sar4jc@virginia.edu{
9412848Sar4jc@virginia.edu    // Packet instantiated calling sendMessage() in signalInterrupt()
9512848Sar4jc@virginia.edu    delete pkt->req;
9612848Sar4jc@virginia.edu    delete pkt;
9712848Sar4jc@virginia.edu    return 0;
9812848Sar4jc@virginia.edu}
9912848Sar4jc@virginia.edu
10012848Sar4jc@virginia.eduTick
10112848Sar4jc@virginia.eduX86ISA::I82094AA::read(PacketPtr pkt)
10212848Sar4jc@virginia.edu{
10312848Sar4jc@virginia.edu    assert(pkt->getSize() == 4);
10412848Sar4jc@virginia.edu    Addr offset = pkt->getAddr() - pioAddr;
10512848Sar4jc@virginia.edu    switch(offset) {
10612848Sar4jc@virginia.edu      case 0:
10712848Sar4jc@virginia.edu        pkt->set<uint32_t>(regSel);
10812848Sar4jc@virginia.edu        break;
10912848Sar4jc@virginia.edu      case 16:
11012848Sar4jc@virginia.edu        pkt->set<uint32_t>(readReg(regSel));
11112848Sar4jc@virginia.edu        break;
11212848Sar4jc@virginia.edu      default:
11312848Sar4jc@virginia.edu        panic("Illegal read from I/O APIC.\n");
11412848Sar4jc@virginia.edu    }
11512848Sar4jc@virginia.edu    pkt->makeAtomicResponse();
11612848Sar4jc@virginia.edu    return pioDelay;
11712848Sar4jc@virginia.edu}
11812848Sar4jc@virginia.edu
11912848Sar4jc@virginia.eduTick
12011723Sar4jc@virginia.eduX86ISA::I82094AA::write(PacketPtr pkt)
12111723Sar4jc@virginia.edu{
12211723Sar4jc@virginia.edu    assert(pkt->getSize() == 4);
12311723Sar4jc@virginia.edu    Addr offset = pkt->getAddr() - pioAddr;
12411723Sar4jc@virginia.edu    switch(offset) {
12512848Sar4jc@virginia.edu      case 0:
12611723Sar4jc@virginia.edu        regSel = pkt->get<uint32_t>();
12711723Sar4jc@virginia.edu        break;
12812848Sar4jc@virginia.edu      case 16:
12912848Sar4jc@virginia.edu        writeReg(regSel, pkt->get<uint32_t>());
13011723Sar4jc@virginia.edu        break;
13111723Sar4jc@virginia.edu      default:
13212849Sar4jc@virginia.edu        panic("Illegal write to I/O APIC.\n");
13312848Sar4jc@virginia.edu    }
13412848Sar4jc@virginia.edu    pkt->makeAtomicResponse();
13512849Sar4jc@virginia.edu    return pioDelay;
13611723Sar4jc@virginia.edu}
13712848Sar4jc@virginia.edu
13812848Sar4jc@virginia.eduvoid
13911723Sar4jc@virginia.eduX86ISA::I82094AA::writeReg(uint8_t offset, uint32_t value)
14011723Sar4jc@virginia.edu{
14112808Srobert.scheffel1@tu-dresden.de    if (offset == 0x0) {
14212808Srobert.scheffel1@tu-dresden.de        id = bits(value, 31, 24);
14312808Srobert.scheffel1@tu-dresden.de    } else if (offset == 0x1) {
14412808Srobert.scheffel1@tu-dresden.de        // The IOAPICVER register is read only.
14512808Srobert.scheffel1@tu-dresden.de    } else if (offset == 0x2) {
14612808Srobert.scheffel1@tu-dresden.de        arbId = bits(value, 31, 24);
14712808Srobert.scheffel1@tu-dresden.de    } else if (offset >= 0x10 && offset <= (0x10 + TableSize * 2)) {
14812808Srobert.scheffel1@tu-dresden.de        int index = (offset - 0x10) / 2;
14912808Srobert.scheffel1@tu-dresden.de        if (offset % 2) {
15012808Srobert.scheffel1@tu-dresden.de            redirTable[index].topDW = value;
15112808Srobert.scheffel1@tu-dresden.de            redirTable[index].topReserved = 0;
15212808Srobert.scheffel1@tu-dresden.de        } else {
15312808Srobert.scheffel1@tu-dresden.de            redirTable[index].bottomDW = value;
15412808Srobert.scheffel1@tu-dresden.de            redirTable[index].bottomReserved = 0;
15512808Srobert.scheffel1@tu-dresden.de        }
15612808Srobert.scheffel1@tu-dresden.de    } else {
15712808Srobert.scheffel1@tu-dresden.de        warn("Access to undefined I/O APIC register %#x.\n", offset);
15812808Srobert.scheffel1@tu-dresden.de    }
15912808Srobert.scheffel1@tu-dresden.de    DPRINTF(I82094AA,
16012808Srobert.scheffel1@tu-dresden.de            "Wrote %#x to I/O APIC register %#x .\n", value, offset);
16112808Srobert.scheffel1@tu-dresden.de}
16211723Sar4jc@virginia.edu
16312849Sar4jc@virginia.eduuint32_t
16412849Sar4jc@virginia.eduX86ISA::I82094AA::readReg(uint8_t offset)
16512849Sar4jc@virginia.edu{
16612849Sar4jc@virginia.edu    uint32_t result = 0;
16712849Sar4jc@virginia.edu    if (offset == 0x0) {
16812849Sar4jc@virginia.edu        result = id << 24;
16912849Sar4jc@virginia.edu    } else if (offset == 0x1) {
17012849Sar4jc@virginia.edu        result = ((TableSize - 1) << 16) | APICVersion;
17112849Sar4jc@virginia.edu    } else if (offset == 0x2) {
17212849Sar4jc@virginia.edu        result = arbId << 24;
17312849Sar4jc@virginia.edu    } else if (offset >= 0x10 && offset <= (0x10 + TableSize * 2)) {
17412849Sar4jc@virginia.edu        int index = (offset - 0x10) / 2;
17512849Sar4jc@virginia.edu        if (offset % 2) {
17612849Sar4jc@virginia.edu            result = redirTable[index].topDW;
17711723Sar4jc@virginia.edu        } else {
17811723Sar4jc@virginia.edu            result = redirTable[index].bottomDW;
17912849Sar4jc@virginia.edu        }
18012849Sar4jc@virginia.edu    } else {
18111723Sar4jc@virginia.edu        warn("Access to undefined I/O APIC register %#x.\n", offset);
18211723Sar4jc@virginia.edu    }
18312848Sar4jc@virginia.edu    DPRINTF(I82094AA,
18411723Sar4jc@virginia.edu            "Read %#x from I/O APIC register %#x.\n", result, offset);
18511723Sar4jc@virginia.edu    return result;
18612849Sar4jc@virginia.edu}
18712136Sar4jc@virginia.edu
18812136Sar4jc@virginia.eduvoid
18912136Sar4jc@virginia.eduX86ISA::I82094AA::signalInterrupt(int line)
19012848Sar4jc@virginia.edu{
19112136Sar4jc@virginia.edu    DPRINTF(I82094AA, "Received interrupt %d.\n", line);
19212849Sar4jc@virginia.edu    assert(line < TableSize);
19312849Sar4jc@virginia.edu    RedirTableEntry entry = redirTable[line];
19412136Sar4jc@virginia.edu    if (entry.mask) {
19512136Sar4jc@virginia.edu        DPRINTF(I82094AA, "Entry was masked.\n");
19612848Sar4jc@virginia.edu        return;
19712136Sar4jc@virginia.edu    } else {
19812136Sar4jc@virginia.edu        TriggerIntMessage message = 0;
19912849Sar4jc@virginia.edu        message.destination = entry.dest;
20011723Sar4jc@virginia.edu        if (entry.deliveryMode == DeliveryMode::ExtInt) {
20111723Sar4jc@virginia.edu            assert(extIntPic);
20211723Sar4jc@virginia.edu            message.vector = extIntPic->getVector();
20312848Sar4jc@virginia.edu        } else {
20411723Sar4jc@virginia.edu            message.vector = entry.vector;
20512849Sar4jc@virginia.edu        }
20612849Sar4jc@virginia.edu        message.deliveryMode = entry.deliveryMode;
20712848Sar4jc@virginia.edu        message.destMode = entry.destMode;
20811723Sar4jc@virginia.edu        message.level = entry.polarity;
20911723Sar4jc@virginia.edu        message.trigger = entry.trigger;
21012848Sar4jc@virginia.edu        ApicList apics;
21111723Sar4jc@virginia.edu        int numContexts = sys->numContexts();
21211723Sar4jc@virginia.edu        if (message.destMode == 0) {
21312849Sar4jc@virginia.edu            if (message.deliveryMode == DeliveryMode::LowestPriority) {
21411725Sar4jc@virginia.edu                panic("Lowest priority delivery mode from the "
21511725Sar4jc@virginia.edu                        "IO APIC aren't supported in physical "
21611725Sar4jc@virginia.edu                        "destination mode.\n");
21712848Sar4jc@virginia.edu            }
21811725Sar4jc@virginia.edu            if (message.destination == 0xFF) {
21912849Sar4jc@virginia.edu                for (int i = 0; i < numContexts; i++) {
22012849Sar4jc@virginia.edu                    apics.push_back(i);
22112848Sar4jc@virginia.edu                }
22211725Sar4jc@virginia.edu            } else {
22311725Sar4jc@virginia.edu                apics.push_back(message.destination);
22412848Sar4jc@virginia.edu            }
22511725Sar4jc@virginia.edu        } else {
22611725Sar4jc@virginia.edu            for (int i = 0; i < numContexts; i++) {
22712849Sar4jc@virginia.edu                Interrupts *localApic = sys->getThreadContext(i)->
22812849Sar4jc@virginia.edu                    getCpuPtr()->getInterruptController(0);
22912849Sar4jc@virginia.edu                if ((localApic->readReg(APIC_LOGICAL_DESTINATION) >> 24) &
23012849Sar4jc@virginia.edu                        message.destination) {
23112849Sar4jc@virginia.edu                    apics.push_back(localApic->getInitialApicId());
23212849Sar4jc@virginia.edu                }
23312849Sar4jc@virginia.edu            }
23412849Sar4jc@virginia.edu            if (message.deliveryMode == DeliveryMode::LowestPriority &&
23512849Sar4jc@virginia.edu                    apics.size()) {
23612849Sar4jc@virginia.edu                // The manual seems to suggest that the chipset just does
23712849Sar4jc@virginia.edu                // something reasonable for these instead of actually using
23812849Sar4jc@virginia.edu                // state from the local APIC. We'll just rotate an offset
23912849Sar4jc@virginia.edu                // through the set of APICs selected above.
24011723Sar4jc@virginia.edu                uint64_t modOffset = lowestPriorityOffset % apics.size();
24111723Sar4jc@virginia.edu                lowestPriorityOffset++;
24212849Sar4jc@virginia.edu                ApicList::iterator apicIt = apics.begin();
24312849Sar4jc@virginia.edu                while (modOffset--) {
24412849Sar4jc@virginia.edu                    apicIt++;
24511723Sar4jc@virginia.edu                    assert(apicIt != apics.end());
24612849Sar4jc@virginia.edu                }
24712849Sar4jc@virginia.edu                int selected = *apicIt;
24812849Sar4jc@virginia.edu                apics.clear();
24912849Sar4jc@virginia.edu                apics.push_back(selected);
25012849Sar4jc@virginia.edu            }
25112848Sar4jc@virginia.edu        }
25211723Sar4jc@virginia.edu        intMasterPort.sendMessage(apics, message, sys->isTimingMode());
25311723Sar4jc@virginia.edu    }
25411723Sar4jc@virginia.edu}
25511723Sar4jc@virginia.edu
25611723Sar4jc@virginia.eduvoid
25711723Sar4jc@virginia.eduX86ISA::I82094AA::raiseInterruptPin(int number)
25811723Sar4jc@virginia.edu{
25912848Sar4jc@virginia.edu    assert(number < TableSize);
26012848Sar4jc@virginia.edu    if (!pinStates[number])
26111723Sar4jc@virginia.edu        signalInterrupt(number);
26211723Sar4jc@virginia.edu    pinStates[number] = true;
26311723Sar4jc@virginia.edu}
26411723Sar4jc@virginia.edu
26512849Sar4jc@virginia.eduvoid
266X86ISA::I82094AA::lowerInterruptPin(int number)
267{
268    assert(number < TableSize);
269    pinStates[number] = false;
270}
271
272void
273X86ISA::I82094AA::serialize(CheckpointOut &cp) const
274{
275    uint64_t* redirTableArray = (uint64_t*)redirTable;
276    SERIALIZE_SCALAR(regSel);
277    SERIALIZE_SCALAR(initialApicId);
278    SERIALIZE_SCALAR(id);
279    SERIALIZE_SCALAR(arbId);
280    SERIALIZE_SCALAR(lowestPriorityOffset);
281    SERIALIZE_ARRAY(redirTableArray, TableSize);
282    SERIALIZE_ARRAY(pinStates, TableSize);
283}
284
285void
286X86ISA::I82094AA::unserialize(CheckpointIn &cp)
287{
288    uint64_t redirTableArray[TableSize];
289    UNSERIALIZE_SCALAR(regSel);
290    UNSERIALIZE_SCALAR(initialApicId);
291    UNSERIALIZE_SCALAR(id);
292    UNSERIALIZE_SCALAR(arbId);
293    UNSERIALIZE_SCALAR(lowestPriorityOffset);
294    UNSERIALIZE_ARRAY(redirTableArray, TableSize);
295    UNSERIALIZE_ARRAY(pinStates, TableSize);
296    for (int i = 0; i < TableSize; i++) {
297        redirTable[i] = (RedirTableEntry)redirTableArray[i];
298    }
299}
300
301X86ISA::I82094AA *
302I82094AAParams::create()
303{
304    return new X86ISA::I82094AA(this);
305}
306