Revision e5ad936b hw/apic.c
b/hw/apic.c | ||
---|---|---|
35 | 35 |
#define MSI_ADDR_DEST_ID_SHIFT 12 |
36 | 36 |
#define MSI_ADDR_DEST_ID_MASK 0x00ffff0 |
37 | 37 |
|
38 |
#define SYNC_FROM_VAPIC 0x1 |
|
39 |
#define SYNC_TO_VAPIC 0x2 |
|
40 |
#define SYNC_ISR_IRR_TO_VAPIC 0x4 |
|
41 |
|
|
38 | 42 |
static APICCommonState *local_apics[MAX_APICS + 1]; |
39 | 43 |
|
40 | 44 |
static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode); |
... | ... | |
78 | 82 |
return !!(tab[i] & mask); |
79 | 83 |
} |
80 | 84 |
|
85 |
/* return -1 if no bit is set */ |
|
86 |
static int get_highest_priority_int(uint32_t *tab) |
|
87 |
{ |
|
88 |
int i; |
|
89 |
for (i = 7; i >= 0; i--) { |
|
90 |
if (tab[i] != 0) { |
|
91 |
return i * 32 + fls_bit(tab[i]); |
|
92 |
} |
|
93 |
} |
|
94 |
return -1; |
|
95 |
} |
|
96 |
|
|
97 |
static void apic_sync_vapic(APICCommonState *s, int sync_type) |
|
98 |
{ |
|
99 |
VAPICState vapic_state; |
|
100 |
size_t length; |
|
101 |
off_t start; |
|
102 |
int vector; |
|
103 |
|
|
104 |
if (!s->vapic_paddr) { |
|
105 |
return; |
|
106 |
} |
|
107 |
if (sync_type & SYNC_FROM_VAPIC) { |
|
108 |
cpu_physical_memory_rw(s->vapic_paddr, (void *)&vapic_state, |
|
109 |
sizeof(vapic_state), 0); |
|
110 |
s->tpr = vapic_state.tpr; |
|
111 |
} |
|
112 |
if (sync_type & (SYNC_TO_VAPIC | SYNC_ISR_IRR_TO_VAPIC)) { |
|
113 |
start = offsetof(VAPICState, isr); |
|
114 |
length = offsetof(VAPICState, enabled) - offsetof(VAPICState, isr); |
|
115 |
|
|
116 |
if (sync_type & SYNC_TO_VAPIC) { |
|
117 |
assert(qemu_cpu_is_self(s->cpu_env)); |
|
118 |
|
|
119 |
vapic_state.tpr = s->tpr; |
|
120 |
vapic_state.enabled = 1; |
|
121 |
start = 0; |
|
122 |
length = sizeof(VAPICState); |
|
123 |
} |
|
124 |
|
|
125 |
vector = get_highest_priority_int(s->isr); |
|
126 |
if (vector < 0) { |
|
127 |
vector = 0; |
|
128 |
} |
|
129 |
vapic_state.isr = vector & 0xf0; |
|
130 |
|
|
131 |
vapic_state.zero = 0; |
|
132 |
|
|
133 |
vector = get_highest_priority_int(s->irr); |
|
134 |
if (vector < 0) { |
|
135 |
vector = 0; |
|
136 |
} |
|
137 |
vapic_state.irr = vector & 0xff; |
|
138 |
|
|
139 |
cpu_physical_memory_write_rom(s->vapic_paddr + start, |
|
140 |
((void *)&vapic_state) + start, length); |
|
141 |
} |
|
142 |
} |
|
143 |
|
|
144 |
static void apic_vapic_base_update(APICCommonState *s) |
|
145 |
{ |
|
146 |
apic_sync_vapic(s, SYNC_TO_VAPIC); |
|
147 |
} |
|
148 |
|
|
81 | 149 |
static void apic_local_deliver(APICCommonState *s, int vector) |
82 | 150 |
{ |
83 | 151 |
uint32_t lvt = s->lvt[vector]; |
... | ... | |
239 | 307 |
|
240 | 308 |
static void apic_set_tpr(APICCommonState *s, uint8_t val) |
241 | 309 |
{ |
242 |
s->tpr = (val & 0x0f) << 4; |
|
243 |
apic_update_irq(s); |
|
310 |
/* Updates from cr8 are ignored while the VAPIC is active */ |
|
311 |
if (!s->vapic_paddr) { |
|
312 |
s->tpr = val << 4; |
|
313 |
apic_update_irq(s); |
|
314 |
} |
|
244 | 315 |
} |
245 | 316 |
|
246 |
/* return -1 if no bit is set */ |
|
247 |
static int get_highest_priority_int(uint32_t *tab) |
|
317 |
static uint8_t apic_get_tpr(APICCommonState *s) |
|
248 | 318 |
{ |
249 |
int i; |
|
250 |
for(i = 7; i >= 0; i--) { |
|
251 |
if (tab[i] != 0) { |
|
252 |
return i * 32 + fls_bit(tab[i]); |
|
253 |
} |
|
254 |
} |
|
255 |
return -1; |
|
319 |
apic_sync_vapic(s, SYNC_FROM_VAPIC); |
|
320 |
return s->tpr >> 4; |
|
256 | 321 |
} |
257 | 322 |
|
258 | 323 |
static int apic_get_ppr(APICCommonState *s) |
... | ... | |
312 | 377 |
} |
313 | 378 |
} |
314 | 379 |
|
380 |
void apic_poll_irq(DeviceState *d) |
|
381 |
{ |
|
382 |
APICCommonState *s = APIC_COMMON(d); |
|
383 |
|
|
384 |
apic_sync_vapic(s, SYNC_FROM_VAPIC); |
|
385 |
apic_update_irq(s); |
|
386 |
} |
|
387 |
|
|
315 | 388 |
static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode) |
316 | 389 |
{ |
317 | 390 |
apic_report_irq_delivered(!get_bit(s->irr, vector_num)); |
... | ... | |
321 | 394 |
set_bit(s->tmr, vector_num); |
322 | 395 |
else |
323 | 396 |
reset_bit(s->tmr, vector_num); |
397 |
if (s->vapic_paddr) { |
|
398 |
apic_sync_vapic(s, SYNC_ISR_IRR_TO_VAPIC); |
|
399 |
/* |
|
400 |
* The vcpu thread needs to see the new IRR before we pull its current |
|
401 |
* TPR value. That way, if we miss a lowering of the TRP, the guest |
|
402 |
* has the chance to notice the new IRR and poll for IRQs on its own. |
|
403 |
*/ |
|
404 |
smp_wmb(); |
|
405 |
apic_sync_vapic(s, SYNC_FROM_VAPIC); |
|
406 |
} |
|
324 | 407 |
apic_update_irq(s); |
325 | 408 |
} |
326 | 409 |
|
... | ... | |
334 | 417 |
if (!(s->spurious_vec & APIC_SV_DIRECTED_IO) && get_bit(s->tmr, isrv)) { |
335 | 418 |
ioapic_eoi_broadcast(isrv); |
336 | 419 |
} |
420 |
apic_sync_vapic(s, SYNC_FROM_VAPIC | SYNC_TO_VAPIC); |
|
337 | 421 |
apic_update_irq(s); |
338 | 422 |
} |
339 | 423 |
|
... | ... | |
471 | 555 |
if (!(s->spurious_vec & APIC_SV_ENABLE)) |
472 | 556 |
return -1; |
473 | 557 |
|
558 |
apic_sync_vapic(s, SYNC_FROM_VAPIC); |
|
474 | 559 |
intno = apic_irq_pending(s); |
475 | 560 |
|
476 | 561 |
if (intno == 0) { |
562 |
apic_sync_vapic(s, SYNC_TO_VAPIC); |
|
477 | 563 |
return -1; |
478 | 564 |
} else if (intno < 0) { |
565 |
apic_sync_vapic(s, SYNC_TO_VAPIC); |
|
479 | 566 |
return s->spurious_vec & 0xff; |
480 | 567 |
} |
481 | 568 |
reset_bit(s->irr, intno); |
482 | 569 |
set_bit(s->isr, intno); |
570 |
apic_sync_vapic(s, SYNC_TO_VAPIC); |
|
483 | 571 |
apic_update_irq(s); |
484 | 572 |
return intno; |
485 | 573 |
} |
... | ... | |
576 | 664 |
val = 0x11 | ((APIC_LVT_NB - 1) << 16); /* version 0x11 */ |
577 | 665 |
break; |
578 | 666 |
case 0x08: |
667 |
apic_sync_vapic(s, SYNC_FROM_VAPIC); |
|
668 |
if (apic_report_tpr_access) { |
|
669 |
cpu_report_tpr_access(s->cpu_env, TPR_ACCESS_READ); |
|
670 |
} |
|
579 | 671 |
val = s->tpr; |
580 | 672 |
break; |
581 | 673 |
case 0x09: |
... | ... | |
675 | 767 |
case 0x03: |
676 | 768 |
break; |
677 | 769 |
case 0x08: |
770 |
if (apic_report_tpr_access) { |
|
771 |
cpu_report_tpr_access(s->cpu_env, TPR_ACCESS_WRITE); |
|
772 |
} |
|
678 | 773 |
s->tpr = val; |
774 |
apic_sync_vapic(s, SYNC_TO_VAPIC); |
|
679 | 775 |
apic_update_irq(s); |
680 | 776 |
break; |
681 | 777 |
case 0x09: |
... | ... | |
737 | 833 |
} |
738 | 834 |
} |
739 | 835 |
|
836 |
static void apic_pre_save(APICCommonState *s) |
|
837 |
{ |
|
838 |
apic_sync_vapic(s, SYNC_FROM_VAPIC); |
|
839 |
} |
|
840 |
|
|
740 | 841 |
static void apic_post_load(APICCommonState *s) |
741 | 842 |
{ |
742 | 843 |
if (s->timer_expiry != -1) { |
... | ... | |
770 | 871 |
k->init = apic_init; |
771 | 872 |
k->set_base = apic_set_base; |
772 | 873 |
k->set_tpr = apic_set_tpr; |
874 |
k->get_tpr = apic_get_tpr; |
|
875 |
k->vapic_base_update = apic_vapic_base_update; |
|
773 | 876 |
k->external_nmi = apic_external_nmi; |
877 |
k->pre_save = apic_pre_save; |
|
774 | 878 |
k->post_load = apic_post_load; |
775 | 879 |
} |
776 | 880 |
|
Also available in: Unified diff