i82094aa.cc revision 5651
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/intmessage.hh"
32#include "dev/x86/i82094aa.hh"
33#include "mem/packet.hh"
34#include "mem/packet_access.hh"
35#include "sim/system.hh"
36
37X86ISA::I82094AA::I82094AA(Params *p) : PioDevice(p), IntDev(this),
38   latency(p->pio_latency), pioAddr(p->pio_addr)
39{
40    // This assumes there's only one I/O APIC in the system
41    id = sys->getNumCPUs();
42    assert(id <= 0xf);
43    arbId = id;
44    regSel = 0;
45    memset(redirTable, 0, sizeof(RedirTableEntry) * TableSize);
46}
47
48Tick
49X86ISA::I82094AA::read(PacketPtr pkt)
50{
51    assert(pkt->getSize() == 4);
52    Addr offset = pkt->getAddr() - pioAddr;
53    switch(offset) {
54      case 0:
55        pkt->set<uint32_t>(regSel);
56        break;
57      case 16:
58        pkt->set<uint32_t>(readReg(regSel));
59        break;
60      default:
61        panic("Illegal read from I/O APIC.\n");
62    }
63    return latency;
64}
65
66Tick
67X86ISA::I82094AA::write(PacketPtr pkt)
68{
69    assert(pkt->getSize() == 4);
70    Addr offset = pkt->getAddr() - pioAddr;
71    switch(offset) {
72      case 0:
73        regSel = pkt->get<uint32_t>();
74        break;
75      case 16:
76        writeReg(regSel, pkt->get<uint32_t>());
77        break;
78      default:
79        panic("Illegal write to I/O APIC.\n");
80    }
81    return latency;
82}
83
84void
85X86ISA::I82094AA::writeReg(uint8_t offset, uint32_t value)
86{
87    if (offset == 0x0) {
88        id = bits(value, 27, 24);
89    } else if (offset == 0x1) {
90        // The IOAPICVER register is read only.
91    } else if (offset == 0x2) {
92        arbId = bits(value, 27, 24);
93    } else if (offset >= 0x10 && offset <= (0x10 + TableSize * 2)) {
94        int index = (offset - 0x10) / 2;
95        if (offset % 2) {
96            redirTable[index].topDW = value;
97            redirTable[index].topReserved = 0;
98        } else {
99            redirTable[index].bottomDW = value;
100            redirTable[index].bottomReserved = 0;
101        }
102    } else {
103        warn("Access to undefined I/O APIC register %#x.\n", offset);
104    }
105    DPRINTF(I82094AA,
106            "Wrote %#x to I/O APIC register %#x .\n", value, offset);
107}
108
109uint32_t
110X86ISA::I82094AA::readReg(uint8_t offset)
111{
112    uint32_t result = 0;
113    if (offset == 0x0) {
114        result = id << 24;
115    } else if (offset == 0x1) {
116        result = ((TableSize - 1) << 16) | APICVersion;
117    } else if (offset == 0x2) {
118        result = arbId << 24;
119    } else if (offset >= 0x10 && offset <= (0x10 + TableSize * 2)) {
120        int index = (offset - 0x10) / 2;
121        if (offset % 2) {
122            result = redirTable[index].topDW;
123        } else {
124            result = redirTable[index].bottomDW;
125        }
126    } else {
127        warn("Access to undefined I/O APIC register %#x.\n", offset);
128    }
129    DPRINTF(I82094AA,
130            "Read %#x from I/O APIC register %#x.\n", result, offset);
131    return result;
132}
133
134void
135X86ISA::I82094AA::signalInterrupt(int line)
136{
137    DPRINTF(I82094AA, "Received interrupt %d.\n", line);
138    assert(line < TableSize);
139    RedirTableEntry entry = redirTable[line];
140    if (entry.mask) {
141        DPRINTF(I82094AA, "Entry was masked.\n");
142        return;
143    } else {
144        if (DTRACE(I82094AA)) {
145            switch(entry.deliveryMode) {
146              case 0:
147                DPRINTF(I82094AA, "Delivery mode is: Fixed.\n");
148                break;
149              case 1:
150                DPRINTF(I82094AA, "Delivery mode is: Lowest Priority.\n");
151                break;
152              case 2:
153                DPRINTF(I82094AA, "Delivery mode is: SMI.\n");
154                break;
155              case 3:
156                fatal("Tried to use reserved delivery mode "
157                        "for IO APIC entry %d.\n", line);
158                break;
159              case 4:
160                DPRINTF(I82094AA, "Delivery mode is: NMI.\n");
161                break;
162              case 5:
163                DPRINTF(I82094AA, "Delivery mode is: INIT.\n");
164                break;
165              case 6:
166                fatal("Tried to use reserved delivery mode "
167                        "for IO APIC entry %d.\n", line);
168                break;
169              case 7:
170                DPRINTF(I82094AA, "Delivery mode is: ExtINT.\n");
171                break;
172            }
173            DPRINTF(I82094AA, "Vector is %#x.\n", entry.vector);
174        }
175
176        TriggerIntMessage message;
177        message.destination = entry.dest;
178        message.vector = entry.vector;
179        message.deliveryMode = entry.deliveryMode;
180        message.destMode = entry.destMode;
181
182        if (entry.destMode == 0) {
183            DPRINTF(I82094AA,
184                    "Sending interrupt to APIC ID %d.\n", entry.dest);
185            PacketPtr pkt = buildIntRequest(entry.dest, message);
186            if (sys->getMemoryMode() == Enums::timing)
187                intPort->sendMessageTiming(pkt, latency);
188            else if (sys->getMemoryMode() == Enums::atomic)
189                intPort->sendMessageAtomic(pkt);
190            else
191                panic("Unrecognized memory mode.\n");
192        } else {
193            DPRINTF(I82094AA, "Sending interrupts to APIC IDs:"
194                    "%s%s%s%s%s%s%s%s\n",
195                    bits((int)entry.dest, 0) ? " 0": "",
196                    bits((int)entry.dest, 1) ? " 1": "",
197                    bits((int)entry.dest, 2) ? " 2": "",
198                    bits((int)entry.dest, 3) ? " 3": "",
199                    bits((int)entry.dest, 4) ? " 4": "",
200                    bits((int)entry.dest, 5) ? " 5": "",
201                    bits((int)entry.dest, 6) ? " 6": "",
202                    bits((int)entry.dest, 7) ? " 7": ""
203                    );
204            uint8_t dests = entry.dest;
205            uint8_t id = 0;
206            while(dests) {
207                if (dests & 0x1) {
208                    PacketPtr pkt = buildIntRequest(id, message);
209                    if (sys->getMemoryMode() == Enums::timing)
210                        intPort->sendMessageTiming(pkt, latency);
211                    else if (sys->getMemoryMode() == Enums::atomic)
212                        intPort->sendMessageAtomic(pkt);
213                    else
214                        panic("Unrecognized memory mode.\n");
215                }
216                dests >>= 1;
217                id++;
218            }
219        }
220    }
221}
222
223X86ISA::I82094AA *
224I82094AAParams::create()
225{
226    return new X86ISA::I82094AA(this);
227}
228