blob: 3052843c87946e280466a7f01e24a671feac9c92 [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
aurel32fad6cb12009-01-04 22:05:52 +000018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
bellard574bbf72005-01-03 23:27:31 +000019 */
pbrook87ecb682007-11-17 17:14:51 +000020#include "hw.h"
21#include "pc.h"
22#include "qemu-timer.h"
aurel32bb7e7292008-10-12 20:16:03 +000023#include "host-utils.h"
bellard574bbf72005-01-03 23:27:31 +000024
25//#define DEBUG_APIC
bellardd592d302005-07-23 19:05:37 +000026//#define DEBUG_IOAPIC
bellard574bbf72005-01-03 23:27:31 +000027
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
bellardd592d302005-07-23 19:05:37 +000046/* APIC destination mode */
47#define APIC_DESTMODE_FLAT 0xf
48#define APIC_DESTMODE_CLUSTER 1
49
bellard574bbf72005-01-03 23:27:31 +000050#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
bellardd592d302005-07-23 19:05:37 +000060#define IOAPIC_NUM_PINS 0x18
61
bellard574bbf72005-01-03 23:27:31 +000062#define ESR_ILLEGAL_ADDRESS (1 << 7)
63
64#define APIC_SV_ENABLE (1 << 8)
65
bellardd3e9db92005-12-17 01:27:28 +000066#define MAX_APICS 255
67#define MAX_APIC_WORDS 8
68
bellard574bbf72005-01-03 23:27:31 +000069typedef struct APICState {
70 CPUState *cpu_env;
71 uint32_t apicbase;
72 uint8_t id;
bellardd592d302005-07-23 19:05:37 +000073 uint8_t arb_id;
bellard574bbf72005-01-03 23:27:31 +000074 uint8_t tpr;
75 uint32_t spurious_vec;
bellardd592d302005-07-23 19:05:37 +000076 uint8_t log_dest;
77 uint8_t dest_mode;
bellard574bbf72005-01-03 23:27:31 +000078 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
bellardd592d302005-07-23 19:05:37 +000092struct IOAPICState {
93 uint8_t id;
94 uint8_t ioregsel;
95
96 uint32_t irr;
97 uint64_t ioredtbl[IOAPIC_NUM_PINS];
98};
99
bellard574bbf72005-01-03 23:27:31 +0000100static int apic_io_memory;
bellardd3e9db92005-12-17 01:27:28 +0000101static APICState *local_apics[MAX_APICS + 1];
bellardd592d302005-07-23 19:05:37 +0000102static int last_apic_id = 0;
aliguori73822ec2009-01-15 20:11:34 +0000103static int apic_irq_delivered;
104
bellardd592d302005-07-23 19:05:37 +0000105
106static void apic_init_ipi(APICState *s);
107static void apic_set_irq(APICState *s, int vector_num, int trigger_mode);
108static void apic_update_irq(APICState *s);
109
aurel323b63c042008-12-06 10:46:35 +0000110/* Find first bit starting from msb */
111static int fls_bit(uint32_t value)
112{
113 return 31 - clz32(value);
114}
115
aurel32e95f5492008-10-12 00:53:17 +0000116/* Find first bit starting from lsb */
bellardd3e9db92005-12-17 01:27:28 +0000117static int ffs_bit(uint32_t value)
118{
aurel32bb7e7292008-10-12 20:16:03 +0000119 return ctz32(value);
bellardd3e9db92005-12-17 01:27:28 +0000120}
121
122static inline void set_bit(uint32_t *tab, int index)
123{
124 int i, mask;
125 i = index >> 5;
126 mask = 1 << (index & 0x1f);
127 tab[i] |= mask;
128}
129
130static inline void reset_bit(uint32_t *tab, int index)
131{
132 int i, mask;
133 i = index >> 5;
134 mask = 1 << (index & 0x1f);
135 tab[i] &= ~mask;
136}
137
aliguori73822ec2009-01-15 20:11:34 +0000138static inline int get_bit(uint32_t *tab, int index)
139{
140 int i, mask;
141 i = index >> 5;
142 mask = 1 << (index & 0x1f);
143 return !!(tab[i] & mask);
144}
145
aurel321a7de942008-08-21 03:14:52 +0000146static void apic_local_deliver(CPUState *env, int vector)
aurel32a5b38b52008-04-13 16:08:30 +0000147{
148 APICState *s = env->apic_state;
149 uint32_t lvt = s->lvt[vector];
150 int trigger_mode;
151
152 if (lvt & APIC_LVT_MASKED)
153 return;
154
155 switch ((lvt >> 8) & 7) {
156 case APIC_DM_SMI:
157 cpu_interrupt(env, CPU_INTERRUPT_SMI);
158 break;
159
160 case APIC_DM_NMI:
161 cpu_interrupt(env, CPU_INTERRUPT_NMI);
162 break;
163
164 case APIC_DM_EXTINT:
165 cpu_interrupt(env, CPU_INTERRUPT_HARD);
166 break;
167
168 case APIC_DM_FIXED:
169 trigger_mode = APIC_TRIGGER_EDGE;
170 if ((vector == APIC_LVT_LINT0 || vector == APIC_LVT_LINT1) &&
171 (lvt & APIC_LVT_LEVEL_TRIGGER))
172 trigger_mode = APIC_TRIGGER_LEVEL;
173 apic_set_irq(s, lvt & 0xff, trigger_mode);
174 }
175}
176
aurel321a7de942008-08-21 03:14:52 +0000177void apic_deliver_pic_intr(CPUState *env, int level)
178{
179 if (level)
180 apic_local_deliver(env, APIC_LVT_LINT0);
181 else {
182 APICState *s = env->apic_state;
183 uint32_t lvt = s->lvt[APIC_LVT_LINT0];
184
185 switch ((lvt >> 8) & 7) {
186 case APIC_DM_FIXED:
187 if (!(lvt & APIC_LVT_LEVEL_TRIGGER))
188 break;
189 reset_bit(s->irr, lvt & 0xff);
190 /* fall through */
191 case APIC_DM_EXTINT:
192 cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
193 break;
194 }
195 }
196}
197
bellardd3e9db92005-12-17 01:27:28 +0000198#define foreach_apic(apic, deliver_bitmask, code) \
199{\
200 int __i, __j, __mask;\
201 for(__i = 0; __i < MAX_APIC_WORDS; __i++) {\
202 __mask = deliver_bitmask[__i];\
203 if (__mask) {\
204 for(__j = 0; __j < 32; __j++) {\
205 if (__mask & (1 << __j)) {\
206 apic = local_apics[__i * 32 + __j];\
207 if (apic) {\
208 code;\
209 }\
210 }\
211 }\
212 }\
213 }\
214}
215
ths5fafdf22007-09-16 21:08:06 +0000216static void apic_bus_deliver(const uint32_t *deliver_bitmask,
bellardd3e9db92005-12-17 01:27:28 +0000217 uint8_t delivery_mode,
bellardd592d302005-07-23 19:05:37 +0000218 uint8_t vector_num, uint8_t polarity,
219 uint8_t trigger_mode)
220{
221 APICState *apic_iter;
222
223 switch (delivery_mode) {
224 case APIC_DM_LOWPRI:
bellard8dd69b82005-11-23 20:59:44 +0000225 /* XXX: search for focus processor, arbitration */
bellardd3e9db92005-12-17 01:27:28 +0000226 {
227 int i, d;
228 d = -1;
229 for(i = 0; i < MAX_APIC_WORDS; i++) {
230 if (deliver_bitmask[i]) {
231 d = i * 32 + ffs_bit(deliver_bitmask[i]);
232 break;
233 }
234 }
235 if (d >= 0) {
236 apic_iter = local_apics[d];
237 if (apic_iter) {
238 apic_set_irq(apic_iter, vector_num, trigger_mode);
239 }
240 }
bellard8dd69b82005-11-23 20:59:44 +0000241 }
bellardd3e9db92005-12-17 01:27:28 +0000242 return;
bellard8dd69b82005-11-23 20:59:44 +0000243
bellardd592d302005-07-23 19:05:37 +0000244 case APIC_DM_FIXED:
bellardd592d302005-07-23 19:05:37 +0000245 break;
246
247 case APIC_DM_SMI:
aurel32e2eb9d32008-04-13 16:08:23 +0000248 foreach_apic(apic_iter, deliver_bitmask,
249 cpu_interrupt(apic_iter->cpu_env, CPU_INTERRUPT_SMI) );
250 return;
251
bellardd592d302005-07-23 19:05:37 +0000252 case APIC_DM_NMI:
aurel32e2eb9d32008-04-13 16:08:23 +0000253 foreach_apic(apic_iter, deliver_bitmask,
254 cpu_interrupt(apic_iter->cpu_env, CPU_INTERRUPT_NMI) );
255 return;
bellardd592d302005-07-23 19:05:37 +0000256
257 case APIC_DM_INIT:
258 /* normal INIT IPI sent to processors */
ths5fafdf22007-09-16 21:08:06 +0000259 foreach_apic(apic_iter, deliver_bitmask,
bellardd3e9db92005-12-17 01:27:28 +0000260 apic_init_ipi(apic_iter) );
bellardd592d302005-07-23 19:05:37 +0000261 return;
ths3b46e622007-09-17 08:09:54 +0000262
bellardd592d302005-07-23 19:05:37 +0000263 case APIC_DM_EXTINT:
bellardb1fc0342005-07-23 21:43:15 +0000264 /* handled in I/O APIC code */
bellardd592d302005-07-23 19:05:37 +0000265 break;
266
267 default:
268 return;
269 }
270
ths5fafdf22007-09-16 21:08:06 +0000271 foreach_apic(apic_iter, deliver_bitmask,
bellardd3e9db92005-12-17 01:27:28 +0000272 apic_set_irq(apic_iter, vector_num, trigger_mode) );
bellardd592d302005-07-23 19:05:37 +0000273}
bellard574bbf72005-01-03 23:27:31 +0000274
275void cpu_set_apic_base(CPUState *env, uint64_t val)
276{
277 APICState *s = env->apic_state;
278#ifdef DEBUG_APIC
bellard26a76462006-06-25 18:15:32 +0000279 printf("cpu_set_apic_base: %016" PRIx64 "\n", val);
bellard574bbf72005-01-03 23:27:31 +0000280#endif
ths5fafdf22007-09-16 21:08:06 +0000281 s->apicbase = (val & 0xfffff000) |
bellard574bbf72005-01-03 23:27:31 +0000282 (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
283 /* if disabled, cannot be enabled again */
284 if (!(val & MSR_IA32_APICBASE_ENABLE)) {
285 s->apicbase &= ~MSR_IA32_APICBASE_ENABLE;
286 env->cpuid_features &= ~CPUID_APIC;
287 s->spurious_vec &= ~APIC_SV_ENABLE;
288 }
289}
290
291uint64_t cpu_get_apic_base(CPUState *env)
292{
293 APICState *s = env->apic_state;
294#ifdef DEBUG_APIC
bellard26a76462006-06-25 18:15:32 +0000295 printf("cpu_get_apic_base: %016" PRIx64 "\n", (uint64_t)s->apicbase);
bellard574bbf72005-01-03 23:27:31 +0000296#endif
297 return s->apicbase;
298}
299
bellard9230e662005-01-23 20:46:56 +0000300void cpu_set_apic_tpr(CPUX86State *env, uint8_t val)
301{
302 APICState *s = env->apic_state;
303 s->tpr = (val & 0x0f) << 4;
bellardd592d302005-07-23 19:05:37 +0000304 apic_update_irq(s);
bellard9230e662005-01-23 20:46:56 +0000305}
306
307uint8_t cpu_get_apic_tpr(CPUX86State *env)
308{
309 APICState *s = env->apic_state;
310 return s->tpr >> 4;
311}
312
bellardd592d302005-07-23 19:05:37 +0000313/* return -1 if no bit is set */
314static int get_highest_priority_int(uint32_t *tab)
315{
316 int i;
317 for(i = 7; i >= 0; i--) {
318 if (tab[i] != 0) {
aurel323b63c042008-12-06 10:46:35 +0000319 return i * 32 + fls_bit(tab[i]);
bellardd592d302005-07-23 19:05:37 +0000320 }
321 }
322 return -1;
323}
324
bellard574bbf72005-01-03 23:27:31 +0000325static int apic_get_ppr(APICState *s)
326{
327 int tpr, isrv, ppr;
328
329 tpr = (s->tpr >> 4);
330 isrv = get_highest_priority_int(s->isr);
331 if (isrv < 0)
332 isrv = 0;
333 isrv >>= 4;
334 if (tpr >= isrv)
335 ppr = s->tpr;
336 else
337 ppr = isrv << 4;
338 return ppr;
339}
340
bellardd592d302005-07-23 19:05:37 +0000341static int apic_get_arb_pri(APICState *s)
342{
343 /* XXX: arbitration */
344 return 0;
345}
346
bellard574bbf72005-01-03 23:27:31 +0000347/* signal the CPU if an irq is pending */
348static void apic_update_irq(APICState *s)
349{
bellardd592d302005-07-23 19:05:37 +0000350 int irrv, ppr;
351 if (!(s->spurious_vec & APIC_SV_ENABLE))
352 return;
bellard574bbf72005-01-03 23:27:31 +0000353 irrv = get_highest_priority_int(s->irr);
354 if (irrv < 0)
355 return;
bellardd592d302005-07-23 19:05:37 +0000356 ppr = apic_get_ppr(s);
357 if (ppr && (irrv & 0xf0) <= (ppr & 0xf0))
bellard574bbf72005-01-03 23:27:31 +0000358 return;
359 cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
360}
361
aliguori73822ec2009-01-15 20:11:34 +0000362void apic_reset_irq_delivered(void)
363{
364 apic_irq_delivered = 0;
365}
366
367int apic_get_irq_delivered(void)
368{
369 return apic_irq_delivered;
370}
371
bellard574bbf72005-01-03 23:27:31 +0000372static void apic_set_irq(APICState *s, int vector_num, int trigger_mode)
373{
aliguori73822ec2009-01-15 20:11:34 +0000374 apic_irq_delivered += !get_bit(s->irr, vector_num);
375
bellard574bbf72005-01-03 23:27:31 +0000376 set_bit(s->irr, vector_num);
377 if (trigger_mode)
378 set_bit(s->tmr, vector_num);
379 else
380 reset_bit(s->tmr, vector_num);
381 apic_update_irq(s);
382}
383
384static void apic_eoi(APICState *s)
385{
386 int isrv;
387 isrv = get_highest_priority_int(s->isr);
388 if (isrv < 0)
389 return;
390 reset_bit(s->isr, isrv);
bellardd592d302005-07-23 19:05:37 +0000391 /* XXX: send the EOI packet to the APIC bus to allow the I/O APIC to
392 set the remote IRR bit for level triggered interrupts. */
bellard574bbf72005-01-03 23:27:31 +0000393 apic_update_irq(s);
394}
395
bellardd3e9db92005-12-17 01:27:28 +0000396static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
397 uint8_t dest, uint8_t dest_mode)
bellardd592d302005-07-23 19:05:37 +0000398{
bellardd592d302005-07-23 19:05:37 +0000399 APICState *apic_iter;
bellardd3e9db92005-12-17 01:27:28 +0000400 int i;
bellardd592d302005-07-23 19:05:37 +0000401
402 if (dest_mode == 0) {
bellardd3e9db92005-12-17 01:27:28 +0000403 if (dest == 0xff) {
404 memset(deliver_bitmask, 0xff, MAX_APIC_WORDS * sizeof(uint32_t));
405 } else {
406 memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t));
407 set_bit(deliver_bitmask, dest);
408 }
bellardd592d302005-07-23 19:05:37 +0000409 } else {
410 /* XXX: cluster mode */
bellardd3e9db92005-12-17 01:27:28 +0000411 memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t));
412 for(i = 0; i < MAX_APICS; i++) {
413 apic_iter = local_apics[i];
414 if (apic_iter) {
415 if (apic_iter->dest_mode == 0xf) {
416 if (dest & apic_iter->log_dest)
417 set_bit(deliver_bitmask, i);
418 } else if (apic_iter->dest_mode == 0x0) {
419 if ((dest & 0xf0) == (apic_iter->log_dest & 0xf0) &&
420 (dest & apic_iter->log_dest & 0x0f)) {
421 set_bit(deliver_bitmask, i);
422 }
423 }
424 }
bellardd592d302005-07-23 19:05:37 +0000425 }
426 }
bellardd592d302005-07-23 19:05:37 +0000427}
428
429
430static void apic_init_ipi(APICState *s)
431{
432 int i;
433
bellardd592d302005-07-23 19:05:37 +0000434 s->tpr = 0;
435 s->spurious_vec = 0xff;
436 s->log_dest = 0;
bellarde0fd8782005-11-21 23:26:26 +0000437 s->dest_mode = 0xf;
bellardd592d302005-07-23 19:05:37 +0000438 memset(s->isr, 0, sizeof(s->isr));
439 memset(s->tmr, 0, sizeof(s->tmr));
440 memset(s->irr, 0, sizeof(s->irr));
bellardb4511722006-10-08 18:20:51 +0000441 for(i = 0; i < APIC_LVT_NB; i++)
442 s->lvt[i] = 1 << 16; /* mask LVT */
bellardd592d302005-07-23 19:05:37 +0000443 s->esr = 0;
444 memset(s->icr, 0, sizeof(s->icr));
445 s->divide_conf = 0;
446 s->count_shift = 0;
447 s->initial_count = 0;
448 s->initial_count_load_time = 0;
449 s->next_time = 0;
aurel323003b8b2008-10-01 22:01:28 +0000450
451 cpu_reset(s->cpu_env);
452
453 if (!(s->apicbase & MSR_IA32_APICBASE_BSP))
454 s->cpu_env->halted = 1;
bellardd592d302005-07-23 19:05:37 +0000455}
456
bellarde0fd8782005-11-21 23:26:26 +0000457/* send a SIPI message to the CPU to start it */
458static void apic_startup(APICState *s, int vector_num)
459{
460 CPUState *env = s->cpu_env;
bellardce5232c2008-05-28 17:14:10 +0000461 if (!env->halted)
bellarde0fd8782005-11-21 23:26:26 +0000462 return;
463 env->eip = 0;
ths5fafdf22007-09-16 21:08:06 +0000464 cpu_x86_load_seg_cache(env, R_CS, vector_num << 8, vector_num << 12,
bellarde0fd8782005-11-21 23:26:26 +0000465 0xffff, 0);
bellardce5232c2008-05-28 17:14:10 +0000466 env->halted = 0;
bellarde0fd8782005-11-21 23:26:26 +0000467}
468
bellardd592d302005-07-23 19:05:37 +0000469static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode,
470 uint8_t delivery_mode, uint8_t vector_num,
471 uint8_t polarity, uint8_t trigger_mode)
472{
bellardd3e9db92005-12-17 01:27:28 +0000473 uint32_t deliver_bitmask[MAX_APIC_WORDS];
bellardd592d302005-07-23 19:05:37 +0000474 int dest_shorthand = (s->icr[0] >> 18) & 3;
475 APICState *apic_iter;
476
bellarde0fd8782005-11-21 23:26:26 +0000477 switch (dest_shorthand) {
bellardd3e9db92005-12-17 01:27:28 +0000478 case 0:
479 apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
480 break;
481 case 1:
482 memset(deliver_bitmask, 0x00, sizeof(deliver_bitmask));
483 set_bit(deliver_bitmask, s->id);
484 break;
485 case 2:
486 memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
487 break;
488 case 3:
489 memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
490 reset_bit(deliver_bitmask, s->id);
491 break;
bellarde0fd8782005-11-21 23:26:26 +0000492 }
493
bellardd592d302005-07-23 19:05:37 +0000494 switch (delivery_mode) {
bellardd592d302005-07-23 19:05:37 +0000495 case APIC_DM_INIT:
496 {
497 int trig_mode = (s->icr[0] >> 15) & 1;
498 int level = (s->icr[0] >> 14) & 1;
499 if (level == 0 && trig_mode == 1) {
ths5fafdf22007-09-16 21:08:06 +0000500 foreach_apic(apic_iter, deliver_bitmask,
bellardd3e9db92005-12-17 01:27:28 +0000501 apic_iter->arb_id = apic_iter->id );
bellardd592d302005-07-23 19:05:37 +0000502 return;
503 }
504 }
505 break;
506
507 case APIC_DM_SIPI:
ths5fafdf22007-09-16 21:08:06 +0000508 foreach_apic(apic_iter, deliver_bitmask,
bellardd3e9db92005-12-17 01:27:28 +0000509 apic_startup(apic_iter, vector_num) );
bellardd592d302005-07-23 19:05:37 +0000510 return;
511 }
512
bellardd592d302005-07-23 19:05:37 +0000513 apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, polarity,
514 trigger_mode);
515}
516
bellard574bbf72005-01-03 23:27:31 +0000517int apic_get_interrupt(CPUState *env)
518{
519 APICState *s = env->apic_state;
520 int intno;
521
522 /* if the APIC is installed or enabled, we let the 8259 handle the
523 IRQs */
524 if (!s)
525 return -1;
526 if (!(s->spurious_vec & APIC_SV_ENABLE))
527 return -1;
ths3b46e622007-09-17 08:09:54 +0000528
bellard574bbf72005-01-03 23:27:31 +0000529 /* XXX: spurious IRQ handling */
530 intno = get_highest_priority_int(s->irr);
531 if (intno < 0)
532 return -1;
bellardd592d302005-07-23 19:05:37 +0000533 if (s->tpr && intno <= s->tpr)
534 return s->spurious_vec & 0xff;
bellardb4511722006-10-08 18:20:51 +0000535 reset_bit(s->irr, intno);
bellard574bbf72005-01-03 23:27:31 +0000536 set_bit(s->isr, intno);
537 apic_update_irq(s);
538 return intno;
539}
540
ths0e21e122007-10-09 03:08:56 +0000541int apic_accept_pic_intr(CPUState *env)
542{
543 APICState *s = env->apic_state;
544 uint32_t lvt0;
545
546 if (!s)
547 return -1;
548
549 lvt0 = s->lvt[APIC_LVT_LINT0];
550
aurel32a5b38b52008-04-13 16:08:30 +0000551 if ((s->apicbase & MSR_IA32_APICBASE_ENABLE) == 0 ||
552 (lvt0 & APIC_LVT_MASKED) == 0)
ths0e21e122007-10-09 03:08:56 +0000553 return 1;
554
555 return 0;
556}
557
bellard574bbf72005-01-03 23:27:31 +0000558static uint32_t apic_get_current_count(APICState *s)
559{
560 int64_t d;
561 uint32_t val;
ths5fafdf22007-09-16 21:08:06 +0000562 d = (qemu_get_clock(vm_clock) - s->initial_count_load_time) >>
bellard574bbf72005-01-03 23:27:31 +0000563 s->count_shift;
564 if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
565 /* periodic */
bellardd592d302005-07-23 19:05:37 +0000566 val = s->initial_count - (d % ((uint64_t)s->initial_count + 1));
bellard574bbf72005-01-03 23:27:31 +0000567 } else {
568 if (d >= s->initial_count)
569 val = 0;
570 else
571 val = s->initial_count - d;
572 }
573 return val;
574}
575
576static void apic_timer_update(APICState *s, int64_t current_time)
577{
578 int64_t next_time, d;
ths3b46e622007-09-17 08:09:54 +0000579
bellard574bbf72005-01-03 23:27:31 +0000580 if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
ths5fafdf22007-09-16 21:08:06 +0000581 d = (current_time - s->initial_count_load_time) >>
bellard574bbf72005-01-03 23:27:31 +0000582 s->count_shift;
583 if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
aliguori681f8c22008-08-18 14:19:42 +0000584 if (!s->initial_count)
585 goto no_timer;
bellardd592d302005-07-23 19:05:37 +0000586 d = ((d / ((uint64_t)s->initial_count + 1)) + 1) * ((uint64_t)s->initial_count + 1);
bellard574bbf72005-01-03 23:27:31 +0000587 } else {
588 if (d >= s->initial_count)
589 goto no_timer;
bellardd592d302005-07-23 19:05:37 +0000590 d = (uint64_t)s->initial_count + 1;
bellard574bbf72005-01-03 23:27:31 +0000591 }
592 next_time = s->initial_count_load_time + (d << s->count_shift);
593 qemu_mod_timer(s->timer, next_time);
594 s->next_time = next_time;
595 } else {
596 no_timer:
597 qemu_del_timer(s->timer);
598 }
599}
600
601static void apic_timer(void *opaque)
602{
603 APICState *s = opaque;
604
aurel32a5b38b52008-04-13 16:08:30 +0000605 apic_local_deliver(s->cpu_env, APIC_LVT_TIMER);
bellard574bbf72005-01-03 23:27:31 +0000606 apic_timer_update(s, s->next_time);
607}
608
609static uint32_t apic_mem_readb(void *opaque, target_phys_addr_t addr)
610{
611 return 0;
612}
613
614static uint32_t apic_mem_readw(void *opaque, target_phys_addr_t addr)
615{
616 return 0;
617}
618
619static void apic_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
620{
621}
622
623static void apic_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
624{
625}
626
627static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
628{
629 CPUState *env;
630 APICState *s;
631 uint32_t val;
632 int index;
633
634 env = cpu_single_env;
635 if (!env)
636 return 0;
637 s = env->apic_state;
638
639 index = (addr >> 4) & 0xff;
640 switch(index) {
641 case 0x02: /* id */
642 val = s->id << 24;
643 break;
644 case 0x03: /* version */
645 val = 0x11 | ((APIC_LVT_NB - 1) << 16); /* version 0x11 */
646 break;
647 case 0x08:
648 val = s->tpr;
649 break;
bellardd592d302005-07-23 19:05:37 +0000650 case 0x09:
651 val = apic_get_arb_pri(s);
652 break;
bellard574bbf72005-01-03 23:27:31 +0000653 case 0x0a:
654 /* ppr */
655 val = apic_get_ppr(s);
656 break;
aurel32b237db32008-03-28 22:31:36 +0000657 case 0x0b:
658 val = 0;
659 break;
bellardd592d302005-07-23 19:05:37 +0000660 case 0x0d:
661 val = s->log_dest << 24;
662 break;
663 case 0x0e:
664 val = s->dest_mode << 28;
665 break;
bellard574bbf72005-01-03 23:27:31 +0000666 case 0x0f:
667 val = s->spurious_vec;
668 break;
669 case 0x10 ... 0x17:
670 val = s->isr[index & 7];
671 break;
672 case 0x18 ... 0x1f:
673 val = s->tmr[index & 7];
674 break;
675 case 0x20 ... 0x27:
676 val = s->irr[index & 7];
677 break;
678 case 0x28:
679 val = s->esr;
680 break;
bellard574bbf72005-01-03 23:27:31 +0000681 case 0x30:
682 case 0x31:
683 val = s->icr[index & 1];
684 break;
bellarde0fd8782005-11-21 23:26:26 +0000685 case 0x32 ... 0x37:
686 val = s->lvt[index - 0x32];
687 break;
bellard574bbf72005-01-03 23:27:31 +0000688 case 0x38:
689 val = s->initial_count;
690 break;
691 case 0x39:
692 val = apic_get_current_count(s);
693 break;
694 case 0x3e:
695 val = s->divide_conf;
696 break;
697 default:
698 s->esr |= ESR_ILLEGAL_ADDRESS;
699 val = 0;
700 break;
701 }
702#ifdef DEBUG_APIC
703 printf("APIC read: %08x = %08x\n", (uint32_t)addr, val);
704#endif
705 return val;
706}
707
708static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
709{
710 CPUState *env;
711 APICState *s;
712 int index;
713
714 env = cpu_single_env;
715 if (!env)
716 return;
717 s = env->apic_state;
718
719#ifdef DEBUG_APIC
720 printf("APIC write: %08x = %08x\n", (uint32_t)addr, val);
721#endif
722
723 index = (addr >> 4) & 0xff;
724 switch(index) {
725 case 0x02:
726 s->id = (val >> 24);
727 break;
bellarde0fd8782005-11-21 23:26:26 +0000728 case 0x03:
729 break;
bellard574bbf72005-01-03 23:27:31 +0000730 case 0x08:
731 s->tpr = val;
bellardd592d302005-07-23 19:05:37 +0000732 apic_update_irq(s);
bellard574bbf72005-01-03 23:27:31 +0000733 break;
bellarde0fd8782005-11-21 23:26:26 +0000734 case 0x09:
735 case 0x0a:
736 break;
bellard574bbf72005-01-03 23:27:31 +0000737 case 0x0b: /* EOI */
738 apic_eoi(s);
739 break;
bellardd592d302005-07-23 19:05:37 +0000740 case 0x0d:
741 s->log_dest = val >> 24;
742 break;
743 case 0x0e:
744 s->dest_mode = val >> 28;
745 break;
bellard574bbf72005-01-03 23:27:31 +0000746 case 0x0f:
747 s->spurious_vec = val & 0x1ff;
bellardd592d302005-07-23 19:05:37 +0000748 apic_update_irq(s);
bellard574bbf72005-01-03 23:27:31 +0000749 break;
bellarde0fd8782005-11-21 23:26:26 +0000750 case 0x10 ... 0x17:
751 case 0x18 ... 0x1f:
752 case 0x20 ... 0x27:
753 case 0x28:
754 break;
bellard574bbf72005-01-03 23:27:31 +0000755 case 0x30:
bellardd592d302005-07-23 19:05:37 +0000756 s->icr[0] = val;
757 apic_deliver(s, (s->icr[1] >> 24) & 0xff, (s->icr[0] >> 11) & 1,
758 (s->icr[0] >> 8) & 7, (s->icr[0] & 0xff),
759 (s->icr[0] >> 14) & 1, (s->icr[0] >> 15) & 1);
760 break;
bellard574bbf72005-01-03 23:27:31 +0000761 case 0x31:
bellardd592d302005-07-23 19:05:37 +0000762 s->icr[1] = val;
bellard574bbf72005-01-03 23:27:31 +0000763 break;
764 case 0x32 ... 0x37:
765 {
766 int n = index - 0x32;
767 s->lvt[n] = val;
768 if (n == APIC_LVT_TIMER)
769 apic_timer_update(s, qemu_get_clock(vm_clock));
770 }
771 break;
772 case 0x38:
773 s->initial_count = val;
774 s->initial_count_load_time = qemu_get_clock(vm_clock);
775 apic_timer_update(s, s->initial_count_load_time);
776 break;
bellarde0fd8782005-11-21 23:26:26 +0000777 case 0x39:
778 break;
bellard574bbf72005-01-03 23:27:31 +0000779 case 0x3e:
780 {
781 int v;
782 s->divide_conf = val & 0xb;
783 v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
784 s->count_shift = (v + 1) & 7;
785 }
786 break;
787 default:
788 s->esr |= ESR_ILLEGAL_ADDRESS;
789 break;
790 }
791}
792
bellardd592d302005-07-23 19:05:37 +0000793static void apic_save(QEMUFile *f, void *opaque)
794{
795 APICState *s = opaque;
796 int i;
bellard574bbf72005-01-03 23:27:31 +0000797
bellardd592d302005-07-23 19:05:37 +0000798 qemu_put_be32s(f, &s->apicbase);
799 qemu_put_8s(f, &s->id);
800 qemu_put_8s(f, &s->arb_id);
801 qemu_put_8s(f, &s->tpr);
802 qemu_put_be32s(f, &s->spurious_vec);
803 qemu_put_8s(f, &s->log_dest);
804 qemu_put_8s(f, &s->dest_mode);
805 for (i = 0; i < 8; i++) {
806 qemu_put_be32s(f, &s->isr[i]);
807 qemu_put_be32s(f, &s->tmr[i]);
808 qemu_put_be32s(f, &s->irr[i]);
809 }
810 for (i = 0; i < APIC_LVT_NB; i++) {
811 qemu_put_be32s(f, &s->lvt[i]);
812 }
813 qemu_put_be32s(f, &s->esr);
814 qemu_put_be32s(f, &s->icr[0]);
815 qemu_put_be32s(f, &s->icr[1]);
816 qemu_put_be32s(f, &s->divide_conf);
thsbee8d682007-12-16 23:41:11 +0000817 qemu_put_be32(f, s->count_shift);
bellardd592d302005-07-23 19:05:37 +0000818 qemu_put_be32s(f, &s->initial_count);
thsbee8d682007-12-16 23:41:11 +0000819 qemu_put_be64(f, s->initial_count_load_time);
820 qemu_put_be64(f, s->next_time);
bellarde6cf6a82006-08-17 10:48:06 +0000821
822 qemu_put_timer(f, s->timer);
bellardd592d302005-07-23 19:05:37 +0000823}
824
825static int apic_load(QEMUFile *f, void *opaque, int version_id)
826{
827 APICState *s = opaque;
828 int i;
829
bellarde6cf6a82006-08-17 10:48:06 +0000830 if (version_id > 2)
bellardd592d302005-07-23 19:05:37 +0000831 return -EINVAL;
832
833 /* XXX: what if the base changes? (registered memory regions) */
834 qemu_get_be32s(f, &s->apicbase);
835 qemu_get_8s(f, &s->id);
836 qemu_get_8s(f, &s->arb_id);
837 qemu_get_8s(f, &s->tpr);
838 qemu_get_be32s(f, &s->spurious_vec);
839 qemu_get_8s(f, &s->log_dest);
840 qemu_get_8s(f, &s->dest_mode);
841 for (i = 0; i < 8; i++) {
842 qemu_get_be32s(f, &s->isr[i]);
843 qemu_get_be32s(f, &s->tmr[i]);
844 qemu_get_be32s(f, &s->irr[i]);
845 }
846 for (i = 0; i < APIC_LVT_NB; i++) {
847 qemu_get_be32s(f, &s->lvt[i]);
848 }
849 qemu_get_be32s(f, &s->esr);
850 qemu_get_be32s(f, &s->icr[0]);
851 qemu_get_be32s(f, &s->icr[1]);
852 qemu_get_be32s(f, &s->divide_conf);
thsbee8d682007-12-16 23:41:11 +0000853 s->count_shift=qemu_get_be32(f);
bellardd592d302005-07-23 19:05:37 +0000854 qemu_get_be32s(f, &s->initial_count);
thsbee8d682007-12-16 23:41:11 +0000855 s->initial_count_load_time=qemu_get_be64(f);
856 s->next_time=qemu_get_be64(f);
bellarde6cf6a82006-08-17 10:48:06 +0000857
858 if (version_id >= 2)
859 qemu_get_timer(f, s->timer);
bellardd592d302005-07-23 19:05:37 +0000860 return 0;
861}
862
863static void apic_reset(void *opaque)
864{
865 APICState *s = opaque;
aurel32fec5fa02008-09-02 00:09:08 +0000866
867 s->apicbase = 0xfee00000 |
868 (s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE;
869
bellardd592d302005-07-23 19:05:37 +0000870 apic_init_ipi(s);
ths0e21e122007-10-09 03:08:56 +0000871
aurel32a5b38b52008-04-13 16:08:30 +0000872 if (s->id == 0) {
873 /*
874 * LINT0 delivery mode on CPU #0 is set to ExtInt at initialization
875 * time typically by BIOS, so PIC interrupt can be delivered to the
876 * processor when local APIC is enabled.
877 */
878 s->lvt[APIC_LVT_LINT0] = 0x700;
879 }
bellardd592d302005-07-23 19:05:37 +0000880}
bellard574bbf72005-01-03 23:27:31 +0000881
882static CPUReadMemoryFunc *apic_mem_read[3] = {
883 apic_mem_readb,
884 apic_mem_readw,
885 apic_mem_readl,
886};
887
888static CPUWriteMemoryFunc *apic_mem_write[3] = {
889 apic_mem_writeb,
890 apic_mem_writew,
891 apic_mem_writel,
892};
893
894int apic_init(CPUState *env)
895{
896 APICState *s;
bellard574bbf72005-01-03 23:27:31 +0000897
bellardd3e9db92005-12-17 01:27:28 +0000898 if (last_apic_id >= MAX_APICS)
899 return -1;
bellardd592d302005-07-23 19:05:37 +0000900 s = qemu_mallocz(sizeof(APICState));
bellard574bbf72005-01-03 23:27:31 +0000901 if (!s)
902 return -1;
bellard574bbf72005-01-03 23:27:31 +0000903 env->apic_state = s;
bellardd592d302005-07-23 19:05:37 +0000904 s->id = last_apic_id++;
thseae76292007-04-03 16:38:34 +0000905 env->cpuid_apic_id = s->id;
bellard574bbf72005-01-03 23:27:31 +0000906 s->cpu_env = env;
bellard574bbf72005-01-03 23:27:31 +0000907
aurel32a5b38b52008-04-13 16:08:30 +0000908 apic_reset(s);
ths0e21e122007-10-09 03:08:56 +0000909
bellardd592d302005-07-23 19:05:37 +0000910 /* XXX: mapping more APICs at the same memory location */
bellard574bbf72005-01-03 23:27:31 +0000911 if (apic_io_memory == 0) {
912 /* NOTE: the APIC is directly connected to the CPU - it is not
913 on the global memory bus. */
ths5fafdf22007-09-16 21:08:06 +0000914 apic_io_memory = cpu_register_io_memory(0, apic_mem_read,
bellard574bbf72005-01-03 23:27:31 +0000915 apic_mem_write, NULL);
bellardd592d302005-07-23 19:05:37 +0000916 cpu_register_physical_memory(s->apicbase & ~0xfff, 0x1000,
917 apic_io_memory);
bellard574bbf72005-01-03 23:27:31 +0000918 }
919 s->timer = qemu_new_timer(vm_clock, apic_timer, s);
bellardd592d302005-07-23 19:05:37 +0000920
thsbe0164f2007-08-26 17:33:08 +0000921 register_savevm("apic", s->id, 2, apic_save, apic_load, s);
bellardd592d302005-07-23 19:05:37 +0000922 qemu_register_reset(apic_reset, s);
ths3b46e622007-09-17 08:09:54 +0000923
bellardd3e9db92005-12-17 01:27:28 +0000924 local_apics[s->id] = s;
bellard574bbf72005-01-03 23:27:31 +0000925 return 0;
926}
bellardd592d302005-07-23 19:05:37 +0000927
928static void ioapic_service(IOAPICState *s)
929{
bellardb1fc0342005-07-23 21:43:15 +0000930 uint8_t i;
931 uint8_t trig_mode;
bellardd592d302005-07-23 19:05:37 +0000932 uint8_t vector;
bellardb1fc0342005-07-23 21:43:15 +0000933 uint8_t delivery_mode;
bellardd592d302005-07-23 19:05:37 +0000934 uint32_t mask;
935 uint64_t entry;
936 uint8_t dest;
937 uint8_t dest_mode;
bellardb1fc0342005-07-23 21:43:15 +0000938 uint8_t polarity;
bellardd3e9db92005-12-17 01:27:28 +0000939 uint32_t deliver_bitmask[MAX_APIC_WORDS];
bellardd592d302005-07-23 19:05:37 +0000940
bellardb1fc0342005-07-23 21:43:15 +0000941 for (i = 0; i < IOAPIC_NUM_PINS; i++) {
942 mask = 1 << i;
bellardd592d302005-07-23 19:05:37 +0000943 if (s->irr & mask) {
bellardb1fc0342005-07-23 21:43:15 +0000944 entry = s->ioredtbl[i];
bellardd592d302005-07-23 19:05:37 +0000945 if (!(entry & APIC_LVT_MASKED)) {
bellardb1fc0342005-07-23 21:43:15 +0000946 trig_mode = ((entry >> 15) & 1);
bellardd592d302005-07-23 19:05:37 +0000947 dest = entry >> 56;
948 dest_mode = (entry >> 11) & 1;
bellardb1fc0342005-07-23 21:43:15 +0000949 delivery_mode = (entry >> 8) & 7;
950 polarity = (entry >> 13) & 1;
951 if (trig_mode == APIC_TRIGGER_EDGE)
952 s->irr &= ~mask;
953 if (delivery_mode == APIC_DM_EXTINT)
954 vector = pic_read_irq(isa_pic);
955 else
956 vector = entry & 0xff;
ths3b46e622007-09-17 08:09:54 +0000957
bellardd3e9db92005-12-17 01:27:28 +0000958 apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
ths5fafdf22007-09-16 21:08:06 +0000959 apic_bus_deliver(deliver_bitmask, delivery_mode,
bellardd3e9db92005-12-17 01:27:28 +0000960 vector, polarity, trig_mode);
bellardd592d302005-07-23 19:05:37 +0000961 }
962 }
963 }
964}
965
966void ioapic_set_irq(void *opaque, int vector, int level)
967{
968 IOAPICState *s = opaque;
969
aliguori16b29ae2008-12-17 23:28:44 +0000970 /* ISA IRQs map to GSI 1-1 except for IRQ0 which maps
971 * to GSI 2. GSI maps to ioapic 1-1. This is not
972 * the cleanest way of doing it but it should work. */
973
974 if (vector == 0)
975 vector = 2;
976
bellardd592d302005-07-23 19:05:37 +0000977 if (vector >= 0 && vector < IOAPIC_NUM_PINS) {
978 uint32_t mask = 1 << vector;
979 uint64_t entry = s->ioredtbl[vector];
980
981 if ((entry >> 15) & 1) {
982 /* level triggered */
983 if (level) {
984 s->irr |= mask;
985 ioapic_service(s);
986 } else {
987 s->irr &= ~mask;
988 }
989 } else {
990 /* edge triggered */
991 if (level) {
992 s->irr |= mask;
993 ioapic_service(s);
994 }
995 }
996 }
997}
998
999static uint32_t ioapic_mem_readl(void *opaque, target_phys_addr_t addr)
1000{
1001 IOAPICState *s = opaque;
1002 int index;
1003 uint32_t val = 0;
1004
1005 addr &= 0xff;
1006 if (addr == 0x00) {
1007 val = s->ioregsel;
1008 } else if (addr == 0x10) {
1009 switch (s->ioregsel) {
1010 case 0x00:
1011 val = s->id << 24;
1012 break;
1013 case 0x01:
1014 val = 0x11 | ((IOAPIC_NUM_PINS - 1) << 16); /* version 0x11 */
1015 break;
1016 case 0x02:
1017 val = 0;
1018 break;
1019 default:
1020 index = (s->ioregsel - 0x10) >> 1;
1021 if (index >= 0 && index < IOAPIC_NUM_PINS) {
1022 if (s->ioregsel & 1)
1023 val = s->ioredtbl[index] >> 32;
1024 else
1025 val = s->ioredtbl[index] & 0xffffffff;
1026 }
1027 }
1028#ifdef DEBUG_IOAPIC
1029 printf("I/O APIC read: %08x = %08x\n", s->ioregsel, val);
1030#endif
1031 }
1032 return val;
1033}
1034
1035static void ioapic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
1036{
1037 IOAPICState *s = opaque;
1038 int index;
1039
1040 addr &= 0xff;
1041 if (addr == 0x00) {
1042 s->ioregsel = val;
1043 return;
1044 } else if (addr == 0x10) {
1045#ifdef DEBUG_IOAPIC
1046 printf("I/O APIC write: %08x = %08x\n", s->ioregsel, val);
1047#endif
1048 switch (s->ioregsel) {
1049 case 0x00:
1050 s->id = (val >> 24) & 0xff;
1051 return;
1052 case 0x01:
1053 case 0x02:
1054 return;
1055 default:
1056 index = (s->ioregsel - 0x10) >> 1;
1057 if (index >= 0 && index < IOAPIC_NUM_PINS) {
1058 if (s->ioregsel & 1) {
1059 s->ioredtbl[index] &= 0xffffffff;
1060 s->ioredtbl[index] |= (uint64_t)val << 32;
1061 } else {
1062 s->ioredtbl[index] &= ~0xffffffffULL;
1063 s->ioredtbl[index] |= val;
1064 }
1065 ioapic_service(s);
1066 }
1067 }
1068 }
1069}
1070
1071static void ioapic_save(QEMUFile *f, void *opaque)
1072{
1073 IOAPICState *s = opaque;
1074 int i;
1075
1076 qemu_put_8s(f, &s->id);
1077 qemu_put_8s(f, &s->ioregsel);
1078 for (i = 0; i < IOAPIC_NUM_PINS; i++) {
1079 qemu_put_be64s(f, &s->ioredtbl[i]);
1080 }
1081}
1082
1083static int ioapic_load(QEMUFile *f, void *opaque, int version_id)
1084{
1085 IOAPICState *s = opaque;
1086 int i;
1087
1088 if (version_id != 1)
1089 return -EINVAL;
1090
1091 qemu_get_8s(f, &s->id);
1092 qemu_get_8s(f, &s->ioregsel);
1093 for (i = 0; i < IOAPIC_NUM_PINS; i++) {
1094 qemu_get_be64s(f, &s->ioredtbl[i]);
1095 }
1096 return 0;
1097}
1098
1099static void ioapic_reset(void *opaque)
1100{
1101 IOAPICState *s = opaque;
1102 int i;
1103
1104 memset(s, 0, sizeof(*s));
1105 for(i = 0; i < IOAPIC_NUM_PINS; i++)
1106 s->ioredtbl[i] = 1 << 16; /* mask LVT */
1107}
1108
1109static CPUReadMemoryFunc *ioapic_mem_read[3] = {
1110 ioapic_mem_readl,
1111 ioapic_mem_readl,
1112 ioapic_mem_readl,
1113};
1114
1115static CPUWriteMemoryFunc *ioapic_mem_write[3] = {
1116 ioapic_mem_writel,
1117 ioapic_mem_writel,
1118 ioapic_mem_writel,
1119};
1120
1121IOAPICState *ioapic_init(void)
1122{
1123 IOAPICState *s;
1124 int io_memory;
1125
bellardb1fc0342005-07-23 21:43:15 +00001126 s = qemu_mallocz(sizeof(IOAPICState));
bellardd592d302005-07-23 19:05:37 +00001127 if (!s)
1128 return NULL;
bellardd592d302005-07-23 19:05:37 +00001129 ioapic_reset(s);
1130 s->id = last_apic_id++;
1131
ths5fafdf22007-09-16 21:08:06 +00001132 io_memory = cpu_register_io_memory(0, ioapic_mem_read,
bellardd592d302005-07-23 19:05:37 +00001133 ioapic_mem_write, s);
1134 cpu_register_physical_memory(0xfec00000, 0x1000, io_memory);
1135
1136 register_savevm("ioapic", 0, 1, ioapic_save, ioapic_load, s);
1137 qemu_register_reset(ioapic_reset, s);
ths3b46e622007-09-17 08:09:54 +00001138
bellardd592d302005-07-23 19:05:37 +00001139 return s;
1140}