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