interrupts.cc (8711:c7e14f52c682) interrupts.cc (8742:9df38d259935)
1/*
2 * Copyright (c) 2008 The Hewlett-Packard Development Company
3 * All rights reserved.
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Gabe Black
38 */
39
40#include "arch/x86/regs/apic.hh"
41#include "arch/x86/interrupts.hh"
42#include "arch/x86/intmessage.hh"
43#include "cpu/base.hh"
44#include "debug/LocalApic.hh"
45#include "dev/x86/i82094aa.hh"
46#include "dev/x86/pc.hh"
47#include "dev/x86/south_bridge.hh"
48#include "mem/packet_access.hh"
49#include "sim/system.hh"
50
51int
52divideFromConf(uint32_t conf)
53{
54 // This figures out what division we want from the division configuration
55 // register in the local APIC. The encoding is a little odd but it can
56 // be deciphered fairly easily.
57 int shift = ((conf & 0x8) >> 1) | (conf & 0x3);
58 shift = (shift + 1) % 8;
59 return 1 << shift;
60}
61
62namespace X86ISA
63{
64
65ApicRegIndex
66decodeAddr(Addr paddr)
67{
68 ApicRegIndex regNum;
69 paddr &= ~mask(3);
70 switch (paddr)
71 {
72 case 0x20:
73 regNum = APIC_ID;
74 break;
75 case 0x30:
76 regNum = APIC_VERSION;
77 break;
78 case 0x80:
79 regNum = APIC_TASK_PRIORITY;
80 break;
81 case 0x90:
82 regNum = APIC_ARBITRATION_PRIORITY;
83 break;
84 case 0xA0:
85 regNum = APIC_PROCESSOR_PRIORITY;
86 break;
87 case 0xB0:
88 regNum = APIC_EOI;
89 break;
90 case 0xD0:
91 regNum = APIC_LOGICAL_DESTINATION;
92 break;
93 case 0xE0:
94 regNum = APIC_DESTINATION_FORMAT;
95 break;
96 case 0xF0:
97 regNum = APIC_SPURIOUS_INTERRUPT_VECTOR;
98 break;
99 case 0x100:
100 case 0x108:
101 case 0x110:
102 case 0x118:
103 case 0x120:
104 case 0x128:
105 case 0x130:
106 case 0x138:
107 case 0x140:
108 case 0x148:
109 case 0x150:
110 case 0x158:
111 case 0x160:
112 case 0x168:
113 case 0x170:
114 case 0x178:
115 regNum = APIC_IN_SERVICE((paddr - 0x100) / 0x8);
116 break;
117 case 0x180:
118 case 0x188:
119 case 0x190:
120 case 0x198:
121 case 0x1A0:
122 case 0x1A8:
123 case 0x1B0:
124 case 0x1B8:
125 case 0x1C0:
126 case 0x1C8:
127 case 0x1D0:
128 case 0x1D8:
129 case 0x1E0:
130 case 0x1E8:
131 case 0x1F0:
132 case 0x1F8:
133 regNum = APIC_TRIGGER_MODE((paddr - 0x180) / 0x8);
134 break;
135 case 0x200:
136 case 0x208:
137 case 0x210:
138 case 0x218:
139 case 0x220:
140 case 0x228:
141 case 0x230:
142 case 0x238:
143 case 0x240:
144 case 0x248:
145 case 0x250:
146 case 0x258:
147 case 0x260:
148 case 0x268:
149 case 0x270:
150 case 0x278:
151 regNum = APIC_INTERRUPT_REQUEST((paddr - 0x200) / 0x8);
152 break;
153 case 0x280:
154 regNum = APIC_ERROR_STATUS;
155 break;
156 case 0x300:
157 regNum = APIC_INTERRUPT_COMMAND_LOW;
158 break;
159 case 0x310:
160 regNum = APIC_INTERRUPT_COMMAND_HIGH;
161 break;
162 case 0x320:
163 regNum = APIC_LVT_TIMER;
164 break;
165 case 0x330:
166 regNum = APIC_LVT_THERMAL_SENSOR;
167 break;
168 case 0x340:
169 regNum = APIC_LVT_PERFORMANCE_MONITORING_COUNTERS;
170 break;
171 case 0x350:
172 regNum = APIC_LVT_LINT0;
173 break;
174 case 0x360:
175 regNum = APIC_LVT_LINT1;
176 break;
177 case 0x370:
178 regNum = APIC_LVT_ERROR;
179 break;
180 case 0x380:
181 regNum = APIC_INITIAL_COUNT;
182 break;
183 case 0x390:
184 regNum = APIC_CURRENT_COUNT;
185 break;
186 case 0x3E0:
187 regNum = APIC_DIVIDE_CONFIGURATION;
188 break;
189 default:
190 // A reserved register field.
191 panic("Accessed reserved register field %#x.\n", paddr);
192 break;
193 }
194 return regNum;
195}
196}
197
198Tick
199X86ISA::Interrupts::read(PacketPtr pkt)
200{
201 Addr offset = pkt->getAddr() - pioAddr;
202 //Make sure we're at least only accessing one register.
203 if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3)))
204 panic("Accessed more than one register at a time in the APIC!\n");
205 ApicRegIndex reg = decodeAddr(offset);
206 uint32_t val = htog(readReg(reg));
207 DPRINTF(LocalApic,
208 "Reading Local APIC register %d at offset %#x as %#x.\n",
209 reg, offset, val);
210 pkt->setData(((uint8_t *)&val) + (offset & mask(3)));
211 pkt->makeAtomicResponse();
212 return latency;
213}
214
215Tick
216X86ISA::Interrupts::write(PacketPtr pkt)
217{
218 Addr offset = pkt->getAddr() - pioAddr;
219 //Make sure we're at least only accessing one register.
220 if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3)))
221 panic("Accessed more than one register at a time in the APIC!\n");
222 ApicRegIndex reg = decodeAddr(offset);
223 uint32_t val = regs[reg];
224 pkt->writeData(((uint8_t *)&val) + (offset & mask(3)));
225 DPRINTF(LocalApic,
226 "Writing Local APIC register %d at offset %#x as %#x.\n",
227 reg, offset, gtoh(val));
228 setReg(reg, gtoh(val));
229 pkt->makeAtomicResponse();
230 return latency;
231}
232void
233X86ISA::Interrupts::requestInterrupt(uint8_t vector,
234 uint8_t deliveryMode, bool level)
235{
236 /*
237 * Fixed and lowest-priority delivery mode interrupts are handled
238 * using the IRR/ISR registers, checking against the TPR, etc.
239 * The SMI, NMI, ExtInt, INIT, etc interrupts go straight through.
240 */
241 if (deliveryMode == DeliveryMode::Fixed ||
242 deliveryMode == DeliveryMode::LowestPriority) {
243 DPRINTF(LocalApic, "Interrupt is an %s.\n",
244 DeliveryMode::names[deliveryMode]);
245 // Queue up the interrupt in the IRR.
246 if (vector > IRRV)
247 IRRV = vector;
248 if (!getRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, vector)) {
249 setRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, vector);
250 if (level) {
251 setRegArrayBit(APIC_TRIGGER_MODE_BASE, vector);
252 } else {
253 clearRegArrayBit(APIC_TRIGGER_MODE_BASE, vector);
254 }
255 }
256 } else if (!DeliveryMode::isReserved(deliveryMode)) {
257 DPRINTF(LocalApic, "Interrupt is an %s.\n",
258 DeliveryMode::names[deliveryMode]);
259 if (deliveryMode == DeliveryMode::SMI && !pendingSmi) {
260 pendingUnmaskableInt = pendingSmi = true;
261 smiVector = vector;
262 } else if (deliveryMode == DeliveryMode::NMI && !pendingNmi) {
263 pendingUnmaskableInt = pendingNmi = true;
264 nmiVector = vector;
265 } else if (deliveryMode == DeliveryMode::ExtInt && !pendingExtInt) {
266 pendingExtInt = true;
267 extIntVector = vector;
268 } else if (deliveryMode == DeliveryMode::INIT && !pendingInit) {
269 pendingUnmaskableInt = pendingInit = true;
270 initVector = vector;
271 } else if (deliveryMode == DeliveryMode::SIPI &&
272 !pendingStartup && !startedUp) {
273 pendingUnmaskableInt = pendingStartup = true;
274 startupVector = vector;
275 }
276 }
277 cpu->wakeup();
278}
279
280
281void
282X86ISA::Interrupts::setCPU(BaseCPU * newCPU)
283{
284 assert(newCPU);
285 if (cpu != NULL && cpu->cpuId() != newCPU->cpuId()) {
286 panic("Local APICs can't be moved between CPUs"
287 " with different IDs.\n");
288 }
289 cpu = newCPU;
290 initialApicId = cpu->cpuId();
291 regs[APIC_ID] = (initialApicId << 24);
292}
293
294
295void
296X86ISA::Interrupts::init()
297{
298 //
299 // The local apic must register its address ranges on both its pio port
300 // via the basicpiodevice(piodevice) init() function and its int port
301 // that it inherited from IntDev. Note IntDev is not a SimObject itself.
302 //
303 BasicPioDevice::init();
304 IntDev::init();
1/*
2 * Copyright (c) 2008 The Hewlett-Packard Development Company
3 * All rights reserved.
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Gabe Black
38 */
39
40#include "arch/x86/regs/apic.hh"
41#include "arch/x86/interrupts.hh"
42#include "arch/x86/intmessage.hh"
43#include "cpu/base.hh"
44#include "debug/LocalApic.hh"
45#include "dev/x86/i82094aa.hh"
46#include "dev/x86/pc.hh"
47#include "dev/x86/south_bridge.hh"
48#include "mem/packet_access.hh"
49#include "sim/system.hh"
50
51int
52divideFromConf(uint32_t conf)
53{
54 // This figures out what division we want from the division configuration
55 // register in the local APIC. The encoding is a little odd but it can
56 // be deciphered fairly easily.
57 int shift = ((conf & 0x8) >> 1) | (conf & 0x3);
58 shift = (shift + 1) % 8;
59 return 1 << shift;
60}
61
62namespace X86ISA
63{
64
65ApicRegIndex
66decodeAddr(Addr paddr)
67{
68 ApicRegIndex regNum;
69 paddr &= ~mask(3);
70 switch (paddr)
71 {
72 case 0x20:
73 regNum = APIC_ID;
74 break;
75 case 0x30:
76 regNum = APIC_VERSION;
77 break;
78 case 0x80:
79 regNum = APIC_TASK_PRIORITY;
80 break;
81 case 0x90:
82 regNum = APIC_ARBITRATION_PRIORITY;
83 break;
84 case 0xA0:
85 regNum = APIC_PROCESSOR_PRIORITY;
86 break;
87 case 0xB0:
88 regNum = APIC_EOI;
89 break;
90 case 0xD0:
91 regNum = APIC_LOGICAL_DESTINATION;
92 break;
93 case 0xE0:
94 regNum = APIC_DESTINATION_FORMAT;
95 break;
96 case 0xF0:
97 regNum = APIC_SPURIOUS_INTERRUPT_VECTOR;
98 break;
99 case 0x100:
100 case 0x108:
101 case 0x110:
102 case 0x118:
103 case 0x120:
104 case 0x128:
105 case 0x130:
106 case 0x138:
107 case 0x140:
108 case 0x148:
109 case 0x150:
110 case 0x158:
111 case 0x160:
112 case 0x168:
113 case 0x170:
114 case 0x178:
115 regNum = APIC_IN_SERVICE((paddr - 0x100) / 0x8);
116 break;
117 case 0x180:
118 case 0x188:
119 case 0x190:
120 case 0x198:
121 case 0x1A0:
122 case 0x1A8:
123 case 0x1B0:
124 case 0x1B8:
125 case 0x1C0:
126 case 0x1C8:
127 case 0x1D0:
128 case 0x1D8:
129 case 0x1E0:
130 case 0x1E8:
131 case 0x1F0:
132 case 0x1F8:
133 regNum = APIC_TRIGGER_MODE((paddr - 0x180) / 0x8);
134 break;
135 case 0x200:
136 case 0x208:
137 case 0x210:
138 case 0x218:
139 case 0x220:
140 case 0x228:
141 case 0x230:
142 case 0x238:
143 case 0x240:
144 case 0x248:
145 case 0x250:
146 case 0x258:
147 case 0x260:
148 case 0x268:
149 case 0x270:
150 case 0x278:
151 regNum = APIC_INTERRUPT_REQUEST((paddr - 0x200) / 0x8);
152 break;
153 case 0x280:
154 regNum = APIC_ERROR_STATUS;
155 break;
156 case 0x300:
157 regNum = APIC_INTERRUPT_COMMAND_LOW;
158 break;
159 case 0x310:
160 regNum = APIC_INTERRUPT_COMMAND_HIGH;
161 break;
162 case 0x320:
163 regNum = APIC_LVT_TIMER;
164 break;
165 case 0x330:
166 regNum = APIC_LVT_THERMAL_SENSOR;
167 break;
168 case 0x340:
169 regNum = APIC_LVT_PERFORMANCE_MONITORING_COUNTERS;
170 break;
171 case 0x350:
172 regNum = APIC_LVT_LINT0;
173 break;
174 case 0x360:
175 regNum = APIC_LVT_LINT1;
176 break;
177 case 0x370:
178 regNum = APIC_LVT_ERROR;
179 break;
180 case 0x380:
181 regNum = APIC_INITIAL_COUNT;
182 break;
183 case 0x390:
184 regNum = APIC_CURRENT_COUNT;
185 break;
186 case 0x3E0:
187 regNum = APIC_DIVIDE_CONFIGURATION;
188 break;
189 default:
190 // A reserved register field.
191 panic("Accessed reserved register field %#x.\n", paddr);
192 break;
193 }
194 return regNum;
195}
196}
197
198Tick
199X86ISA::Interrupts::read(PacketPtr pkt)
200{
201 Addr offset = pkt->getAddr() - pioAddr;
202 //Make sure we're at least only accessing one register.
203 if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3)))
204 panic("Accessed more than one register at a time in the APIC!\n");
205 ApicRegIndex reg = decodeAddr(offset);
206 uint32_t val = htog(readReg(reg));
207 DPRINTF(LocalApic,
208 "Reading Local APIC register %d at offset %#x as %#x.\n",
209 reg, offset, val);
210 pkt->setData(((uint8_t *)&val) + (offset & mask(3)));
211 pkt->makeAtomicResponse();
212 return latency;
213}
214
215Tick
216X86ISA::Interrupts::write(PacketPtr pkt)
217{
218 Addr offset = pkt->getAddr() - pioAddr;
219 //Make sure we're at least only accessing one register.
220 if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3)))
221 panic("Accessed more than one register at a time in the APIC!\n");
222 ApicRegIndex reg = decodeAddr(offset);
223 uint32_t val = regs[reg];
224 pkt->writeData(((uint8_t *)&val) + (offset & mask(3)));
225 DPRINTF(LocalApic,
226 "Writing Local APIC register %d at offset %#x as %#x.\n",
227 reg, offset, gtoh(val));
228 setReg(reg, gtoh(val));
229 pkt->makeAtomicResponse();
230 return latency;
231}
232void
233X86ISA::Interrupts::requestInterrupt(uint8_t vector,
234 uint8_t deliveryMode, bool level)
235{
236 /*
237 * Fixed and lowest-priority delivery mode interrupts are handled
238 * using the IRR/ISR registers, checking against the TPR, etc.
239 * The SMI, NMI, ExtInt, INIT, etc interrupts go straight through.
240 */
241 if (deliveryMode == DeliveryMode::Fixed ||
242 deliveryMode == DeliveryMode::LowestPriority) {
243 DPRINTF(LocalApic, "Interrupt is an %s.\n",
244 DeliveryMode::names[deliveryMode]);
245 // Queue up the interrupt in the IRR.
246 if (vector > IRRV)
247 IRRV = vector;
248 if (!getRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, vector)) {
249 setRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, vector);
250 if (level) {
251 setRegArrayBit(APIC_TRIGGER_MODE_BASE, vector);
252 } else {
253 clearRegArrayBit(APIC_TRIGGER_MODE_BASE, vector);
254 }
255 }
256 } else if (!DeliveryMode::isReserved(deliveryMode)) {
257 DPRINTF(LocalApic, "Interrupt is an %s.\n",
258 DeliveryMode::names[deliveryMode]);
259 if (deliveryMode == DeliveryMode::SMI && !pendingSmi) {
260 pendingUnmaskableInt = pendingSmi = true;
261 smiVector = vector;
262 } else if (deliveryMode == DeliveryMode::NMI && !pendingNmi) {
263 pendingUnmaskableInt = pendingNmi = true;
264 nmiVector = vector;
265 } else if (deliveryMode == DeliveryMode::ExtInt && !pendingExtInt) {
266 pendingExtInt = true;
267 extIntVector = vector;
268 } else if (deliveryMode == DeliveryMode::INIT && !pendingInit) {
269 pendingUnmaskableInt = pendingInit = true;
270 initVector = vector;
271 } else if (deliveryMode == DeliveryMode::SIPI &&
272 !pendingStartup && !startedUp) {
273 pendingUnmaskableInt = pendingStartup = true;
274 startupVector = vector;
275 }
276 }
277 cpu->wakeup();
278}
279
280
281void
282X86ISA::Interrupts::setCPU(BaseCPU * newCPU)
283{
284 assert(newCPU);
285 if (cpu != NULL && cpu->cpuId() != newCPU->cpuId()) {
286 panic("Local APICs can't be moved between CPUs"
287 " with different IDs.\n");
288 }
289 cpu = newCPU;
290 initialApicId = cpu->cpuId();
291 regs[APIC_ID] = (initialApicId << 24);
292}
293
294
295void
296X86ISA::Interrupts::init()
297{
298 //
299 // The local apic must register its address ranges on both its pio port
300 // via the basicpiodevice(piodevice) init() function and its int port
301 // that it inherited from IntDev. Note IntDev is not a SimObject itself.
302 //
303 BasicPioDevice::init();
304 IntDev::init();
305
305#if FULL_SYSTEM
306 Pc * pc = dynamic_cast<Pc *>(platform);
307 assert(pc);
308 pc->southBridge->ioApic->registerLocalApic(initialApicId, this);
306 Pc * pc = dynamic_cast<Pc *>(platform);
307 assert(pc);
308 pc->southBridge->ioApic->registerLocalApic(initialApicId, this);
309#endif
309}
310
311
312Tick
313X86ISA::Interrupts::recvMessage(PacketPtr pkt)
314{
315 Addr offset = pkt->getAddr() - x86InterruptAddress(initialApicId, 0);
316 assert(pkt->cmd == MemCmd::MessageReq);
317 switch(offset)
318 {
319 case 0:
320 {
321 TriggerIntMessage message = pkt->get<TriggerIntMessage>();
322 DPRINTF(LocalApic,
323 "Got Trigger Interrupt message with vector %#x.\n",
324 message.vector);
325
326 requestInterrupt(message.vector,
327 message.deliveryMode, message.trigger);
328 }
329 break;
330 default:
331 panic("Local apic got unknown interrupt message at offset %#x.\n",
332 offset);
333 break;
334 }
335 pkt->makeAtomicResponse();
336 return latency;
337}
338
339
340Tick
341X86ISA::Interrupts::recvResponse(PacketPtr pkt)
342{
343 assert(!pkt->isError());
344 assert(pkt->cmd == MemCmd::MessageResp);
345 if (--pendingIPIs == 0) {
346 InterruptCommandRegLow low = regs[APIC_INTERRUPT_COMMAND_LOW];
347 // Record that the ICR is now idle.
348 low.deliveryStatus = 0;
349 regs[APIC_INTERRUPT_COMMAND_LOW] = low;
350 }
351 DPRINTF(LocalApic, "ICR is now idle.\n");
352 return 0;
353}
354
355
310}
311
312
313Tick
314X86ISA::Interrupts::recvMessage(PacketPtr pkt)
315{
316 Addr offset = pkt->getAddr() - x86InterruptAddress(initialApicId, 0);
317 assert(pkt->cmd == MemCmd::MessageReq);
318 switch(offset)
319 {
320 case 0:
321 {
322 TriggerIntMessage message = pkt->get<TriggerIntMessage>();
323 DPRINTF(LocalApic,
324 "Got Trigger Interrupt message with vector %#x.\n",
325 message.vector);
326
327 requestInterrupt(message.vector,
328 message.deliveryMode, message.trigger);
329 }
330 break;
331 default:
332 panic("Local apic got unknown interrupt message at offset %#x.\n",
333 offset);
334 break;
335 }
336 pkt->makeAtomicResponse();
337 return latency;
338}
339
340
341Tick
342X86ISA::Interrupts::recvResponse(PacketPtr pkt)
343{
344 assert(!pkt->isError());
345 assert(pkt->cmd == MemCmd::MessageResp);
346 if (--pendingIPIs == 0) {
347 InterruptCommandRegLow low = regs[APIC_INTERRUPT_COMMAND_LOW];
348 // Record that the ICR is now idle.
349 low.deliveryStatus = 0;
350 regs[APIC_INTERRUPT_COMMAND_LOW] = low;
351 }
352 DPRINTF(LocalApic, "ICR is now idle.\n");
353 return 0;
354}
355
356
356AddrRangeList
357X86ISA::Interrupts::getAddrRanges()
357void
358X86ISA::Interrupts::addressRanges(AddrRangeList &range_list)
358{
359{
359 AddrRangeList ranges;
360 range_list.clear();
360 Range<Addr> range = RangeEx(x86LocalAPICAddress(initialApicId, 0),
361 x86LocalAPICAddress(initialApicId, 0) +
362 PageBytes);
361 Range<Addr> range = RangeEx(x86LocalAPICAddress(initialApicId, 0),
362 x86LocalAPICAddress(initialApicId, 0) +
363 PageBytes);
363 ranges.push_back(range);
364 range_list.push_back(range);
364 pioAddr = range.start;
365 pioAddr = range.start;
365 return ranges;
366}
367
368
366}
367
368
369AddrRangeList
370X86ISA::Interrupts::getIntAddrRange()
369void
370X86ISA::Interrupts::getIntAddrRange(AddrRangeList &range_list)
371{
371{
372 AddrRangeList ranges;
373 ranges.push_back(RangeEx(x86InterruptAddress(initialApicId, 0),
374 x86InterruptAddress(initialApicId, 0) +
375 PhysAddrAPICRangeSize));
376 return ranges;
372 range_list.clear();
373 range_list.push_back(RangeEx(x86InterruptAddress(initialApicId, 0),
374 x86InterruptAddress(initialApicId, 0) +
375 PhysAddrAPICRangeSize));
377}
378
379
380uint32_t
381X86ISA::Interrupts::readReg(ApicRegIndex reg)
382{
383 if (reg >= APIC_TRIGGER_MODE(0) &&
384 reg <= APIC_TRIGGER_MODE(15)) {
385 panic("Local APIC Trigger Mode registers are unimplemented.\n");
386 }
387 switch (reg) {
388 case APIC_ARBITRATION_PRIORITY:
389 panic("Local APIC Arbitration Priority register unimplemented.\n");
390 break;
391 case APIC_PROCESSOR_PRIORITY:
392 panic("Local APIC Processor Priority register unimplemented.\n");
393 break;
394 case APIC_ERROR_STATUS:
395 regs[APIC_INTERNAL_STATE] &= ~ULL(0x1);
396 break;
397 case APIC_CURRENT_COUNT:
398 {
399 if (apicTimerEvent.scheduled()) {
400 assert(clock);
401 // Compute how many m5 ticks happen per count.
402 uint64_t ticksPerCount = clock *
403 divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]);
404 // Compute how many m5 ticks are left.
405 uint64_t val = apicTimerEvent.when() - curTick();
406 // Turn that into a count.
407 val = (val + ticksPerCount - 1) / ticksPerCount;
408 return val;
409 } else {
410 return 0;
411 }
412 }
413 default:
414 break;
415 }
416 return regs[reg];
417}
418
419void
420X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val)
421{
422 uint32_t newVal = val;
423 if (reg >= APIC_IN_SERVICE(0) &&
424 reg <= APIC_IN_SERVICE(15)) {
425 panic("Local APIC In-Service registers are unimplemented.\n");
426 }
427 if (reg >= APIC_TRIGGER_MODE(0) &&
428 reg <= APIC_TRIGGER_MODE(15)) {
429 panic("Local APIC Trigger Mode registers are unimplemented.\n");
430 }
431 if (reg >= APIC_INTERRUPT_REQUEST(0) &&
432 reg <= APIC_INTERRUPT_REQUEST(15)) {
433 panic("Local APIC Interrupt Request registers "
434 "are unimplemented.\n");
435 }
436 switch (reg) {
437 case APIC_ID:
438 newVal = val & 0xFF;
439 break;
440 case APIC_VERSION:
441 // The Local APIC Version register is read only.
442 return;
443 case APIC_TASK_PRIORITY:
444 newVal = val & 0xFF;
445 break;
446 case APIC_ARBITRATION_PRIORITY:
447 panic("Local APIC Arbitration Priority register unimplemented.\n");
448 break;
449 case APIC_PROCESSOR_PRIORITY:
450 panic("Local APIC Processor Priority register unimplemented.\n");
451 break;
452 case APIC_EOI:
453 // Remove the interrupt that just completed from the local apic state.
454 clearRegArrayBit(APIC_IN_SERVICE_BASE, ISRV);
455 updateISRV();
456 return;
457 case APIC_LOGICAL_DESTINATION:
458 newVal = val & 0xFF000000;
459 break;
460 case APIC_DESTINATION_FORMAT:
461 newVal = val | 0x0FFFFFFF;
462 break;
463 case APIC_SPURIOUS_INTERRUPT_VECTOR:
464 regs[APIC_INTERNAL_STATE] &= ~ULL(1 << 1);
465 regs[APIC_INTERNAL_STATE] |= val & (1 << 8);
466 if (val & (1 << 9))
467 warn("Focus processor checking not implemented.\n");
468 break;
469 case APIC_ERROR_STATUS:
470 {
471 if (regs[APIC_INTERNAL_STATE] & 0x1) {
472 regs[APIC_INTERNAL_STATE] &= ~ULL(0x1);
473 newVal = 0;
474 } else {
475 regs[APIC_INTERNAL_STATE] |= ULL(0x1);
476 return;
477 }
478
479 }
480 break;
481 case APIC_INTERRUPT_COMMAND_LOW:
482 {
483 InterruptCommandRegLow low = regs[APIC_INTERRUPT_COMMAND_LOW];
484 // Check if we're already sending an IPI.
485 if (low.deliveryStatus) {
486 newVal = low;
487 break;
488 }
489 low = val;
490 InterruptCommandRegHigh high = regs[APIC_INTERRUPT_COMMAND_HIGH];
491 // Record that an IPI is being sent.
492 low.deliveryStatus = 1;
493 TriggerIntMessage message = 0;
494 message.destination = high.destination;
495 message.vector = low.vector;
496 message.deliveryMode = low.deliveryMode;
497 message.destMode = low.destMode;
498 message.level = low.level;
499 message.trigger = low.trigger;
500 bool timing = sys->getMemoryMode() == Enums::timing;
501 // Be careful no updates of the delivery status bit get lost.
502 regs[APIC_INTERRUPT_COMMAND_LOW] = low;
503 ApicList apics;
504 int numContexts = sys->numContexts();
505 switch (low.destShorthand) {
506 case 0:
507 if (message.deliveryMode == DeliveryMode::LowestPriority) {
508 panic("Lowest priority delivery mode "
509 "IPIs aren't implemented.\n");
510 }
511 if (message.destMode == 1) {
512 int dest = message.destination;
513 hack_once("Assuming logical destinations are 1 << id.\n");
514 for (int i = 0; i < numContexts; i++) {
515 if (dest & 0x1)
516 apics.push_back(i);
517 dest = dest >> 1;
518 }
519 } else {
520 if (message.destination == 0xFF) {
521 for (int i = 0; i < numContexts; i++) {
522 if (i == initialApicId) {
523 requestInterrupt(message.vector,
524 message.deliveryMode, message.trigger);
525 } else {
526 apics.push_back(i);
527 }
528 }
529 } else {
530 if (message.destination == initialApicId) {
531 requestInterrupt(message.vector,
532 message.deliveryMode, message.trigger);
533 } else {
534 apics.push_back(message.destination);
535 }
536 }
537 }
538 break;
539 case 1:
540 newVal = val;
541 requestInterrupt(message.vector,
542 message.deliveryMode, message.trigger);
543 break;
544 case 2:
545 requestInterrupt(message.vector,
546 message.deliveryMode, message.trigger);
547 // Fall through
548 case 3:
549 {
550 for (int i = 0; i < numContexts; i++) {
551 if (i != initialApicId) {
552 apics.push_back(i);
553 }
554 }
555 }
556 break;
557 }
558 pendingIPIs += apics.size();
559 intPort->sendMessage(apics, message, timing);
560 newVal = regs[APIC_INTERRUPT_COMMAND_LOW];
561 }
562 break;
563 case APIC_LVT_TIMER:
564 case APIC_LVT_THERMAL_SENSOR:
565 case APIC_LVT_PERFORMANCE_MONITORING_COUNTERS:
566 case APIC_LVT_LINT0:
567 case APIC_LVT_LINT1:
568 case APIC_LVT_ERROR:
569 {
570 uint64_t readOnlyMask = (1 << 12) | (1 << 14);
571 newVal = (val & ~readOnlyMask) |
572 (regs[reg] & readOnlyMask);
573 }
574 break;
575 case APIC_INITIAL_COUNT:
576 {
577 assert(clock);
578 newVal = bits(val, 31, 0);
579 // Compute how many timer ticks we're being programmed for.
580 uint64_t newCount = newVal *
581 (divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]));
582 // Schedule on the edge of the next tick plus the new count.
583 Tick offset = curTick() % clock;
584 if (offset) {
585 reschedule(apicTimerEvent,
586 curTick() + (newCount + 1) * clock - offset, true);
587 } else {
588 reschedule(apicTimerEvent,
589 curTick() + newCount * clock, true);
590 }
591 }
592 break;
593 case APIC_CURRENT_COUNT:
594 //Local APIC Current Count register is read only.
595 return;
596 case APIC_DIVIDE_CONFIGURATION:
597 newVal = val & 0xB;
598 break;
599 default:
600 break;
601 }
602 regs[reg] = newVal;
603 return;
604}
605
606
607X86ISA::Interrupts::Interrupts(Params * p) :
608 BasicPioDevice(p), IntDev(this, p->int_latency), latency(p->pio_latency),
609 clock(0),
610 apicTimerEvent(this),
611 pendingSmi(false), smiVector(0),
612 pendingNmi(false), nmiVector(0),
613 pendingExtInt(false), extIntVector(0),
614 pendingInit(false), initVector(0),
615 pendingStartup(false), startupVector(0),
616 startedUp(false), pendingUnmaskableInt(false),
617 pendingIPIs(0), cpu(NULL)
376}
377
378
379uint32_t
380X86ISA::Interrupts::readReg(ApicRegIndex reg)
381{
382 if (reg >= APIC_TRIGGER_MODE(0) &&
383 reg <= APIC_TRIGGER_MODE(15)) {
384 panic("Local APIC Trigger Mode registers are unimplemented.\n");
385 }
386 switch (reg) {
387 case APIC_ARBITRATION_PRIORITY:
388 panic("Local APIC Arbitration Priority register unimplemented.\n");
389 break;
390 case APIC_PROCESSOR_PRIORITY:
391 panic("Local APIC Processor Priority register unimplemented.\n");
392 break;
393 case APIC_ERROR_STATUS:
394 regs[APIC_INTERNAL_STATE] &= ~ULL(0x1);
395 break;
396 case APIC_CURRENT_COUNT:
397 {
398 if (apicTimerEvent.scheduled()) {
399 assert(clock);
400 // Compute how many m5 ticks happen per count.
401 uint64_t ticksPerCount = clock *
402 divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]);
403 // Compute how many m5 ticks are left.
404 uint64_t val = apicTimerEvent.when() - curTick();
405 // Turn that into a count.
406 val = (val + ticksPerCount - 1) / ticksPerCount;
407 return val;
408 } else {
409 return 0;
410 }
411 }
412 default:
413 break;
414 }
415 return regs[reg];
416}
417
418void
419X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val)
420{
421 uint32_t newVal = val;
422 if (reg >= APIC_IN_SERVICE(0) &&
423 reg <= APIC_IN_SERVICE(15)) {
424 panic("Local APIC In-Service registers are unimplemented.\n");
425 }
426 if (reg >= APIC_TRIGGER_MODE(0) &&
427 reg <= APIC_TRIGGER_MODE(15)) {
428 panic("Local APIC Trigger Mode registers are unimplemented.\n");
429 }
430 if (reg >= APIC_INTERRUPT_REQUEST(0) &&
431 reg <= APIC_INTERRUPT_REQUEST(15)) {
432 panic("Local APIC Interrupt Request registers "
433 "are unimplemented.\n");
434 }
435 switch (reg) {
436 case APIC_ID:
437 newVal = val & 0xFF;
438 break;
439 case APIC_VERSION:
440 // The Local APIC Version register is read only.
441 return;
442 case APIC_TASK_PRIORITY:
443 newVal = val & 0xFF;
444 break;
445 case APIC_ARBITRATION_PRIORITY:
446 panic("Local APIC Arbitration Priority register unimplemented.\n");
447 break;
448 case APIC_PROCESSOR_PRIORITY:
449 panic("Local APIC Processor Priority register unimplemented.\n");
450 break;
451 case APIC_EOI:
452 // Remove the interrupt that just completed from the local apic state.
453 clearRegArrayBit(APIC_IN_SERVICE_BASE, ISRV);
454 updateISRV();
455 return;
456 case APIC_LOGICAL_DESTINATION:
457 newVal = val & 0xFF000000;
458 break;
459 case APIC_DESTINATION_FORMAT:
460 newVal = val | 0x0FFFFFFF;
461 break;
462 case APIC_SPURIOUS_INTERRUPT_VECTOR:
463 regs[APIC_INTERNAL_STATE] &= ~ULL(1 << 1);
464 regs[APIC_INTERNAL_STATE] |= val & (1 << 8);
465 if (val & (1 << 9))
466 warn("Focus processor checking not implemented.\n");
467 break;
468 case APIC_ERROR_STATUS:
469 {
470 if (regs[APIC_INTERNAL_STATE] & 0x1) {
471 regs[APIC_INTERNAL_STATE] &= ~ULL(0x1);
472 newVal = 0;
473 } else {
474 regs[APIC_INTERNAL_STATE] |= ULL(0x1);
475 return;
476 }
477
478 }
479 break;
480 case APIC_INTERRUPT_COMMAND_LOW:
481 {
482 InterruptCommandRegLow low = regs[APIC_INTERRUPT_COMMAND_LOW];
483 // Check if we're already sending an IPI.
484 if (low.deliveryStatus) {
485 newVal = low;
486 break;
487 }
488 low = val;
489 InterruptCommandRegHigh high = regs[APIC_INTERRUPT_COMMAND_HIGH];
490 // Record that an IPI is being sent.
491 low.deliveryStatus = 1;
492 TriggerIntMessage message = 0;
493 message.destination = high.destination;
494 message.vector = low.vector;
495 message.deliveryMode = low.deliveryMode;
496 message.destMode = low.destMode;
497 message.level = low.level;
498 message.trigger = low.trigger;
499 bool timing = sys->getMemoryMode() == Enums::timing;
500 // Be careful no updates of the delivery status bit get lost.
501 regs[APIC_INTERRUPT_COMMAND_LOW] = low;
502 ApicList apics;
503 int numContexts = sys->numContexts();
504 switch (low.destShorthand) {
505 case 0:
506 if (message.deliveryMode == DeliveryMode::LowestPriority) {
507 panic("Lowest priority delivery mode "
508 "IPIs aren't implemented.\n");
509 }
510 if (message.destMode == 1) {
511 int dest = message.destination;
512 hack_once("Assuming logical destinations are 1 << id.\n");
513 for (int i = 0; i < numContexts; i++) {
514 if (dest & 0x1)
515 apics.push_back(i);
516 dest = dest >> 1;
517 }
518 } else {
519 if (message.destination == 0xFF) {
520 for (int i = 0; i < numContexts; i++) {
521 if (i == initialApicId) {
522 requestInterrupt(message.vector,
523 message.deliveryMode, message.trigger);
524 } else {
525 apics.push_back(i);
526 }
527 }
528 } else {
529 if (message.destination == initialApicId) {
530 requestInterrupt(message.vector,
531 message.deliveryMode, message.trigger);
532 } else {
533 apics.push_back(message.destination);
534 }
535 }
536 }
537 break;
538 case 1:
539 newVal = val;
540 requestInterrupt(message.vector,
541 message.deliveryMode, message.trigger);
542 break;
543 case 2:
544 requestInterrupt(message.vector,
545 message.deliveryMode, message.trigger);
546 // Fall through
547 case 3:
548 {
549 for (int i = 0; i < numContexts; i++) {
550 if (i != initialApicId) {
551 apics.push_back(i);
552 }
553 }
554 }
555 break;
556 }
557 pendingIPIs += apics.size();
558 intPort->sendMessage(apics, message, timing);
559 newVal = regs[APIC_INTERRUPT_COMMAND_LOW];
560 }
561 break;
562 case APIC_LVT_TIMER:
563 case APIC_LVT_THERMAL_SENSOR:
564 case APIC_LVT_PERFORMANCE_MONITORING_COUNTERS:
565 case APIC_LVT_LINT0:
566 case APIC_LVT_LINT1:
567 case APIC_LVT_ERROR:
568 {
569 uint64_t readOnlyMask = (1 << 12) | (1 << 14);
570 newVal = (val & ~readOnlyMask) |
571 (regs[reg] & readOnlyMask);
572 }
573 break;
574 case APIC_INITIAL_COUNT:
575 {
576 assert(clock);
577 newVal = bits(val, 31, 0);
578 // Compute how many timer ticks we're being programmed for.
579 uint64_t newCount = newVal *
580 (divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]));
581 // Schedule on the edge of the next tick plus the new count.
582 Tick offset = curTick() % clock;
583 if (offset) {
584 reschedule(apicTimerEvent,
585 curTick() + (newCount + 1) * clock - offset, true);
586 } else {
587 reschedule(apicTimerEvent,
588 curTick() + newCount * clock, true);
589 }
590 }
591 break;
592 case APIC_CURRENT_COUNT:
593 //Local APIC Current Count register is read only.
594 return;
595 case APIC_DIVIDE_CONFIGURATION:
596 newVal = val & 0xB;
597 break;
598 default:
599 break;
600 }
601 regs[reg] = newVal;
602 return;
603}
604
605
606X86ISA::Interrupts::Interrupts(Params * p) :
607 BasicPioDevice(p), IntDev(this, p->int_latency), latency(p->pio_latency),
608 clock(0),
609 apicTimerEvent(this),
610 pendingSmi(false), smiVector(0),
611 pendingNmi(false), nmiVector(0),
612 pendingExtInt(false), extIntVector(0),
613 pendingInit(false), initVector(0),
614 pendingStartup(false), startupVector(0),
615 startedUp(false), pendingUnmaskableInt(false),
616 pendingIPIs(0), cpu(NULL)
617#if FULL_SYSTEM
618 , platform(p->platform)
619#endif
618{
619 pioSize = PageBytes;
620 memset(regs, 0, sizeof(regs));
621 //Set the local apic DFR to the flat model.
622 regs[APIC_DESTINATION_FORMAT] = (uint32_t)(-1);
623 ISRV = 0;
624 IRRV = 0;
625}
626
627
628bool
629X86ISA::Interrupts::checkInterrupts(ThreadContext *tc) const
630{
631 RFLAGS rflags = tc->readMiscRegNoEffect(MISCREG_RFLAGS);
632 if (pendingUnmaskableInt) {
633 DPRINTF(LocalApic, "Reported pending unmaskable interrupt.\n");
634 return true;
635 }
636 if (rflags.intf) {
637 if (pendingExtInt) {
638 DPRINTF(LocalApic, "Reported pending external interrupt.\n");
639 return true;
640 }
641 if (IRRV > ISRV && bits(IRRV, 7, 4) >
642 bits(regs[APIC_TASK_PRIORITY], 7, 4)) {
643 DPRINTF(LocalApic, "Reported pending regular interrupt.\n");
644 return true;
645 }
646 }
647 return false;
648}
649
650Fault
651X86ISA::Interrupts::getInterrupt(ThreadContext *tc)
652{
653 assert(checkInterrupts(tc));
654 // These are all probably fairly uncommon, so we'll make them easier to
655 // check for.
656 if (pendingUnmaskableInt) {
657 if (pendingSmi) {
658 DPRINTF(LocalApic, "Generated SMI fault object.\n");
659 return new SystemManagementInterrupt();
660 } else if (pendingNmi) {
661 DPRINTF(LocalApic, "Generated NMI fault object.\n");
662 return new NonMaskableInterrupt(nmiVector);
663 } else if (pendingInit) {
664 DPRINTF(LocalApic, "Generated INIT fault object.\n");
665 return new InitInterrupt(initVector);
666 } else if (pendingStartup) {
667 DPRINTF(LocalApic, "Generating SIPI fault object.\n");
668 return new StartupInterrupt(startupVector);
669 } else {
670 panic("pendingUnmaskableInt set, but no unmaskable "
671 "ints were pending.\n");
672 return NoFault;
673 }
674 } else if (pendingExtInt) {
675 DPRINTF(LocalApic, "Generated external interrupt fault object.\n");
676 return new ExternalInterrupt(extIntVector);
677 } else {
678 DPRINTF(LocalApic, "Generated regular interrupt fault object.\n");
679 // The only thing left are fixed and lowest priority interrupts.
680 return new ExternalInterrupt(IRRV);
681 }
682}
683
684void
685X86ISA::Interrupts::updateIntrInfo(ThreadContext *tc)
686{
687 assert(checkInterrupts(tc));
688 if (pendingUnmaskableInt) {
689 if (pendingSmi) {
690 DPRINTF(LocalApic, "SMI sent to core.\n");
691 pendingSmi = false;
692 } else if (pendingNmi) {
693 DPRINTF(LocalApic, "NMI sent to core.\n");
694 pendingNmi = false;
695 } else if (pendingInit) {
696 DPRINTF(LocalApic, "Init sent to core.\n");
697 pendingInit = false;
698 startedUp = false;
699 } else if (pendingStartup) {
700 DPRINTF(LocalApic, "SIPI sent to core.\n");
701 pendingStartup = false;
702 startedUp = true;
703 }
704 if (!(pendingSmi || pendingNmi || pendingInit || pendingStartup))
705 pendingUnmaskableInt = false;
706 } else if (pendingExtInt) {
707 pendingExtInt = false;
708 } else {
709 DPRINTF(LocalApic, "Interrupt %d sent to core.\n", IRRV);
710 // Mark the interrupt as "in service".
711 ISRV = IRRV;
712 setRegArrayBit(APIC_IN_SERVICE_BASE, ISRV);
713 // Clear it out of the IRR.
714 clearRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, IRRV);
715 updateIRRV();
716 }
717}
718
719void
720X86ISA::Interrupts::serialize(std::ostream &os)
721{
722 SERIALIZE_ARRAY(regs, NUM_APIC_REGS);
723 SERIALIZE_SCALAR(clock);
724 SERIALIZE_SCALAR(pendingSmi);
725 SERIALIZE_SCALAR(smiVector);
726 SERIALIZE_SCALAR(pendingNmi);
727 SERIALIZE_SCALAR(nmiVector);
728 SERIALIZE_SCALAR(pendingExtInt);
729 SERIALIZE_SCALAR(extIntVector);
730 SERIALIZE_SCALAR(pendingInit);
731 SERIALIZE_SCALAR(initVector);
732 SERIALIZE_SCALAR(pendingStartup);
733 SERIALIZE_SCALAR(startupVector);
734 SERIALIZE_SCALAR(startedUp);
735 SERIALIZE_SCALAR(pendingUnmaskableInt);
736 SERIALIZE_SCALAR(pendingIPIs);
737 SERIALIZE_SCALAR(IRRV);
738 SERIALIZE_SCALAR(ISRV);
739 bool apicTimerEventScheduled = apicTimerEvent.scheduled();
740 SERIALIZE_SCALAR(apicTimerEventScheduled);
741 Tick apicTimerEventTick = apicTimerEvent.when();
742 SERIALIZE_SCALAR(apicTimerEventTick);
743}
744
745void
746X86ISA::Interrupts::unserialize(Checkpoint *cp, const std::string &section)
747{
748 UNSERIALIZE_ARRAY(regs, NUM_APIC_REGS);
749 UNSERIALIZE_SCALAR(clock);
750 UNSERIALIZE_SCALAR(pendingSmi);
751 UNSERIALIZE_SCALAR(smiVector);
752 UNSERIALIZE_SCALAR(pendingNmi);
753 UNSERIALIZE_SCALAR(nmiVector);
754 UNSERIALIZE_SCALAR(pendingExtInt);
755 UNSERIALIZE_SCALAR(extIntVector);
756 UNSERIALIZE_SCALAR(pendingInit);
757 UNSERIALIZE_SCALAR(initVector);
758 UNSERIALIZE_SCALAR(pendingStartup);
759 UNSERIALIZE_SCALAR(startupVector);
760 UNSERIALIZE_SCALAR(startedUp);
761 UNSERIALIZE_SCALAR(pendingUnmaskableInt);
762 UNSERIALIZE_SCALAR(pendingIPIs);
763 UNSERIALIZE_SCALAR(IRRV);
764 UNSERIALIZE_SCALAR(ISRV);
765 bool apicTimerEventScheduled;
766 UNSERIALIZE_SCALAR(apicTimerEventScheduled);
767 if (apicTimerEventScheduled) {
768 Tick apicTimerEventTick;
769 UNSERIALIZE_SCALAR(apicTimerEventTick);
770 if (apicTimerEvent.scheduled()) {
771 reschedule(apicTimerEvent, apicTimerEventTick, true);
772 } else {
773 schedule(apicTimerEvent, apicTimerEventTick);
774 }
775 }
776}
777
778X86ISA::Interrupts *
779X86LocalApicParams::create()
780{
781 return new X86ISA::Interrupts(this);
782}
620{
621 pioSize = PageBytes;
622 memset(regs, 0, sizeof(regs));
623 //Set the local apic DFR to the flat model.
624 regs[APIC_DESTINATION_FORMAT] = (uint32_t)(-1);
625 ISRV = 0;
626 IRRV = 0;
627}
628
629
630bool
631X86ISA::Interrupts::checkInterrupts(ThreadContext *tc) const
632{
633 RFLAGS rflags = tc->readMiscRegNoEffect(MISCREG_RFLAGS);
634 if (pendingUnmaskableInt) {
635 DPRINTF(LocalApic, "Reported pending unmaskable interrupt.\n");
636 return true;
637 }
638 if (rflags.intf) {
639 if (pendingExtInt) {
640 DPRINTF(LocalApic, "Reported pending external interrupt.\n");
641 return true;
642 }
643 if (IRRV > ISRV && bits(IRRV, 7, 4) >
644 bits(regs[APIC_TASK_PRIORITY], 7, 4)) {
645 DPRINTF(LocalApic, "Reported pending regular interrupt.\n");
646 return true;
647 }
648 }
649 return false;
650}
651
652Fault
653X86ISA::Interrupts::getInterrupt(ThreadContext *tc)
654{
655 assert(checkInterrupts(tc));
656 // These are all probably fairly uncommon, so we'll make them easier to
657 // check for.
658 if (pendingUnmaskableInt) {
659 if (pendingSmi) {
660 DPRINTF(LocalApic, "Generated SMI fault object.\n");
661 return new SystemManagementInterrupt();
662 } else if (pendingNmi) {
663 DPRINTF(LocalApic, "Generated NMI fault object.\n");
664 return new NonMaskableInterrupt(nmiVector);
665 } else if (pendingInit) {
666 DPRINTF(LocalApic, "Generated INIT fault object.\n");
667 return new InitInterrupt(initVector);
668 } else if (pendingStartup) {
669 DPRINTF(LocalApic, "Generating SIPI fault object.\n");
670 return new StartupInterrupt(startupVector);
671 } else {
672 panic("pendingUnmaskableInt set, but no unmaskable "
673 "ints were pending.\n");
674 return NoFault;
675 }
676 } else if (pendingExtInt) {
677 DPRINTF(LocalApic, "Generated external interrupt fault object.\n");
678 return new ExternalInterrupt(extIntVector);
679 } else {
680 DPRINTF(LocalApic, "Generated regular interrupt fault object.\n");
681 // The only thing left are fixed and lowest priority interrupts.
682 return new ExternalInterrupt(IRRV);
683 }
684}
685
686void
687X86ISA::Interrupts::updateIntrInfo(ThreadContext *tc)
688{
689 assert(checkInterrupts(tc));
690 if (pendingUnmaskableInt) {
691 if (pendingSmi) {
692 DPRINTF(LocalApic, "SMI sent to core.\n");
693 pendingSmi = false;
694 } else if (pendingNmi) {
695 DPRINTF(LocalApic, "NMI sent to core.\n");
696 pendingNmi = false;
697 } else if (pendingInit) {
698 DPRINTF(LocalApic, "Init sent to core.\n");
699 pendingInit = false;
700 startedUp = false;
701 } else if (pendingStartup) {
702 DPRINTF(LocalApic, "SIPI sent to core.\n");
703 pendingStartup = false;
704 startedUp = true;
705 }
706 if (!(pendingSmi || pendingNmi || pendingInit || pendingStartup))
707 pendingUnmaskableInt = false;
708 } else if (pendingExtInt) {
709 pendingExtInt = false;
710 } else {
711 DPRINTF(LocalApic, "Interrupt %d sent to core.\n", IRRV);
712 // Mark the interrupt as "in service".
713 ISRV = IRRV;
714 setRegArrayBit(APIC_IN_SERVICE_BASE, ISRV);
715 // Clear it out of the IRR.
716 clearRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, IRRV);
717 updateIRRV();
718 }
719}
720
721void
722X86ISA::Interrupts::serialize(std::ostream &os)
723{
724 SERIALIZE_ARRAY(regs, NUM_APIC_REGS);
725 SERIALIZE_SCALAR(clock);
726 SERIALIZE_SCALAR(pendingSmi);
727 SERIALIZE_SCALAR(smiVector);
728 SERIALIZE_SCALAR(pendingNmi);
729 SERIALIZE_SCALAR(nmiVector);
730 SERIALIZE_SCALAR(pendingExtInt);
731 SERIALIZE_SCALAR(extIntVector);
732 SERIALIZE_SCALAR(pendingInit);
733 SERIALIZE_SCALAR(initVector);
734 SERIALIZE_SCALAR(pendingStartup);
735 SERIALIZE_SCALAR(startupVector);
736 SERIALIZE_SCALAR(startedUp);
737 SERIALIZE_SCALAR(pendingUnmaskableInt);
738 SERIALIZE_SCALAR(pendingIPIs);
739 SERIALIZE_SCALAR(IRRV);
740 SERIALIZE_SCALAR(ISRV);
741 bool apicTimerEventScheduled = apicTimerEvent.scheduled();
742 SERIALIZE_SCALAR(apicTimerEventScheduled);
743 Tick apicTimerEventTick = apicTimerEvent.when();
744 SERIALIZE_SCALAR(apicTimerEventTick);
745}
746
747void
748X86ISA::Interrupts::unserialize(Checkpoint *cp, const std::string &section)
749{
750 UNSERIALIZE_ARRAY(regs, NUM_APIC_REGS);
751 UNSERIALIZE_SCALAR(clock);
752 UNSERIALIZE_SCALAR(pendingSmi);
753 UNSERIALIZE_SCALAR(smiVector);
754 UNSERIALIZE_SCALAR(pendingNmi);
755 UNSERIALIZE_SCALAR(nmiVector);
756 UNSERIALIZE_SCALAR(pendingExtInt);
757 UNSERIALIZE_SCALAR(extIntVector);
758 UNSERIALIZE_SCALAR(pendingInit);
759 UNSERIALIZE_SCALAR(initVector);
760 UNSERIALIZE_SCALAR(pendingStartup);
761 UNSERIALIZE_SCALAR(startupVector);
762 UNSERIALIZE_SCALAR(startedUp);
763 UNSERIALIZE_SCALAR(pendingUnmaskableInt);
764 UNSERIALIZE_SCALAR(pendingIPIs);
765 UNSERIALIZE_SCALAR(IRRV);
766 UNSERIALIZE_SCALAR(ISRV);
767 bool apicTimerEventScheduled;
768 UNSERIALIZE_SCALAR(apicTimerEventScheduled);
769 if (apicTimerEventScheduled) {
770 Tick apicTimerEventTick;
771 UNSERIALIZE_SCALAR(apicTimerEventTick);
772 if (apicTimerEvent.scheduled()) {
773 reschedule(apicTimerEvent, apicTimerEventTick, true);
774 } else {
775 schedule(apicTimerEvent, apicTimerEventTick);
776 }
777 }
778}
779
780X86ISA::Interrupts *
781X86LocalApicParams::create()
782{
783 return new X86ISA::Interrupts(this);
784}