|
1 /* |
|
2 * APIC support |
|
3 * |
|
4 * Copyright (c) 2004-2005 Fabrice Bellard |
|
5 * |
|
6 * This library is free software; you can redistribute it and/or |
|
7 * modify it under the terms of the GNU Lesser General Public |
|
8 * License as published by the Free Software Foundation; either |
|
9 * version 2 of the License, or (at your option) any later version. |
|
10 * |
|
11 * This library is distributed in the hope that it will be useful, |
|
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
14 * Lesser General Public License for more details. |
|
15 * |
|
16 * You should have received a copy of the GNU Lesser General Public |
|
17 * License along with this library; if not, write to the Free Software |
|
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
19 */ |
|
20 #include "hw.h" |
|
21 #include "pc.h" |
|
22 #include "qemu-timer.h" |
|
23 #include "host-utils.h" |
|
24 |
|
25 //#define DEBUG_APIC |
|
26 //#define DEBUG_IOAPIC |
|
27 |
|
28 /* APIC Local Vector Table */ |
|
29 #define APIC_LVT_TIMER 0 |
|
30 #define APIC_LVT_THERMAL 1 |
|
31 #define APIC_LVT_PERFORM 2 |
|
32 #define APIC_LVT_LINT0 3 |
|
33 #define APIC_LVT_LINT1 4 |
|
34 #define APIC_LVT_ERROR 5 |
|
35 #define APIC_LVT_NB 6 |
|
36 |
|
37 /* APIC delivery modes */ |
|
38 #define APIC_DM_FIXED 0 |
|
39 #define APIC_DM_LOWPRI 1 |
|
40 #define APIC_DM_SMI 2 |
|
41 #define APIC_DM_NMI 4 |
|
42 #define APIC_DM_INIT 5 |
|
43 #define APIC_DM_SIPI 6 |
|
44 #define APIC_DM_EXTINT 7 |
|
45 |
|
46 /* APIC destination mode */ |
|
47 #define APIC_DESTMODE_FLAT 0xf |
|
48 #define APIC_DESTMODE_CLUSTER 1 |
|
49 |
|
50 #define APIC_TRIGGER_EDGE 0 |
|
51 #define APIC_TRIGGER_LEVEL 1 |
|
52 |
|
53 #define APIC_LVT_TIMER_PERIODIC (1<<17) |
|
54 #define APIC_LVT_MASKED (1<<16) |
|
55 #define APIC_LVT_LEVEL_TRIGGER (1<<15) |
|
56 #define APIC_LVT_REMOTE_IRR (1<<14) |
|
57 #define APIC_INPUT_POLARITY (1<<13) |
|
58 #define APIC_SEND_PENDING (1<<12) |
|
59 |
|
60 #define IOAPIC_NUM_PINS 0x18 |
|
61 |
|
62 #define ESR_ILLEGAL_ADDRESS (1 << 7) |
|
63 |
|
64 #define APIC_SV_ENABLE (1 << 8) |
|
65 |
|
66 #define MAX_APICS 255 |
|
67 #define MAX_APIC_WORDS 8 |
|
68 |
|
69 typedef struct APICState { |
|
70 CPUState *cpu_env; |
|
71 uint32_t apicbase; |
|
72 uint8_t id; |
|
73 uint8_t arb_id; |
|
74 uint8_t tpr; |
|
75 uint32_t spurious_vec; |
|
76 uint8_t log_dest; |
|
77 uint8_t dest_mode; |
|
78 uint32_t isr[8]; /* in service register */ |
|
79 uint32_t tmr[8]; /* trigger mode register */ |
|
80 uint32_t irr[8]; /* interrupt request register */ |
|
81 uint32_t lvt[APIC_LVT_NB]; |
|
82 uint32_t esr; /* error register */ |
|
83 uint32_t icr[2]; |
|
84 |
|
85 uint32_t divide_conf; |
|
86 int count_shift; |
|
87 uint32_t initial_count; |
|
88 int64_t initial_count_load_time, next_time; |
|
89 QEMUTimer *timer; |
|
90 } APICState; |
|
91 |
|
92 struct IOAPICState { |
|
93 uint8_t id; |
|
94 uint8_t ioregsel; |
|
95 |
|
96 uint32_t irr; |
|
97 uint64_t ioredtbl[IOAPIC_NUM_PINS]; |
|
98 }; |
|
99 |
|
100 static int apic_io_memory; |
|
101 static APICState *local_apics[MAX_APICS + 1]; |
|
102 static int last_apic_id = 0; |
|
103 |
|
104 static void apic_init_ipi(APICState *s); |
|
105 static void apic_set_irq(APICState *s, int vector_num, int trigger_mode); |
|
106 static void apic_update_irq(APICState *s); |
|
107 |
|
108 /* Find first bit starting from msb */ |
|
109 static int fls_bit(uint32_t value) |
|
110 { |
|
111 return 31 - clz32(value); |
|
112 } |
|
113 |
|
114 /* Find first bit starting from lsb */ |
|
115 static int ffs_bit(uint32_t value) |
|
116 { |
|
117 return ctz32(value); |
|
118 } |
|
119 |
|
120 static inline void set_bit(uint32_t *tab, int index) |
|
121 { |
|
122 int i, mask; |
|
123 i = index >> 5; |
|
124 mask = 1 << (index & 0x1f); |
|
125 tab[i] |= mask; |
|
126 } |
|
127 |
|
128 static inline void reset_bit(uint32_t *tab, int index) |
|
129 { |
|
130 int i, mask; |
|
131 i = index >> 5; |
|
132 mask = 1 << (index & 0x1f); |
|
133 tab[i] &= ~mask; |
|
134 } |
|
135 |
|
136 static void apic_local_deliver(CPUState *env, int vector) |
|
137 { |
|
138 APICState *s = env->apic_state; |
|
139 uint32_t lvt = s->lvt[vector]; |
|
140 int trigger_mode; |
|
141 |
|
142 if (lvt & APIC_LVT_MASKED) |
|
143 return; |
|
144 |
|
145 switch ((lvt >> 8) & 7) { |
|
146 case APIC_DM_SMI: |
|
147 cpu_interrupt(env, CPU_INTERRUPT_SMI); |
|
148 break; |
|
149 |
|
150 case APIC_DM_NMI: |
|
151 cpu_interrupt(env, CPU_INTERRUPT_NMI); |
|
152 break; |
|
153 |
|
154 case APIC_DM_EXTINT: |
|
155 cpu_interrupt(env, CPU_INTERRUPT_HARD); |
|
156 break; |
|
157 |
|
158 case APIC_DM_FIXED: |
|
159 trigger_mode = APIC_TRIGGER_EDGE; |
|
160 if ((vector == APIC_LVT_LINT0 || vector == APIC_LVT_LINT1) && |
|
161 (lvt & APIC_LVT_LEVEL_TRIGGER)) |
|
162 trigger_mode = APIC_TRIGGER_LEVEL; |
|
163 apic_set_irq(s, lvt & 0xff, trigger_mode); |
|
164 } |
|
165 } |
|
166 |
|
167 void apic_deliver_pic_intr(CPUState *env, int level) |
|
168 { |
|
169 if (level) |
|
170 apic_local_deliver(env, APIC_LVT_LINT0); |
|
171 else { |
|
172 APICState *s = env->apic_state; |
|
173 uint32_t lvt = s->lvt[APIC_LVT_LINT0]; |
|
174 |
|
175 switch ((lvt >> 8) & 7) { |
|
176 case APIC_DM_FIXED: |
|
177 if (!(lvt & APIC_LVT_LEVEL_TRIGGER)) |
|
178 break; |
|
179 reset_bit(s->irr, lvt & 0xff); |
|
180 /* fall through */ |
|
181 case APIC_DM_EXTINT: |
|
182 cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); |
|
183 break; |
|
184 } |
|
185 } |
|
186 } |
|
187 |
|
188 #define foreach_apic(apic, deliver_bitmask, code) \ |
|
189 {\ |
|
190 int __i, __j, __mask;\ |
|
191 for(__i = 0; __i < MAX_APIC_WORDS; __i++) {\ |
|
192 __mask = deliver_bitmask[__i];\ |
|
193 if (__mask) {\ |
|
194 for(__j = 0; __j < 32; __j++) {\ |
|
195 if (__mask & (1 << __j)) {\ |
|
196 apic = local_apics[__i * 32 + __j];\ |
|
197 if (apic) {\ |
|
198 code;\ |
|
199 }\ |
|
200 }\ |
|
201 }\ |
|
202 }\ |
|
203 }\ |
|
204 } |
|
205 |
|
206 static void apic_bus_deliver(const uint32_t *deliver_bitmask, |
|
207 uint8_t delivery_mode, |
|
208 uint8_t vector_num, uint8_t polarity, |
|
209 uint8_t trigger_mode) |
|
210 { |
|
211 APICState *apic_iter; |
|
212 |
|
213 switch (delivery_mode) { |
|
214 case APIC_DM_LOWPRI: |
|
215 /* XXX: search for focus processor, arbitration */ |
|
216 { |
|
217 int i, d; |
|
218 d = -1; |
|
219 for(i = 0; i < MAX_APIC_WORDS; i++) { |
|
220 if (deliver_bitmask[i]) { |
|
221 d = i * 32 + ffs_bit(deliver_bitmask[i]); |
|
222 break; |
|
223 } |
|
224 } |
|
225 if (d >= 0) { |
|
226 apic_iter = local_apics[d]; |
|
227 if (apic_iter) { |
|
228 apic_set_irq(apic_iter, vector_num, trigger_mode); |
|
229 } |
|
230 } |
|
231 } |
|
232 return; |
|
233 |
|
234 case APIC_DM_FIXED: |
|
235 break; |
|
236 |
|
237 case APIC_DM_SMI: |
|
238 foreach_apic(apic_iter, deliver_bitmask, |
|
239 cpu_interrupt(apic_iter->cpu_env, CPU_INTERRUPT_SMI) ); |
|
240 return; |
|
241 |
|
242 case APIC_DM_NMI: |
|
243 foreach_apic(apic_iter, deliver_bitmask, |
|
244 cpu_interrupt(apic_iter->cpu_env, CPU_INTERRUPT_NMI) ); |
|
245 return; |
|
246 |
|
247 case APIC_DM_INIT: |
|
248 /* normal INIT IPI sent to processors */ |
|
249 foreach_apic(apic_iter, deliver_bitmask, |
|
250 apic_init_ipi(apic_iter) ); |
|
251 return; |
|
252 |
|
253 case APIC_DM_EXTINT: |
|
254 /* handled in I/O APIC code */ |
|
255 break; |
|
256 |
|
257 default: |
|
258 return; |
|
259 } |
|
260 |
|
261 foreach_apic(apic_iter, deliver_bitmask, |
|
262 apic_set_irq(apic_iter, vector_num, trigger_mode) ); |
|
263 } |
|
264 |
|
265 void cpu_set_apic_base(CPUState *env, uint64_t val) |
|
266 { |
|
267 APICState *s = env->apic_state; |
|
268 #ifdef DEBUG_APIC |
|
269 printf("cpu_set_apic_base: %016" PRIx64 "\n", val); |
|
270 #endif |
|
271 s->apicbase = (val & 0xfffff000) | |
|
272 (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE)); |
|
273 /* if disabled, cannot be enabled again */ |
|
274 if (!(val & MSR_IA32_APICBASE_ENABLE)) { |
|
275 s->apicbase &= ~MSR_IA32_APICBASE_ENABLE; |
|
276 env->cpuid_features &= ~CPUID_APIC; |
|
277 s->spurious_vec &= ~APIC_SV_ENABLE; |
|
278 } |
|
279 } |
|
280 |
|
281 uint64_t cpu_get_apic_base(CPUState *env) |
|
282 { |
|
283 APICState *s = env->apic_state; |
|
284 #ifdef DEBUG_APIC |
|
285 printf("cpu_get_apic_base: %016" PRIx64 "\n", (uint64_t)s->apicbase); |
|
286 #endif |
|
287 return s->apicbase; |
|
288 } |
|
289 |
|
290 void cpu_set_apic_tpr(CPUX86State *env, uint8_t val) |
|
291 { |
|
292 APICState *s = env->apic_state; |
|
293 s->tpr = (val & 0x0f) << 4; |
|
294 apic_update_irq(s); |
|
295 } |
|
296 |
|
297 uint8_t cpu_get_apic_tpr(CPUX86State *env) |
|
298 { |
|
299 APICState *s = env->apic_state; |
|
300 return s->tpr >> 4; |
|
301 } |
|
302 |
|
303 /* return -1 if no bit is set */ |
|
304 static int get_highest_priority_int(uint32_t *tab) |
|
305 { |
|
306 int i; |
|
307 for(i = 7; i >= 0; i--) { |
|
308 if (tab[i] != 0) { |
|
309 return i * 32 + fls_bit(tab[i]); |
|
310 } |
|
311 } |
|
312 return -1; |
|
313 } |
|
314 |
|
315 static int apic_get_ppr(APICState *s) |
|
316 { |
|
317 int tpr, isrv, ppr; |
|
318 |
|
319 tpr = (s->tpr >> 4); |
|
320 isrv = get_highest_priority_int(s->isr); |
|
321 if (isrv < 0) |
|
322 isrv = 0; |
|
323 isrv >>= 4; |
|
324 if (tpr >= isrv) |
|
325 ppr = s->tpr; |
|
326 else |
|
327 ppr = isrv << 4; |
|
328 return ppr; |
|
329 } |
|
330 |
|
331 static int apic_get_arb_pri(APICState *s) |
|
332 { |
|
333 /* XXX: arbitration */ |
|
334 return 0; |
|
335 } |
|
336 |
|
337 /* signal the CPU if an irq is pending */ |
|
338 static void apic_update_irq(APICState *s) |
|
339 { |
|
340 int irrv, ppr; |
|
341 if (!(s->spurious_vec & APIC_SV_ENABLE)) |
|
342 return; |
|
343 irrv = get_highest_priority_int(s->irr); |
|
344 if (irrv < 0) |
|
345 return; |
|
346 ppr = apic_get_ppr(s); |
|
347 if (ppr && (irrv & 0xf0) <= (ppr & 0xf0)) |
|
348 return; |
|
349 cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD); |
|
350 } |
|
351 |
|
352 static void apic_set_irq(APICState *s, int vector_num, int trigger_mode) |
|
353 { |
|
354 set_bit(s->irr, vector_num); |
|
355 if (trigger_mode) |
|
356 set_bit(s->tmr, vector_num); |
|
357 else |
|
358 reset_bit(s->tmr, vector_num); |
|
359 apic_update_irq(s); |
|
360 } |
|
361 |
|
362 static void apic_eoi(APICState *s) |
|
363 { |
|
364 int isrv; |
|
365 isrv = get_highest_priority_int(s->isr); |
|
366 if (isrv < 0) |
|
367 return; |
|
368 reset_bit(s->isr, isrv); |
|
369 /* XXX: send the EOI packet to the APIC bus to allow the I/O APIC to |
|
370 set the remote IRR bit for level triggered interrupts. */ |
|
371 apic_update_irq(s); |
|
372 } |
|
373 |
|
374 static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask, |
|
375 uint8_t dest, uint8_t dest_mode) |
|
376 { |
|
377 APICState *apic_iter; |
|
378 int i; |
|
379 |
|
380 if (dest_mode == 0) { |
|
381 if (dest == 0xff) { |
|
382 memset(deliver_bitmask, 0xff, MAX_APIC_WORDS * sizeof(uint32_t)); |
|
383 } else { |
|
384 memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t)); |
|
385 set_bit(deliver_bitmask, dest); |
|
386 } |
|
387 } else { |
|
388 /* XXX: cluster mode */ |
|
389 memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t)); |
|
390 for(i = 0; i < MAX_APICS; i++) { |
|
391 apic_iter = local_apics[i]; |
|
392 if (apic_iter) { |
|
393 if (apic_iter->dest_mode == 0xf) { |
|
394 if (dest & apic_iter->log_dest) |
|
395 set_bit(deliver_bitmask, i); |
|
396 } else if (apic_iter->dest_mode == 0x0) { |
|
397 if ((dest & 0xf0) == (apic_iter->log_dest & 0xf0) && |
|
398 (dest & apic_iter->log_dest & 0x0f)) { |
|
399 set_bit(deliver_bitmask, i); |
|
400 } |
|
401 } |
|
402 } |
|
403 } |
|
404 } |
|
405 } |
|
406 |
|
407 |
|
408 static void apic_init_ipi(APICState *s) |
|
409 { |
|
410 int i; |
|
411 |
|
412 s->tpr = 0; |
|
413 s->spurious_vec = 0xff; |
|
414 s->log_dest = 0; |
|
415 s->dest_mode = 0xf; |
|
416 memset(s->isr, 0, sizeof(s->isr)); |
|
417 memset(s->tmr, 0, sizeof(s->tmr)); |
|
418 memset(s->irr, 0, sizeof(s->irr)); |
|
419 for(i = 0; i < APIC_LVT_NB; i++) |
|
420 s->lvt[i] = 1 << 16; /* mask LVT */ |
|
421 s->esr = 0; |
|
422 memset(s->icr, 0, sizeof(s->icr)); |
|
423 s->divide_conf = 0; |
|
424 s->count_shift = 0; |
|
425 s->initial_count = 0; |
|
426 s->initial_count_load_time = 0; |
|
427 s->next_time = 0; |
|
428 |
|
429 cpu_reset(s->cpu_env); |
|
430 |
|
431 if (!(s->apicbase & MSR_IA32_APICBASE_BSP)) |
|
432 s->cpu_env->halted = 1; |
|
433 } |
|
434 |
|
435 /* send a SIPI message to the CPU to start it */ |
|
436 static void apic_startup(APICState *s, int vector_num) |
|
437 { |
|
438 CPUState *env = s->cpu_env; |
|
439 if (!env->halted) |
|
440 return; |
|
441 env->eip = 0; |
|
442 cpu_x86_load_seg_cache(env, R_CS, vector_num << 8, vector_num << 12, |
|
443 0xffff, 0); |
|
444 env->halted = 0; |
|
445 } |
|
446 |
|
447 static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode, |
|
448 uint8_t delivery_mode, uint8_t vector_num, |
|
449 uint8_t polarity, uint8_t trigger_mode) |
|
450 { |
|
451 uint32_t deliver_bitmask[MAX_APIC_WORDS]; |
|
452 int dest_shorthand = (s->icr[0] >> 18) & 3; |
|
453 APICState *apic_iter; |
|
454 |
|
455 switch (dest_shorthand) { |
|
456 case 0: |
|
457 apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode); |
|
458 break; |
|
459 case 1: |
|
460 memset(deliver_bitmask, 0x00, sizeof(deliver_bitmask)); |
|
461 set_bit(deliver_bitmask, s->id); |
|
462 break; |
|
463 case 2: |
|
464 memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask)); |
|
465 break; |
|
466 case 3: |
|
467 memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask)); |
|
468 reset_bit(deliver_bitmask, s->id); |
|
469 break; |
|
470 } |
|
471 |
|
472 switch (delivery_mode) { |
|
473 case APIC_DM_INIT: |
|
474 { |
|
475 int trig_mode = (s->icr[0] >> 15) & 1; |
|
476 int level = (s->icr[0] >> 14) & 1; |
|
477 if (level == 0 && trig_mode == 1) { |
|
478 foreach_apic(apic_iter, deliver_bitmask, |
|
479 apic_iter->arb_id = apic_iter->id ); |
|
480 return; |
|
481 } |
|
482 } |
|
483 break; |
|
484 |
|
485 case APIC_DM_SIPI: |
|
486 foreach_apic(apic_iter, deliver_bitmask, |
|
487 apic_startup(apic_iter, vector_num) ); |
|
488 return; |
|
489 } |
|
490 |
|
491 apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, polarity, |
|
492 trigger_mode); |
|
493 } |
|
494 |
|
495 int apic_get_interrupt(CPUState *env) |
|
496 { |
|
497 APICState *s = env->apic_state; |
|
498 int intno; |
|
499 |
|
500 /* if the APIC is installed or enabled, we let the 8259 handle the |
|
501 IRQs */ |
|
502 if (!s) |
|
503 return -1; |
|
504 if (!(s->spurious_vec & APIC_SV_ENABLE)) |
|
505 return -1; |
|
506 |
|
507 /* XXX: spurious IRQ handling */ |
|
508 intno = get_highest_priority_int(s->irr); |
|
509 if (intno < 0) |
|
510 return -1; |
|
511 if (s->tpr && intno <= s->tpr) |
|
512 return s->spurious_vec & 0xff; |
|
513 reset_bit(s->irr, intno); |
|
514 set_bit(s->isr, intno); |
|
515 apic_update_irq(s); |
|
516 return intno; |
|
517 } |
|
518 |
|
519 int apic_accept_pic_intr(CPUState *env) |
|
520 { |
|
521 APICState *s = env->apic_state; |
|
522 uint32_t lvt0; |
|
523 |
|
524 if (!s) |
|
525 return -1; |
|
526 |
|
527 lvt0 = s->lvt[APIC_LVT_LINT0]; |
|
528 |
|
529 if ((s->apicbase & MSR_IA32_APICBASE_ENABLE) == 0 || |
|
530 (lvt0 & APIC_LVT_MASKED) == 0) |
|
531 return 1; |
|
532 |
|
533 return 0; |
|
534 } |
|
535 |
|
536 static uint32_t apic_get_current_count(APICState *s) |
|
537 { |
|
538 int64_t d; |
|
539 uint32_t val; |
|
540 d = (qemu_get_clock(vm_clock) - s->initial_count_load_time) >> |
|
541 s->count_shift; |
|
542 if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) { |
|
543 /* periodic */ |
|
544 val = s->initial_count - (d % ((uint64_t)s->initial_count + 1)); |
|
545 } else { |
|
546 if (d >= s->initial_count) |
|
547 val = 0; |
|
548 else |
|
549 val = s->initial_count - d; |
|
550 } |
|
551 return val; |
|
552 } |
|
553 |
|
554 static void apic_timer_update(APICState *s, int64_t current_time) |
|
555 { |
|
556 int64_t next_time, d; |
|
557 |
|
558 if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) { |
|
559 d = (current_time - s->initial_count_load_time) >> |
|
560 s->count_shift; |
|
561 if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) { |
|
562 if (!s->initial_count) |
|
563 goto no_timer; |
|
564 d = ((d / ((uint64_t)s->initial_count + 1)) + 1) * ((uint64_t)s->initial_count + 1); |
|
565 } else { |
|
566 if (d >= s->initial_count) |
|
567 goto no_timer; |
|
568 d = (uint64_t)s->initial_count + 1; |
|
569 } |
|
570 next_time = s->initial_count_load_time + (d << s->count_shift); |
|
571 qemu_mod_timer(s->timer, next_time); |
|
572 s->next_time = next_time; |
|
573 } else { |
|
574 no_timer: |
|
575 qemu_del_timer(s->timer); |
|
576 } |
|
577 } |
|
578 |
|
579 static void apic_timer(void *opaque) |
|
580 { |
|
581 APICState *s = opaque; |
|
582 |
|
583 apic_local_deliver(s->cpu_env, APIC_LVT_TIMER); |
|
584 apic_timer_update(s, s->next_time); |
|
585 } |
|
586 |
|
587 static uint32_t apic_mem_readb(void *opaque, target_phys_addr_t addr) |
|
588 { |
|
589 return 0; |
|
590 } |
|
591 |
|
592 static uint32_t apic_mem_readw(void *opaque, target_phys_addr_t addr) |
|
593 { |
|
594 return 0; |
|
595 } |
|
596 |
|
597 static void apic_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) |
|
598 { |
|
599 } |
|
600 |
|
601 static void apic_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) |
|
602 { |
|
603 } |
|
604 |
|
605 static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr) |
|
606 { |
|
607 CPUState *env; |
|
608 APICState *s; |
|
609 uint32_t val; |
|
610 int index; |
|
611 |
|
612 env = cpu_single_env; |
|
613 if (!env) |
|
614 return 0; |
|
615 s = env->apic_state; |
|
616 |
|
617 index = (addr >> 4) & 0xff; |
|
618 switch(index) { |
|
619 case 0x02: /* id */ |
|
620 val = s->id << 24; |
|
621 break; |
|
622 case 0x03: /* version */ |
|
623 val = 0x11 | ((APIC_LVT_NB - 1) << 16); /* version 0x11 */ |
|
624 break; |
|
625 case 0x08: |
|
626 val = s->tpr; |
|
627 break; |
|
628 case 0x09: |
|
629 val = apic_get_arb_pri(s); |
|
630 break; |
|
631 case 0x0a: |
|
632 /* ppr */ |
|
633 val = apic_get_ppr(s); |
|
634 break; |
|
635 case 0x0b: |
|
636 val = 0; |
|
637 break; |
|
638 case 0x0d: |
|
639 val = s->log_dest << 24; |
|
640 break; |
|
641 case 0x0e: |
|
642 val = s->dest_mode << 28; |
|
643 break; |
|
644 case 0x0f: |
|
645 val = s->spurious_vec; |
|
646 break; |
|
647 case 0x10 ... 0x17: |
|
648 val = s->isr[index & 7]; |
|
649 break; |
|
650 case 0x18 ... 0x1f: |
|
651 val = s->tmr[index & 7]; |
|
652 break; |
|
653 case 0x20 ... 0x27: |
|
654 val = s->irr[index & 7]; |
|
655 break; |
|
656 case 0x28: |
|
657 val = s->esr; |
|
658 break; |
|
659 case 0x30: |
|
660 case 0x31: |
|
661 val = s->icr[index & 1]; |
|
662 break; |
|
663 case 0x32 ... 0x37: |
|
664 val = s->lvt[index - 0x32]; |
|
665 break; |
|
666 case 0x38: |
|
667 val = s->initial_count; |
|
668 break; |
|
669 case 0x39: |
|
670 val = apic_get_current_count(s); |
|
671 break; |
|
672 case 0x3e: |
|
673 val = s->divide_conf; |
|
674 break; |
|
675 default: |
|
676 s->esr |= ESR_ILLEGAL_ADDRESS; |
|
677 val = 0; |
|
678 break; |
|
679 } |
|
680 #ifdef DEBUG_APIC |
|
681 printf("APIC read: %08x = %08x\n", (uint32_t)addr, val); |
|
682 #endif |
|
683 return val; |
|
684 } |
|
685 |
|
686 static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) |
|
687 { |
|
688 CPUState *env; |
|
689 APICState *s; |
|
690 int index; |
|
691 |
|
692 env = cpu_single_env; |
|
693 if (!env) |
|
694 return; |
|
695 s = env->apic_state; |
|
696 |
|
697 #ifdef DEBUG_APIC |
|
698 printf("APIC write: %08x = %08x\n", (uint32_t)addr, val); |
|
699 #endif |
|
700 |
|
701 index = (addr >> 4) & 0xff; |
|
702 switch(index) { |
|
703 case 0x02: |
|
704 s->id = (val >> 24); |
|
705 break; |
|
706 case 0x03: |
|
707 break; |
|
708 case 0x08: |
|
709 s->tpr = val; |
|
710 apic_update_irq(s); |
|
711 break; |
|
712 case 0x09: |
|
713 case 0x0a: |
|
714 break; |
|
715 case 0x0b: /* EOI */ |
|
716 apic_eoi(s); |
|
717 break; |
|
718 case 0x0d: |
|
719 s->log_dest = val >> 24; |
|
720 break; |
|
721 case 0x0e: |
|
722 s->dest_mode = val >> 28; |
|
723 break; |
|
724 case 0x0f: |
|
725 s->spurious_vec = val & 0x1ff; |
|
726 apic_update_irq(s); |
|
727 break; |
|
728 case 0x10 ... 0x17: |
|
729 case 0x18 ... 0x1f: |
|
730 case 0x20 ... 0x27: |
|
731 case 0x28: |
|
732 break; |
|
733 case 0x30: |
|
734 s->icr[0] = val; |
|
735 apic_deliver(s, (s->icr[1] >> 24) & 0xff, (s->icr[0] >> 11) & 1, |
|
736 (s->icr[0] >> 8) & 7, (s->icr[0] & 0xff), |
|
737 (s->icr[0] >> 14) & 1, (s->icr[0] >> 15) & 1); |
|
738 break; |
|
739 case 0x31: |
|
740 s->icr[1] = val; |
|
741 break; |
|
742 case 0x32 ... 0x37: |
|
743 { |
|
744 int n = index - 0x32; |
|
745 s->lvt[n] = val; |
|
746 if (n == APIC_LVT_TIMER) |
|
747 apic_timer_update(s, qemu_get_clock(vm_clock)); |
|
748 } |
|
749 break; |
|
750 case 0x38: |
|
751 s->initial_count = val; |
|
752 s->initial_count_load_time = qemu_get_clock(vm_clock); |
|
753 apic_timer_update(s, s->initial_count_load_time); |
|
754 break; |
|
755 case 0x39: |
|
756 break; |
|
757 case 0x3e: |
|
758 { |
|
759 int v; |
|
760 s->divide_conf = val & 0xb; |
|
761 v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4); |
|
762 s->count_shift = (v + 1) & 7; |
|
763 } |
|
764 break; |
|
765 default: |
|
766 s->esr |= ESR_ILLEGAL_ADDRESS; |
|
767 break; |
|
768 } |
|
769 } |
|
770 |
|
771 static void apic_save(QEMUFile *f, void *opaque) |
|
772 { |
|
773 APICState *s = opaque; |
|
774 int i; |
|
775 |
|
776 qemu_put_be32s(f, &s->apicbase); |
|
777 qemu_put_8s(f, &s->id); |
|
778 qemu_put_8s(f, &s->arb_id); |
|
779 qemu_put_8s(f, &s->tpr); |
|
780 qemu_put_be32s(f, &s->spurious_vec); |
|
781 qemu_put_8s(f, &s->log_dest); |
|
782 qemu_put_8s(f, &s->dest_mode); |
|
783 for (i = 0; i < 8; i++) { |
|
784 qemu_put_be32s(f, &s->isr[i]); |
|
785 qemu_put_be32s(f, &s->tmr[i]); |
|
786 qemu_put_be32s(f, &s->irr[i]); |
|
787 } |
|
788 for (i = 0; i < APIC_LVT_NB; i++) { |
|
789 qemu_put_be32s(f, &s->lvt[i]); |
|
790 } |
|
791 qemu_put_be32s(f, &s->esr); |
|
792 qemu_put_be32s(f, &s->icr[0]); |
|
793 qemu_put_be32s(f, &s->icr[1]); |
|
794 qemu_put_be32s(f, &s->divide_conf); |
|
795 qemu_put_be32(f, s->count_shift); |
|
796 qemu_put_be32s(f, &s->initial_count); |
|
797 qemu_put_be64(f, s->initial_count_load_time); |
|
798 qemu_put_be64(f, s->next_time); |
|
799 |
|
800 qemu_put_timer(f, s->timer); |
|
801 } |
|
802 |
|
803 static int apic_load(QEMUFile *f, void *opaque, int version_id) |
|
804 { |
|
805 APICState *s = opaque; |
|
806 int i; |
|
807 |
|
808 if (version_id > 2) |
|
809 return -EINVAL; |
|
810 |
|
811 /* XXX: what if the base changes? (registered memory regions) */ |
|
812 qemu_get_be32s(f, &s->apicbase); |
|
813 qemu_get_8s(f, &s->id); |
|
814 qemu_get_8s(f, &s->arb_id); |
|
815 qemu_get_8s(f, &s->tpr); |
|
816 qemu_get_be32s(f, &s->spurious_vec); |
|
817 qemu_get_8s(f, &s->log_dest); |
|
818 qemu_get_8s(f, &s->dest_mode); |
|
819 for (i = 0; i < 8; i++) { |
|
820 qemu_get_be32s(f, &s->isr[i]); |
|
821 qemu_get_be32s(f, &s->tmr[i]); |
|
822 qemu_get_be32s(f, &s->irr[i]); |
|
823 } |
|
824 for (i = 0; i < APIC_LVT_NB; i++) { |
|
825 qemu_get_be32s(f, &s->lvt[i]); |
|
826 } |
|
827 qemu_get_be32s(f, &s->esr); |
|
828 qemu_get_be32s(f, &s->icr[0]); |
|
829 qemu_get_be32s(f, &s->icr[1]); |
|
830 qemu_get_be32s(f, &s->divide_conf); |
|
831 s->count_shift=qemu_get_be32(f); |
|
832 qemu_get_be32s(f, &s->initial_count); |
|
833 s->initial_count_load_time=qemu_get_be64(f); |
|
834 s->next_time=qemu_get_be64(f); |
|
835 |
|
836 if (version_id >= 2) |
|
837 qemu_get_timer(f, s->timer); |
|
838 return 0; |
|
839 } |
|
840 |
|
841 static void apic_reset(void *opaque) |
|
842 { |
|
843 APICState *s = opaque; |
|
844 |
|
845 s->apicbase = 0xfee00000 | |
|
846 (s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE; |
|
847 |
|
848 apic_init_ipi(s); |
|
849 |
|
850 if (s->id == 0) { |
|
851 /* |
|
852 * LINT0 delivery mode on CPU #0 is set to ExtInt at initialization |
|
853 * time typically by BIOS, so PIC interrupt can be delivered to the |
|
854 * processor when local APIC is enabled. |
|
855 */ |
|
856 s->lvt[APIC_LVT_LINT0] = 0x700; |
|
857 } |
|
858 } |
|
859 |
|
860 static CPUReadMemoryFunc *apic_mem_read[3] = { |
|
861 apic_mem_readb, |
|
862 apic_mem_readw, |
|
863 apic_mem_readl, |
|
864 }; |
|
865 |
|
866 static CPUWriteMemoryFunc *apic_mem_write[3] = { |
|
867 apic_mem_writeb, |
|
868 apic_mem_writew, |
|
869 apic_mem_writel, |
|
870 }; |
|
871 |
|
872 int apic_init(CPUState *env) |
|
873 { |
|
874 APICState *s; |
|
875 |
|
876 if (last_apic_id >= MAX_APICS) |
|
877 return -1; |
|
878 s = qemu_mallocz(sizeof(APICState)); |
|
879 if (!s) |
|
880 return -1; |
|
881 env->apic_state = s; |
|
882 s->id = last_apic_id++; |
|
883 env->cpuid_apic_id = s->id; |
|
884 s->cpu_env = env; |
|
885 |
|
886 apic_reset(s); |
|
887 |
|
888 /* XXX: mapping more APICs at the same memory location */ |
|
889 if (apic_io_memory == 0) { |
|
890 /* NOTE: the APIC is directly connected to the CPU - it is not |
|
891 on the global memory bus. */ |
|
892 apic_io_memory = cpu_register_io_memory(0, apic_mem_read, |
|
893 apic_mem_write, NULL); |
|
894 cpu_register_physical_memory(s->apicbase & ~0xfff, 0x1000, |
|
895 apic_io_memory); |
|
896 } |
|
897 s->timer = qemu_new_timer(vm_clock, apic_timer, s); |
|
898 |
|
899 register_savevm("apic", s->id, 2, apic_save, apic_load, s); |
|
900 qemu_register_reset(apic_reset, s); |
|
901 |
|
902 local_apics[s->id] = s; |
|
903 return 0; |
|
904 } |
|
905 |
|
906 static void ioapic_service(IOAPICState *s) |
|
907 { |
|
908 uint8_t i; |
|
909 uint8_t trig_mode; |
|
910 uint8_t vector; |
|
911 uint8_t delivery_mode; |
|
912 uint32_t mask; |
|
913 uint64_t entry; |
|
914 uint8_t dest; |
|
915 uint8_t dest_mode; |
|
916 uint8_t polarity; |
|
917 uint32_t deliver_bitmask[MAX_APIC_WORDS]; |
|
918 |
|
919 for (i = 0; i < IOAPIC_NUM_PINS; i++) { |
|
920 mask = 1 << i; |
|
921 if (s->irr & mask) { |
|
922 entry = s->ioredtbl[i]; |
|
923 if (!(entry & APIC_LVT_MASKED)) { |
|
924 trig_mode = ((entry >> 15) & 1); |
|
925 dest = entry >> 56; |
|
926 dest_mode = (entry >> 11) & 1; |
|
927 delivery_mode = (entry >> 8) & 7; |
|
928 polarity = (entry >> 13) & 1; |
|
929 if (trig_mode == APIC_TRIGGER_EDGE) |
|
930 s->irr &= ~mask; |
|
931 if (delivery_mode == APIC_DM_EXTINT) |
|
932 vector = pic_read_irq(isa_pic); |
|
933 else |
|
934 vector = entry & 0xff; |
|
935 |
|
936 apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode); |
|
937 apic_bus_deliver(deliver_bitmask, delivery_mode, |
|
938 vector, polarity, trig_mode); |
|
939 } |
|
940 } |
|
941 } |
|
942 } |
|
943 |
|
944 void ioapic_set_irq(void *opaque, int vector, int level) |
|
945 { |
|
946 IOAPICState *s = opaque; |
|
947 |
|
948 /* ISA IRQs map to GSI 1-1 except for IRQ0 which maps |
|
949 * to GSI 2. GSI maps to ioapic 1-1. This is not |
|
950 * the cleanest way of doing it but it should work. */ |
|
951 |
|
952 if (vector == 0) |
|
953 vector = 2; |
|
954 |
|
955 if (vector >= 0 && vector < IOAPIC_NUM_PINS) { |
|
956 uint32_t mask = 1 << vector; |
|
957 uint64_t entry = s->ioredtbl[vector]; |
|
958 |
|
959 if ((entry >> 15) & 1) { |
|
960 /* level triggered */ |
|
961 if (level) { |
|
962 s->irr |= mask; |
|
963 ioapic_service(s); |
|
964 } else { |
|
965 s->irr &= ~mask; |
|
966 } |
|
967 } else { |
|
968 /* edge triggered */ |
|
969 if (level) { |
|
970 s->irr |= mask; |
|
971 ioapic_service(s); |
|
972 } |
|
973 } |
|
974 } |
|
975 } |
|
976 |
|
977 static uint32_t ioapic_mem_readl(void *opaque, target_phys_addr_t addr) |
|
978 { |
|
979 IOAPICState *s = opaque; |
|
980 int index; |
|
981 uint32_t val = 0; |
|
982 |
|
983 addr &= 0xff; |
|
984 if (addr == 0x00) { |
|
985 val = s->ioregsel; |
|
986 } else if (addr == 0x10) { |
|
987 switch (s->ioregsel) { |
|
988 case 0x00: |
|
989 val = s->id << 24; |
|
990 break; |
|
991 case 0x01: |
|
992 val = 0x11 | ((IOAPIC_NUM_PINS - 1) << 16); /* version 0x11 */ |
|
993 break; |
|
994 case 0x02: |
|
995 val = 0; |
|
996 break; |
|
997 default: |
|
998 index = (s->ioregsel - 0x10) >> 1; |
|
999 if (index >= 0 && index < IOAPIC_NUM_PINS) { |
|
1000 if (s->ioregsel & 1) |
|
1001 val = s->ioredtbl[index] >> 32; |
|
1002 else |
|
1003 val = s->ioredtbl[index] & 0xffffffff; |
|
1004 } |
|
1005 } |
|
1006 #ifdef DEBUG_IOAPIC |
|
1007 printf("I/O APIC read: %08x = %08x\n", s->ioregsel, val); |
|
1008 #endif |
|
1009 } |
|
1010 return val; |
|
1011 } |
|
1012 |
|
1013 static void ioapic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) |
|
1014 { |
|
1015 IOAPICState *s = opaque; |
|
1016 int index; |
|
1017 |
|
1018 addr &= 0xff; |
|
1019 if (addr == 0x00) { |
|
1020 s->ioregsel = val; |
|
1021 return; |
|
1022 } else if (addr == 0x10) { |
|
1023 #ifdef DEBUG_IOAPIC |
|
1024 printf("I/O APIC write: %08x = %08x\n", s->ioregsel, val); |
|
1025 #endif |
|
1026 switch (s->ioregsel) { |
|
1027 case 0x00: |
|
1028 s->id = (val >> 24) & 0xff; |
|
1029 return; |
|
1030 case 0x01: |
|
1031 case 0x02: |
|
1032 return; |
|
1033 default: |
|
1034 index = (s->ioregsel - 0x10) >> 1; |
|
1035 if (index >= 0 && index < IOAPIC_NUM_PINS) { |
|
1036 if (s->ioregsel & 1) { |
|
1037 s->ioredtbl[index] &= 0xffffffff; |
|
1038 s->ioredtbl[index] |= (uint64_t)val << 32; |
|
1039 } else { |
|
1040 s->ioredtbl[index] &= ~0xffffffffULL; |
|
1041 s->ioredtbl[index] |= val; |
|
1042 } |
|
1043 ioapic_service(s); |
|
1044 } |
|
1045 } |
|
1046 } |
|
1047 } |
|
1048 |
|
1049 static void ioapic_save(QEMUFile *f, void *opaque) |
|
1050 { |
|
1051 IOAPICState *s = opaque; |
|
1052 int i; |
|
1053 |
|
1054 qemu_put_8s(f, &s->id); |
|
1055 qemu_put_8s(f, &s->ioregsel); |
|
1056 for (i = 0; i < IOAPIC_NUM_PINS; i++) { |
|
1057 qemu_put_be64s(f, &s->ioredtbl[i]); |
|
1058 } |
|
1059 } |
|
1060 |
|
1061 static int ioapic_load(QEMUFile *f, void *opaque, int version_id) |
|
1062 { |
|
1063 IOAPICState *s = opaque; |
|
1064 int i; |
|
1065 |
|
1066 if (version_id != 1) |
|
1067 return -EINVAL; |
|
1068 |
|
1069 qemu_get_8s(f, &s->id); |
|
1070 qemu_get_8s(f, &s->ioregsel); |
|
1071 for (i = 0; i < IOAPIC_NUM_PINS; i++) { |
|
1072 qemu_get_be64s(f, &s->ioredtbl[i]); |
|
1073 } |
|
1074 return 0; |
|
1075 } |
|
1076 |
|
1077 static void ioapic_reset(void *opaque) |
|
1078 { |
|
1079 IOAPICState *s = opaque; |
|
1080 int i; |
|
1081 |
|
1082 memset(s, 0, sizeof(*s)); |
|
1083 for(i = 0; i < IOAPIC_NUM_PINS; i++) |
|
1084 s->ioredtbl[i] = 1 << 16; /* mask LVT */ |
|
1085 } |
|
1086 |
|
1087 static CPUReadMemoryFunc *ioapic_mem_read[3] = { |
|
1088 ioapic_mem_readl, |
|
1089 ioapic_mem_readl, |
|
1090 ioapic_mem_readl, |
|
1091 }; |
|
1092 |
|
1093 static CPUWriteMemoryFunc *ioapic_mem_write[3] = { |
|
1094 ioapic_mem_writel, |
|
1095 ioapic_mem_writel, |
|
1096 ioapic_mem_writel, |
|
1097 }; |
|
1098 |
|
1099 IOAPICState *ioapic_init(void) |
|
1100 { |
|
1101 IOAPICState *s; |
|
1102 int io_memory; |
|
1103 |
|
1104 s = qemu_mallocz(sizeof(IOAPICState)); |
|
1105 if (!s) |
|
1106 return NULL; |
|
1107 ioapic_reset(s); |
|
1108 s->id = last_apic_id++; |
|
1109 |
|
1110 io_memory = cpu_register_io_memory(0, ioapic_mem_read, |
|
1111 ioapic_mem_write, s); |
|
1112 cpu_register_physical_memory(0xfec00000, 0x1000, io_memory); |
|
1113 |
|
1114 register_savevm("ioapic", 0, 1, ioapic_save, ioapic_load, s); |
|
1115 qemu_register_reset(ioapic_reset, s); |
|
1116 |
|
1117 return s; |
|
1118 } |