i82094aa.cc revision 6138:6cbdd76b93db
1/*
2 * Copyright (c) 2008 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Gabe Black
29 */
30
31#include "arch/x86/interrupts.hh"
32#include "arch/x86/intmessage.hh"
33#include "dev/x86/i82094aa.hh"
34#include "dev/x86/i8259.hh"
35#include "mem/packet.hh"
36#include "mem/packet_access.hh"
37#include "sim/system.hh"
38
39X86ISA::I82094AA::I82094AA(Params *p) : PioDevice(p), IntDev(this),
40    latency(p->pio_latency), pioAddr(p->pio_addr),
41    extIntPic(p->external_int_pic)
42{
43    // This assumes there's only one I/O APIC in the system
44    initialApicId = id = p->apic_id;
45    assert(id <= 0xf);
46    arbId = id;
47    regSel = 0;
48    RedirTableEntry entry = 0;
49    entry.mask = 1;
50    for (int i = 0; i < TableSize; i++) {
51        redirTable[i] = entry;
52        pinStates[i] = false;
53    }
54}
55
56Tick
57X86ISA::I82094AA::read(PacketPtr pkt)
58{
59    assert(pkt->getSize() == 4);
60    Addr offset = pkt->getAddr() - pioAddr;
61    switch(offset) {
62      case 0:
63        pkt->set<uint32_t>(regSel);
64        break;
65      case 16:
66        pkt->set<uint32_t>(readReg(regSel));
67        break;
68      default:
69        panic("Illegal read from I/O APIC.\n");
70    }
71    pkt->makeAtomicResponse();
72    return latency;
73}
74
75Tick
76X86ISA::I82094AA::write(PacketPtr pkt)
77{
78    assert(pkt->getSize() == 4);
79    Addr offset = pkt->getAddr() - pioAddr;
80    switch(offset) {
81      case 0:
82        regSel = pkt->get<uint32_t>();
83        break;
84      case 16:
85        writeReg(regSel, pkt->get<uint32_t>());
86        break;
87      default:
88        panic("Illegal write to I/O APIC.\n");
89    }
90    pkt->makeAtomicResponse();
91    return latency;
92}
93
94void
95X86ISA::I82094AA::writeReg(uint8_t offset, uint32_t value)
96{
97    if (offset == 0x0) {
98        id = bits(value, 27, 24);
99    } else if (offset == 0x1) {
100        // The IOAPICVER register is read only.
101    } else if (offset == 0x2) {
102        arbId = bits(value, 27, 24);
103    } else if (offset >= 0x10 && offset <= (0x10 + TableSize * 2)) {
104        int index = (offset - 0x10) / 2;
105        if (offset % 2) {
106            redirTable[index].topDW = value;
107            redirTable[index].topReserved = 0;
108        } else {
109            redirTable[index].bottomDW = value;
110            redirTable[index].bottomReserved = 0;
111        }
112    } else {
113        warn("Access to undefined I/O APIC register %#x.\n", offset);
114    }
115    DPRINTF(I82094AA,
116            "Wrote %#x to I/O APIC register %#x .\n", value, offset);
117}
118
119uint32_t
120X86ISA::I82094AA::readReg(uint8_t offset)
121{
122    uint32_t result = 0;
123    if (offset == 0x0) {
124        result = id << 24;
125    } else if (offset == 0x1) {
126        result = ((TableSize - 1) << 16) | APICVersion;
127    } else if (offset == 0x2) {
128        result = arbId << 24;
129    } else if (offset >= 0x10 && offset <= (0x10 + TableSize * 2)) {
130        int index = (offset - 0x10) / 2;
131        if (offset % 2) {
132            result = redirTable[index].topDW;
133        } else {
134            result = redirTable[index].bottomDW;
135        }
136    } else {
137        warn("Access to undefined I/O APIC register %#x.\n", offset);
138    }
139    DPRINTF(I82094AA,
140            "Read %#x from I/O APIC register %#x.\n", result, offset);
141    return result;
142}
143
144void
145X86ISA::I82094AA::signalInterrupt(int line)
146{
147    DPRINTF(I82094AA, "Received interrupt %d.\n", line);
148    assert(line < TableSize);
149    RedirTableEntry entry = redirTable[line];
150    if (entry.mask) {
151        DPRINTF(I82094AA, "Entry was masked.\n");
152        return;
153    } else {
154        TriggerIntMessage message;
155        message.destination = entry.dest;
156        if (entry.deliveryMode == DeliveryMode::ExtInt) {
157            assert(extIntPic);
158            message.vector = extIntPic->getVector();
159        } else {
160            message.vector = entry.vector;
161        }
162        message.deliveryMode = entry.deliveryMode;
163        message.destMode = entry.destMode;
164        message.level = entry.polarity;
165        message.trigger = entry.trigger;
166        ApicList apics;
167        int numContexts = sys->numContexts();
168        if (message.destMode == 0) {
169            if (message.deliveryMode == DeliveryMode::LowestPriority) {
170                panic("Lowest priority delivery mode from the "
171                        "IO APIC aren't supported in physical "
172                        "destination mode.\n");
173            }
174            if (message.destination == 0xFF) {
175                for (int i = 0; i < numContexts; i++) {
176                    apics.push_back(i);
177                }
178            } else {
179                apics.push_back(message.destination);
180            }
181        } else {
182            for (int i = 0; i < numContexts; i++) {
183                std::map<int, Interrupts *>::iterator localApicIt =
184                    localApics.find(i);
185                assert(localApicIt != localApics.end());
186                Interrupts *localApic = localApicIt->second;
187                if ((localApic->readReg(APIC_LOGICAL_DESTINATION) >> 24) &
188                        message.destination) {
189                    apics.push_back(localApicIt->first);
190                }
191            }
192            if (message.deliveryMode == DeliveryMode::LowestPriority) {
193                panic("Lowest priority delivery mode is not implemented.\n");
194            }
195        }
196        intPort->sendMessage(apics, message,
197                sys->getMemoryMode() == Enums::timing);
198    }
199}
200
201void
202X86ISA::I82094AA::raiseInterruptPin(int number)
203{
204    assert(number < TableSize);
205    if (!pinStates[number])
206        signalInterrupt(number);
207    pinStates[number] = true;
208}
209
210void
211X86ISA::I82094AA::lowerInterruptPin(int number)
212{
213    assert(number < TableSize);
214    pinStates[number] = false;
215}
216
217void
218X86ISA::I82094AA::registerLocalApic(int initialId, Interrupts *localApic)
219{
220    assert(localApic);
221    localApics[initialId] = localApic;
222}
223
224X86ISA::I82094AA *
225I82094AAParams::create()
226{
227    return new X86ISA::I82094AA(this);
228}
229