interrupts.cc (5648:e8abda6e0980) interrupts.cc (5649:0e9c904551c1)
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 "cpu/base.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));
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 "cpu/base.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);
218 pkt->setData(((uint8_t *)&val) + (offset & mask(3)));
219 return latency;
220}
221
222Tick
223X86ISA::Interrupts::write(PacketPtr pkt)
224{
225 Addr offset = pkt->getAddr() - pioAddr;
226 //Make sure we're at least only accessing one register.
227 if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3)))
228 panic("Accessed more than one register at a time in the APIC!\n");
229 ApicRegIndex reg = decodeAddr(offset);
230 uint32_t val = regs[reg];
231 pkt->writeData(((uint8_t *)&val) + (offset & mask(3)));
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));
232 setReg(reg, gtoh(val));
233 return latency;
234}
235
236uint32_t
237X86ISA::Interrupts::readReg(ApicRegIndex reg)
238{
239 if (reg >= APIC_TRIGGER_MODE(0) &&
240 reg <= APIC_TRIGGER_MODE(15)) {
241 panic("Local APIC Trigger Mode registers are unimplemented.\n");
242 }
243 switch (reg) {
244 case APIC_ARBITRATION_PRIORITY:
245 panic("Local APIC Arbitration Priority register unimplemented.\n");
246 break;
247 case APIC_PROCESSOR_PRIORITY:
248 panic("Local APIC Processor Priority register unimplemented.\n");
249 break;
250 case APIC_EOI:
251 panic("Local APIC EOI register unimplemented.\n");
252 break;
253 case APIC_ERROR_STATUS:
254 regs[APIC_INTERNAL_STATE] &= ~ULL(0x1);
255 break;
256 case APIC_INTERRUPT_COMMAND_LOW:
257 panic("Local APIC Interrupt Command low"
258 " register unimplemented.\n");
259 break;
260 case APIC_INTERRUPT_COMMAND_HIGH:
261 panic("Local APIC Interrupt Command high"
262 " register unimplemented.\n");
263 break;
264 case APIC_CURRENT_COUNT:
265 {
266 assert(clock);
267 uint32_t val = regs[reg] - curTick / clock;
268 val /= (16 * divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]));
269 return val;
270 }
271 default:
272 break;
273 }
274 return regs[reg];
275}
276
277void
278X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val)
279{
280 uint32_t newVal = val;
281 if (reg >= APIC_IN_SERVICE(0) &&
282 reg <= APIC_IN_SERVICE(15)) {
283 panic("Local APIC In-Service registers are unimplemented.\n");
284 }
285 if (reg >= APIC_TRIGGER_MODE(0) &&
286 reg <= APIC_TRIGGER_MODE(15)) {
287 panic("Local APIC Trigger Mode registers are unimplemented.\n");
288 }
289 if (reg >= APIC_INTERRUPT_REQUEST(0) &&
290 reg <= APIC_INTERRUPT_REQUEST(15)) {
291 panic("Local APIC Interrupt Request registers "
292 "are unimplemented.\n");
293 }
294 switch (reg) {
295 case APIC_ID:
296 newVal = val & 0xFF;
297 break;
298 case APIC_VERSION:
299 // The Local APIC Version register is read only.
300 return;
301 case APIC_TASK_PRIORITY:
302 newVal = val & 0xFF;
303 break;
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_LOGICAL_DESTINATION:
314 newVal = val & 0xFF000000;
315 break;
316 case APIC_DESTINATION_FORMAT:
317 newVal = val | 0x0FFFFFFF;
318 break;
319 case APIC_SPURIOUS_INTERRUPT_VECTOR:
320 regs[APIC_INTERNAL_STATE] &= ~ULL(1 << 1);
321 regs[APIC_INTERNAL_STATE] |= val & (1 << 8);
322 if (val & (1 << 9))
323 warn("Focus processor checking not implemented.\n");
324 break;
325 case APIC_ERROR_STATUS:
326 {
327 if (regs[APIC_INTERNAL_STATE] & 0x1) {
328 regs[APIC_INTERNAL_STATE] &= ~ULL(0x1);
329 newVal = 0;
330 } else {
331 regs[APIC_INTERNAL_STATE] |= ULL(0x1);
332 return;
333 }
334
335 }
336 break;
337 case APIC_INTERRUPT_COMMAND_LOW:
338 panic("Local APIC Interrupt Command low"
339 " register unimplemented.\n");
340 break;
341 case APIC_INTERRUPT_COMMAND_HIGH:
342 panic("Local APIC Interrupt Command high"
343 " register unimplemented.\n");
344 break;
345 case APIC_LVT_TIMER:
346 case APIC_LVT_THERMAL_SENSOR:
347 case APIC_LVT_PERFORMANCE_MONITORING_COUNTERS:
348 case APIC_LVT_LINT0:
349 case APIC_LVT_LINT1:
350 case APIC_LVT_ERROR:
351 {
352 uint64_t readOnlyMask = (1 << 12) | (1 << 14);
353 newVal = (val & ~readOnlyMask) |
354 (regs[reg] & readOnlyMask);
355 }
356 break;
357 case APIC_INITIAL_COUNT:
358 {
359 assert(clock);
360 newVal = bits(val, 31, 0);
361 uint32_t newCount = newVal *
362 (divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]) * 16);
363 regs[APIC_CURRENT_COUNT] = newCount + curTick / clock;
364 // Find out how long a "tick" of the timer should take.
365 Tick timerTick = 16 * clock;
366 // Schedule on the edge of the next tick plus the new count.
367 Tick offset = curTick % timerTick;
368 if (offset) {
369 reschedule(apicTimerEvent,
370 curTick + (newCount + 1) * timerTick - offset, true);
371 } else {
372 reschedule(apicTimerEvent,
373 curTick + newCount * timerTick, true);
374 }
375 }
376 break;
377 case APIC_CURRENT_COUNT:
378 //Local APIC Current Count register is read only.
379 return;
380 case APIC_DIVIDE_CONFIGURATION:
381 newVal = val & 0xB;
382 break;
383 default:
384 break;
385 }
386 regs[reg] = newVal;
387 return;
388}
389
390X86ISA::Interrupts *
391X86LocalApicParams::create()
392{
393 return new X86ISA::Interrupts(this);
394}
238 setReg(reg, gtoh(val));
239 return latency;
240}
241
242uint32_t
243X86ISA::Interrupts::readReg(ApicRegIndex reg)
244{
245 if (reg >= APIC_TRIGGER_MODE(0) &&
246 reg <= APIC_TRIGGER_MODE(15)) {
247 panic("Local APIC Trigger Mode registers are unimplemented.\n");
248 }
249 switch (reg) {
250 case APIC_ARBITRATION_PRIORITY:
251 panic("Local APIC Arbitration Priority register unimplemented.\n");
252 break;
253 case APIC_PROCESSOR_PRIORITY:
254 panic("Local APIC Processor Priority register unimplemented.\n");
255 break;
256 case APIC_EOI:
257 panic("Local APIC EOI register unimplemented.\n");
258 break;
259 case APIC_ERROR_STATUS:
260 regs[APIC_INTERNAL_STATE] &= ~ULL(0x1);
261 break;
262 case APIC_INTERRUPT_COMMAND_LOW:
263 panic("Local APIC Interrupt Command low"
264 " register unimplemented.\n");
265 break;
266 case APIC_INTERRUPT_COMMAND_HIGH:
267 panic("Local APIC Interrupt Command high"
268 " register unimplemented.\n");
269 break;
270 case APIC_CURRENT_COUNT:
271 {
272 assert(clock);
273 uint32_t val = regs[reg] - curTick / clock;
274 val /= (16 * divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]));
275 return val;
276 }
277 default:
278 break;
279 }
280 return regs[reg];
281}
282
283void
284X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val)
285{
286 uint32_t newVal = val;
287 if (reg >= APIC_IN_SERVICE(0) &&
288 reg <= APIC_IN_SERVICE(15)) {
289 panic("Local APIC In-Service registers are unimplemented.\n");
290 }
291 if (reg >= APIC_TRIGGER_MODE(0) &&
292 reg <= APIC_TRIGGER_MODE(15)) {
293 panic("Local APIC Trigger Mode registers are unimplemented.\n");
294 }
295 if (reg >= APIC_INTERRUPT_REQUEST(0) &&
296 reg <= APIC_INTERRUPT_REQUEST(15)) {
297 panic("Local APIC Interrupt Request registers "
298 "are unimplemented.\n");
299 }
300 switch (reg) {
301 case APIC_ID:
302 newVal = val & 0xFF;
303 break;
304 case APIC_VERSION:
305 // The Local APIC Version register is read only.
306 return;
307 case APIC_TASK_PRIORITY:
308 newVal = val & 0xFF;
309 break;
310 case APIC_ARBITRATION_PRIORITY:
311 panic("Local APIC Arbitration Priority register unimplemented.\n");
312 break;
313 case APIC_PROCESSOR_PRIORITY:
314 panic("Local APIC Processor Priority register unimplemented.\n");
315 break;
316 case APIC_EOI:
317 panic("Local APIC EOI register unimplemented.\n");
318 break;
319 case APIC_LOGICAL_DESTINATION:
320 newVal = val & 0xFF000000;
321 break;
322 case APIC_DESTINATION_FORMAT:
323 newVal = val | 0x0FFFFFFF;
324 break;
325 case APIC_SPURIOUS_INTERRUPT_VECTOR:
326 regs[APIC_INTERNAL_STATE] &= ~ULL(1 << 1);
327 regs[APIC_INTERNAL_STATE] |= val & (1 << 8);
328 if (val & (1 << 9))
329 warn("Focus processor checking not implemented.\n");
330 break;
331 case APIC_ERROR_STATUS:
332 {
333 if (regs[APIC_INTERNAL_STATE] & 0x1) {
334 regs[APIC_INTERNAL_STATE] &= ~ULL(0x1);
335 newVal = 0;
336 } else {
337 regs[APIC_INTERNAL_STATE] |= ULL(0x1);
338 return;
339 }
340
341 }
342 break;
343 case APIC_INTERRUPT_COMMAND_LOW:
344 panic("Local APIC Interrupt Command low"
345 " register unimplemented.\n");
346 break;
347 case APIC_INTERRUPT_COMMAND_HIGH:
348 panic("Local APIC Interrupt Command high"
349 " register unimplemented.\n");
350 break;
351 case APIC_LVT_TIMER:
352 case APIC_LVT_THERMAL_SENSOR:
353 case APIC_LVT_PERFORMANCE_MONITORING_COUNTERS:
354 case APIC_LVT_LINT0:
355 case APIC_LVT_LINT1:
356 case APIC_LVT_ERROR:
357 {
358 uint64_t readOnlyMask = (1 << 12) | (1 << 14);
359 newVal = (val & ~readOnlyMask) |
360 (regs[reg] & readOnlyMask);
361 }
362 break;
363 case APIC_INITIAL_COUNT:
364 {
365 assert(clock);
366 newVal = bits(val, 31, 0);
367 uint32_t newCount = newVal *
368 (divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]) * 16);
369 regs[APIC_CURRENT_COUNT] = newCount + curTick / clock;
370 // Find out how long a "tick" of the timer should take.
371 Tick timerTick = 16 * clock;
372 // Schedule on the edge of the next tick plus the new count.
373 Tick offset = curTick % timerTick;
374 if (offset) {
375 reschedule(apicTimerEvent,
376 curTick + (newCount + 1) * timerTick - offset, true);
377 } else {
378 reschedule(apicTimerEvent,
379 curTick + newCount * timerTick, true);
380 }
381 }
382 break;
383 case APIC_CURRENT_COUNT:
384 //Local APIC Current Count register is read only.
385 return;
386 case APIC_DIVIDE_CONFIGURATION:
387 newVal = val & 0xB;
388 break;
389 default:
390 break;
391 }
392 regs[reg] = newVal;
393 return;
394}
395
396X86ISA::Interrupts *
397X86LocalApicParams::create()
398{
399 return new X86ISA::Interrupts(this);
400}