blob: 43d748cabd6901380f0405440d03c8313b9acc90 [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
bellardd3e9db92005-12-17 01:27:28 +0000107/* Find first bit starting from msb. Return 0 if value = 0 */
108static int fls_bit(uint32_t value)
109{
110 unsigned int ret = 0;
111
112#if defined(HOST_I386)
113 __asm__ __volatile__ ("bsr %1, %0\n" : "+r" (ret) : "rm" (value));
114 return ret;
115#else
116 if (value > 0xffff)
117 value >>= 16, ret = 16;
118 if (value > 0xff)
119 value >>= 8, ret += 8;
120 if (value > 0xf)
121 value >>= 4, ret += 4;
122 if (value > 0x3)
123 value >>= 2, ret += 2;
124 return ret + (value >> 1);
125#endif
126}
127
128/* Find first bit starting from lsb. Return 0 if value = 0 */
129static int ffs_bit(uint32_t value)
130{
131 unsigned int ret = 0;
132
133#if defined(HOST_I386)
134 __asm__ __volatile__ ("bsf %1, %0\n" : "+r" (ret) : "rm" (value));
135 return ret;
136#else
137 if (!value)
138 return 0;
139 if (!(value & 0xffff))
140 value >>= 16, ret = 16;
141 if (!(value & 0xff))
142 value >>= 8, ret += 8;
143 if (!(value & 0xf))
144 value >>= 4, ret += 4;
145 if (!(value & 0x3))
146 value >>= 2, ret += 2;
147 if (!(value & 0x1))
148 ret++;
149 return ret;
150#endif
151}
152
153static inline void set_bit(uint32_t *tab, int index)
154{
155 int i, mask;
156 i = index >> 5;
157 mask = 1 << (index & 0x1f);
158 tab[i] |= mask;
159}
160
161static inline void reset_bit(uint32_t *tab, int index)
162{
163 int i, mask;
164 i = index >> 5;
165 mask = 1 << (index & 0x1f);
166 tab[i] &= ~mask;
167}
168
aurel321a7de942008-08-21 03:14:52 +0000169static void apic_local_deliver(CPUState *env, int vector)
aurel32a5b38b52008-04-13 16:08:30 +0000170{
171 APICState *s = env->apic_state;
172 uint32_t lvt = s->lvt[vector];
173 int trigger_mode;
174
175 if (lvt & APIC_LVT_MASKED)
176 return;
177
178 switch ((lvt >> 8) & 7) {
179 case APIC_DM_SMI:
180 cpu_interrupt(env, CPU_INTERRUPT_SMI);
181 break;
182
183 case APIC_DM_NMI:
184 cpu_interrupt(env, CPU_INTERRUPT_NMI);
185 break;
186
187 case APIC_DM_EXTINT:
188 cpu_interrupt(env, CPU_INTERRUPT_HARD);
189 break;
190
191 case APIC_DM_FIXED:
192 trigger_mode = APIC_TRIGGER_EDGE;
193 if ((vector == APIC_LVT_LINT0 || vector == APIC_LVT_LINT1) &&
194 (lvt & APIC_LVT_LEVEL_TRIGGER))
195 trigger_mode = APIC_TRIGGER_LEVEL;
196 apic_set_irq(s, lvt & 0xff, trigger_mode);
197 }
198}
199
aurel321a7de942008-08-21 03:14:52 +0000200void apic_deliver_pic_intr(CPUState *env, int level)
201{
202 if (level)
203 apic_local_deliver(env, APIC_LVT_LINT0);
204 else {
205 APICState *s = env->apic_state;
206 uint32_t lvt = s->lvt[APIC_LVT_LINT0];
207
208 switch ((lvt >> 8) & 7) {
209 case APIC_DM_FIXED:
210 if (!(lvt & APIC_LVT_LEVEL_TRIGGER))
211 break;
212 reset_bit(s->irr, lvt & 0xff);
213 /* fall through */
214 case APIC_DM_EXTINT:
215 cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
216 break;
217 }
218 }
219}
220
bellardd3e9db92005-12-17 01:27:28 +0000221#define foreach_apic(apic, deliver_bitmask, code) \
222{\
223 int __i, __j, __mask;\
224 for(__i = 0; __i < MAX_APIC_WORDS; __i++) {\
225 __mask = deliver_bitmask[__i];\
226 if (__mask) {\
227 for(__j = 0; __j < 32; __j++) {\
228 if (__mask & (1 << __j)) {\
229 apic = local_apics[__i * 32 + __j];\
230 if (apic) {\
231 code;\
232 }\
233 }\
234 }\
235 }\
236 }\
237}
238
ths5fafdf22007-09-16 21:08:06 +0000239static void apic_bus_deliver(const uint32_t *deliver_bitmask,
bellardd3e9db92005-12-17 01:27:28 +0000240 uint8_t delivery_mode,
bellardd592d302005-07-23 19:05:37 +0000241 uint8_t vector_num, uint8_t polarity,
242 uint8_t trigger_mode)
243{
244 APICState *apic_iter;
245
246 switch (delivery_mode) {
247 case APIC_DM_LOWPRI:
bellard8dd69b82005-11-23 20:59:44 +0000248 /* XXX: search for focus processor, arbitration */
bellardd3e9db92005-12-17 01:27:28 +0000249 {
250 int i, d;
251 d = -1;
252 for(i = 0; i < MAX_APIC_WORDS; i++) {
253 if (deliver_bitmask[i]) {
254 d = i * 32 + ffs_bit(deliver_bitmask[i]);
255 break;
256 }
257 }
258 if (d >= 0) {
259 apic_iter = local_apics[d];
260 if (apic_iter) {
261 apic_set_irq(apic_iter, vector_num, trigger_mode);
262 }
263 }
bellard8dd69b82005-11-23 20:59:44 +0000264 }
bellardd3e9db92005-12-17 01:27:28 +0000265 return;
bellard8dd69b82005-11-23 20:59:44 +0000266
bellardd592d302005-07-23 19:05:37 +0000267 case APIC_DM_FIXED:
bellardd592d302005-07-23 19:05:37 +0000268 break;
269
270 case APIC_DM_SMI:
aurel32e2eb9d32008-04-13 16:08:23 +0000271 foreach_apic(apic_iter, deliver_bitmask,
272 cpu_interrupt(apic_iter->cpu_env, CPU_INTERRUPT_SMI) );
273 return;
274
bellardd592d302005-07-23 19:05:37 +0000275 case APIC_DM_NMI:
aurel32e2eb9d32008-04-13 16:08:23 +0000276 foreach_apic(apic_iter, deliver_bitmask,
277 cpu_interrupt(apic_iter->cpu_env, CPU_INTERRUPT_NMI) );
278 return;
bellardd592d302005-07-23 19:05:37 +0000279
280 case APIC_DM_INIT:
281 /* normal INIT IPI sent to processors */
ths5fafdf22007-09-16 21:08:06 +0000282 foreach_apic(apic_iter, deliver_bitmask,
bellardd3e9db92005-12-17 01:27:28 +0000283 apic_init_ipi(apic_iter) );
bellardd592d302005-07-23 19:05:37 +0000284 return;
ths3b46e622007-09-17 08:09:54 +0000285
bellardd592d302005-07-23 19:05:37 +0000286 case APIC_DM_EXTINT:
bellardb1fc0342005-07-23 21:43:15 +0000287 /* handled in I/O APIC code */
bellardd592d302005-07-23 19:05:37 +0000288 break;
289
290 default:
291 return;
292 }
293
ths5fafdf22007-09-16 21:08:06 +0000294 foreach_apic(apic_iter, deliver_bitmask,
bellardd3e9db92005-12-17 01:27:28 +0000295 apic_set_irq(apic_iter, vector_num, trigger_mode) );
bellardd592d302005-07-23 19:05:37 +0000296}
bellard574bbf72005-01-03 23:27:31 +0000297
298void cpu_set_apic_base(CPUState *env, uint64_t val)
299{
300 APICState *s = env->apic_state;
301#ifdef DEBUG_APIC
bellard26a76462006-06-25 18:15:32 +0000302 printf("cpu_set_apic_base: %016" PRIx64 "\n", val);
bellard574bbf72005-01-03 23:27:31 +0000303#endif
ths5fafdf22007-09-16 21:08:06 +0000304 s->apicbase = (val & 0xfffff000) |
bellard574bbf72005-01-03 23:27:31 +0000305 (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
306 /* if disabled, cannot be enabled again */
307 if (!(val & MSR_IA32_APICBASE_ENABLE)) {
308 s->apicbase &= ~MSR_IA32_APICBASE_ENABLE;
309 env->cpuid_features &= ~CPUID_APIC;
310 s->spurious_vec &= ~APIC_SV_ENABLE;
311 }
312}
313
314uint64_t cpu_get_apic_base(CPUState *env)
315{
316 APICState *s = env->apic_state;
317#ifdef DEBUG_APIC
bellard26a76462006-06-25 18:15:32 +0000318 printf("cpu_get_apic_base: %016" PRIx64 "\n", (uint64_t)s->apicbase);
bellard574bbf72005-01-03 23:27:31 +0000319#endif
320 return s->apicbase;
321}
322
bellard9230e662005-01-23 20:46:56 +0000323void cpu_set_apic_tpr(CPUX86State *env, uint8_t val)
324{
325 APICState *s = env->apic_state;
326 s->tpr = (val & 0x0f) << 4;
bellardd592d302005-07-23 19:05:37 +0000327 apic_update_irq(s);
bellard9230e662005-01-23 20:46:56 +0000328}
329
330uint8_t cpu_get_apic_tpr(CPUX86State *env)
331{
332 APICState *s = env->apic_state;
333 return s->tpr >> 4;
334}
335
bellardd592d302005-07-23 19:05:37 +0000336/* return -1 if no bit is set */
337static int get_highest_priority_int(uint32_t *tab)
338{
339 int i;
340 for(i = 7; i >= 0; i--) {
341 if (tab[i] != 0) {
342 return i * 32 + fls_bit(tab[i]);
343 }
344 }
345 return -1;
346}
347
bellard574bbf72005-01-03 23:27:31 +0000348static int apic_get_ppr(APICState *s)
349{
350 int tpr, isrv, ppr;
351
352 tpr = (s->tpr >> 4);
353 isrv = get_highest_priority_int(s->isr);
354 if (isrv < 0)
355 isrv = 0;
356 isrv >>= 4;
357 if (tpr >= isrv)
358 ppr = s->tpr;
359 else
360 ppr = isrv << 4;
361 return ppr;
362}
363
bellardd592d302005-07-23 19:05:37 +0000364static int apic_get_arb_pri(APICState *s)
365{
366 /* XXX: arbitration */
367 return 0;
368}
369
bellard574bbf72005-01-03 23:27:31 +0000370/* signal the CPU if an irq is pending */
371static void apic_update_irq(APICState *s)
372{
bellardd592d302005-07-23 19:05:37 +0000373 int irrv, ppr;
374 if (!(s->spurious_vec & APIC_SV_ENABLE))
375 return;
bellard574bbf72005-01-03 23:27:31 +0000376 irrv = get_highest_priority_int(s->irr);
377 if (irrv < 0)
378 return;
bellardd592d302005-07-23 19:05:37 +0000379 ppr = apic_get_ppr(s);
380 if (ppr && (irrv & 0xf0) <= (ppr & 0xf0))
bellard574bbf72005-01-03 23:27:31 +0000381 return;
382 cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
383}
384
385static void apic_set_irq(APICState *s, int vector_num, int trigger_mode)
386{
387 set_bit(s->irr, vector_num);
388 if (trigger_mode)
389 set_bit(s->tmr, vector_num);
390 else
391 reset_bit(s->tmr, vector_num);
392 apic_update_irq(s);
393}
394
395static void apic_eoi(APICState *s)
396{
397 int isrv;
398 isrv = get_highest_priority_int(s->isr);
399 if (isrv < 0)
400 return;
401 reset_bit(s->isr, isrv);
bellardd592d302005-07-23 19:05:37 +0000402 /* XXX: send the EOI packet to the APIC bus to allow the I/O APIC to
403 set the remote IRR bit for level triggered interrupts. */
bellard574bbf72005-01-03 23:27:31 +0000404 apic_update_irq(s);
405}
406
bellardd3e9db92005-12-17 01:27:28 +0000407static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
408 uint8_t dest, uint8_t dest_mode)
bellardd592d302005-07-23 19:05:37 +0000409{
bellardd592d302005-07-23 19:05:37 +0000410 APICState *apic_iter;
bellardd3e9db92005-12-17 01:27:28 +0000411 int i;
bellardd592d302005-07-23 19:05:37 +0000412
413 if (dest_mode == 0) {
bellardd3e9db92005-12-17 01:27:28 +0000414 if (dest == 0xff) {
415 memset(deliver_bitmask, 0xff, MAX_APIC_WORDS * sizeof(uint32_t));
416 } else {
417 memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t));
418 set_bit(deliver_bitmask, dest);
419 }
bellardd592d302005-07-23 19:05:37 +0000420 } else {
421 /* XXX: cluster mode */
bellardd3e9db92005-12-17 01:27:28 +0000422 memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t));
423 for(i = 0; i < MAX_APICS; i++) {
424 apic_iter = local_apics[i];
425 if (apic_iter) {
426 if (apic_iter->dest_mode == 0xf) {
427 if (dest & apic_iter->log_dest)
428 set_bit(deliver_bitmask, i);
429 } else if (apic_iter->dest_mode == 0x0) {
430 if ((dest & 0xf0) == (apic_iter->log_dest & 0xf0) &&
431 (dest & apic_iter->log_dest & 0x0f)) {
432 set_bit(deliver_bitmask, i);
433 }
434 }
435 }
bellardd592d302005-07-23 19:05:37 +0000436 }
437 }
bellardd592d302005-07-23 19:05:37 +0000438}
439
440
441static void apic_init_ipi(APICState *s)
442{
443 int i;
444
bellardd592d302005-07-23 19:05:37 +0000445 s->tpr = 0;
446 s->spurious_vec = 0xff;
447 s->log_dest = 0;
bellarde0fd8782005-11-21 23:26:26 +0000448 s->dest_mode = 0xf;
bellardd592d302005-07-23 19:05:37 +0000449 memset(s->isr, 0, sizeof(s->isr));
450 memset(s->tmr, 0, sizeof(s->tmr));
451 memset(s->irr, 0, sizeof(s->irr));
bellardb4511722006-10-08 18:20:51 +0000452 for(i = 0; i < APIC_LVT_NB; i++)
453 s->lvt[i] = 1 << 16; /* mask LVT */
bellardd592d302005-07-23 19:05:37 +0000454 s->esr = 0;
455 memset(s->icr, 0, sizeof(s->icr));
456 s->divide_conf = 0;
457 s->count_shift = 0;
458 s->initial_count = 0;
459 s->initial_count_load_time = 0;
460 s->next_time = 0;
461}
462
bellarde0fd8782005-11-21 23:26:26 +0000463/* send a SIPI message to the CPU to start it */
464static void apic_startup(APICState *s, int vector_num)
465{
466 CPUState *env = s->cpu_env;
bellardce5232c2008-05-28 17:14:10 +0000467 if (!env->halted)
bellarde0fd8782005-11-21 23:26:26 +0000468 return;
469 env->eip = 0;
ths5fafdf22007-09-16 21:08:06 +0000470 cpu_x86_load_seg_cache(env, R_CS, vector_num << 8, vector_num << 12,
bellarde0fd8782005-11-21 23:26:26 +0000471 0xffff, 0);
bellardce5232c2008-05-28 17:14:10 +0000472 env->halted = 0;
bellarde0fd8782005-11-21 23:26:26 +0000473}
474
bellardd592d302005-07-23 19:05:37 +0000475static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode,
476 uint8_t delivery_mode, uint8_t vector_num,
477 uint8_t polarity, uint8_t trigger_mode)
478{
bellardd3e9db92005-12-17 01:27:28 +0000479 uint32_t deliver_bitmask[MAX_APIC_WORDS];
bellardd592d302005-07-23 19:05:37 +0000480 int dest_shorthand = (s->icr[0] >> 18) & 3;
481 APICState *apic_iter;
482
bellarde0fd8782005-11-21 23:26:26 +0000483 switch (dest_shorthand) {
bellardd3e9db92005-12-17 01:27:28 +0000484 case 0:
485 apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
486 break;
487 case 1:
488 memset(deliver_bitmask, 0x00, sizeof(deliver_bitmask));
489 set_bit(deliver_bitmask, s->id);
490 break;
491 case 2:
492 memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
493 break;
494 case 3:
495 memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
496 reset_bit(deliver_bitmask, s->id);
497 break;
bellarde0fd8782005-11-21 23:26:26 +0000498 }
499
bellardd592d302005-07-23 19:05:37 +0000500 switch (delivery_mode) {
bellardd592d302005-07-23 19:05:37 +0000501 case APIC_DM_INIT:
502 {
503 int trig_mode = (s->icr[0] >> 15) & 1;
504 int level = (s->icr[0] >> 14) & 1;
505 if (level == 0 && trig_mode == 1) {
ths5fafdf22007-09-16 21:08:06 +0000506 foreach_apic(apic_iter, deliver_bitmask,
bellardd3e9db92005-12-17 01:27:28 +0000507 apic_iter->arb_id = apic_iter->id );
bellardd592d302005-07-23 19:05:37 +0000508 return;
509 }
510 }
511 break;
512
513 case APIC_DM_SIPI:
ths5fafdf22007-09-16 21:08:06 +0000514 foreach_apic(apic_iter, deliver_bitmask,
bellardd3e9db92005-12-17 01:27:28 +0000515 apic_startup(apic_iter, vector_num) );
bellardd592d302005-07-23 19:05:37 +0000516 return;
517 }
518
bellardd592d302005-07-23 19:05:37 +0000519 apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, polarity,
520 trigger_mode);
521}
522
bellard574bbf72005-01-03 23:27:31 +0000523int apic_get_interrupt(CPUState *env)
524{
525 APICState *s = env->apic_state;
526 int intno;
527
528 /* if the APIC is installed or enabled, we let the 8259 handle the
529 IRQs */
530 if (!s)
531 return -1;
532 if (!(s->spurious_vec & APIC_SV_ENABLE))
533 return -1;
ths3b46e622007-09-17 08:09:54 +0000534
bellard574bbf72005-01-03 23:27:31 +0000535 /* XXX: spurious IRQ handling */
536 intno = get_highest_priority_int(s->irr);
537 if (intno < 0)
538 return -1;
bellardd592d302005-07-23 19:05:37 +0000539 if (s->tpr && intno <= s->tpr)
540 return s->spurious_vec & 0xff;
bellardb4511722006-10-08 18:20:51 +0000541 reset_bit(s->irr, intno);
bellard574bbf72005-01-03 23:27:31 +0000542 set_bit(s->isr, intno);
543 apic_update_irq(s);
544 return intno;
545}
546
ths0e21e122007-10-09 03:08:56 +0000547int apic_accept_pic_intr(CPUState *env)
548{
549 APICState *s = env->apic_state;
550 uint32_t lvt0;
551
552 if (!s)
553 return -1;
554
555 lvt0 = s->lvt[APIC_LVT_LINT0];
556
aurel32a5b38b52008-04-13 16:08:30 +0000557 if ((s->apicbase & MSR_IA32_APICBASE_ENABLE) == 0 ||
558 (lvt0 & APIC_LVT_MASKED) == 0)
ths0e21e122007-10-09 03:08:56 +0000559 return 1;
560
561 return 0;
562}
563
bellard574bbf72005-01-03 23:27:31 +0000564static uint32_t apic_get_current_count(APICState *s)
565{
566 int64_t d;
567 uint32_t val;
ths5fafdf22007-09-16 21:08:06 +0000568 d = (qemu_get_clock(vm_clock) - s->initial_count_load_time) >>
bellard574bbf72005-01-03 23:27:31 +0000569 s->count_shift;
570 if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
571 /* periodic */
bellardd592d302005-07-23 19:05:37 +0000572 val = s->initial_count - (d % ((uint64_t)s->initial_count + 1));
bellard574bbf72005-01-03 23:27:31 +0000573 } else {
574 if (d >= s->initial_count)
575 val = 0;
576 else
577 val = s->initial_count - d;
578 }
579 return val;
580}
581
582static void apic_timer_update(APICState *s, int64_t current_time)
583{
584 int64_t next_time, d;
ths3b46e622007-09-17 08:09:54 +0000585
bellard574bbf72005-01-03 23:27:31 +0000586 if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
ths5fafdf22007-09-16 21:08:06 +0000587 d = (current_time - s->initial_count_load_time) >>
bellard574bbf72005-01-03 23:27:31 +0000588 s->count_shift;
589 if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
aliguori681f8c22008-08-18 14:19:42 +0000590 if (!s->initial_count)
591 goto no_timer;
bellardd592d302005-07-23 19:05:37 +0000592 d = ((d / ((uint64_t)s->initial_count + 1)) + 1) * ((uint64_t)s->initial_count + 1);
bellard574bbf72005-01-03 23:27:31 +0000593 } else {
594 if (d >= s->initial_count)
595 goto no_timer;
bellardd592d302005-07-23 19:05:37 +0000596 d = (uint64_t)s->initial_count + 1;
bellard574bbf72005-01-03 23:27:31 +0000597 }
598 next_time = s->initial_count_load_time + (d << s->count_shift);
599 qemu_mod_timer(s->timer, next_time);
600 s->next_time = next_time;
601 } else {
602 no_timer:
603 qemu_del_timer(s->timer);
604 }
605}
606
607static void apic_timer(void *opaque)
608{
609 APICState *s = opaque;
610
aurel32a5b38b52008-04-13 16:08:30 +0000611 apic_local_deliver(s->cpu_env, APIC_LVT_TIMER);
bellard574bbf72005-01-03 23:27:31 +0000612 apic_timer_update(s, s->next_time);
613}
614
615static uint32_t apic_mem_readb(void *opaque, target_phys_addr_t addr)
616{
617 return 0;
618}
619
620static uint32_t apic_mem_readw(void *opaque, target_phys_addr_t addr)
621{
622 return 0;
623}
624
625static void apic_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
626{
627}
628
629static void apic_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
630{
631}
632
633static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
634{
635 CPUState *env;
636 APICState *s;
637 uint32_t val;
638 int index;
639
640 env = cpu_single_env;
641 if (!env)
642 return 0;
643 s = env->apic_state;
644
645 index = (addr >> 4) & 0xff;
646 switch(index) {
647 case 0x02: /* id */
648 val = s->id << 24;
649 break;
650 case 0x03: /* version */
651 val = 0x11 | ((APIC_LVT_NB - 1) << 16); /* version 0x11 */
652 break;
653 case 0x08:
654 val = s->tpr;
655 break;
bellardd592d302005-07-23 19:05:37 +0000656 case 0x09:
657 val = apic_get_arb_pri(s);
658 break;
bellard574bbf72005-01-03 23:27:31 +0000659 case 0x0a:
660 /* ppr */
661 val = apic_get_ppr(s);
662 break;
aurel32b237db32008-03-28 22:31:36 +0000663 case 0x0b:
664 val = 0;
665 break;
bellardd592d302005-07-23 19:05:37 +0000666 case 0x0d:
667 val = s->log_dest << 24;
668 break;
669 case 0x0e:
670 val = s->dest_mode << 28;
671 break;
bellard574bbf72005-01-03 23:27:31 +0000672 case 0x0f:
673 val = s->spurious_vec;
674 break;
675 case 0x10 ... 0x17:
676 val = s->isr[index & 7];
677 break;
678 case 0x18 ... 0x1f:
679 val = s->tmr[index & 7];
680 break;
681 case 0x20 ... 0x27:
682 val = s->irr[index & 7];
683 break;
684 case 0x28:
685 val = s->esr;
686 break;
bellard574bbf72005-01-03 23:27:31 +0000687 case 0x30:
688 case 0x31:
689 val = s->icr[index & 1];
690 break;
bellarde0fd8782005-11-21 23:26:26 +0000691 case 0x32 ... 0x37:
692 val = s->lvt[index - 0x32];
693 break;
bellard574bbf72005-01-03 23:27:31 +0000694 case 0x38:
695 val = s->initial_count;
696 break;
697 case 0x39:
698 val = apic_get_current_count(s);
699 break;
700 case 0x3e:
701 val = s->divide_conf;
702 break;
703 default:
704 s->esr |= ESR_ILLEGAL_ADDRESS;
705 val = 0;
706 break;
707 }
708#ifdef DEBUG_APIC
709 printf("APIC read: %08x = %08x\n", (uint32_t)addr, val);
710#endif
711 return val;
712}
713
714static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
715{
716 CPUState *env;
717 APICState *s;
718 int index;
719
720 env = cpu_single_env;
721 if (!env)
722 return;
723 s = env->apic_state;
724
725#ifdef DEBUG_APIC
726 printf("APIC write: %08x = %08x\n", (uint32_t)addr, val);
727#endif
728
729 index = (addr >> 4) & 0xff;
730 switch(index) {
731 case 0x02:
732 s->id = (val >> 24);
733 break;
bellarde0fd8782005-11-21 23:26:26 +0000734 case 0x03:
735 break;
bellard574bbf72005-01-03 23:27:31 +0000736 case 0x08:
737 s->tpr = val;
bellardd592d302005-07-23 19:05:37 +0000738 apic_update_irq(s);
bellard574bbf72005-01-03 23:27:31 +0000739 break;
bellarde0fd8782005-11-21 23:26:26 +0000740 case 0x09:
741 case 0x0a:
742 break;
bellard574bbf72005-01-03 23:27:31 +0000743 case 0x0b: /* EOI */
744 apic_eoi(s);
745 break;
bellardd592d302005-07-23 19:05:37 +0000746 case 0x0d:
747 s->log_dest = val >> 24;
748 break;
749 case 0x0e:
750 s->dest_mode = val >> 28;
751 break;
bellard574bbf72005-01-03 23:27:31 +0000752 case 0x0f:
753 s->spurious_vec = val & 0x1ff;
bellardd592d302005-07-23 19:05:37 +0000754 apic_update_irq(s);
bellard574bbf72005-01-03 23:27:31 +0000755 break;
bellarde0fd8782005-11-21 23:26:26 +0000756 case 0x10 ... 0x17:
757 case 0x18 ... 0x1f:
758 case 0x20 ... 0x27:
759 case 0x28:
760 break;
bellard574bbf72005-01-03 23:27:31 +0000761 case 0x30:
bellardd592d302005-07-23 19:05:37 +0000762 s->icr[0] = val;
763 apic_deliver(s, (s->icr[1] >> 24) & 0xff, (s->icr[0] >> 11) & 1,
764 (s->icr[0] >> 8) & 7, (s->icr[0] & 0xff),
765 (s->icr[0] >> 14) & 1, (s->icr[0] >> 15) & 1);
766 break;
bellard574bbf72005-01-03 23:27:31 +0000767 case 0x31:
bellardd592d302005-07-23 19:05:37 +0000768 s->icr[1] = val;
bellard574bbf72005-01-03 23:27:31 +0000769 break;
770 case 0x32 ... 0x37:
771 {
772 int n = index - 0x32;
773 s->lvt[n] = val;
774 if (n == APIC_LVT_TIMER)
775 apic_timer_update(s, qemu_get_clock(vm_clock));
776 }
777 break;
778 case 0x38:
779 s->initial_count = val;
780 s->initial_count_load_time = qemu_get_clock(vm_clock);
781 apic_timer_update(s, s->initial_count_load_time);
782 break;
bellarde0fd8782005-11-21 23:26:26 +0000783 case 0x39:
784 break;
bellard574bbf72005-01-03 23:27:31 +0000785 case 0x3e:
786 {
787 int v;
788 s->divide_conf = val & 0xb;
789 v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
790 s->count_shift = (v + 1) & 7;
791 }
792 break;
793 default:
794 s->esr |= ESR_ILLEGAL_ADDRESS;
795 break;
796 }
797}
798
bellardd592d302005-07-23 19:05:37 +0000799static void apic_save(QEMUFile *f, void *opaque)
800{
801 APICState *s = opaque;
802 int i;
bellard574bbf72005-01-03 23:27:31 +0000803
bellardd592d302005-07-23 19:05:37 +0000804 qemu_put_be32s(f, &s->apicbase);
805 qemu_put_8s(f, &s->id);
806 qemu_put_8s(f, &s->arb_id);
807 qemu_put_8s(f, &s->tpr);
808 qemu_put_be32s(f, &s->spurious_vec);
809 qemu_put_8s(f, &s->log_dest);
810 qemu_put_8s(f, &s->dest_mode);
811 for (i = 0; i < 8; i++) {
812 qemu_put_be32s(f, &s->isr[i]);
813 qemu_put_be32s(f, &s->tmr[i]);
814 qemu_put_be32s(f, &s->irr[i]);
815 }
816 for (i = 0; i < APIC_LVT_NB; i++) {
817 qemu_put_be32s(f, &s->lvt[i]);
818 }
819 qemu_put_be32s(f, &s->esr);
820 qemu_put_be32s(f, &s->icr[0]);
821 qemu_put_be32s(f, &s->icr[1]);
822 qemu_put_be32s(f, &s->divide_conf);
thsbee8d682007-12-16 23:41:11 +0000823 qemu_put_be32(f, s->count_shift);
bellardd592d302005-07-23 19:05:37 +0000824 qemu_put_be32s(f, &s->initial_count);
thsbee8d682007-12-16 23:41:11 +0000825 qemu_put_be64(f, s->initial_count_load_time);
826 qemu_put_be64(f, s->next_time);
bellarde6cf6a82006-08-17 10:48:06 +0000827
828 qemu_put_timer(f, s->timer);
bellardd592d302005-07-23 19:05:37 +0000829}
830
831static int apic_load(QEMUFile *f, void *opaque, int version_id)
832{
833 APICState *s = opaque;
834 int i;
835
bellarde6cf6a82006-08-17 10:48:06 +0000836 if (version_id > 2)
bellardd592d302005-07-23 19:05:37 +0000837 return -EINVAL;
838
839 /* XXX: what if the base changes? (registered memory regions) */
840 qemu_get_be32s(f, &s->apicbase);
841 qemu_get_8s(f, &s->id);
842 qemu_get_8s(f, &s->arb_id);
843 qemu_get_8s(f, &s->tpr);
844 qemu_get_be32s(f, &s->spurious_vec);
845 qemu_get_8s(f, &s->log_dest);
846 qemu_get_8s(f, &s->dest_mode);
847 for (i = 0; i < 8; i++) {
848 qemu_get_be32s(f, &s->isr[i]);
849 qemu_get_be32s(f, &s->tmr[i]);
850 qemu_get_be32s(f, &s->irr[i]);
851 }
852 for (i = 0; i < APIC_LVT_NB; i++) {
853 qemu_get_be32s(f, &s->lvt[i]);
854 }
855 qemu_get_be32s(f, &s->esr);
856 qemu_get_be32s(f, &s->icr[0]);
857 qemu_get_be32s(f, &s->icr[1]);
858 qemu_get_be32s(f, &s->divide_conf);
thsbee8d682007-12-16 23:41:11 +0000859 s->count_shift=qemu_get_be32(f);
bellardd592d302005-07-23 19:05:37 +0000860 qemu_get_be32s(f, &s->initial_count);
thsbee8d682007-12-16 23:41:11 +0000861 s->initial_count_load_time=qemu_get_be64(f);
862 s->next_time=qemu_get_be64(f);
bellarde6cf6a82006-08-17 10:48:06 +0000863
864 if (version_id >= 2)
865 qemu_get_timer(f, s->timer);
bellardd592d302005-07-23 19:05:37 +0000866 return 0;
867}
868
869static void apic_reset(void *opaque)
870{
871 APICState *s = opaque;
872 apic_init_ipi(s);
ths0e21e122007-10-09 03:08:56 +0000873
aurel32a5b38b52008-04-13 16:08:30 +0000874 if (s->id == 0) {
875 /*
876 * LINT0 delivery mode on CPU #0 is set to ExtInt at initialization
877 * time typically by BIOS, so PIC interrupt can be delivered to the
878 * processor when local APIC is enabled.
879 */
880 s->lvt[APIC_LVT_LINT0] = 0x700;
881 }
bellardd592d302005-07-23 19:05:37 +0000882}
bellard574bbf72005-01-03 23:27:31 +0000883
884static CPUReadMemoryFunc *apic_mem_read[3] = {
885 apic_mem_readb,
886 apic_mem_readw,
887 apic_mem_readl,
888};
889
890static CPUWriteMemoryFunc *apic_mem_write[3] = {
891 apic_mem_writeb,
892 apic_mem_writew,
893 apic_mem_writel,
894};
895
896int apic_init(CPUState *env)
897{
898 APICState *s;
bellard574bbf72005-01-03 23:27:31 +0000899
bellardd3e9db92005-12-17 01:27:28 +0000900 if (last_apic_id >= MAX_APICS)
901 return -1;
bellardd592d302005-07-23 19:05:37 +0000902 s = qemu_mallocz(sizeof(APICState));
bellard574bbf72005-01-03 23:27:31 +0000903 if (!s)
904 return -1;
bellard574bbf72005-01-03 23:27:31 +0000905 env->apic_state = s;
bellardd592d302005-07-23 19:05:37 +0000906 s->id = last_apic_id++;
thseae76292007-04-03 16:38:34 +0000907 env->cpuid_apic_id = s->id;
bellard574bbf72005-01-03 23:27:31 +0000908 s->cpu_env = env;
ths5fafdf22007-09-16 21:08:06 +0000909 s->apicbase = 0xfee00000 |
bellardd592d302005-07-23 19:05:37 +0000910 (s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE;
bellard574bbf72005-01-03 23:27:31 +0000911
aurel32a5b38b52008-04-13 16:08:30 +0000912 apic_reset(s);
ths0e21e122007-10-09 03:08:56 +0000913
bellardd592d302005-07-23 19:05:37 +0000914 /* XXX: mapping more APICs at the same memory location */
bellard574bbf72005-01-03 23:27:31 +0000915 if (apic_io_memory == 0) {
916 /* NOTE: the APIC is directly connected to the CPU - it is not
917 on the global memory bus. */
ths5fafdf22007-09-16 21:08:06 +0000918 apic_io_memory = cpu_register_io_memory(0, apic_mem_read,
bellard574bbf72005-01-03 23:27:31 +0000919 apic_mem_write, NULL);
bellardd592d302005-07-23 19:05:37 +0000920 cpu_register_physical_memory(s->apicbase & ~0xfff, 0x1000,
921 apic_io_memory);
bellard574bbf72005-01-03 23:27:31 +0000922 }
923 s->timer = qemu_new_timer(vm_clock, apic_timer, s);
bellardd592d302005-07-23 19:05:37 +0000924
thsbe0164f2007-08-26 17:33:08 +0000925 register_savevm("apic", s->id, 2, apic_save, apic_load, s);
bellardd592d302005-07-23 19:05:37 +0000926 qemu_register_reset(apic_reset, s);
ths3b46e622007-09-17 08:09:54 +0000927
bellardd3e9db92005-12-17 01:27:28 +0000928 local_apics[s->id] = s;
bellard574bbf72005-01-03 23:27:31 +0000929 return 0;
930}
bellardd592d302005-07-23 19:05:37 +0000931
932static void ioapic_service(IOAPICState *s)
933{
bellardb1fc0342005-07-23 21:43:15 +0000934 uint8_t i;
935 uint8_t trig_mode;
bellardd592d302005-07-23 19:05:37 +0000936 uint8_t vector;
bellardb1fc0342005-07-23 21:43:15 +0000937 uint8_t delivery_mode;
bellardd592d302005-07-23 19:05:37 +0000938 uint32_t mask;
939 uint64_t entry;
940 uint8_t dest;
941 uint8_t dest_mode;
bellardb1fc0342005-07-23 21:43:15 +0000942 uint8_t polarity;
bellardd3e9db92005-12-17 01:27:28 +0000943 uint32_t deliver_bitmask[MAX_APIC_WORDS];
bellardd592d302005-07-23 19:05:37 +0000944
bellardb1fc0342005-07-23 21:43:15 +0000945 for (i = 0; i < IOAPIC_NUM_PINS; i++) {
946 mask = 1 << i;
bellardd592d302005-07-23 19:05:37 +0000947 if (s->irr & mask) {
bellardb1fc0342005-07-23 21:43:15 +0000948 entry = s->ioredtbl[i];
bellardd592d302005-07-23 19:05:37 +0000949 if (!(entry & APIC_LVT_MASKED)) {
bellardb1fc0342005-07-23 21:43:15 +0000950 trig_mode = ((entry >> 15) & 1);
bellardd592d302005-07-23 19:05:37 +0000951 dest = entry >> 56;
952 dest_mode = (entry >> 11) & 1;
bellardb1fc0342005-07-23 21:43:15 +0000953 delivery_mode = (entry >> 8) & 7;
954 polarity = (entry >> 13) & 1;
955 if (trig_mode == APIC_TRIGGER_EDGE)
956 s->irr &= ~mask;
957 if (delivery_mode == APIC_DM_EXTINT)
958 vector = pic_read_irq(isa_pic);
959 else
960 vector = entry & 0xff;
ths3b46e622007-09-17 08:09:54 +0000961
bellardd3e9db92005-12-17 01:27:28 +0000962 apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
ths5fafdf22007-09-16 21:08:06 +0000963 apic_bus_deliver(deliver_bitmask, delivery_mode,
bellardd3e9db92005-12-17 01:27:28 +0000964 vector, polarity, trig_mode);
bellardd592d302005-07-23 19:05:37 +0000965 }
966 }
967 }
968}
969
970void ioapic_set_irq(void *opaque, int vector, int level)
971{
972 IOAPICState *s = opaque;
973
974 if (vector >= 0 && vector < IOAPIC_NUM_PINS) {
975 uint32_t mask = 1 << vector;
976 uint64_t entry = s->ioredtbl[vector];
977
978 if ((entry >> 15) & 1) {
979 /* level triggered */
980 if (level) {
981 s->irr |= mask;
982 ioapic_service(s);
983 } else {
984 s->irr &= ~mask;
985 }
986 } else {
987 /* edge triggered */
988 if (level) {
989 s->irr |= mask;
990 ioapic_service(s);
991 }
992 }
993 }
994}
995
996static uint32_t ioapic_mem_readl(void *opaque, target_phys_addr_t addr)
997{
998 IOAPICState *s = opaque;
999 int index;
1000 uint32_t val = 0;
1001
1002 addr &= 0xff;
1003 if (addr == 0x00) {
1004 val = s->ioregsel;
1005 } else if (addr == 0x10) {
1006 switch (s->ioregsel) {
1007 case 0x00:
1008 val = s->id << 24;
1009 break;
1010 case 0x01:
1011 val = 0x11 | ((IOAPIC_NUM_PINS - 1) << 16); /* version 0x11 */
1012 break;
1013 case 0x02:
1014 val = 0;
1015 break;
1016 default:
1017 index = (s->ioregsel - 0x10) >> 1;
1018 if (index >= 0 && index < IOAPIC_NUM_PINS) {
1019 if (s->ioregsel & 1)
1020 val = s->ioredtbl[index] >> 32;
1021 else
1022 val = s->ioredtbl[index] & 0xffffffff;
1023 }
1024 }
1025#ifdef DEBUG_IOAPIC
1026 printf("I/O APIC read: %08x = %08x\n", s->ioregsel, val);
1027#endif
1028 }
1029 return val;
1030}
1031
1032static void ioapic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
1033{
1034 IOAPICState *s = opaque;
1035 int index;
1036
1037 addr &= 0xff;
1038 if (addr == 0x00) {
1039 s->ioregsel = val;
1040 return;
1041 } else if (addr == 0x10) {
1042#ifdef DEBUG_IOAPIC
1043 printf("I/O APIC write: %08x = %08x\n", s->ioregsel, val);
1044#endif
1045 switch (s->ioregsel) {
1046 case 0x00:
1047 s->id = (val >> 24) & 0xff;
1048 return;
1049 case 0x01:
1050 case 0x02:
1051 return;
1052 default:
1053 index = (s->ioregsel - 0x10) >> 1;
1054 if (index >= 0 && index < IOAPIC_NUM_PINS) {
1055 if (s->ioregsel & 1) {
1056 s->ioredtbl[index] &= 0xffffffff;
1057 s->ioredtbl[index] |= (uint64_t)val << 32;
1058 } else {
1059 s->ioredtbl[index] &= ~0xffffffffULL;
1060 s->ioredtbl[index] |= val;
1061 }
1062 ioapic_service(s);
1063 }
1064 }
1065 }
1066}
1067
1068static void ioapic_save(QEMUFile *f, void *opaque)
1069{
1070 IOAPICState *s = opaque;
1071 int i;
1072
1073 qemu_put_8s(f, &s->id);
1074 qemu_put_8s(f, &s->ioregsel);
1075 for (i = 0; i < IOAPIC_NUM_PINS; i++) {
1076 qemu_put_be64s(f, &s->ioredtbl[i]);
1077 }
1078}
1079
1080static int ioapic_load(QEMUFile *f, void *opaque, int version_id)
1081{
1082 IOAPICState *s = opaque;
1083 int i;
1084
1085 if (version_id != 1)
1086 return -EINVAL;
1087
1088 qemu_get_8s(f, &s->id);
1089 qemu_get_8s(f, &s->ioregsel);
1090 for (i = 0; i < IOAPIC_NUM_PINS; i++) {
1091 qemu_get_be64s(f, &s->ioredtbl[i]);
1092 }
1093 return 0;
1094}
1095
1096static void ioapic_reset(void *opaque)
1097{
1098 IOAPICState *s = opaque;
1099 int i;
1100
1101 memset(s, 0, sizeof(*s));
1102 for(i = 0; i < IOAPIC_NUM_PINS; i++)
1103 s->ioredtbl[i] = 1 << 16; /* mask LVT */
1104}
1105
1106static CPUReadMemoryFunc *ioapic_mem_read[3] = {
1107 ioapic_mem_readl,
1108 ioapic_mem_readl,
1109 ioapic_mem_readl,
1110};
1111
1112static CPUWriteMemoryFunc *ioapic_mem_write[3] = {
1113 ioapic_mem_writel,
1114 ioapic_mem_writel,
1115 ioapic_mem_writel,
1116};
1117
1118IOAPICState *ioapic_init(void)
1119{
1120 IOAPICState *s;
1121 int io_memory;
1122
bellardb1fc0342005-07-23 21:43:15 +00001123 s = qemu_mallocz(sizeof(IOAPICState));
bellardd592d302005-07-23 19:05:37 +00001124 if (!s)
1125 return NULL;
bellardd592d302005-07-23 19:05:37 +00001126 ioapic_reset(s);
1127 s->id = last_apic_id++;
1128
ths5fafdf22007-09-16 21:08:06 +00001129 io_memory = cpu_register_io_memory(0, ioapic_mem_read,
bellardd592d302005-07-23 19:05:37 +00001130 ioapic_mem_write, s);
1131 cpu_register_physical_memory(0xfec00000, 0x1000, io_memory);
1132
1133 register_savevm("ioapic", 0, 1, ioapic_save, ioapic_load, s);
1134 qemu_register_reset(ioapic_reset, s);
ths3b46e622007-09-17 08:09:54 +00001135
bellardd592d302005-07-23 19:05:37 +00001136 return s;
1137}