]> git.proxmox.com Git - mirror_qemu.git/blame - hw/apic.c
qom: Unify type registration
[mirror_qemu.git] / hw / apic.c
CommitLineData
574bbf7b
FB
1/*
2 * APIC support
5fafdf24 3 *
574bbf7b
FB
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
8167ee88 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>
574bbf7b 18 */
dae01685 19#include "apic_internal.h"
aa28b9bf 20#include "apic.h"
0280b571 21#include "ioapic.h"
bb7e7293 22#include "host-utils.h"
d8023f31 23#include "trace.h"
d96e1737 24#include "pc.h"
574bbf7b 25
d3e9db93
FB
26#define MAX_APIC_WORDS 8
27
54c96da7
MT
28/* Intel APIC constants: from include/asm/msidef.h */
29#define MSI_DATA_VECTOR_SHIFT 0
30#define MSI_DATA_VECTOR_MASK 0x000000ff
31#define MSI_DATA_DELIVERY_MODE_SHIFT 8
32#define MSI_DATA_TRIGGER_SHIFT 15
33#define MSI_DATA_LEVEL_SHIFT 14
34#define MSI_ADDR_DEST_MODE_SHIFT 2
35#define MSI_ADDR_DEST_ID_SHIFT 12
36#define MSI_ADDR_DEST_ID_MASK 0x00ffff0
37
dae01685 38static APICCommonState *local_apics[MAX_APICS + 1];
73822ec8 39
dae01685
JK
40static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode);
41static void apic_update_irq(APICCommonState *s);
610626af
AL
42static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
43 uint8_t dest, uint8_t dest_mode);
d592d303 44
3b63c04e
AJ
45/* Find first bit starting from msb */
46static int fls_bit(uint32_t value)
47{
48 return 31 - clz32(value);
49}
50
e95f5491 51/* Find first bit starting from lsb */
d3e9db93
FB
52static int ffs_bit(uint32_t value)
53{
bb7e7293 54 return ctz32(value);
d3e9db93
FB
55}
56
57static inline void set_bit(uint32_t *tab, int index)
58{
59 int i, mask;
60 i = index >> 5;
61 mask = 1 << (index & 0x1f);
62 tab[i] |= mask;
63}
64
65static inline void reset_bit(uint32_t *tab, int index)
66{
67 int i, mask;
68 i = index >> 5;
69 mask = 1 << (index & 0x1f);
70 tab[i] &= ~mask;
71}
72
73822ec8
AL
73static inline int get_bit(uint32_t *tab, int index)
74{
75 int i, mask;
76 i = index >> 5;
77 mask = 1 << (index & 0x1f);
78 return !!(tab[i] & mask);
79}
80
dae01685 81static void apic_local_deliver(APICCommonState *s, int vector)
a5b38b51 82{
a5b38b51
AJ
83 uint32_t lvt = s->lvt[vector];
84 int trigger_mode;
85
d8023f31
BS
86 trace_apic_local_deliver(vector, (lvt >> 8) & 7);
87
a5b38b51
AJ
88 if (lvt & APIC_LVT_MASKED)
89 return;
90
91 switch ((lvt >> 8) & 7) {
92 case APIC_DM_SMI:
cf6d64bf 93 cpu_interrupt(s->cpu_env, CPU_INTERRUPT_SMI);
a5b38b51
AJ
94 break;
95
96 case APIC_DM_NMI:
cf6d64bf 97 cpu_interrupt(s->cpu_env, CPU_INTERRUPT_NMI);
a5b38b51
AJ
98 break;
99
100 case APIC_DM_EXTINT:
cf6d64bf 101 cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
a5b38b51
AJ
102 break;
103
104 case APIC_DM_FIXED:
105 trigger_mode = APIC_TRIGGER_EDGE;
106 if ((vector == APIC_LVT_LINT0 || vector == APIC_LVT_LINT1) &&
107 (lvt & APIC_LVT_LEVEL_TRIGGER))
108 trigger_mode = APIC_TRIGGER_LEVEL;
109 apic_set_irq(s, lvt & 0xff, trigger_mode);
110 }
111}
112
92a16d7a 113void apic_deliver_pic_intr(DeviceState *d, int level)
1a7de94a 114{
dae01685 115 APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
92a16d7a 116
cf6d64bf
BS
117 if (level) {
118 apic_local_deliver(s, APIC_LVT_LINT0);
119 } else {
1a7de94a
AJ
120 uint32_t lvt = s->lvt[APIC_LVT_LINT0];
121
122 switch ((lvt >> 8) & 7) {
123 case APIC_DM_FIXED:
124 if (!(lvt & APIC_LVT_LEVEL_TRIGGER))
125 break;
126 reset_bit(s->irr, lvt & 0xff);
127 /* fall through */
128 case APIC_DM_EXTINT:
cf6d64bf 129 cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
1a7de94a
AJ
130 break;
131 }
132 }
133}
134
dae01685 135static void apic_external_nmi(APICCommonState *s)
02c09195 136{
02c09195
JK
137 apic_local_deliver(s, APIC_LVT_LINT1);
138}
139
d3e9db93
FB
140#define foreach_apic(apic, deliver_bitmask, code) \
141{\
142 int __i, __j, __mask;\
143 for(__i = 0; __i < MAX_APIC_WORDS; __i++) {\
144 __mask = deliver_bitmask[__i];\
145 if (__mask) {\
146 for(__j = 0; __j < 32; __j++) {\
147 if (__mask & (1 << __j)) {\
148 apic = local_apics[__i * 32 + __j];\
149 if (apic) {\
150 code;\
151 }\
152 }\
153 }\
154 }\
155 }\
156}
157
5fafdf24 158static void apic_bus_deliver(const uint32_t *deliver_bitmask,
1f6f408c 159 uint8_t delivery_mode, uint8_t vector_num,
d592d303
FB
160 uint8_t trigger_mode)
161{
dae01685 162 APICCommonState *apic_iter;
d592d303
FB
163
164 switch (delivery_mode) {
165 case APIC_DM_LOWPRI:
8dd69b8f 166 /* XXX: search for focus processor, arbitration */
d3e9db93
FB
167 {
168 int i, d;
169 d = -1;
170 for(i = 0; i < MAX_APIC_WORDS; i++) {
171 if (deliver_bitmask[i]) {
172 d = i * 32 + ffs_bit(deliver_bitmask[i]);
173 break;
174 }
175 }
176 if (d >= 0) {
177 apic_iter = local_apics[d];
178 if (apic_iter) {
179 apic_set_irq(apic_iter, vector_num, trigger_mode);
180 }
181 }
8dd69b8f 182 }
d3e9db93 183 return;
8dd69b8f 184
d592d303 185 case APIC_DM_FIXED:
d592d303
FB
186 break;
187
188 case APIC_DM_SMI:
e2eb9d3e
AJ
189 foreach_apic(apic_iter, deliver_bitmask,
190 cpu_interrupt(apic_iter->cpu_env, CPU_INTERRUPT_SMI) );
191 return;
192
d592d303 193 case APIC_DM_NMI:
e2eb9d3e
AJ
194 foreach_apic(apic_iter, deliver_bitmask,
195 cpu_interrupt(apic_iter->cpu_env, CPU_INTERRUPT_NMI) );
196 return;
d592d303
FB
197
198 case APIC_DM_INIT:
199 /* normal INIT IPI sent to processors */
5fafdf24 200 foreach_apic(apic_iter, deliver_bitmask,
b09ea7d5 201 cpu_interrupt(apic_iter->cpu_env, CPU_INTERRUPT_INIT) );
d592d303 202 return;
3b46e624 203
d592d303 204 case APIC_DM_EXTINT:
b1fc0348 205 /* handled in I/O APIC code */
d592d303
FB
206 break;
207
208 default:
209 return;
210 }
211
5fafdf24 212 foreach_apic(apic_iter, deliver_bitmask,
d3e9db93 213 apic_set_irq(apic_iter, vector_num, trigger_mode) );
d592d303 214}
574bbf7b 215
1f6f408c
JK
216void apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode,
217 uint8_t vector_num, uint8_t trigger_mode)
610626af
AL
218{
219 uint32_t deliver_bitmask[MAX_APIC_WORDS];
220
d8023f31 221 trace_apic_deliver_irq(dest, dest_mode, delivery_mode, vector_num,
1f6f408c 222 trigger_mode);
d8023f31 223
610626af 224 apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
1f6f408c 225 apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode);
610626af
AL
226}
227
dae01685 228static void apic_set_base(APICCommonState *s, uint64_t val)
574bbf7b 229{
5fafdf24 230 s->apicbase = (val & 0xfffff000) |
574bbf7b
FB
231 (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
232 /* if disabled, cannot be enabled again */
233 if (!(val & MSR_IA32_APICBASE_ENABLE)) {
234 s->apicbase &= ~MSR_IA32_APICBASE_ENABLE;
0e26b7b8 235 cpu_clear_apic_feature(s->cpu_env);
574bbf7b
FB
236 s->spurious_vec &= ~APIC_SV_ENABLE;
237 }
238}
239
dae01685 240static void apic_set_tpr(APICCommonState *s, uint8_t val)
574bbf7b 241{
9230e66e 242 s->tpr = (val & 0x0f) << 4;
d592d303 243 apic_update_irq(s);
9230e66e
FB
244}
245
d592d303
FB
246/* return -1 if no bit is set */
247static int get_highest_priority_int(uint32_t *tab)
248{
249 int i;
250 for(i = 7; i >= 0; i--) {
251 if (tab[i] != 0) {
3b63c04e 252 return i * 32 + fls_bit(tab[i]);
d592d303
FB
253 }
254 }
255 return -1;
256}
257
dae01685 258static int apic_get_ppr(APICCommonState *s)
574bbf7b
FB
259{
260 int tpr, isrv, ppr;
261
262 tpr = (s->tpr >> 4);
263 isrv = get_highest_priority_int(s->isr);
264 if (isrv < 0)
265 isrv = 0;
266 isrv >>= 4;
267 if (tpr >= isrv)
268 ppr = s->tpr;
269 else
270 ppr = isrv << 4;
271 return ppr;
272}
273
dae01685 274static int apic_get_arb_pri(APICCommonState *s)
d592d303
FB
275{
276 /* XXX: arbitration */
277 return 0;
278}
279
0fbfbb59
GN
280
281/*
282 * <0 - low prio interrupt,
283 * 0 - no interrupt,
284 * >0 - interrupt number
285 */
dae01685 286static int apic_irq_pending(APICCommonState *s)
574bbf7b 287{
d592d303 288 int irrv, ppr;
574bbf7b 289 irrv = get_highest_priority_int(s->irr);
0fbfbb59
GN
290 if (irrv < 0) {
291 return 0;
292 }
d592d303 293 ppr = apic_get_ppr(s);
0fbfbb59
GN
294 if (ppr && (irrv & 0xf0) <= (ppr & 0xf0)) {
295 return -1;
296 }
297
298 return irrv;
299}
300
301/* signal the CPU if an irq is pending */
dae01685 302static void apic_update_irq(APICCommonState *s)
0fbfbb59
GN
303{
304 if (!(s->spurious_vec & APIC_SV_ENABLE)) {
574bbf7b 305 return;
0fbfbb59
GN
306 }
307 if (apic_irq_pending(s) > 0) {
308 cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
d96e1737
JK
309 } else if (apic_accept_pic_intr(&s->busdev.qdev) &&
310 pic_get_output(isa_pic)) {
311 apic_deliver_pic_intr(&s->busdev.qdev, 1);
0fbfbb59 312 }
574bbf7b
FB
313}
314
dae01685 315static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode)
574bbf7b 316{
343270ea 317 apic_report_irq_delivered(!get_bit(s->irr, vector_num));
73822ec8 318
574bbf7b
FB
319 set_bit(s->irr, vector_num);
320 if (trigger_mode)
321 set_bit(s->tmr, vector_num);
322 else
323 reset_bit(s->tmr, vector_num);
324 apic_update_irq(s);
325}
326
dae01685 327static void apic_eoi(APICCommonState *s)
574bbf7b
FB
328{
329 int isrv;
330 isrv = get_highest_priority_int(s->isr);
331 if (isrv < 0)
332 return;
333 reset_bit(s->isr, isrv);
0280b571
JK
334 if (!(s->spurious_vec & APIC_SV_DIRECTED_IO) && get_bit(s->tmr, isrv)) {
335 ioapic_eoi_broadcast(isrv);
336 }
574bbf7b
FB
337 apic_update_irq(s);
338}
339
678e12cc
GN
340static int apic_find_dest(uint8_t dest)
341{
dae01685 342 APICCommonState *apic = local_apics[dest];
678e12cc
GN
343 int i;
344
345 if (apic && apic->id == dest)
346 return dest; /* shortcut in case apic->id == apic->idx */
347
348 for (i = 0; i < MAX_APICS; i++) {
349 apic = local_apics[i];
350 if (apic && apic->id == dest)
351 return i;
b538e53e
AW
352 if (!apic)
353 break;
678e12cc
GN
354 }
355
356 return -1;
357}
358
d3e9db93
FB
359static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
360 uint8_t dest, uint8_t dest_mode)
d592d303 361{
dae01685 362 APICCommonState *apic_iter;
d3e9db93 363 int i;
d592d303
FB
364
365 if (dest_mode == 0) {
d3e9db93
FB
366 if (dest == 0xff) {
367 memset(deliver_bitmask, 0xff, MAX_APIC_WORDS * sizeof(uint32_t));
368 } else {
678e12cc 369 int idx = apic_find_dest(dest);
d3e9db93 370 memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t));
678e12cc
GN
371 if (idx >= 0)
372 set_bit(deliver_bitmask, idx);
d3e9db93 373 }
d592d303
FB
374 } else {
375 /* XXX: cluster mode */
d3e9db93
FB
376 memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t));
377 for(i = 0; i < MAX_APICS; i++) {
378 apic_iter = local_apics[i];
379 if (apic_iter) {
380 if (apic_iter->dest_mode == 0xf) {
381 if (dest & apic_iter->log_dest)
382 set_bit(deliver_bitmask, i);
383 } else if (apic_iter->dest_mode == 0x0) {
384 if ((dest & 0xf0) == (apic_iter->log_dest & 0xf0) &&
385 (dest & apic_iter->log_dest & 0x0f)) {
386 set_bit(deliver_bitmask, i);
387 }
388 }
b538e53e
AW
389 } else {
390 break;
d3e9db93 391 }
d592d303
FB
392 }
393 }
d592d303
FB
394}
395
dae01685 396static void apic_startup(APICCommonState *s, int vector_num)
e0fd8781 397{
b09ea7d5
GN
398 s->sipi_vector = vector_num;
399 cpu_interrupt(s->cpu_env, CPU_INTERRUPT_SIPI);
400}
401
92a16d7a 402void apic_sipi(DeviceState *d)
b09ea7d5 403{
dae01685 404 APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
92a16d7a 405
4a942cea 406 cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_SIPI);
b09ea7d5
GN
407
408 if (!s->wait_for_sipi)
e0fd8781 409 return;
0e26b7b8 410 cpu_x86_load_seg_cache_sipi(s->cpu_env, s->sipi_vector);
b09ea7d5 411 s->wait_for_sipi = 0;
e0fd8781
FB
412}
413
92a16d7a 414static void apic_deliver(DeviceState *d, uint8_t dest, uint8_t dest_mode,
d592d303 415 uint8_t delivery_mode, uint8_t vector_num,
1f6f408c 416 uint8_t trigger_mode)
d592d303 417{
dae01685 418 APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
d3e9db93 419 uint32_t deliver_bitmask[MAX_APIC_WORDS];
d592d303 420 int dest_shorthand = (s->icr[0] >> 18) & 3;
dae01685 421 APICCommonState *apic_iter;
d592d303 422
e0fd8781 423 switch (dest_shorthand) {
d3e9db93
FB
424 case 0:
425 apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
426 break;
427 case 1:
428 memset(deliver_bitmask, 0x00, sizeof(deliver_bitmask));
678e12cc 429 set_bit(deliver_bitmask, s->idx);
d3e9db93
FB
430 break;
431 case 2:
432 memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
433 break;
434 case 3:
435 memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
678e12cc 436 reset_bit(deliver_bitmask, s->idx);
d3e9db93 437 break;
e0fd8781
FB
438 }
439
d592d303 440 switch (delivery_mode) {
d592d303
FB
441 case APIC_DM_INIT:
442 {
443 int trig_mode = (s->icr[0] >> 15) & 1;
444 int level = (s->icr[0] >> 14) & 1;
445 if (level == 0 && trig_mode == 1) {
5fafdf24 446 foreach_apic(apic_iter, deliver_bitmask,
d3e9db93 447 apic_iter->arb_id = apic_iter->id );
d592d303
FB
448 return;
449 }
450 }
451 break;
452
453 case APIC_DM_SIPI:
5fafdf24 454 foreach_apic(apic_iter, deliver_bitmask,
d3e9db93 455 apic_startup(apic_iter, vector_num) );
d592d303
FB
456 return;
457 }
458
1f6f408c 459 apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode);
d592d303
FB
460}
461
92a16d7a 462int apic_get_interrupt(DeviceState *d)
574bbf7b 463{
dae01685 464 APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
574bbf7b
FB
465 int intno;
466
467 /* if the APIC is installed or enabled, we let the 8259 handle the
468 IRQs */
469 if (!s)
470 return -1;
471 if (!(s->spurious_vec & APIC_SV_ENABLE))
472 return -1;
3b46e624 473
0fbfbb59
GN
474 intno = apic_irq_pending(s);
475
476 if (intno == 0) {
574bbf7b 477 return -1;
0fbfbb59 478 } else if (intno < 0) {
d592d303 479 return s->spurious_vec & 0xff;
0fbfbb59 480 }
b4511723 481 reset_bit(s->irr, intno);
574bbf7b
FB
482 set_bit(s->isr, intno);
483 apic_update_irq(s);
484 return intno;
485}
486
92a16d7a 487int apic_accept_pic_intr(DeviceState *d)
0e21e12b 488{
dae01685 489 APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
0e21e12b
TS
490 uint32_t lvt0;
491
492 if (!s)
493 return -1;
494
495 lvt0 = s->lvt[APIC_LVT_LINT0];
496
a5b38b51
AJ
497 if ((s->apicbase & MSR_IA32_APICBASE_ENABLE) == 0 ||
498 (lvt0 & APIC_LVT_MASKED) == 0)
0e21e12b
TS
499 return 1;
500
501 return 0;
502}
503
dae01685 504static uint32_t apic_get_current_count(APICCommonState *s)
574bbf7b
FB
505{
506 int64_t d;
507 uint32_t val;
74475455 508 d = (qemu_get_clock_ns(vm_clock) - s->initial_count_load_time) >>
574bbf7b
FB
509 s->count_shift;
510 if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
511 /* periodic */
d592d303 512 val = s->initial_count - (d % ((uint64_t)s->initial_count + 1));
574bbf7b
FB
513 } else {
514 if (d >= s->initial_count)
515 val = 0;
516 else
517 val = s->initial_count - d;
518 }
519 return val;
520}
521
dae01685 522static void apic_timer_update(APICCommonState *s, int64_t current_time)
574bbf7b 523{
7a380ca3
JK
524 if (apic_next_timer(s, current_time)) {
525 qemu_mod_timer(s->timer, s->next_time);
574bbf7b 526 } else {
574bbf7b
FB
527 qemu_del_timer(s->timer);
528 }
529}
530
531static void apic_timer(void *opaque)
532{
dae01685 533 APICCommonState *s = opaque;
574bbf7b 534
cf6d64bf 535 apic_local_deliver(s, APIC_LVT_TIMER);
574bbf7b
FB
536 apic_timer_update(s, s->next_time);
537}
538
c227f099 539static uint32_t apic_mem_readb(void *opaque, target_phys_addr_t addr)
574bbf7b
FB
540{
541 return 0;
542}
543
c227f099 544static uint32_t apic_mem_readw(void *opaque, target_phys_addr_t addr)
574bbf7b
FB
545{
546 return 0;
547}
548
c227f099 549static void apic_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
574bbf7b
FB
550{
551}
552
c227f099 553static void apic_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
574bbf7b
FB
554{
555}
556
c227f099 557static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
574bbf7b 558{
92a16d7a 559 DeviceState *d;
dae01685 560 APICCommonState *s;
574bbf7b
FB
561 uint32_t val;
562 int index;
563
92a16d7a
BS
564 d = cpu_get_current_apic();
565 if (!d) {
574bbf7b 566 return 0;
0e26b7b8 567 }
dae01685 568 s = DO_UPCAST(APICCommonState, busdev.qdev, d);
574bbf7b
FB
569
570 index = (addr >> 4) & 0xff;
571 switch(index) {
572 case 0x02: /* id */
573 val = s->id << 24;
574 break;
575 case 0x03: /* version */
576 val = 0x11 | ((APIC_LVT_NB - 1) << 16); /* version 0x11 */
577 break;
578 case 0x08:
579 val = s->tpr;
580 break;
d592d303
FB
581 case 0x09:
582 val = apic_get_arb_pri(s);
583 break;
574bbf7b
FB
584 case 0x0a:
585 /* ppr */
586 val = apic_get_ppr(s);
587 break;
b237db36
AJ
588 case 0x0b:
589 val = 0;
590 break;
d592d303
FB
591 case 0x0d:
592 val = s->log_dest << 24;
593 break;
594 case 0x0e:
595 val = s->dest_mode << 28;
596 break;
574bbf7b
FB
597 case 0x0f:
598 val = s->spurious_vec;
599 break;
600 case 0x10 ... 0x17:
601 val = s->isr[index & 7];
602 break;
603 case 0x18 ... 0x1f:
604 val = s->tmr[index & 7];
605 break;
606 case 0x20 ... 0x27:
607 val = s->irr[index & 7];
608 break;
609 case 0x28:
610 val = s->esr;
611 break;
574bbf7b
FB
612 case 0x30:
613 case 0x31:
614 val = s->icr[index & 1];
615 break;
e0fd8781
FB
616 case 0x32 ... 0x37:
617 val = s->lvt[index - 0x32];
618 break;
574bbf7b
FB
619 case 0x38:
620 val = s->initial_count;
621 break;
622 case 0x39:
623 val = apic_get_current_count(s);
624 break;
625 case 0x3e:
626 val = s->divide_conf;
627 break;
628 default:
629 s->esr |= ESR_ILLEGAL_ADDRESS;
630 val = 0;
631 break;
632 }
d8023f31 633 trace_apic_mem_readl(addr, val);
574bbf7b
FB
634 return val;
635}
636
f5095c63 637static void apic_send_msi(target_phys_addr_t addr, uint32_t data)
54c96da7
MT
638{
639 uint8_t dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
640 uint8_t vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
641 uint8_t dest_mode = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1;
642 uint8_t trigger_mode = (data >> MSI_DATA_TRIGGER_SHIFT) & 0x1;
643 uint8_t delivery = (data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7;
644 /* XXX: Ignore redirection hint. */
1f6f408c 645 apic_deliver_irq(dest, dest_mode, delivery, vector, trigger_mode);
54c96da7
MT
646}
647
c227f099 648static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
574bbf7b 649{
92a16d7a 650 DeviceState *d;
dae01685 651 APICCommonState *s;
54c96da7
MT
652 int index = (addr >> 4) & 0xff;
653 if (addr > 0xfff || !index) {
654 /* MSI and MMIO APIC are at the same memory location,
655 * but actually not on the global bus: MSI is on PCI bus
656 * APIC is connected directly to the CPU.
657 * Mapping them on the global bus happens to work because
658 * MSI registers are reserved in APIC MMIO and vice versa. */
659 apic_send_msi(addr, val);
660 return;
661 }
574bbf7b 662
92a16d7a
BS
663 d = cpu_get_current_apic();
664 if (!d) {
574bbf7b 665 return;
0e26b7b8 666 }
dae01685 667 s = DO_UPCAST(APICCommonState, busdev.qdev, d);
574bbf7b 668
d8023f31 669 trace_apic_mem_writel(addr, val);
574bbf7b 670
574bbf7b
FB
671 switch(index) {
672 case 0x02:
673 s->id = (val >> 24);
674 break;
e0fd8781
FB
675 case 0x03:
676 break;
574bbf7b
FB
677 case 0x08:
678 s->tpr = val;
d592d303 679 apic_update_irq(s);
574bbf7b 680 break;
e0fd8781
FB
681 case 0x09:
682 case 0x0a:
683 break;
574bbf7b
FB
684 case 0x0b: /* EOI */
685 apic_eoi(s);
686 break;
d592d303
FB
687 case 0x0d:
688 s->log_dest = val >> 24;
689 break;
690 case 0x0e:
691 s->dest_mode = val >> 28;
692 break;
574bbf7b
FB
693 case 0x0f:
694 s->spurious_vec = val & 0x1ff;
d592d303 695 apic_update_irq(s);
574bbf7b 696 break;
e0fd8781
FB
697 case 0x10 ... 0x17:
698 case 0x18 ... 0x1f:
699 case 0x20 ... 0x27:
700 case 0x28:
701 break;
574bbf7b 702 case 0x30:
d592d303 703 s->icr[0] = val;
92a16d7a 704 apic_deliver(d, (s->icr[1] >> 24) & 0xff, (s->icr[0] >> 11) & 1,
d592d303 705 (s->icr[0] >> 8) & 7, (s->icr[0] & 0xff),
1f6f408c 706 (s->icr[0] >> 15) & 1);
d592d303 707 break;
574bbf7b 708 case 0x31:
d592d303 709 s->icr[1] = val;
574bbf7b
FB
710 break;
711 case 0x32 ... 0x37:
712 {
713 int n = index - 0x32;
714 s->lvt[n] = val;
715 if (n == APIC_LVT_TIMER)
74475455 716 apic_timer_update(s, qemu_get_clock_ns(vm_clock));
574bbf7b
FB
717 }
718 break;
719 case 0x38:
720 s->initial_count = val;
74475455 721 s->initial_count_load_time = qemu_get_clock_ns(vm_clock);
574bbf7b
FB
722 apic_timer_update(s, s->initial_count_load_time);
723 break;
e0fd8781
FB
724 case 0x39:
725 break;
574bbf7b
FB
726 case 0x3e:
727 {
728 int v;
729 s->divide_conf = val & 0xb;
730 v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
731 s->count_shift = (v + 1) & 7;
732 }
733 break;
734 default:
735 s->esr |= ESR_ILLEGAL_ADDRESS;
736 break;
737 }
738}
739
7a380ca3
JK
740static void apic_post_load(APICCommonState *s)
741{
742 if (s->timer_expiry != -1) {
743 qemu_mod_timer(s->timer, s->timer_expiry);
744 } else {
745 qemu_del_timer(s->timer);
746 }
747}
748
312b4234
AK
749static const MemoryRegionOps apic_io_ops = {
750 .old_mmio = {
751 .read = { apic_mem_readb, apic_mem_readw, apic_mem_readl, },
752 .write = { apic_mem_writeb, apic_mem_writew, apic_mem_writel, },
753 },
754 .endianness = DEVICE_NATIVE_ENDIAN,
574bbf7b
FB
755};
756
dae01685 757static void apic_init(APICCommonState *s)
8546b099 758{
dae01685
JK
759 memory_region_init_io(&s->io_memory, &apic_io_ops, s, "apic-msi",
760 MSI_SPACE_SIZE);
8546b099 761
74475455 762 s->timer = qemu_new_timer_ns(vm_clock, apic_timer, s);
8546b099 763 local_apics[s->idx] = s;
8546b099
BS
764}
765
999e12bb
AL
766static void apic_class_init(ObjectClass *klass, void *data)
767{
768 APICCommonClass *k = APIC_COMMON_CLASS(klass);
769
770 k->init = apic_init;
771 k->set_base = apic_set_base;
772 k->set_tpr = apic_set_tpr;
773 k->external_nmi = apic_external_nmi;
774 k->post_load = apic_post_load;
775}
776
39bffca2
AL
777static TypeInfo apic_info = {
778 .name = "apic",
779 .instance_size = sizeof(APICCommonState),
780 .parent = TYPE_APIC_COMMON,
781 .class_init = apic_class_init,
8546b099
BS
782};
783
83f7d43a 784static void apic_register_types(void)
8546b099 785{
39bffca2 786 type_register_static(&apic_info);
8546b099
BS
787}
788
83f7d43a 789type_init(apic_register_types)