ia64/xen-unstable

view tools/ioemu/hw/ioapic.c @ 6946:e703abaf6e3d

Add behaviour to the remove methods to remove the transaction's path itself. This allows us to write Remove(path) to remove the specified path rather than having to slice the path ourselves.
author emellor@ewan
date Sun Sep 18 14:42:13 2005 +0100 (2005-09-18)
parents 4669354bba9a
children b3a255e88810
line source
1 /////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2001 MandrakeSoft S.A.
4 //
5 // MandrakeSoft S.A.
6 // 43, rue d'Aboukir
7 // 75002 Paris - France
8 // http://www.linux-mandrake.com/
9 // http://www.mandrakesoft.com/
10 //
11 // This library is free software; you can redistribute it and/or
12 // modify it under the terms of the GNU Lesser General Public
13 // License as published by the Free Software Foundation; either
14 // version 2 of the License, or (at your option) any later version.
15 //
16 // This library is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 // Lesser General Public License for more details.
20 //
21 // You should have received a copy of the GNU Lesser General Public
22 // License along with this library; if not, write to the Free Software
23 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 //
26 #include "vl.h"
27 #include "ioapic.h"
29 #ifdef __OS
30 #undef __OS
31 #endif
32 #ifdef __i386__
33 #define __OS "l"
34 #else
35 #define __OS "q"
36 #endif
37 #define ADDR (*(volatile long *) addr)
39 #ifdef IOAPIC_DEBUG
40 #define IOAPIC_LOG(a...) fprintf(logfile, ##a)
41 #else
42 #define IOAPIC_LOG(a...)
43 #endif
45 static IOAPICState *ioapic;
47 #define IOAPIC_ERR(a...) fprintf(logfile, ##a)
48 static __inline__ int test_and_set_bit(long nr, volatile void * addr)
49 {
50 long oldbit;
52 __asm__ __volatile__(
53 "bts"__OS" %2,%1\n\tsbb"__OS" %0,%0"
54 :"=r" (oldbit),"=m" (ADDR)
55 :"Ir" (nr) : "memory");
56 return oldbit;
57 }
59 static __inline__ int test_and_clear_bit(long nr, volatile void * addr)
60 {
61 long oldbit;
63 __asm__ __volatile__( LOCK_PREFIX
64 "btr"__OS" %2,%1\n\tsbb"__OS" %0,%0"
65 :"=r" (oldbit),"=m" (ADDR)
66 :"dIr" (nr) : "memory");
67 return oldbit;
68 }
70 static __inline__ void clear_bit(long nr, volatile void * addr)
71 {
72 __asm__ __volatile__(
73 "btr"__OS" %1,%0"
74 :"=m" (ADDR)
75 :"Ir" (nr));
76 }
78 static inline
79 void get_shareinfo_apic_msg(vlapic_info *share_info){
80 while(test_and_set_bit(VL_STATE_MSG_LOCK, &share_info->vl_state)){};
81 }
83 static inline
84 void put_shareinfo_apic_msg(vlapic_info *share_info){
85 clear_bit(VL_STATE_MSG_LOCK, &share_info->vl_state);
86 }
87 static inline
88 void get_shareinfo_eoi(vlapic_info *share_info){
89 while(test_and_set_bit(VL_STATE_EOI_LOCK, &share_info->vl_state)){};
90 }
92 static inline
93 void put_shareinfo_eoi(vlapic_info *share_info){
94 clear_bit(VL_STATE_EOI_LOCK, &share_info->vl_state);
95 }
98 static inline
99 void get_shareinfo_ext(vlapic_info *share_info){
100 while(test_and_set_bit(VL_STATE_EXT_LOCK, &share_info->vl_state));
101 }
103 static inline
104 void put_shareinfo_ext(vlapic_info *share_info){
105 clear_bit(VL_STATE_EXT_LOCK, &share_info->vl_state);
106 }
109 static __inline__ int test_bit(int nr, uint32_t value){
110 return value & (1 << nr);
111 }
113 static void ioapic_enable(IOAPICState *s, uint8_t enable)
114 {
115 if (!enable ^ IOAPICEnabled(s)) return;
116 if(enable)
117 s->flags |= IOAPIC_ENABLE_FLAG;
118 else
119 s->flags &= ~IOAPIC_ENABLE_FLAG;
120 }
122 #ifdef IOAPIC_DEBUG
123 static void
124 ioapic_dump_redir(IOAPICState *s, uint8_t entry)
125 {
126 if (!s)
127 return;
129 RedirStatus redir = s->redirtbl[entry];
131 fprintf(logfile, "entry %x: "
132 "vector %x deliver_mod %x destmode %x delivestatus %x "
133 "polarity %x remote_irr %x trigmod %x mask %x dest_id %x\n",
134 entry,
135 redir.RedirForm.vector, redir.RedirForm.deliver_mode,
136 redir.RedirForm.destmode, redir.RedirForm.delivestatus,
137 redir.RedirForm.polarity, redir.RedirForm.remoteirr,
138 redir.RedirForm.trigmod, redir.RedirForm.mask,
139 redir.RedirForm.dest_id);
140 }
142 static void
143 ioapic_dump_shareinfo(IOAPICState *s , int number)
144 {
145 if (!s || !s->lapic_info[number])
146 return;
147 vlapic_info *m = s->lapic_info[number];
148 IOAPIC_LOG("lapic_info %x : "
149 "vl_lapic_id %x vl_logical_dest %x vl_dest_format %x vl_arb_id %x\n",
150 number, m->vl_lapic_id, m->vl_logical_dest, m->vl_dest_format, m->vl_arb_id );
151 }
152 #endif
154 static void
155 ioapic_save(QEMUFile* f,void* opaque)
156 {
157 IOAPIC_ERR("no implementation for ioapic_save\n");
158 }
160 static
161 int ioapic_load(QEMUFile* f,void* opaque,int version_id)
162 {
163 IOAPIC_ERR("no implementation for ioapic_load\n");
164 return 0;
165 }
167 uint32_t
168 ioapic_mem_readb(void *opaque, target_phys_addr_t addr)
169 {
170 IOAPIC_ERR("ioapic_mem_readb\n");
171 return 0;
172 }
174 uint32_t
175 ioapic_mem_readw(void *opaque, target_phys_addr_t addr)
176 {
177 IOAPIC_ERR("ioapic_mem_readw\n");
178 return 0;
179 }
181 static
182 void ioapic_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
183 {
184 IOAPIC_ERR("ioapic_mem_writeb\n");
185 }
187 static
188 void ioapic_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
189 {
190 IOAPIC_ERR("ioapic_mem_writew\n");
191 }
193 static
194 uint32_t ioapic_mem_readl(void *opaque, target_phys_addr_t addr)
195 {
196 unsigned short ioregsel;
197 IOAPICState *s = opaque;
198 uint32_t result = 0;
199 uint32_t redir_index = 0;
200 uint64_t redir_content = 0;
202 IOAPIC_LOG("apic_mem_readl addr %x\n", addr);
203 if (!s){
204 IOAPIC_ERR("null pointer for apic_mem_readl\n");
205 return result;
206 }
208 addr &= 0xff;
209 if(addr == 0x00){
210 result = s->ioregsel;
211 return result;
212 }else if (addr != 0x10){
213 IOAPIC_ERR("apic_mem_readl address error\n");
214 return result;
215 }
217 ioregsel = s->ioregsel;
219 switch (ioregsel){
220 case IOAPIC_REG_APIC_ID:
221 result = ((s->id & 0xf) << 24);
222 break;
223 case IOAPIC_REG_VERSION:
224 result = ((((IOAPIC_NUM_PINS-1) & 0xff) << 16)
225 | (IOAPIC_VERSION_ID & 0x0f));
226 break;
227 case IOAPIC_REG_ARB_ID:
228 //FIXME
229 result = ((s->id & 0xf) << 24);
230 break;
231 default:
232 redir_index = (ioregsel - 0x10) >> 1;
233 if (redir_index >= 0 && redir_index < IOAPIC_NUM_PINS){
234 redir_content = s->redirtbl[redir_index].value;
235 result = (ioregsel & 0x1)?
236 (redir_content >> 32) & 0xffffffff :
237 redir_content & 0xffffffff;
238 }else{
239 IOAPIC_ERR(
240 "upic_mem_readl:undefined ioregsel %x\n",
241 ioregsel);
242 }
243 }
244 return result;
245 }
247 static
248 void ioapic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
249 {
250 IOAPICState *s = opaque;
251 uint32_t redir_index = 0;
252 uint64_t redir_content;
254 IOAPIC_LOG("apic_mem_writel addr %x val %x\n", addr, val);
256 if (!s){
257 IOAPIC_ERR("apic_mem_writel: null opaque\n");
258 return;
259 }
261 addr &= 0xff;
262 if (addr == 0x00){
263 s->ioregsel = val;
264 return;
265 }else if (addr != 0x10){
266 IOAPIC_ERR("apic_mem_writel: unsupported address\n");
267 }
269 switch (s->ioregsel){
270 case IOAPIC_REG_APIC_ID:
271 s->id = (val >> 24) & 0xf;
272 break;
273 case IOAPIC_REG_VERSION:
274 IOAPIC_ERR("apic_mem_writel: version register read only\n");
275 break;
276 case IOAPIC_REG_ARB_ID:
277 s->arb_id = val;
278 break;
279 default:
280 redir_index = (s->ioregsel - 0x10) >> 1;
281 // IOAPIC_LOG("apic_mem_write: change redir :index %x before %lx, val %x\n", redir_index, s->redirtbl[redir_index].value, val);
282 if (redir_index >= 0 && redir_index < IOAPIC_NUM_PINS){
283 redir_content = s->redirtbl[redir_index].value;
284 if (s->ioregsel & 0x1)
285 redir_content = (((uint64_t)val & 0xffffffff) << 32) | (redir_content & 0xffffffff);
286 else
287 redir_content = ((redir_content >> 32) << 32) | (val & 0xffffffff);
288 s->redirtbl[redir_index].value = redir_content;
289 }else {
290 IOAPIC_ERR("apic_mem_writel: error register\n");
291 }
292 //IOAPIC_LOG("after value is %lx\n", s->redirtbl[redir_index].value);
293 }
294 }
296 static CPUReadMemoryFunc *ioapic_mem_read[3] = {
297 ioapic_mem_readb,
298 ioapic_mem_readw,
299 ioapic_mem_readl,
300 };
302 static CPUWriteMemoryFunc *ioapic_mem_write[3] = {
303 ioapic_mem_writeb,
304 ioapic_mem_writew,
305 ioapic_mem_writel,
306 };
308 void
309 IOAPICReset(IOAPICState *s)
310 {
311 int i;
312 if (!s)
313 return ;
315 memset(s, 0, sizeof(IOAPICState));
317 for (i = 0; i < IOAPIC_NUM_PINS; i++)
318 s->redirtbl[i].RedirForm.mask = 0x1;
319 // IOAPIC_LOG("after Reset %lx\n", s->redirtbl[0].value);
320 }
322 void
323 ioapic_update_config(IOAPICState *s, unsigned long address, uint8_t enable)
324 {
325 int ioapic_mem;
326 if (!s)
327 return;
329 ioapic_enable(s, enable);
331 if (address != s->base_address){
332 ioapic_mem = cpu_register_io_memory(0, ioapic_mem_read, ioapic_mem_write, s);
333 cpu_register_physical_memory(address, IOAPIC_MEM_LENGTH, ioapic_mem);
334 s->base_address = ioapic_mem;
335 }
336 }
338 #define direct_intr(mode) \
339 (mode == VLAPIC_DELIV_MODE_SMI || \
340 mode == VLAPIC_DELIV_MODE_NMI || \
341 mode == VLAPIC_DELIV_MODE_INIT ||\
342 mode == VLAPIC_DELIV_MODE_STARTUP)
344 int
345 ioapic_inj_irq(IOAPICState *s, uint8_t dest, uint8_t vector, uint8_t trig_mode, uint8_t delivery_mode)
346 {
347 int msg_count;
348 if (!s || !s->lapic_info[dest]){
349 IOAPIC_ERR("ioapic_inj_irq NULL parameter\n");
350 return 0;
351 }
352 IOAPIC_LOG("ioapic_inj_irq %d , trig %d delive mode %d\n",
353 vector, trig_mode, delivery_mode);
354 switch(delivery_mode){
355 case VLAPIC_DELIV_MODE_FIXED:
356 case VLAPIC_DELIV_MODE_LPRI:
357 get_shareinfo_apic_msg(s->lapic_info[dest]);
358 msg_count = s->lapic_info[dest]->apic_msg_count;
359 s->lapic_info[dest]->vl_apic_msg[msg_count].deliv_mode = delivery_mode;
360 s->lapic_info[dest]->vl_apic_msg[msg_count].level = trig_mode;
361 s->lapic_info[dest]->vl_apic_msg[msg_count].vector = vector;
362 s->lapic_info[dest]->vl_apic_msg[msg_count].vector = vector;
363 s->lapic_info[dest]->apic_msg_count ++;
364 put_shareinfo_apic_msg(s->lapic_info[dest]);
365 break;
366 case VLAPIC_DELIV_MODE_EXT:
367 /* get_shareinfo_ext(s->lapic_info[dest]);
368 test_and_set_bit(vector, &s->lapic_info[dest]->vl_ext_intr[0]);
369 put_shareinfo_ext(s->lapic_info[dest]);*/
370 IOAPIC_ERR("<ioapic_inj_irq> Ext interrupt\n");
371 return 0;
372 default:
373 IOAPIC_ERR("<ioapic_inj_irq> error delivery mode\n");
374 break;
375 }
376 return 1;
377 }
379 int
380 ioapic_match_logical_addr(IOAPICState *s, int number, uint8_t address)
381 {
382 if(!s || !s->lapic_info[number]){
383 IOAPIC_ERR("ioapic_match_logical_addr NULL parameter: "
384 "number: %i s %p address %x\n",
385 number, s, address);
386 return 0;
387 }
388 IOAPIC_LOG("ioapic_match_logical_addr number %i address %x\n",
389 number, address);
391 if (((s->lapic_info[number]->vl_dest_format >> 28 ) & 0xf) != 0xf) {
392 IOAPIC_ERR("ioapic_match_logical_addr: cluster model not implemented still%x"
393 ,s->lapic_info[number]->vl_dest_format);
394 #ifdef IOAPIC_DEBUG
395 ioapic_dump_shareinfo(s, number);
396 #endif
397 return 0;
398 }
399 return ((address & ((s->lapic_info[number]->vl_logical_dest >> 24) & 0xff)) != 0);
400 }
402 int
403 ioapic_get_apr_lowpri(IOAPICState *s, int number)
404 {
405 if(!s || !s->lapic_info[number]){
406 IOAPIC_ERR("ioapic_get_apr_lowpri NULL parameter\n");
407 return 0;
408 }
409 return s->lapic_info[number]->vl_arb_id;
410 }
412 uint32_t
413 ioapic_get_delivery_bitmask(IOAPICState *s,
414 uint8_t dest, uint8_t dest_mode, uint8_t vector, uint8_t delivery_mode)
415 {
416 uint32_t mask = 0;
417 int low_priority = 256, selected = -1, i;
418 fprintf(logfile, "<ioapic_get_delivery_bitmask>: dest %d dest_mode %d"
419 "vector %d del_mode %d, lapic_count %d\n",
420 dest, dest_mode, vector, delivery_mode, s->lapic_count);
421 if (!s) return mask;
422 if (dest_mode == 0) { //Physical mode
423 if ((dest < s->lapic_count) && s->lapic_info[dest])
424 mask = 1 << dest;
425 }
426 else {
427 /* logical destination. call match_logical_addr for each APIC. */
428 if (dest == 0) return 0;
429 for (i=0; i< s->lapic_count; i++) {
430 //FIXME focus one, since no such issue on IPF, shoudl we add it?
431 if ( s->lapic_info[i] && ioapic_match_logical_addr(s, i, dest)){
432 if (delivery_mode != APIC_DM_LOWPRI)
433 mask |= (1<<i);
434 else {
435 if (low_priority > ioapic_get_apr_lowpri(s, i)){
436 low_priority = ioapic_get_apr_lowpri(s, i);
437 selected = i;
438 }
439 fprintf(logfile, "%d low_priority %d apr %d select %d\n",
440 i, low_priority, ioapic_get_apr_lowpri(s, i), selected);
441 }
442 }
443 }
444 if (delivery_mode == APIC_DM_LOWPRI && (selected != -1))
445 mask |= (1<< selected);
446 }
447 return mask;
448 }
450 void
451 ioapic_deliver(IOAPICState *s, int irqno){
452 uint8_t dest = s->redirtbl[irqno].RedirForm.dest_id;
453 uint8_t dest_mode = s->redirtbl[irqno].RedirForm.destmode;
454 uint8_t delivery_mode = s->redirtbl[irqno].RedirForm.deliver_mode;
455 uint8_t vector = s->redirtbl[irqno].RedirForm.vector;
456 uint8_t trig_mode = s->redirtbl[irqno].RedirForm.trigmod;
457 uint8_t bit;
458 uint32_t deliver_bitmask;
460 IOAPIC_LOG("IOAPIC deliver: "
461 "dest %x dest_mode %x delivery_mode %x vector %x trig_mode %x\n",
462 dest, dest_mode, delivery_mode, vector, trig_mode);
464 deliver_bitmask =
465 ioapic_get_delivery_bitmask(s, dest, dest_mode, vector, delivery_mode);
467 IOAPIC_LOG("ioapic_get_delivery_bitmask return %x\n", deliver_bitmask);
468 if (!deliver_bitmask){
469 IOAPIC_ERR("Ioapic deliver, no target on destination\n");
470 return ;
471 }
473 switch (delivery_mode){
474 case VLAPIC_DELIV_MODE_FIXED:
475 case VLAPIC_DELIV_MODE_LPRI:
476 case VLAPIC_DELIV_MODE_EXT:
477 break;
478 case VLAPIC_DELIV_MODE_SMI:
479 case VLAPIC_DELIV_MODE_NMI:
480 case VLAPIC_DELIV_MODE_INIT:
481 case VLAPIC_DELIV_MODE_STARTUP:
482 default:
483 IOAPIC_ERR("Not support delivey mode %d\n", delivery_mode);
484 return ;
485 }
487 for (bit = 0; bit < s->lapic_count; bit++){
488 if (deliver_bitmask & (1 << bit)){
489 if (s->lapic_info[bit]){
490 ioapic_inj_irq(s, bit, vector, trig_mode, delivery_mode);
491 }
492 }
493 }
494 }
496 static inline int __fls(u32 word)
497 {
498 int bit;
499 __asm__("bsrl %1,%0"
500 :"=r" (bit)
501 :"rm" (word));
502 return word ? bit : -1;
503 }
505 #if 0
506 static __inline__ int find_highest_bit(unsigned long *data, int length){
507 while(length && !data[--length]);
508 return __fls(data[length]) + 32 * length;
509 }
510 #endif
511 int
512 ioapic_get_highest_irq(IOAPICState *s){
513 uint32_t irqs;
514 if (!s)
515 return -1;
516 irqs = s->irr & ~s->isr;
517 return __fls(irqs);
518 }
521 void
522 service_ioapic(IOAPICState *s){
523 int irqno;
525 while((irqno = ioapic_get_highest_irq(s)) != -1){
526 IOAPIC_LOG("service_ioapic: highest irqno %x\n", irqno);
528 if (!s->redirtbl[irqno].RedirForm.mask)
529 ioapic_deliver(s, irqno);
531 if (s->redirtbl[irqno].RedirForm.trigmod == IOAPIC_LEVEL_TRIGGER){
532 s->isr |= (1 << irqno);
533 }
534 // clear_bit(irqno, &s->irr);
535 s->irr &= ~(1 << irqno);
536 }
537 }
539 void
540 ioapic_update_irq(IOAPICState *s)
541 {
542 s->INTR = 1;
543 }
545 void
546 ioapic_set_irq(IOAPICState *s, int irq, int level)
547 {
548 IOAPIC_LOG("ioapic_set_irq %x %x\n", irq, level);
550 /* Timer interrupt implemented on HV side */
551 if(irq == 0x0) return;
552 if (!s){
553 fprintf(logfile, "ioapic_set_irq null parameter\n");
554 return;
555 }
556 if (!IOAPICEnabled(s) || s->redirtbl[irq].RedirForm.mask)
557 return;
558 #ifdef IOAPIC_DEBUG
559 ioapic_dump_redir(s, irq);
560 #endif
561 if (irq >= 0 && irq < IOAPIC_NUM_PINS){
562 uint32_t bit = 1 << irq;
563 if (s->redirtbl[irq].RedirForm.trigmod == IOAPIC_LEVEL_TRIGGER){
564 if(level)
565 s->irr |= bit;
566 else
567 s->irr &= ~bit;
568 }else{
569 if(level)
570 /* XXX No irr clear for edge interrupt */
571 s->irr |= bit;
572 }
573 }
575 ioapic_update_irq(s);
576 }
578 void
579 ioapic_legacy_irq(int irq, int level)
580 {
581 ioapic_set_irq(ioapic, irq, level);
582 }
584 static inline int find_highest_bit(u32 *data, int length){
585 while(length && !data[--length]);
586 return __fls(data[length]) + 32 * length;
587 }
589 int
590 get_redir_num(IOAPICState *s, int vector){
591 int i = 0;
592 if(!s){
593 IOAPIC_ERR("Null parameter for get_redir_num\n");
594 return -1;
595 }
596 for(; i < IOAPIC_NUM_PINS-1; i++){
597 if (s->redirtbl[i].RedirForm.vector == vector)
598 return i;
599 }
600 return -1;
601 }
603 void
604 ioapic_update_EOI()
605 {
606 int i = 0;
607 uint32_t isr_info ;
608 uint32_t vector;
609 IOAPICState *s = ioapic;
611 isr_info = s->isr;
613 for (i = 0; i < s->lapic_count; i++){
614 if (!s->lapic_info[i] ||
615 !test_bit(VL_STATE_EOI, s->lapic_info[i]->vl_state))
616 continue;
617 get_shareinfo_eoi(s->lapic_info[i]);
618 while((vector = find_highest_bit((unsigned int *)&s->lapic_info[i]->vl_eoi[0],VLAPIC_INT_COUNT_32)) != -1){
619 int redir_num;
620 if ((redir_num = get_redir_num(s, vector)) == -1){
621 IOAPIC_ERR("Can't find redir item for %d EOI \n", vector);
622 continue;
623 }
624 if (!test_and_clear_bit(redir_num, &s->isr)){
625 IOAPIC_ERR("redir %d not set for %d EOI\n", redir_num, vector);
626 continue;
627 }
628 clear_bit(vector, &s->lapic_info[i]->vl_eoi[0]);
629 }
630 clear_bit(VL_STATE_EOI, &s->lapic_info[i]->vl_state);
631 put_shareinfo_eoi(s->lapic_info[i]);
632 }
633 }
636 void
637 ioapic_init_apic_info(IOAPICState *s)
638 {
639 #ifdef IOAPIC_DEBUG
640 fprintf(logfile, "ioapic_init_apic_info\n");
641 if (!s)
642 return;
643 #endif
645 #if 0
646 if (!vio || !(vio->vl_number)){
647 fprintf(logfile, "null vio or o vl number\n");
648 return;
649 }
651 for (i = 0; i < MAX_LAPIC_NUM; i++) s->lapic_info[i] = NULL;
653 s->lapic_count = vio->vl_number;
654 for (i = 0; i < vio->vl_number; i++)
655 s->lapic_info[i] = vio->vl_info + i;
656 #endif
658 }
660 void
661 ioapic_intack(IOAPICState *s)
662 {
663 #ifdef IOAPIC_DEBUG
664 if (!s){
665 fprintf(logfile, "ioapic_intack null parameter\n");
666 return;
667 }
668 #endif
669 if (!s) s->INTR = 0;
670 }
672 int
673 ioapic_has_intr()
674 {
675 return ioapic->INTR;
676 }
678 void
679 do_ioapic()
680 {
681 service_ioapic(ioapic);
682 ioapic_intack(ioapic);
683 }
685 IOAPICState *
686 IOAPICInit( )
687 {
688 IOAPICState *s;
690 s = qemu_mallocz(sizeof(IOAPICState));
691 if (!s){
692 fprintf(logfile, "IOAPICInit: malloc failed\n");
693 return NULL;
694 }
696 IOAPICReset(s);
697 ioapic_init_apic_info(s);
698 register_savevm("ioapic", 0, 1, ioapic_save, ioapic_load, s);
699 /* Remove after GFW ready */
700 ioapic_update_config(s, 0xfec00000, 1);
702 ioapic = s;
703 return s;
704 }