blob: 46daf8a33adc6a57d5607677ac2838dfbf307acc [file] [log] [blame]
bellard574bbf72005-01-03 23:27:31 +00001/*
2 * APIC support
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard574bbf72005-01-03 23:27:31 +00004 * 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 */
pbrook87ecb682007-11-17 17:14:51 +000020#include "hw.h"
21#include "pc.h"
22#include "qemu-timer.h"
bellard574bbf72005-01-03 23:27:31 +000023
24//#define DEBUG_APIC
bellardd592d302005-07-23 19:05:37 +000025//#define DEBUG_IOAPIC
bellard574bbf72005-01-03 23:27:31 +000026
27/* APIC Local Vector Table */
28#define APIC_LVT_TIMER 0
29#define APIC_LVT_THERMAL 1
30#define APIC_LVT_PERFORM 2
31#define APIC_LVT_LINT0 3
32#define APIC_LVT_LINT1 4
33#define APIC_LVT_ERROR 5
34#define APIC_LVT_NB 6
35
36/* APIC delivery modes */
37#define APIC_DM_FIXED 0
38#define APIC_DM_LOWPRI 1
39#define APIC_DM_SMI 2
40#define APIC_DM_NMI 4
41#define APIC_DM_INIT 5
42#define APIC_DM_SIPI 6
43#define APIC_DM_EXTINT 7
44
bellardd592d302005-07-23 19:05:37 +000045/* APIC destination mode */
46#define APIC_DESTMODE_FLAT 0xf
47#define APIC_DESTMODE_CLUSTER 1
48
bellard574bbf72005-01-03 23:27:31 +000049#define APIC_TRIGGER_EDGE 0
50#define APIC_TRIGGER_LEVEL 1
51
52#define APIC_LVT_TIMER_PERIODIC (1<<17)
53#define APIC_LVT_MASKED (1<<16)
54#define APIC_LVT_LEVEL_TRIGGER (1<<15)
55#define APIC_LVT_REMOTE_IRR (1<<14)
56#define APIC_INPUT_POLARITY (1<<13)
57#define APIC_SEND_PENDING (1<<12)
58
bellardd592d302005-07-23 19:05:37 +000059#define IOAPIC_NUM_PINS 0x18
60
bellard574bbf72005-01-03 23:27:31 +000061#define ESR_ILLEGAL_ADDRESS (1 << 7)
62
63#define APIC_SV_ENABLE (1 << 8)
64
bellardd3e9db92005-12-17 01:27:28 +000065#define MAX_APICS 255
66#define MAX_APIC_WORDS 8
67
bellard574bbf72005-01-03 23:27:31 +000068typedef struct APICState {
69 CPUState *cpu_env;
70 uint32_t apicbase;
71 uint8_t id;
bellardd592d302005-07-23 19:05:37 +000072 uint8_t arb_id;
bellard574bbf72005-01-03 23:27:31 +000073 uint8_t tpr;
74 uint32_t spurious_vec;
bellardd592d302005-07-23 19:05:37 +000075 uint8_t log_dest;
76 uint8_t dest_mode;
bellard574bbf72005-01-03 23:27:31 +000077 uint32_t isr[8]; /* in service register */
78 uint32_t tmr[8]; /* trigger mode register */
79 uint32_t irr[8]; /* interrupt request register */
80 uint32_t lvt[APIC_LVT_NB];
81 uint32_t esr; /* error register */
82 uint32_t icr[2];
83
84 uint32_t divide_conf;
85 int count_shift;
86 uint32_t initial_count;
87 int64_t initial_count_load_time, next_time;
88 QEMUTimer *timer;
89} APICState;
90
bellardd592d302005-07-23 19:05:37 +000091struct IOAPICState {
92 uint8_t id;
93 uint8_t ioregsel;
94
95 uint32_t irr;
96 uint64_t ioredtbl[IOAPIC_NUM_PINS];
97};
98
bellard574bbf72005-01-03 23:27:31 +000099static int apic_io_memory;
bellardd3e9db92005-12-17 01:27:28 +0000100static APICState *local_apics[MAX_APICS + 1];
bellardd592d302005-07-23 19:05:37 +0000101static int last_apic_id = 0;
bellardd592d302005-07-23 19:05:37 +0000102
103static void apic_init_ipi(APICState *s);
104static void apic_set_irq(APICState *s, int vector_num, int trigger_mode);
105static void apic_update_irq(APICState *s);
106
aurel32e95f5492008-10-12 00:53:17 +0000107/* Find first bit starting from msb */
bellardd3e9db92005-12-17 01:27:28 +0000108static int fls_bit(uint32_t value)
109{
aurel32e95f5492008-10-12 00:53:17 +0000110#if defined(__GNUC__)
111 return 31 - __builtin_clz(value);
112#else
bellardd3e9db92005-12-17 01:27:28 +0000113 unsigned int ret = 0;
114
bellardd3e9db92005-12-17 01:27:28 +0000115 if (value > 0xffff)
116 value >>= 16, ret = 16;
117 if (value > 0xff)
118 value >>= 8, ret += 8;
119 if (value > 0xf)
120 value >>= 4, ret += 4;
121 if (value > 0x3)
122 value >>= 2, ret += 2;
123 return ret + (value >> 1);
124#endif
125}
126
aurel32e95f5492008-10-12 00:53:17 +0000127/* Find first bit starting from lsb */
bellardd3e9db92005-12-17 01:27:28 +0000128static int ffs_bit(uint32_t value)
129{
aurel32e95f5492008-10-12 00:53:17 +0000130#if defined(__GNUC__)
131 return __builtin_ffs(value) - 1;
132#else
bellardd3e9db92005-12-17 01:27:28 +0000133 unsigned int ret = 0;
134
bellardd3e9db92005-12-17 01:27:28 +0000135 if (!value)
136 return 0;
137 if (!(value & 0xffff))
138 value >>= 16, ret = 16;
139 if (!(value & 0xff))
140 value >>= 8, ret += 8;
141 if (!(value & 0xf))
142 value >>= 4, ret += 4;
143 if (!(value & 0x3))
144 value >>= 2, ret += 2;
145 if (!(value & 0x1))
146 ret++;
147 return ret;
148#endif
149}
150
151static inline void set_bit(uint32_t *tab, int index)
152{
153 int i, mask;
154 i = index >> 5;
155 mask = 1 << (index & 0x1f);
156 tab[i] |= mask;
157}
158
159static inline void reset_bit(uint32_t *tab, int index)
160{
161 int i, mask;
162 i = index >> 5;
163 mask = 1 << (index & 0x1f);
164 tab[i] &= ~mask;
165}
166
aurel321a7de942008-08-21 03:14:52 +0000167static void apic_local_deliver(CPUState *env, int vector)
aurel32a5b38b52008-04-13 16:08:30 +0000168{
169 APICState *s = env->apic_state;
170 uint32_t lvt = s->lvt[vector];
171 int trigger_mode;
172
173 if (lvt & APIC_LVT_MASKED)
174 return;
175
176 switch ((lvt >> 8) & 7) {
177 case APIC_DM_SMI:
178 cpu_interrupt(env, CPU_INTERRUPT_SMI);
179 break;
180
181 case APIC_DM_NMI:
182 cpu_interrupt(env, CPU_INTERRUPT_NMI);
183 break;
184
185 case APIC_DM_EXTINT:
186 cpu_interrupt(env, CPU_INTERRUPT_HARD);
187 break;
188
189 case APIC_DM_FIXED:
190 trigger_mode = APIC_TRIGGER_EDGE;
191 if ((vector == APIC_LVT_LINT0 || vector == APIC_LVT_LINT1) &&
192 (lvt & APIC_LVT_LEVEL_TRIGGER))
193 trigger_mode = APIC_TRIGGER_LEVEL;
194 apic_set_irq(s, lvt & 0xff, trigger_mode);
195 }
196}
197
aurel321a7de942008-08-21 03:14:52 +0000198void apic_deliver_pic_intr(CPUState *env, int level)
199{
200 if (level)
201 apic_local_deliver(env, APIC_LVT_LINT0);
202 else {
203 APICState *s = env->apic_state;
204 uint32_t lvt = s->lvt[APIC_LVT_LINT0];
205
206 switch ((lvt >> 8) & 7) {
207 case APIC_DM_FIXED:
208 if (!(lvt & APIC_LVT_LEVEL_TRIGGER))
209 break;
210 reset_bit(s->irr, lvt & 0xff);
211 /* fall through */
212 case APIC_DM_EXTINT:
213 cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
214 break;
215 }
216 }
217}
218
bellardd3e9db92005-12-17 01:27:28 +0000219#define foreach_apic(apic, deliver_bitmask, code) \
220{\
221 int __i, __j, __mask;\
222 for(__i = 0; __i < MAX_APIC_WORDS; __i++) {\
223 __mask = deliver_bitmask[__i];\
224 if (__mask) {\
225 for(__j = 0; __j < 32; __j++) {\
226 if (__mask & (1 << __j)) {\
227 apic = local_apics[__i * 32 + __j];\
228 if (apic) {\
229 code;\
230 }\
231 }\
232 }\
233 }\
234 }\
235}
236
ths5fafdf22007-09-16 21:08:06 +0000237static void apic_bus_deliver(const uint32_t *deliver_bitmask,
bellardd3e9db92005-12-17 01:27:28 +0000238 uint8_t delivery_mode,
bellardd592d302005-07-23 19:05:37 +0000239 uint8_t vector_num, uint8_t polarity,
240 uint8_t trigger_mode)
241{
242 APICState *apic_iter;
243
244 switch (delivery_mode) {
245 case APIC_DM_LOWPRI:
bellard8dd69b82005-11-23 20:59:44 +0000246 /* XXX: search for focus processor, arbitration */
bellardd3e9db92005-12-17 01:27:28 +0000247 {
248 int i, d;
249 d = -1;
250 for(i = 0; i < MAX_APIC_WORDS; i++) {
251 if (deliver_bitmask[i]) {
252 d = i * 32 + ffs_bit(deliver_bitmask[i]);
253 break;
254 }
255 }
256 if (d >= 0) {
257 apic_iter = local_apics[d];
258 if (apic_iter) {
259 apic_set_irq(apic_iter, vector_num, trigger_mode);
260 }
261 }
bellard8dd69b82005-11-23 20:59:44 +0000262 }
bellardd3e9db92005-12-17 01:27:28 +0000263 return;
bellard8dd69b82005-11-23 20:59:44 +0000264
bellardd592d302005-07-23 19:05:37 +0000265 case APIC_DM_FIXED:
bellardd592d302005-07-23 19:05:37 +0000266 break;
267
268 case APIC_DM_SMI:
aurel32e2eb9d32008-04-13 16:08:23 +0000269 foreach_apic(apic_iter, deliver_bitmask,
270 cpu_interrupt(apic_iter->cpu_env, CPU_INTERRUPT_SMI) );
271 return;
272
bellardd592d302005-07-23 19:05:37 +0000273 case APIC_DM_NMI:
aurel32e2eb9d32008-04-13 16:08:23 +0000274 foreach_apic(apic_iter, deliver_bitmask,
275 cpu_interrupt(apic_iter->cpu_env, CPU_INTERRUPT_NMI) );
276 return;
bellardd592d302005-07-23 19:05:37 +0000277
278 case APIC_DM_INIT:
279 /* normal INIT IPI sent to processors */
ths5fafdf22007-09-16 21:08:06 +0000280 foreach_apic(apic_iter, deliver_bitmask,
bellardd3e9db92005-12-17 01:27:28 +0000281 apic_init_ipi(apic_iter) );
bellardd592d302005-07-23 19:05:37 +0000282 return;
ths3b46e622007-09-17 08:09:54 +0000283
bellardd592d302005-07-23 19:05:37 +0000284 case APIC_DM_EXTINT:
bellardb1fc0342005-07-23 21:43:15 +0000285 /* handled in I/O APIC code */
bellardd592d302005-07-23 19:05:37 +0000286 break;
287
288 default:
289 return;
290 }
291
ths5fafdf22007-09-16 21:08:06 +0000292 foreach_apic(apic_iter, deliver_bitmask,
bellardd3e9db92005-12-17 01:27:28 +0000293 apic_set_irq(apic_iter, vector_num, trigger_mode) );
bellardd592d302005-07-23 19:05:37 +0000294}
bellard574bbf72005-01-03 23:27:31 +0000295
296void cpu_set_apic_base(CPUState *env, uint64_t val)
297{
298 APICState *s = env->apic_state;
299#ifdef DEBUG_APIC
bellard26a76462006-06-25 18:15:32 +0000300 printf("cpu_set_apic_base: %016" PRIx64 "\n", val);
bellard574bbf72005-01-03 23:27:31 +0000301#endif
ths5fafdf22007-09-16 21:08:06 +0000302 s->apicbase = (val & 0xfffff000) |
bellard574bbf72005-01-03 23:27:31 +0000303 (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
304 /* if disabled, cannot be enabled again */
305 if (!(val & MSR_IA32_APICBASE_ENABLE)) {
306 s->apicbase &= ~MSR_IA32_APICBASE_ENABLE;
307 env->cpuid_features &= ~CPUID_APIC;
308 s->spurious_vec &= ~APIC_SV_ENABLE;
309 }
310}
311
312uint64_t cpu_get_apic_base(CPUState *env)
313{
314 APICState *s = env->apic_state;
315#ifdef DEBUG_APIC
bellard26a76462006-06-25 18:15:32 +0000316 printf("cpu_get_apic_base: %016" PRIx64 "\n", (uint64_t)s->apicbase);
bellard574bbf72005-01-03 23:27:31 +0000317#endif
318 return s->apicbase;
319}
320
bellard9230e662005-01-23 20:46:56 +0000321void cpu_set_apic_tpr(CPUX86State *env, uint8_t val)
322{
323 APICState *s = env->apic_state;
324 s->tpr = (val & 0x0f) << 4;
bellardd592d302005-07-23 19:05:37 +0000325 apic_update_irq(s);
bellard9230e662005-01-23 20:46:56 +0000326}
327
328uint8_t cpu_get_apic_tpr(CPUX86State *env)
329{
330 APICState *s = env->apic_state;
331 return s->tpr >> 4;
332}
333
bellardd592d302005-07-23 19:05:37 +0000334/* return -1 if no bit is set */
335static int get_highest_priority_int(uint32_t *tab)
336{
337 int i;
338 for(i = 7; i >= 0; i--) {
339 if (tab[i] != 0) {
340 return i * 32 + fls_bit(tab[i]);
341 }
342 }
343 return -1;
344}
345
bellard574bbf72005-01-03 23:27:31 +0000346static int apic_get_ppr(APICState *s)
347{
348 int tpr, isrv, ppr;
349
350 tpr = (s->tpr >> 4);
351 isrv = get_highest_priority_int(s->isr);
352 if (isrv < 0)
353 isrv = 0;
354 isrv >>= 4;
355 if (tpr >= isrv)
356 ppr = s->tpr;
357 else
358 ppr = isrv << 4;
359 return ppr;
360}
361
bellardd592d302005-07-23 19:05:37 +0000362static int apic_get_arb_pri(APICState *s)
363{
364 /* XXX: arbitration */
365 return 0;
366}
367
bellard574bbf72005-01-03 23:27:31 +0000368/* signal the CPU if an irq is pending */
369static void apic_update_irq(APICState *s)
370{
bellardd592d302005-07-23 19:05:37 +0000371 int irrv, ppr;
372 if (!(s->spurious_vec & APIC_SV_ENABLE))
373 return;
bellard574bbf72005-01-03 23:27:31 +0000374 irrv = get_highest_priority_int(s->irr);
375 if (irrv < 0)
376 return;
bellardd592d302005-07-23 19:05:37 +0000377 ppr = apic_get_ppr(s);
378 if (ppr && (irrv & 0xf0) <= (ppr & 0xf0))
bellard574bbf72005-01-03 23:27:31 +0000379 return;
380 cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
381}
382
383static void apic_set_irq(APICState *s, int vector_num, int trigger_mode)
384{
385 set_bit(s->irr, vector_num);
386 if (trigger_mode)
387 set_bit(s->tmr, vector_num);
388 else
389 reset_bit(s->tmr, vector_num);
390 apic_update_irq(s);
391}
392
393static void apic_eoi(APICState *s)
394{
395 int isrv;
396 isrv = get_highest_priority_int(s->isr);
397 if (isrv < 0)
398 return;
399 reset_bit(s->isr, isrv);
bellardd592d302005-07-23 19:05:37 +0000400 /* XXX: send the EOI packet to the APIC bus to allow the I/O APIC to
401 set the remote IRR bit for level triggered interrupts. */
bellard574bbf72005-01-03 23:27:31 +0000402 apic_update_irq(s);
403}
404
bellardd3e9db92005-12-17 01:27:28 +0000405static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
406 uint8_t dest, uint8_t dest_mode)
bellardd592d302005-07-23 19:05:37 +0000407{
bellardd592d302005-07-23 19:05:37 +0000408 APICState *apic_iter;
bellardd3e9db92005-12-17 01:27:28 +0000409 int i;
bellardd592d302005-07-23 19:05:37 +0000410
411 if (dest_mode == 0) {
bellardd3e9db92005-12-17 01:27:28 +0000412 if (dest == 0xff) {
413 memset(deliver_bitmask, 0xff, MAX_APIC_WORDS * sizeof(uint32_t));
414 } else {
415 memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t));
416 set_bit(deliver_bitmask, dest);
417 }
bellardd592d302005-07-23 19:05:37 +0000418 } else {
419 /* XXX: cluster mode */
bellardd3e9db92005-12-17 01:27:28 +0000420 memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t));
421 for(i = 0; i < MAX_APICS; i++) {
422 apic_iter = local_apics[i];
423 if (apic_iter) {
424 if (apic_iter->dest_mode == 0xf) {
425 if (dest & apic_iter->log_dest)
426 set_bit(deliver_bitmask, i);
427 } else if (apic_iter->dest_mode == 0x0) {
428 if ((dest & 0xf0) == (apic_iter->log_dest & 0xf0) &&
429 (dest & apic_iter->log_dest & 0x0f)) {
430 set_bit(deliver_bitmask, i);
431 }
432 }
433 }
bellardd592d302005-07-23 19:05:37 +0000434 }
435 }
bellardd592d302005-07-23 19:05:37 +0000436}
437
438
439static void apic_init_ipi(APICState *s)
440{
441 int i;
442
bellardd592d302005-07-23 19:05:37 +0000443 s->tpr = 0;
444 s->spurious_vec = 0xff;
445 s->log_dest = 0;
bellarde0fd8782005-11-21 23:26:26 +0000446 s->dest_mode = 0xf;
bellardd592d302005-07-23 19:05:37 +0000447 memset(s->isr, 0, sizeof(s->isr));
448 memset(s->tmr, 0, sizeof(s->tmr));
449 memset(s->irr, 0, sizeof(s->irr));
bellardb4511722006-10-08 18:20:51 +0000450 for(i = 0; i < APIC_LVT_NB; i++)
451 s->lvt[i] = 1 << 16; /* mask LVT */
bellardd592d302005-07-23 19:05:37 +0000452 s->esr = 0;
453 memset(s->icr, 0, sizeof(s->icr));
454 s->divide_conf = 0;
455 s->count_shift = 0;
456 s->initial_count = 0;
457 s->initial_count_load_time = 0;
458 s->next_time = 0;
aurel323003b8b2008-10-01 22:01:28 +0000459
460 cpu_reset(s->cpu_env);
461
462 if (!(s->apicbase & MSR_IA32_APICBASE_BSP))
463 s->cpu_env->halted = 1;
bellardd592d302005-07-23 19:05:37 +0000464}
465
bellarde0fd8782005-11-21 23:26:26 +0000466/* send a SIPI message to the CPU to start it */
467static void apic_startup(APICState *s, int vector_num)
468{
469 CPUState *env = s->cpu_env;
bellardce5232c2008-05-28 17:14:10 +0000470 if (!env->halted)
bellarde0fd8782005-11-21 23:26:26 +0000471 return;
472 env->eip = 0;
ths5fafdf22007-09-16 21:08:06 +0000473 cpu_x86_load_seg_cache(env, R_CS, vector_num << 8, vector_num << 12,
bellarde0fd8782005-11-21 23:26:26 +0000474 0xffff, 0);
bellardce5232c2008-05-28 17:14:10 +0000475 env->halted = 0;
bellarde0fd8782005-11-21 23:26:26 +0000476}
477
bellardd592d302005-07-23 19:05:37 +0000478static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode,
479 uint8_t delivery_mode, uint8_t vector_num,
480 uint8_t polarity, uint8_t trigger_mode)
481{
bellardd3e9db92005-12-17 01:27:28 +0000482 uint32_t deliver_bitmask[MAX_APIC_WORDS];
bellardd592d302005-07-23 19:05:37 +0000483 int dest_shorthand = (s->icr[0] >> 18) & 3;
484 APICState *apic_iter;
485
bellarde0fd8782005-11-21 23:26:26 +0000486 switch (dest_shorthand) {
bellardd3e9db92005-12-17 01:27:28 +0000487 case 0:
488 apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
489 break;
490 case 1:
491 memset(deliver_bitmask, 0x00, sizeof(deliver_bitmask));
492 set_bit(deliver_bitmask, s->id);
493 break;
494 case 2:
495 memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
496 break;
497 case 3:
498 memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
499 reset_bit(deliver_bitmask, s->id);
500 break;
bellarde0fd8782005-11-21 23:26:26 +0000501 }
502
bellardd592d302005-07-23 19:05:37 +0000503 switch (delivery_mode) {
bellardd592d302005-07-23 19:05:37 +0000504 case APIC_DM_INIT:
505 {
506 int trig_mode = (s->icr[0] >> 15) & 1;
507 int level = (s->icr[0] >> 14) & 1;
508 if (level == 0 && trig_mode == 1) {
ths5fafdf22007-09-16 21:08:06 +0000509 foreach_apic(apic_iter, deliver_bitmask,
bellardd3e9db92005-12-17 01:27:28 +0000510 apic_iter->arb_id = apic_iter->id );
bellardd592d302005-07-23 19:05:37 +0000511 return;
512 }
513 }
514 break;
515
516 case APIC_DM_SIPI:
ths5fafdf22007-09-16 21:08:06 +0000517 foreach_apic(apic_iter, deliver_bitmask,
bellardd3e9db92005-12-17 01:27:28 +0000518 apic_startup(apic_iter, vector_num) );
bellardd592d302005-07-23 19:05:37 +0000519 return;
520 }
521
bellardd592d302005-07-23 19:05:37 +0000522 apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, polarity,
523 trigger_mode);
524}
525
bellard574bbf72005-01-03 23:27:31 +0000526int apic_get_interrupt(CPUState *env)
527{
528 APICState *s = env->apic_state;
529 int intno;
530
531 /* if the APIC is installed or enabled, we let the 8259 handle the
532 IRQs */
533 if (!s)
534 return -1;
535 if (!(s->spurious_vec & APIC_SV_ENABLE))
536 return -1;
ths3b46e622007-09-17 08:09:54 +0000537
bellard574bbf72005-01-03 23:27:31 +0000538 /* XXX: spurious IRQ handling */
539 intno = get_highest_priority_int(s->irr);
540 if (intno < 0)
541 return -1;
bellardd592d302005-07-23 19:05:37 +0000542 if (s->tpr && intno <= s->tpr)
543 return s->spurious_vec & 0xff;
bellardb4511722006-10-08 18:20:51 +0000544 reset_bit(s->irr, intno);
bellard574bbf72005-01-03 23:27:31 +0000545 set_bit(s->isr, intno);
546 apic_update_irq(s);
547 return intno;
548}
549
ths0e21e122007-10-09 03:08:56 +0000550int apic_accept_pic_intr(CPUState *env)
551{
552 APICState *s = env->apic_state;
553 uint32_t lvt0;
554
555 if (!s)
556 return -1;
557
558 lvt0 = s->lvt[APIC_LVT_LINT0];
559
aurel32a5b38b52008-04-13 16:08:30 +0000560 if ((s->apicbase & MSR_IA32_APICBASE_ENABLE) == 0 ||
561 (lvt0 & APIC_LVT_MASKED) == 0)
ths0e21e122007-10-09 03:08:56 +0000562 return 1;
563
564 return 0;
565}
566
bellard574bbf72005-01-03 23:27:31 +0000567static uint32_t apic_get_current_count(APICState *s)
568{
569 int64_t d;
570 uint32_t val;
ths5fafdf22007-09-16 21:08:06 +0000571 d = (qemu_get_clock(vm_clock) - s->initial_count_load_time) >>
bellard574bbf72005-01-03 23:27:31 +0000572 s->count_shift;
573 if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
574 /* periodic */
bellardd592d302005-07-23 19:05:37 +0000575 val = s->initial_count - (d % ((uint64_t)s->initial_count + 1));
bellard574bbf72005-01-03 23:27:31 +0000576 } else {
577 if (d >= s->initial_count)
578 val = 0;
579 else
580 val = s->initial_count - d;
581 }
582 return val;
583}
584
585static void apic_timer_update(APICState *s, int64_t current_time)
586{
587 int64_t next_time, d;
ths3b46e622007-09-17 08:09:54 +0000588
bellard574bbf72005-01-03 23:27:31 +0000589 if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
ths5fafdf22007-09-16 21:08:06 +0000590 d = (current_time - s->initial_count_load_time) >>
bellard574bbf72005-01-03 23:27:31 +0000591 s->count_shift;
592 if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
aliguori681f8c22008-08-18 14:19:42 +0000593 if (!s->initial_count)
594 goto no_timer;
bellardd592d302005-07-23 19:05:37 +0000595 d = ((d / ((uint64_t)s->initial_count + 1)) + 1) * ((uint64_t)s->initial_count + 1);
bellard574bbf72005-01-03 23:27:31 +0000596 } else {
597 if (d >= s->initial_count)
598 goto no_timer;
bellardd592d302005-07-23 19:05:37 +0000599 d = (uint64_t)s->initial_count + 1;
bellard574bbf72005-01-03 23:27:31 +0000600 }
601 next_time = s->initial_count_load_time + (d << s->count_shift);
602 qemu_mod_timer(s->timer, next_time);
603 s->next_time = next_time;
604 } else {
605 no_timer:
606 qemu_del_timer(s->timer);
607 }
608}
609
610static void apic_timer(void *opaque)
611{
612 APICState *s = opaque;
613
aurel32a5b38b52008-04-13 16:08:30 +0000614 apic_local_deliver(s->cpu_env, APIC_LVT_TIMER);
bellard574bbf72005-01-03 23:27:31 +0000615 apic_timer_update(s, s->next_time);
616}
617
618static uint32_t apic_mem_readb(void *opaque, target_phys_addr_t addr)
619{
620 return 0;
621}
622
623static uint32_t apic_mem_readw(void *opaque, target_phys_addr_t addr)
624{
625 return 0;
626}
627
628static void apic_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
629{
630}
631
632static void apic_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
633{
634}
635
636static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
637{
638 CPUState *env;
639 APICState *s;
640 uint32_t val;
641 int index;
642
643 env = cpu_single_env;
644 if (!env)
645 return 0;
646 s = env->apic_state;
647
648 index = (addr >> 4) & 0xff;
649 switch(index) {
650 case 0x02: /* id */
651 val = s->id << 24;
652 break;
653 case 0x03: /* version */
654 val = 0x11 | ((APIC_LVT_NB - 1) << 16); /* version 0x11 */
655 break;
656 case 0x08:
657 val = s->tpr;
658 break;
bellardd592d302005-07-23 19:05:37 +0000659 case 0x09:
660 val = apic_get_arb_pri(s);
661 break;
bellard574bbf72005-01-03 23:27:31 +0000662 case 0x0a:
663 /* ppr */
664 val = apic_get_ppr(s);
665 break;
aurel32b237db32008-03-28 22:31:36 +0000666 case 0x0b:
667 val = 0;
668 break;
bellardd592d302005-07-23 19:05:37 +0000669 case 0x0d:
670 val = s->log_dest << 24;
671 break;
672 case 0x0e:
673 val = s->dest_mode << 28;
674 break;
bellard574bbf72005-01-03 23:27:31 +0000675 case 0x0f:
676 val = s->spurious_vec;
677 break;
678 case 0x10 ... 0x17:
679 val = s->isr[index & 7];
680 break;
681 case 0x18 ... 0x1f:
682 val = s->tmr[index & 7];
683 break;
684 case 0x20 ... 0x27:
685 val = s->irr[index & 7];
686 break;
687 case 0x28:
688 val = s->esr;
689 break;
bellard574bbf72005-01-03 23:27:31 +0000690 case 0x30:
691 case 0x31:
692 val = s->icr[index & 1];
693 break;
bellarde0fd8782005-11-21 23:26:26 +0000694 case 0x32 ... 0x37:
695 val = s->lvt[index - 0x32];
696 break;
bellard574bbf72005-01-03 23:27:31 +0000697 case 0x38:
698 val = s->initial_count;
699 break;
700 case 0x39:
701 val = apic_get_current_count(s);
702 break;
703 case 0x3e:
704 val = s->divide_conf;
705 break;
706 default:
707 s->esr |= ESR_ILLEGAL_ADDRESS;
708 val = 0;
709 break;
710 }
711#ifdef DEBUG_APIC
712 printf("APIC read: %08x = %08x\n", (uint32_t)addr, val);
713#endif
714 return val;
715}
716
717static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
718{
719 CPUState *env;
720 APICState *s;
721 int index;
722
723 env = cpu_single_env;
724 if (!env)
725 return;
726 s = env->apic_state;
727
728#ifdef DEBUG_APIC
729 printf("APIC write: %08x = %08x\n", (uint32_t)addr, val);
730#endif
731
732 index = (addr >> 4) & 0xff;
733 switch(index) {
734 case 0x02:
735 s->id = (val >> 24);
736 break;
bellarde0fd8782005-11-21 23:26:26 +0000737 case 0x03:
738 break;
bellard574bbf72005-01-03 23:27:31 +0000739 case 0x08:
740 s->tpr = val;
bellardd592d302005-07-23 19:05:37 +0000741 apic_update_irq(s);
bellard574bbf72005-01-03 23:27:31 +0000742 break;
bellarde0fd8782005-11-21 23:26:26 +0000743 case 0x09:
744 case 0x0a:
745 break;
bellard574bbf72005-01-03 23:27:31 +0000746 case 0x0b: /* EOI */
747 apic_eoi(s);
748 break;
bellardd592d302005-07-23 19:05:37 +0000749 case 0x0d:
750 s->log_dest = val >> 24;
751 break;
752 case 0x0e:
753 s->dest_mode = val >> 28;
754 break;
bellard574bbf72005-01-03 23:27:31 +0000755 case 0x0f:
756 s->spurious_vec = val & 0x1ff;
bellardd592d302005-07-23 19:05:37 +0000757 apic_update_irq(s);
bellard574bbf72005-01-03 23:27:31 +0000758 break;
bellarde0fd8782005-11-21 23:26:26 +0000759 case 0x10 ... 0x17:
760 case 0x18 ... 0x1f:
761 case 0x20 ... 0x27:
762 case 0x28:
763 break;
bellard574bbf72005-01-03 23:27:31 +0000764 case 0x30:
bellardd592d302005-07-23 19:05:37 +0000765 s->icr[0] = val;
766 apic_deliver(s, (s->icr[1] >> 24) & 0xff, (s->icr[0] >> 11) & 1,
767 (s->icr[0] >> 8) & 7, (s->icr[0] & 0xff),
768 (s->icr[0] >> 14) & 1, (s->icr[0] >> 15) & 1);
769 break;
bellard574bbf72005-01-03 23:27:31 +0000770 case 0x31:
bellardd592d302005-07-23 19:05:37 +0000771 s->icr[1] = val;
bellard574bbf72005-01-03 23:27:31 +0000772 break;
773 case 0x32 ... 0x37:
774 {
775 int n = index - 0x32;
776 s->lvt[n] = val;
777 if (n == APIC_LVT_TIMER)
778 apic_timer_update(s, qemu_get_clock(vm_clock));
779 }
780 break;
781 case 0x38:
782 s->initial_count = val;
783 s->initial_count_load_time = qemu_get_clock(vm_clock);
784 apic_timer_update(s, s->initial_count_load_time);
785 break;
bellarde0fd8782005-11-21 23:26:26 +0000786 case 0x39:
787 break;
bellard574bbf72005-01-03 23:27:31 +0000788 case 0x3e:
789 {
790 int v;
791 s->divide_conf = val & 0xb;
792 v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
793 s->count_shift = (v + 1) & 7;
794 }
795 break;
796 default:
797 s->esr |= ESR_ILLEGAL_ADDRESS;
798 break;
799 }
800}
801
bellardd592d302005-07-23 19:05:37 +0000802static void apic_save(QEMUFile *f, void *opaque)
803{
804 APICState *s = opaque;
805 int i;
bellard574bbf72005-01-03 23:27:31 +0000806
bellardd592d302005-07-23 19:05:37 +0000807 qemu_put_be32s(f, &s->apicbase);
808 qemu_put_8s(f, &s->id);
809 qemu_put_8s(f, &s->arb_id);
810 qemu_put_8s(f, &s->tpr);
811 qemu_put_be32s(f, &s->spurious_vec);
812 qemu_put_8s(f, &s->log_dest);
813 qemu_put_8s(f, &s->dest_mode);
814 for (i = 0; i < 8; i++) {
815 qemu_put_be32s(f, &s->isr[i]);
816 qemu_put_be32s(f, &s->tmr[i]);
817 qemu_put_be32s(f, &s->irr[i]);
818 }
819 for (i = 0; i < APIC_LVT_NB; i++) {
820 qemu_put_be32s(f, &s->lvt[i]);
821 }
822 qemu_put_be32s(f, &s->esr);
823 qemu_put_be32s(f, &s->icr[0]);
824 qemu_put_be32s(f, &s->icr[1]);
825 qemu_put_be32s(f, &s->divide_conf);
thsbee8d682007-12-16 23:41:11 +0000826 qemu_put_be32(f, s->count_shift);
bellardd592d302005-07-23 19:05:37 +0000827 qemu_put_be32s(f, &s->initial_count);
thsbee8d682007-12-16 23:41:11 +0000828 qemu_put_be64(f, s->initial_count_load_time);
829 qemu_put_be64(f, s->next_time);
bellarde6cf6a82006-08-17 10:48:06 +0000830
831 qemu_put_timer(f, s->timer);
bellardd592d302005-07-23 19:05:37 +0000832}
833
834static int apic_load(QEMUFile *f, void *opaque, int version_id)
835{
836 APICState *s = opaque;
837 int i;
838
bellarde6cf6a82006-08-17 10:48:06 +0000839 if (version_id > 2)
bellardd592d302005-07-23 19:05:37 +0000840 return -EINVAL;
841
842 /* XXX: what if the base changes? (registered memory regions) */
843 qemu_get_be32s(f, &s->apicbase);
844 qemu_get_8s(f, &s->id);
845 qemu_get_8s(f, &s->arb_id);
846 qemu_get_8s(f, &s->tpr);
847 qemu_get_be32s(f, &s->spurious_vec);
848 qemu_get_8s(f, &s->log_dest);
849 qemu_get_8s(f, &s->dest_mode);
850 for (i = 0; i < 8; i++) {
851 qemu_get_be32s(f, &s->isr[i]);
852 qemu_get_be32s(f, &s->tmr[i]);
853 qemu_get_be32s(f, &s->irr[i]);
854 }
855 for (i = 0; i < APIC_LVT_NB; i++) {
856 qemu_get_be32s(f, &s->lvt[i]);
857 }
858 qemu_get_be32s(f, &s->esr);
859 qemu_get_be32s(f, &s->icr[0]);
860 qemu_get_be32s(f, &s->icr[1]);
861 qemu_get_be32s(f, &s->divide_conf);
thsbee8d682007-12-16 23:41:11 +0000862 s->count_shift=qemu_get_be32(f);
bellardd592d302005-07-23 19:05:37 +0000863 qemu_get_be32s(f, &s->initial_count);
thsbee8d682007-12-16 23:41:11 +0000864 s->initial_count_load_time=qemu_get_be64(f);
865 s->next_time=qemu_get_be64(f);
bellarde6cf6a82006-08-17 10:48:06 +0000866
867 if (version_id >= 2)
868 qemu_get_timer(f, s->timer);
bellardd592d302005-07-23 19:05:37 +0000869 return 0;
870}
871
872static void apic_reset(void *opaque)
873{
874 APICState *s = opaque;
aurel32fec5fa02008-09-02 00:09:08 +0000875
876 s->apicbase = 0xfee00000 |
877 (s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE;
878
bellardd592d302005-07-23 19:05:37 +0000879 apic_init_ipi(s);
ths0e21e122007-10-09 03:08:56 +0000880
aurel32a5b38b52008-04-13 16:08:30 +0000881 if (s->id == 0) {
882 /*
883 * LINT0 delivery mode on CPU #0 is set to ExtInt at initialization
884 * time typically by BIOS, so PIC interrupt can be delivered to the
885 * processor when local APIC is enabled.
886 */
887 s->lvt[APIC_LVT_LINT0] = 0x700;
888 }
bellardd592d302005-07-23 19:05:37 +0000889}
bellard574bbf72005-01-03 23:27:31 +0000890
891static CPUReadMemoryFunc *apic_mem_read[3] = {
892 apic_mem_readb,
893 apic_mem_readw,
894 apic_mem_readl,
895};
896
897static CPUWriteMemoryFunc *apic_mem_write[3] = {
898 apic_mem_writeb,
899 apic_mem_writew,
900 apic_mem_writel,
901};
902
903int apic_init(CPUState *env)
904{
905 APICState *s;
bellard574bbf72005-01-03 23:27:31 +0000906
bellardd3e9db92005-12-17 01:27:28 +0000907 if (last_apic_id >= MAX_APICS)
908 return -1;
bellardd592d302005-07-23 19:05:37 +0000909 s = qemu_mallocz(sizeof(APICState));
bellard574bbf72005-01-03 23:27:31 +0000910 if (!s)
911 return -1;
bellard574bbf72005-01-03 23:27:31 +0000912 env->apic_state = s;
bellardd592d302005-07-23 19:05:37 +0000913 s->id = last_apic_id++;
thseae76292007-04-03 16:38:34 +0000914 env->cpuid_apic_id = s->id;
bellard574bbf72005-01-03 23:27:31 +0000915 s->cpu_env = env;
bellard574bbf72005-01-03 23:27:31 +0000916
aurel32a5b38b52008-04-13 16:08:30 +0000917 apic_reset(s);
ths0e21e122007-10-09 03:08:56 +0000918
bellardd592d302005-07-23 19:05:37 +0000919 /* XXX: mapping more APICs at the same memory location */
bellard574bbf72005-01-03 23:27:31 +0000920 if (apic_io_memory == 0) {
921 /* NOTE: the APIC is directly connected to the CPU - it is not
922 on the global memory bus. */
ths5fafdf22007-09-16 21:08:06 +0000923 apic_io_memory = cpu_register_io_memory(0, apic_mem_read,
bellard574bbf72005-01-03 23:27:31 +0000924 apic_mem_write, NULL);
bellardd592d302005-07-23 19:05:37 +0000925 cpu_register_physical_memory(s->apicbase & ~0xfff, 0x1000,
926 apic_io_memory);
bellard574bbf72005-01-03 23:27:31 +0000927 }
928 s->timer = qemu_new_timer(vm_clock, apic_timer, s);
bellardd592d302005-07-23 19:05:37 +0000929
thsbe0164f2007-08-26 17:33:08 +0000930 register_savevm("apic", s->id, 2, apic_save, apic_load, s);
bellardd592d302005-07-23 19:05:37 +0000931 qemu_register_reset(apic_reset, s);
ths3b46e622007-09-17 08:09:54 +0000932
bellardd3e9db92005-12-17 01:27:28 +0000933 local_apics[s->id] = s;
bellard574bbf72005-01-03 23:27:31 +0000934 return 0;
935}
bellardd592d302005-07-23 19:05:37 +0000936
937static void ioapic_service(IOAPICState *s)
938{
bellardb1fc0342005-07-23 21:43:15 +0000939 uint8_t i;
940 uint8_t trig_mode;
bellardd592d302005-07-23 19:05:37 +0000941 uint8_t vector;
bellardb1fc0342005-07-23 21:43:15 +0000942 uint8_t delivery_mode;
bellardd592d302005-07-23 19:05:37 +0000943 uint32_t mask;
944 uint64_t entry;
945 uint8_t dest;
946 uint8_t dest_mode;
bellardb1fc0342005-07-23 21:43:15 +0000947 uint8_t polarity;
bellardd3e9db92005-12-17 01:27:28 +0000948 uint32_t deliver_bitmask[MAX_APIC_WORDS];
bellardd592d302005-07-23 19:05:37 +0000949
bellardb1fc0342005-07-23 21:43:15 +0000950 for (i = 0; i < IOAPIC_NUM_PINS; i++) {
951 mask = 1 << i;
bellardd592d302005-07-23 19:05:37 +0000952 if (s->irr & mask) {
bellardb1fc0342005-07-23 21:43:15 +0000953 entry = s->ioredtbl[i];
bellardd592d302005-07-23 19:05:37 +0000954 if (!(entry & APIC_LVT_MASKED)) {
bellardb1fc0342005-07-23 21:43:15 +0000955 trig_mode = ((entry >> 15) & 1);
bellardd592d302005-07-23 19:05:37 +0000956 dest = entry >> 56;
957 dest_mode = (entry >> 11) & 1;
bellardb1fc0342005-07-23 21:43:15 +0000958 delivery_mode = (entry >> 8) & 7;
959 polarity = (entry >> 13) & 1;
960 if (trig_mode == APIC_TRIGGER_EDGE)
961 s->irr &= ~mask;
962 if (delivery_mode == APIC_DM_EXTINT)
963 vector = pic_read_irq(isa_pic);
964 else
965 vector = entry & 0xff;
ths3b46e622007-09-17 08:09:54 +0000966
bellardd3e9db92005-12-17 01:27:28 +0000967 apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
ths5fafdf22007-09-16 21:08:06 +0000968 apic_bus_deliver(deliver_bitmask, delivery_mode,
bellardd3e9db92005-12-17 01:27:28 +0000969 vector, polarity, trig_mode);
bellardd592d302005-07-23 19:05:37 +0000970 }
971 }
972 }
973}
974
975void ioapic_set_irq(void *opaque, int vector, int level)
976{
977 IOAPICState *s = opaque;
978
979 if (vector >= 0 && vector < IOAPIC_NUM_PINS) {
980 uint32_t mask = 1 << vector;
981 uint64_t entry = s->ioredtbl[vector];
982
983 if ((entry >> 15) & 1) {
984 /* level triggered */
985 if (level) {
986 s->irr |= mask;
987 ioapic_service(s);
988 } else {
989 s->irr &= ~mask;
990 }
991 } else {
992 /* edge triggered */
993 if (level) {
994 s->irr |= mask;
995 ioapic_service(s);
996 }
997 }
998 }
999}
1000
1001static uint32_t ioapic_mem_readl(void *opaque, target_phys_addr_t addr)
1002{
1003 IOAPICState *s = opaque;
1004 int index;
1005 uint32_t val = 0;
1006
1007 addr &= 0xff;
1008 if (addr == 0x00) {
1009 val = s->ioregsel;
1010 } else if (addr == 0x10) {
1011 switch (s->ioregsel) {
1012 case 0x00:
1013 val = s->id << 24;
1014 break;
1015 case 0x01:
1016 val = 0x11 | ((IOAPIC_NUM_PINS - 1) << 16); /* version 0x11 */
1017 break;
1018 case 0x02:
1019 val = 0;
1020 break;
1021 default:
1022 index = (s->ioregsel - 0x10) >> 1;
1023 if (index >= 0 && index < IOAPIC_NUM_PINS) {
1024 if (s->ioregsel & 1)
1025 val = s->ioredtbl[index] >> 32;
1026 else
1027 val = s->ioredtbl[index] & 0xffffffff;
1028 }
1029 }
1030#ifdef DEBUG_IOAPIC
1031 printf("I/O APIC read: %08x = %08x\n", s->ioregsel, val);
1032#endif
1033 }
1034 return val;
1035}
1036
1037static void ioapic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
1038{
1039 IOAPICState *s = opaque;
1040 int index;
1041
1042 addr &= 0xff;
1043 if (addr == 0x00) {
1044 s->ioregsel = val;
1045 return;
1046 } else if (addr == 0x10) {
1047#ifdef DEBUG_IOAPIC
1048 printf("I/O APIC write: %08x = %08x\n", s->ioregsel, val);
1049#endif
1050 switch (s->ioregsel) {
1051 case 0x00:
1052 s->id = (val >> 24) & 0xff;
1053 return;
1054 case 0x01:
1055 case 0x02:
1056 return;
1057 default:
1058 index = (s->ioregsel - 0x10) >> 1;
1059 if (index >= 0 && index < IOAPIC_NUM_PINS) {
1060 if (s->ioregsel & 1) {
1061 s->ioredtbl[index] &= 0xffffffff;
1062 s->ioredtbl[index] |= (uint64_t)val << 32;
1063 } else {
1064 s->ioredtbl[index] &= ~0xffffffffULL;
1065 s->ioredtbl[index] |= val;
1066 }
1067 ioapic_service(s);
1068 }
1069 }
1070 }
1071}
1072
1073static void ioapic_save(QEMUFile *f, void *opaque)
1074{
1075 IOAPICState *s = opaque;
1076 int i;
1077
1078 qemu_put_8s(f, &s->id);
1079 qemu_put_8s(f, &s->ioregsel);
1080 for (i = 0; i < IOAPIC_NUM_PINS; i++) {
1081 qemu_put_be64s(f, &s->ioredtbl[i]);
1082 }
1083}
1084
1085static int ioapic_load(QEMUFile *f, void *opaque, int version_id)
1086{
1087 IOAPICState *s = opaque;
1088 int i;
1089
1090 if (version_id != 1)
1091 return -EINVAL;
1092
1093 qemu_get_8s(f, &s->id);
1094 qemu_get_8s(f, &s->ioregsel);
1095 for (i = 0; i < IOAPIC_NUM_PINS; i++) {
1096 qemu_get_be64s(f, &s->ioredtbl[i]);
1097 }
1098 return 0;
1099}
1100
1101static void ioapic_reset(void *opaque)
1102{
1103 IOAPICState *s = opaque;
1104 int i;
1105
1106 memset(s, 0, sizeof(*s));
1107 for(i = 0; i < IOAPIC_NUM_PINS; i++)
1108 s->ioredtbl[i] = 1 << 16; /* mask LVT */
1109}
1110
1111static CPUReadMemoryFunc *ioapic_mem_read[3] = {
1112 ioapic_mem_readl,
1113 ioapic_mem_readl,
1114 ioapic_mem_readl,
1115};
1116
1117static CPUWriteMemoryFunc *ioapic_mem_write[3] = {
1118 ioapic_mem_writel,
1119 ioapic_mem_writel,
1120 ioapic_mem_writel,
1121};
1122
1123IOAPICState *ioapic_init(void)
1124{
1125 IOAPICState *s;
1126 int io_memory;
1127
bellardb1fc0342005-07-23 21:43:15 +00001128 s = qemu_mallocz(sizeof(IOAPICState));
bellardd592d302005-07-23 19:05:37 +00001129 if (!s)
1130 return NULL;
bellardd592d302005-07-23 19:05:37 +00001131 ioapic_reset(s);
1132 s->id = last_apic_id++;
1133
ths5fafdf22007-09-16 21:08:06 +00001134 io_memory = cpu_register_io_memory(0, ioapic_mem_read,
bellardd592d302005-07-23 19:05:37 +00001135 ioapic_mem_write, s);
1136 cpu_register_physical_memory(0xfec00000, 0x1000, io_memory);
1137
1138 register_savevm("ioapic", 0, 1, ioapic_save, ioapic_load, s);
1139 qemu_register_reset(ioapic_reset, s);
ths3b46e622007-09-17 08:09:54 +00001140
bellardd592d302005-07-23 19:05:37 +00001141 return s;
1142}