interrupts.cc (5651:7f0c8006c3d7) interrupts.cc (5654:340254de2031)
1/*
2 * Copyright (c) 2008 The Hewlett-Packard Development Company
3 * All rights reserved.
4 *
5 * Redistribution and use of this software in source and binary forms,
6 * with or without modification, are permitted provided that the
7 * following conditions are met:
8 *
9 * The software must be used only for Non-Commercial Use which means any
10 * use which is NOT directed to receiving any direct monetary
11 * compensation for, or commercial advantage from such use. Illustrative
12 * examples of non-commercial use are academic research, personal study,
13 * teaching, education and corporate research & development.
14 * Illustrative examples of commercial use are distributing products for
15 * commercial advantage and providing services using the software for
16 * commercial advantage.
17 *
18 * If you wish to use this software or functionality therein that may be
19 * covered by patents for commercial use, please contact:
20 * Director of Intellectual Property Licensing
21 * Office of Strategy and Technology
22 * Hewlett-Packard Company
23 * 1501 Page Mill Road
24 * Palo Alto, California 94304
25 *
26 * Redistributions of source code must retain the above copyright notice,
27 * this list of conditions and the following disclaimer. Redistributions
28 * in binary form must reproduce the above copyright notice, this list of
29 * conditions and the following disclaimer in the documentation and/or
30 * other materials provided with the distribution. Neither the name of
31 * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
32 * contributors may be used to endorse or promote products derived from
33 * this software without specific prior written permission. No right of
34 * sublicense is granted herewith. Derivatives of the software and
35 * output created using the software may be prepared, but only for
36 * Non-Commercial Uses. Derivatives of the software may be shared with
37 * others provided: (i) the others agree to abide by the list of
38 * conditions herein which includes the Non-Commercial Use restrictions;
39 * and (ii) such Derivatives of the software include the above copyright
40 * notice to acknowledge the contribution from this software where
41 * applicable, this list of conditions and the disclaimer below.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
44 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
45 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
46 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
47 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
48 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
49 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
50 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
51 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
52 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
53 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
54 *
55 * Authors: Gabe Black
56 */
57
58#include "arch/x86/apicregs.hh"
59#include "arch/x86/interrupts.hh"
1/*
2 * Copyright (c) 2008 The Hewlett-Packard Development Company
3 * All rights reserved.
4 *
5 * Redistribution and use of this software in source and binary forms,
6 * with or without modification, are permitted provided that the
7 * following conditions are met:
8 *
9 * The software must be used only for Non-Commercial Use which means any
10 * use which is NOT directed to receiving any direct monetary
11 * compensation for, or commercial advantage from such use. Illustrative
12 * examples of non-commercial use are academic research, personal study,
13 * teaching, education and corporate research & development.
14 * Illustrative examples of commercial use are distributing products for
15 * commercial advantage and providing services using the software for
16 * commercial advantage.
17 *
18 * If you wish to use this software or functionality therein that may be
19 * covered by patents for commercial use, please contact:
20 * Director of Intellectual Property Licensing
21 * Office of Strategy and Technology
22 * Hewlett-Packard Company
23 * 1501 Page Mill Road
24 * Palo Alto, California 94304
25 *
26 * Redistributions of source code must retain the above copyright notice,
27 * this list of conditions and the following disclaimer. Redistributions
28 * in binary form must reproduce the above copyright notice, this list of
29 * conditions and the following disclaimer in the documentation and/or
30 * other materials provided with the distribution. Neither the name of
31 * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
32 * contributors may be used to endorse or promote products derived from
33 * this software without specific prior written permission. No right of
34 * sublicense is granted herewith. Derivatives of the software and
35 * output created using the software may be prepared, but only for
36 * Non-Commercial Uses. Derivatives of the software may be shared with
37 * others provided: (i) the others agree to abide by the list of
38 * conditions herein which includes the Non-Commercial Use restrictions;
39 * and (ii) such Derivatives of the software include the above copyright
40 * notice to acknowledge the contribution from this software where
41 * applicable, this list of conditions and the disclaimer below.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
44 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
45 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
46 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
47 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
48 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
49 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
50 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
51 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
52 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
53 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
54 *
55 * Authors: Gabe Black
56 */
57
58#include "arch/x86/apicregs.hh"
59#include "arch/x86/interrupts.hh"
60#include "arch/x86/intmessage.hh"
60#include "cpu/base.hh"
61#include "cpu/base.hh"
62#include "mem/packet_access.hh"
61
62int
63divideFromConf(uint32_t conf)
64{
65 // This figures out what division we want from the division configuration
66 // register in the local APIC. The encoding is a little odd but it can
67 // be deciphered fairly easily.
68 int shift = ((conf & 0x8) >> 1) | (conf & 0x3);
69 shift = (shift + 1) % 8;
70 return 1 << shift;
71}
72
73namespace X86ISA
74{
75
76ApicRegIndex
77decodeAddr(Addr paddr)
78{
79 ApicRegIndex regNum;
80 paddr &= ~mask(3);
81 switch (paddr)
82 {
83 case 0x20:
84 regNum = APIC_ID;
85 break;
86 case 0x30:
87 regNum = APIC_VERSION;
88 break;
89 case 0x80:
90 regNum = APIC_TASK_PRIORITY;
91 break;
92 case 0x90:
93 regNum = APIC_ARBITRATION_PRIORITY;
94 break;
95 case 0xA0:
96 regNum = APIC_PROCESSOR_PRIORITY;
97 break;
98 case 0xB0:
99 regNum = APIC_EOI;
100 break;
101 case 0xD0:
102 regNum = APIC_LOGICAL_DESTINATION;
103 break;
104 case 0xE0:
105 regNum = APIC_DESTINATION_FORMAT;
106 break;
107 case 0xF0:
108 regNum = APIC_SPURIOUS_INTERRUPT_VECTOR;
109 break;
110 case 0x100:
111 case 0x108:
112 case 0x110:
113 case 0x118:
114 case 0x120:
115 case 0x128:
116 case 0x130:
117 case 0x138:
118 case 0x140:
119 case 0x148:
120 case 0x150:
121 case 0x158:
122 case 0x160:
123 case 0x168:
124 case 0x170:
125 case 0x178:
126 regNum = APIC_IN_SERVICE((paddr - 0x100) / 0x8);
127 break;
128 case 0x180:
129 case 0x188:
130 case 0x190:
131 case 0x198:
132 case 0x1A0:
133 case 0x1A8:
134 case 0x1B0:
135 case 0x1B8:
136 case 0x1C0:
137 case 0x1C8:
138 case 0x1D0:
139 case 0x1D8:
140 case 0x1E0:
141 case 0x1E8:
142 case 0x1F0:
143 case 0x1F8:
144 regNum = APIC_TRIGGER_MODE((paddr - 0x180) / 0x8);
145 break;
146 case 0x200:
147 case 0x208:
148 case 0x210:
149 case 0x218:
150 case 0x220:
151 case 0x228:
152 case 0x230:
153 case 0x238:
154 case 0x240:
155 case 0x248:
156 case 0x250:
157 case 0x258:
158 case 0x260:
159 case 0x268:
160 case 0x270:
161 case 0x278:
162 regNum = APIC_INTERRUPT_REQUEST((paddr - 0x200) / 0x8);
163 break;
164 case 0x280:
165 regNum = APIC_ERROR_STATUS;
166 break;
167 case 0x300:
168 regNum = APIC_INTERRUPT_COMMAND_LOW;
169 break;
170 case 0x310:
171 regNum = APIC_INTERRUPT_COMMAND_HIGH;
172 break;
173 case 0x320:
174 regNum = APIC_LVT_TIMER;
175 break;
176 case 0x330:
177 regNum = APIC_LVT_THERMAL_SENSOR;
178 break;
179 case 0x340:
180 regNum = APIC_LVT_PERFORMANCE_MONITORING_COUNTERS;
181 break;
182 case 0x350:
183 regNum = APIC_LVT_LINT0;
184 break;
185 case 0x360:
186 regNum = APIC_LVT_LINT1;
187 break;
188 case 0x370:
189 regNum = APIC_LVT_ERROR;
190 break;
191 case 0x380:
192 regNum = APIC_INITIAL_COUNT;
193 break;
194 case 0x390:
195 regNum = APIC_CURRENT_COUNT;
196 break;
197 case 0x3E0:
198 regNum = APIC_DIVIDE_CONFIGURATION;
199 break;
200 default:
201 // A reserved register field.
202 panic("Accessed reserved register field %#x.\n", paddr);
203 break;
204 }
205 return regNum;
206}
207}
208
209Tick
210X86ISA::Interrupts::read(PacketPtr pkt)
211{
212 Addr offset = pkt->getAddr() - pioAddr;
213 //Make sure we're at least only accessing one register.
214 if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3)))
215 panic("Accessed more than one register at a time in the APIC!\n");
216 ApicRegIndex reg = decodeAddr(offset);
217 uint32_t val = htog(readReg(reg));
218 DPRINTF(LocalApic,
219 "Reading Local APIC register %d at offset %#x as %#x.\n",
220 reg, offset, val);
221 pkt->setData(((uint8_t *)&val) + (offset & mask(3)));
222 return latency;
223}
224
225Tick
226X86ISA::Interrupts::write(PacketPtr pkt)
227{
228 Addr offset = pkt->getAddr() - pioAddr;
229 //Make sure we're at least only accessing one register.
230 if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3)))
231 panic("Accessed more than one register at a time in the APIC!\n");
232 ApicRegIndex reg = decodeAddr(offset);
233 uint32_t val = regs[reg];
234 pkt->writeData(((uint8_t *)&val) + (offset & mask(3)));
235 DPRINTF(LocalApic,
236 "Writing Local APIC register %d at offset %#x as %#x.\n",
237 reg, offset, gtoh(val));
238 setReg(reg, gtoh(val));
239 return latency;
240}
241
242Tick
243X86ISA::Interrupts::recvMessage(PacketPtr pkt)
244{
63
64int
65divideFromConf(uint32_t conf)
66{
67 // This figures out what division we want from the division configuration
68 // register in the local APIC. The encoding is a little odd but it can
69 // be deciphered fairly easily.
70 int shift = ((conf & 0x8) >> 1) | (conf & 0x3);
71 shift = (shift + 1) % 8;
72 return 1 << shift;
73}
74
75namespace X86ISA
76{
77
78ApicRegIndex
79decodeAddr(Addr paddr)
80{
81 ApicRegIndex regNum;
82 paddr &= ~mask(3);
83 switch (paddr)
84 {
85 case 0x20:
86 regNum = APIC_ID;
87 break;
88 case 0x30:
89 regNum = APIC_VERSION;
90 break;
91 case 0x80:
92 regNum = APIC_TASK_PRIORITY;
93 break;
94 case 0x90:
95 regNum = APIC_ARBITRATION_PRIORITY;
96 break;
97 case 0xA0:
98 regNum = APIC_PROCESSOR_PRIORITY;
99 break;
100 case 0xB0:
101 regNum = APIC_EOI;
102 break;
103 case 0xD0:
104 regNum = APIC_LOGICAL_DESTINATION;
105 break;
106 case 0xE0:
107 regNum = APIC_DESTINATION_FORMAT;
108 break;
109 case 0xF0:
110 regNum = APIC_SPURIOUS_INTERRUPT_VECTOR;
111 break;
112 case 0x100:
113 case 0x108:
114 case 0x110:
115 case 0x118:
116 case 0x120:
117 case 0x128:
118 case 0x130:
119 case 0x138:
120 case 0x140:
121 case 0x148:
122 case 0x150:
123 case 0x158:
124 case 0x160:
125 case 0x168:
126 case 0x170:
127 case 0x178:
128 regNum = APIC_IN_SERVICE((paddr - 0x100) / 0x8);
129 break;
130 case 0x180:
131 case 0x188:
132 case 0x190:
133 case 0x198:
134 case 0x1A0:
135 case 0x1A8:
136 case 0x1B0:
137 case 0x1B8:
138 case 0x1C0:
139 case 0x1C8:
140 case 0x1D0:
141 case 0x1D8:
142 case 0x1E0:
143 case 0x1E8:
144 case 0x1F0:
145 case 0x1F8:
146 regNum = APIC_TRIGGER_MODE((paddr - 0x180) / 0x8);
147 break;
148 case 0x200:
149 case 0x208:
150 case 0x210:
151 case 0x218:
152 case 0x220:
153 case 0x228:
154 case 0x230:
155 case 0x238:
156 case 0x240:
157 case 0x248:
158 case 0x250:
159 case 0x258:
160 case 0x260:
161 case 0x268:
162 case 0x270:
163 case 0x278:
164 regNum = APIC_INTERRUPT_REQUEST((paddr - 0x200) / 0x8);
165 break;
166 case 0x280:
167 regNum = APIC_ERROR_STATUS;
168 break;
169 case 0x300:
170 regNum = APIC_INTERRUPT_COMMAND_LOW;
171 break;
172 case 0x310:
173 regNum = APIC_INTERRUPT_COMMAND_HIGH;
174 break;
175 case 0x320:
176 regNum = APIC_LVT_TIMER;
177 break;
178 case 0x330:
179 regNum = APIC_LVT_THERMAL_SENSOR;
180 break;
181 case 0x340:
182 regNum = APIC_LVT_PERFORMANCE_MONITORING_COUNTERS;
183 break;
184 case 0x350:
185 regNum = APIC_LVT_LINT0;
186 break;
187 case 0x360:
188 regNum = APIC_LVT_LINT1;
189 break;
190 case 0x370:
191 regNum = APIC_LVT_ERROR;
192 break;
193 case 0x380:
194 regNum = APIC_INITIAL_COUNT;
195 break;
196 case 0x390:
197 regNum = APIC_CURRENT_COUNT;
198 break;
199 case 0x3E0:
200 regNum = APIC_DIVIDE_CONFIGURATION;
201 break;
202 default:
203 // A reserved register field.
204 panic("Accessed reserved register field %#x.\n", paddr);
205 break;
206 }
207 return regNum;
208}
209}
210
211Tick
212X86ISA::Interrupts::read(PacketPtr pkt)
213{
214 Addr offset = pkt->getAddr() - pioAddr;
215 //Make sure we're at least only accessing one register.
216 if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3)))
217 panic("Accessed more than one register at a time in the APIC!\n");
218 ApicRegIndex reg = decodeAddr(offset);
219 uint32_t val = htog(readReg(reg));
220 DPRINTF(LocalApic,
221 "Reading Local APIC register %d at offset %#x as %#x.\n",
222 reg, offset, val);
223 pkt->setData(((uint8_t *)&val) + (offset & mask(3)));
224 return latency;
225}
226
227Tick
228X86ISA::Interrupts::write(PacketPtr pkt)
229{
230 Addr offset = pkt->getAddr() - pioAddr;
231 //Make sure we're at least only accessing one register.
232 if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3)))
233 panic("Accessed more than one register at a time in the APIC!\n");
234 ApicRegIndex reg = decodeAddr(offset);
235 uint32_t val = regs[reg];
236 pkt->writeData(((uint8_t *)&val) + (offset & mask(3)));
237 DPRINTF(LocalApic,
238 "Writing Local APIC register %d at offset %#x as %#x.\n",
239 reg, offset, gtoh(val));
240 setReg(reg, gtoh(val));
241 return latency;
242}
243
244Tick
245X86ISA::Interrupts::recvMessage(PacketPtr pkt)
246{
245 Addr offset = pkt->getAddr() - x86InterruptAddress(0, 0);
247 uint8_t id = 0;
248 Addr offset = pkt->getAddr() - x86InterruptAddress(id, 0);
246 assert(pkt->cmd == MemCmd::MessageReq);
247 switch(offset)
248 {
249 case 0:
249 assert(pkt->cmd == MemCmd::MessageReq);
250 switch(offset)
251 {
252 case 0:
250 DPRINTF(LocalApic, "Got Trigger Interrupt message.\n");
253 {
254 TriggerIntMessage message = pkt->get<TriggerIntMessage>();
255 uint8_t vector = message.vector;
256 DPRINTF(LocalApic,
257 "Got Trigger Interrupt message with vector %#x.\n",
258 vector);
259 // Make sure we're really supposed to get this.
260 assert((message.destMode == 0 && message.destination == id) ||
261 (bits((int)message.destination, id)));
262 if (DeliveryMode::isUnmaskable(message.deliveryMode)) {
263 DPRINTF(LocalApic, "Interrupt is an %s and unmaskable.\n",
264 DeliveryMode::names[message.deliveryMode]);
265 panic("Unmaskable interrupts aren't implemented.\n");
266 } else if (DeliveryMode::isMaskable(message.deliveryMode)) {
267 DPRINTF(LocalApic, "Interrupt is an %s and maskable.\n",
268 DeliveryMode::names[message.deliveryMode]);
269 // Queue up the interrupt in the IRR.
270 if (vector > IRRV)
271 IRRV = vector;
272 if (!getRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, vector)) {
273 setRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, vector);
274 if (message.trigger) {
275 // Level triggered.
276 setRegArrayBit(APIC_TRIGGER_MODE_BASE, vector);
277 } else {
278 // Edge triggered.
279 clearRegArrayBit(APIC_TRIGGER_MODE_BASE, vector);
280 }
281 }
282 }
283 }
251 break;
252 default:
253 panic("Local apic got unknown interrupt message at offset %#x.\n",
254 offset);
255 break;
256 }
257 delete pkt->req;
258 delete pkt;
259 return latency;
260}
261
262
263uint32_t
264X86ISA::Interrupts::readReg(ApicRegIndex reg)
265{
266 if (reg >= APIC_TRIGGER_MODE(0) &&
267 reg <= APIC_TRIGGER_MODE(15)) {
268 panic("Local APIC Trigger Mode registers are unimplemented.\n");
269 }
270 switch (reg) {
271 case APIC_ARBITRATION_PRIORITY:
272 panic("Local APIC Arbitration Priority register unimplemented.\n");
273 break;
274 case APIC_PROCESSOR_PRIORITY:
275 panic("Local APIC Processor Priority register unimplemented.\n");
276 break;
277 case APIC_EOI:
278 panic("Local APIC EOI register unimplemented.\n");
279 break;
280 case APIC_ERROR_STATUS:
281 regs[APIC_INTERNAL_STATE] &= ~ULL(0x1);
282 break;
283 case APIC_INTERRUPT_COMMAND_LOW:
284 panic("Local APIC Interrupt Command low"
285 " register unimplemented.\n");
286 break;
287 case APIC_INTERRUPT_COMMAND_HIGH:
288 panic("Local APIC Interrupt Command high"
289 " register unimplemented.\n");
290 break;
291 case APIC_CURRENT_COUNT:
292 {
293 assert(clock);
294 uint32_t val = regs[reg] - curTick / clock;
295 val /= (16 * divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]));
296 return val;
297 }
298 default:
299 break;
300 }
301 return regs[reg];
302}
303
304void
305X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val)
306{
307 uint32_t newVal = val;
308 if (reg >= APIC_IN_SERVICE(0) &&
309 reg <= APIC_IN_SERVICE(15)) {
310 panic("Local APIC In-Service registers are unimplemented.\n");
311 }
312 if (reg >= APIC_TRIGGER_MODE(0) &&
313 reg <= APIC_TRIGGER_MODE(15)) {
314 panic("Local APIC Trigger Mode registers are unimplemented.\n");
315 }
316 if (reg >= APIC_INTERRUPT_REQUEST(0) &&
317 reg <= APIC_INTERRUPT_REQUEST(15)) {
318 panic("Local APIC Interrupt Request registers "
319 "are unimplemented.\n");
320 }
321 switch (reg) {
322 case APIC_ID:
323 newVal = val & 0xFF;
324 break;
325 case APIC_VERSION:
326 // The Local APIC Version register is read only.
327 return;
328 case APIC_TASK_PRIORITY:
329 newVal = val & 0xFF;
330 break;
331 case APIC_ARBITRATION_PRIORITY:
332 panic("Local APIC Arbitration Priority register unimplemented.\n");
333 break;
334 case APIC_PROCESSOR_PRIORITY:
335 panic("Local APIC Processor Priority register unimplemented.\n");
336 break;
337 case APIC_EOI:
338 panic("Local APIC EOI register unimplemented.\n");
339 break;
340 case APIC_LOGICAL_DESTINATION:
341 newVal = val & 0xFF000000;
342 break;
343 case APIC_DESTINATION_FORMAT:
344 newVal = val | 0x0FFFFFFF;
345 break;
346 case APIC_SPURIOUS_INTERRUPT_VECTOR:
347 regs[APIC_INTERNAL_STATE] &= ~ULL(1 << 1);
348 regs[APIC_INTERNAL_STATE] |= val & (1 << 8);
349 if (val & (1 << 9))
350 warn("Focus processor checking not implemented.\n");
351 break;
352 case APIC_ERROR_STATUS:
353 {
354 if (regs[APIC_INTERNAL_STATE] & 0x1) {
355 regs[APIC_INTERNAL_STATE] &= ~ULL(0x1);
356 newVal = 0;
357 } else {
358 regs[APIC_INTERNAL_STATE] |= ULL(0x1);
359 return;
360 }
361
362 }
363 break;
364 case APIC_INTERRUPT_COMMAND_LOW:
365 panic("Local APIC Interrupt Command low"
366 " register unimplemented.\n");
367 break;
368 case APIC_INTERRUPT_COMMAND_HIGH:
369 panic("Local APIC Interrupt Command high"
370 " register unimplemented.\n");
371 break;
372 case APIC_LVT_TIMER:
373 case APIC_LVT_THERMAL_SENSOR:
374 case APIC_LVT_PERFORMANCE_MONITORING_COUNTERS:
375 case APIC_LVT_LINT0:
376 case APIC_LVT_LINT1:
377 case APIC_LVT_ERROR:
378 {
379 uint64_t readOnlyMask = (1 << 12) | (1 << 14);
380 newVal = (val & ~readOnlyMask) |
381 (regs[reg] & readOnlyMask);
382 }
383 break;
384 case APIC_INITIAL_COUNT:
385 {
386 assert(clock);
387 newVal = bits(val, 31, 0);
388 uint32_t newCount = newVal *
389 (divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]) * 16);
390 regs[APIC_CURRENT_COUNT] = newCount + curTick / clock;
391 // Find out how long a "tick" of the timer should take.
392 Tick timerTick = 16 * clock;
393 // Schedule on the edge of the next tick plus the new count.
394 Tick offset = curTick % timerTick;
395 if (offset) {
396 reschedule(apicTimerEvent,
397 curTick + (newCount + 1) * timerTick - offset, true);
398 } else {
399 reschedule(apicTimerEvent,
400 curTick + newCount * timerTick, true);
401 }
402 }
403 break;
404 case APIC_CURRENT_COUNT:
405 //Local APIC Current Count register is read only.
406 return;
407 case APIC_DIVIDE_CONFIGURATION:
408 newVal = val & 0xB;
409 break;
410 default:
411 break;
412 }
413 regs[reg] = newVal;
414 return;
415}
416
284 break;
285 default:
286 panic("Local apic got unknown interrupt message at offset %#x.\n",
287 offset);
288 break;
289 }
290 delete pkt->req;
291 delete pkt;
292 return latency;
293}
294
295
296uint32_t
297X86ISA::Interrupts::readReg(ApicRegIndex reg)
298{
299 if (reg >= APIC_TRIGGER_MODE(0) &&
300 reg <= APIC_TRIGGER_MODE(15)) {
301 panic("Local APIC Trigger Mode registers are unimplemented.\n");
302 }
303 switch (reg) {
304 case APIC_ARBITRATION_PRIORITY:
305 panic("Local APIC Arbitration Priority register unimplemented.\n");
306 break;
307 case APIC_PROCESSOR_PRIORITY:
308 panic("Local APIC Processor Priority register unimplemented.\n");
309 break;
310 case APIC_EOI:
311 panic("Local APIC EOI register unimplemented.\n");
312 break;
313 case APIC_ERROR_STATUS:
314 regs[APIC_INTERNAL_STATE] &= ~ULL(0x1);
315 break;
316 case APIC_INTERRUPT_COMMAND_LOW:
317 panic("Local APIC Interrupt Command low"
318 " register unimplemented.\n");
319 break;
320 case APIC_INTERRUPT_COMMAND_HIGH:
321 panic("Local APIC Interrupt Command high"
322 " register unimplemented.\n");
323 break;
324 case APIC_CURRENT_COUNT:
325 {
326 assert(clock);
327 uint32_t val = regs[reg] - curTick / clock;
328 val /= (16 * divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]));
329 return val;
330 }
331 default:
332 break;
333 }
334 return regs[reg];
335}
336
337void
338X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val)
339{
340 uint32_t newVal = val;
341 if (reg >= APIC_IN_SERVICE(0) &&
342 reg <= APIC_IN_SERVICE(15)) {
343 panic("Local APIC In-Service registers are unimplemented.\n");
344 }
345 if (reg >= APIC_TRIGGER_MODE(0) &&
346 reg <= APIC_TRIGGER_MODE(15)) {
347 panic("Local APIC Trigger Mode registers are unimplemented.\n");
348 }
349 if (reg >= APIC_INTERRUPT_REQUEST(0) &&
350 reg <= APIC_INTERRUPT_REQUEST(15)) {
351 panic("Local APIC Interrupt Request registers "
352 "are unimplemented.\n");
353 }
354 switch (reg) {
355 case APIC_ID:
356 newVal = val & 0xFF;
357 break;
358 case APIC_VERSION:
359 // The Local APIC Version register is read only.
360 return;
361 case APIC_TASK_PRIORITY:
362 newVal = val & 0xFF;
363 break;
364 case APIC_ARBITRATION_PRIORITY:
365 panic("Local APIC Arbitration Priority register unimplemented.\n");
366 break;
367 case APIC_PROCESSOR_PRIORITY:
368 panic("Local APIC Processor Priority register unimplemented.\n");
369 break;
370 case APIC_EOI:
371 panic("Local APIC EOI register unimplemented.\n");
372 break;
373 case APIC_LOGICAL_DESTINATION:
374 newVal = val & 0xFF000000;
375 break;
376 case APIC_DESTINATION_FORMAT:
377 newVal = val | 0x0FFFFFFF;
378 break;
379 case APIC_SPURIOUS_INTERRUPT_VECTOR:
380 regs[APIC_INTERNAL_STATE] &= ~ULL(1 << 1);
381 regs[APIC_INTERNAL_STATE] |= val & (1 << 8);
382 if (val & (1 << 9))
383 warn("Focus processor checking not implemented.\n");
384 break;
385 case APIC_ERROR_STATUS:
386 {
387 if (regs[APIC_INTERNAL_STATE] & 0x1) {
388 regs[APIC_INTERNAL_STATE] &= ~ULL(0x1);
389 newVal = 0;
390 } else {
391 regs[APIC_INTERNAL_STATE] |= ULL(0x1);
392 return;
393 }
394
395 }
396 break;
397 case APIC_INTERRUPT_COMMAND_LOW:
398 panic("Local APIC Interrupt Command low"
399 " register unimplemented.\n");
400 break;
401 case APIC_INTERRUPT_COMMAND_HIGH:
402 panic("Local APIC Interrupt Command high"
403 " register unimplemented.\n");
404 break;
405 case APIC_LVT_TIMER:
406 case APIC_LVT_THERMAL_SENSOR:
407 case APIC_LVT_PERFORMANCE_MONITORING_COUNTERS:
408 case APIC_LVT_LINT0:
409 case APIC_LVT_LINT1:
410 case APIC_LVT_ERROR:
411 {
412 uint64_t readOnlyMask = (1 << 12) | (1 << 14);
413 newVal = (val & ~readOnlyMask) |
414 (regs[reg] & readOnlyMask);
415 }
416 break;
417 case APIC_INITIAL_COUNT:
418 {
419 assert(clock);
420 newVal = bits(val, 31, 0);
421 uint32_t newCount = newVal *
422 (divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]) * 16);
423 regs[APIC_CURRENT_COUNT] = newCount + curTick / clock;
424 // Find out how long a "tick" of the timer should take.
425 Tick timerTick = 16 * clock;
426 // Schedule on the edge of the next tick plus the new count.
427 Tick offset = curTick % timerTick;
428 if (offset) {
429 reschedule(apicTimerEvent,
430 curTick + (newCount + 1) * timerTick - offset, true);
431 } else {
432 reschedule(apicTimerEvent,
433 curTick + newCount * timerTick, true);
434 }
435 }
436 break;
437 case APIC_CURRENT_COUNT:
438 //Local APIC Current Count register is read only.
439 return;
440 case APIC_DIVIDE_CONFIGURATION:
441 newVal = val & 0xB;
442 break;
443 default:
444 break;
445 }
446 regs[reg] = newVal;
447 return;
448}
449
450bool
451X86ISA::Interrupts::check_interrupts(ThreadContext * tc) const
452{
453 RFLAGS rflags = tc->readMiscRegNoEffect(MISCREG_RFLAGS);
454 if (IRRV > ISRV && rflags.intf &&
455 bits(IRRV, 7, 4) > bits(regs[APIC_TASK_PRIORITY], 7, 4)) {
456 return true;
457 }
458 return false;
459}
460
461Fault
462X86ISA::Interrupts::getInterrupt(ThreadContext * tc)
463{
464 assert(check_interrupts(tc));
465 return new ExternalInterrupt(IRRV);
466}
467
468void
469X86ISA::Interrupts::updateIntrInfo(ThreadContext * tc)
470{
471 assert(check_interrupts(tc));
472 // Mark the interrupt as "in service".
473 ISRV = IRRV;
474 setRegArrayBit(APIC_IN_SERVICE_BASE, ISRV);
475 // Clear it out of the IRR.
476 clearRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, IRRV);
477 updateIRRV();
478}
479
417X86ISA::Interrupts *
418X86LocalApicParams::create()
419{
420 return new X86ISA::Interrupts(this);
421}
480X86ISA::Interrupts *
481X86LocalApicParams::create()
482{
483 return new X86ISA::Interrupts(this);
484}