86 |
|
|
87 |
static void pic_irq_request(void *opaque, int level) |
static void pic_irq_request(void *opaque, int level) |
88 |
{ |
{ |
89 |
|
CPUState *env = opaque; |
90 |
if (level) |
if (level) |
91 |
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); |
cpu_interrupt(env, CPU_INTERRUPT_HARD); |
92 |
else |
else |
93 |
cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); |
cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); |
94 |
} |
} |
95 |
|
|
96 |
/* PC cmos mappings */ |
/* PC cmos mappings */ |
288 |
(dummy_refresh_clock << 4); |
(dummy_refresh_clock << 4); |
289 |
} |
} |
290 |
|
|
291 |
|
void ioport_set_a20(int enable) |
292 |
|
{ |
293 |
|
/* XXX: send to all CPUs ? */ |
294 |
|
cpu_x86_set_a20(first_cpu, enable); |
295 |
|
} |
296 |
|
|
297 |
|
int ioport_get_a20(void) |
298 |
|
{ |
299 |
|
return ((first_cpu->a20_mask >> 20) & 1); |
300 |
|
} |
301 |
|
|
302 |
static void ioport92_write(void *opaque, uint32_t addr, uint32_t val) |
static void ioport92_write(void *opaque, uint32_t addr, uint32_t val) |
303 |
{ |
{ |
304 |
cpu_x86_set_a20(cpu_single_env, (val >> 1) & 1); |
ioport_set_a20((val >> 1) & 1); |
305 |
/* XXX: bit 0 is fast reset */ |
/* XXX: bit 0 is fast reset */ |
306 |
} |
} |
307 |
|
|
308 |
static uint32_t ioport92_read(void *opaque, uint32_t addr) |
static uint32_t ioport92_read(void *opaque, uint32_t addr) |
309 |
{ |
{ |
310 |
return ((cpu_single_env->a20_mask >> 20) & 1) << 1; |
return ioport_get_a20() << 1; |
311 |
} |
} |
312 |
|
|
313 |
/***********************************************************/ |
/***********************************************************/ |
403 |
return -1; |
return -1; |
404 |
} |
} |
405 |
|
|
406 |
|
static void main_cpu_reset(void *opaque) |
407 |
|
{ |
408 |
|
CPUState *env = opaque; |
409 |
|
cpu_reset(env); |
410 |
|
} |
411 |
|
|
412 |
|
/*************************************************/ |
413 |
|
|
414 |
|
static void putb(uint8_t **pp, int val) |
415 |
|
{ |
416 |
|
uint8_t *q; |
417 |
|
q = *pp; |
418 |
|
*q++ = val; |
419 |
|
*pp = q; |
420 |
|
} |
421 |
|
|
422 |
|
static void putstr(uint8_t **pp, const char *str) |
423 |
|
{ |
424 |
|
uint8_t *q; |
425 |
|
q = *pp; |
426 |
|
while (*str) |
427 |
|
*q++ = *str++; |
428 |
|
*pp = q; |
429 |
|
} |
430 |
|
|
431 |
|
static void putle16(uint8_t **pp, int val) |
432 |
|
{ |
433 |
|
uint8_t *q; |
434 |
|
q = *pp; |
435 |
|
*q++ = val; |
436 |
|
*q++ = val >> 8; |
437 |
|
*pp = q; |
438 |
|
} |
439 |
|
|
440 |
|
static void putle32(uint8_t **pp, int val) |
441 |
|
{ |
442 |
|
uint8_t *q; |
443 |
|
q = *pp; |
444 |
|
*q++ = val; |
445 |
|
*q++ = val >> 8; |
446 |
|
*q++ = val >> 16; |
447 |
|
*q++ = val >> 24; |
448 |
|
*pp = q; |
449 |
|
} |
450 |
|
|
451 |
|
static int mpf_checksum(const uint8_t *data, int len) |
452 |
|
{ |
453 |
|
int sum, i; |
454 |
|
sum = 0; |
455 |
|
for(i = 0; i < len; i++) |
456 |
|
sum += data[i]; |
457 |
|
return sum & 0xff; |
458 |
|
} |
459 |
|
|
460 |
|
/* Build the Multi Processor table in the BIOS. Same values as Bochs. */ |
461 |
|
static void bios_add_mptable(uint8_t *bios_data) |
462 |
|
{ |
463 |
|
uint8_t *mp_config_table, *q, *float_pointer_struct; |
464 |
|
int ioapic_id, offset, i, len; |
465 |
|
|
466 |
|
if (smp_cpus <= 1) |
467 |
|
return; |
468 |
|
|
469 |
|
mp_config_table = bios_data + 0xcc00; |
470 |
|
q = mp_config_table; |
471 |
|
putstr(&q, "PCMP"); /* "PCMP signature */ |
472 |
|
putle16(&q, 0); /* table length (patched later) */ |
473 |
|
putb(&q, 4); /* spec rev */ |
474 |
|
putb(&q, 0); /* checksum (patched later) */ |
475 |
|
putstr(&q, "QEMUCPU "); /* OEM id */ |
476 |
|
putstr(&q, "0.1 "); /* vendor id */ |
477 |
|
putle32(&q, 0); /* OEM table ptr */ |
478 |
|
putle16(&q, 0); /* OEM table size */ |
479 |
|
putle16(&q, 20); /* entry count */ |
480 |
|
putle32(&q, 0xfee00000); /* local APIC addr */ |
481 |
|
putle16(&q, 0); /* ext table length */ |
482 |
|
putb(&q, 0); /* ext table checksum */ |
483 |
|
putb(&q, 0); /* reserved */ |
484 |
|
|
485 |
|
for(i = 0; i < smp_cpus; i++) { |
486 |
|
putb(&q, 0); /* entry type = processor */ |
487 |
|
putb(&q, i); /* APIC id */ |
488 |
|
putb(&q, 0x11); /* local APIC version number */ |
489 |
|
if (i == 0) |
490 |
|
putb(&q, 3); /* cpu flags: enabled, bootstrap cpu */ |
491 |
|
else |
492 |
|
putb(&q, 1); /* cpu flags: enabled */ |
493 |
|
putb(&q, 0); /* cpu signature */ |
494 |
|
putb(&q, 6); |
495 |
|
putb(&q, 0); |
496 |
|
putb(&q, 0); |
497 |
|
putle16(&q, 0x201); /* feature flags */ |
498 |
|
putle16(&q, 0); |
499 |
|
|
500 |
|
putle16(&q, 0); /* reserved */ |
501 |
|
putle16(&q, 0); |
502 |
|
putle16(&q, 0); |
503 |
|
putle16(&q, 0); |
504 |
|
} |
505 |
|
|
506 |
|
/* isa bus */ |
507 |
|
putb(&q, 1); /* entry type = bus */ |
508 |
|
putb(&q, 0); /* bus ID */ |
509 |
|
putstr(&q, "ISA "); |
510 |
|
|
511 |
|
/* ioapic */ |
512 |
|
ioapic_id = smp_cpus; |
513 |
|
putb(&q, 2); /* entry type = I/O APIC */ |
514 |
|
putb(&q, ioapic_id); /* apic ID */ |
515 |
|
putb(&q, 0x11); /* I/O APIC version number */ |
516 |
|
putb(&q, 1); /* enable */ |
517 |
|
putle32(&q, 0xfec00000); /* I/O APIC addr */ |
518 |
|
|
519 |
|
/* irqs */ |
520 |
|
for(i = 0; i < 16; i++) { |
521 |
|
putb(&q, 3); /* entry type = I/O interrupt */ |
522 |
|
putb(&q, 0); /* interrupt type = vectored interrupt */ |
523 |
|
putb(&q, 0); /* flags: po=0, el=0 */ |
524 |
|
putb(&q, 0); |
525 |
|
putb(&q, 0); /* source bus ID = ISA */ |
526 |
|
putb(&q, i); /* source bus IRQ */ |
527 |
|
putb(&q, ioapic_id); /* dest I/O APIC ID */ |
528 |
|
putb(&q, i); /* dest I/O APIC interrupt in */ |
529 |
|
} |
530 |
|
/* patch length */ |
531 |
|
len = q - mp_config_table; |
532 |
|
mp_config_table[4] = len; |
533 |
|
mp_config_table[5] = len >> 8; |
534 |
|
|
535 |
|
mp_config_table[7] = -mpf_checksum(mp_config_table, q - mp_config_table); |
536 |
|
|
537 |
|
/* align to 16 */ |
538 |
|
offset = q - bios_data; |
539 |
|
offset = (offset + 15) & ~15; |
540 |
|
float_pointer_struct = bios_data + offset; |
541 |
|
|
542 |
|
/* floating pointer structure */ |
543 |
|
q = float_pointer_struct; |
544 |
|
putstr(&q, "_MP_"); |
545 |
|
/* pointer to MP config table */ |
546 |
|
putle32(&q, mp_config_table - bios_data + 0x000f0000); |
547 |
|
|
548 |
|
putb(&q, 1); /* length in 16 byte units */ |
549 |
|
putb(&q, 4); /* MP spec revision */ |
550 |
|
putb(&q, 0); /* checksum (patched later) */ |
551 |
|
putb(&q, 0); /* MP feature byte 1 */ |
552 |
|
|
553 |
|
putb(&q, 0); |
554 |
|
putb(&q, 0); |
555 |
|
putb(&q, 0); |
556 |
|
putb(&q, 0); |
557 |
|
float_pointer_struct[10] = |
558 |
|
-mpf_checksum(float_pointer_struct, q - float_pointer_struct); |
559 |
|
} |
560 |
|
|
561 |
|
|
562 |
static const int ide_iobase[2] = { 0x1f0, 0x170 }; |
static const int ide_iobase[2] = { 0x1f0, 0x170 }; |
563 |
static const int ide_iobase2[2] = { 0x3f6, 0x376 }; |
static const int ide_iobase2[2] = { 0x3f6, 0x376 }; |
564 |
static const int ide_irq[2] = { 14, 15 }; |
static const int ide_irq[2] = { 14, 15 }; |
586 |
unsigned long bios_offset, vga_bios_offset; |
unsigned long bios_offset, vga_bios_offset; |
587 |
int bios_size, isa_bios_size; |
int bios_size, isa_bios_size; |
588 |
PCIBus *pci_bus; |
PCIBus *pci_bus; |
589 |
|
CPUState *env; |
590 |
|
|
591 |
linux_boot = (kernel_filename != NULL); |
linux_boot = (kernel_filename != NULL); |
592 |
|
|
593 |
|
/* init CPUs */ |
594 |
|
for(i = 0; i < smp_cpus; i++) { |
595 |
|
env = cpu_init(); |
596 |
|
if (i != 0) |
597 |
|
env->cpu_halted = 1; |
598 |
|
if (smp_cpus > 1) { |
599 |
|
/* XXX: enable it in all cases */ |
600 |
|
env->cpuid_features |= CPUID_APIC; |
601 |
|
} |
602 |
|
register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); |
603 |
|
qemu_register_reset(main_cpu_reset, env); |
604 |
|
if (pci_enabled) { |
605 |
|
apic_init(env); |
606 |
|
} |
607 |
|
} |
608 |
|
|
609 |
/* allocate RAM */ |
/* allocate RAM */ |
610 |
cpu_register_physical_memory(0, ram_size, 0); |
cpu_register_physical_memory(0, ram_size, 0); |
611 |
|
|
626 |
fprintf(stderr, "qemu: could not load PC bios '%s'\n", buf); |
fprintf(stderr, "qemu: could not load PC bios '%s'\n", buf); |
627 |
exit(1); |
exit(1); |
628 |
} |
} |
629 |
|
if (bios_size == 65536) { |
630 |
|
bios_add_mptable(phys_ram_base + bios_offset); |
631 |
|
} |
632 |
|
|
633 |
/* VGA BIOS load */ |
/* VGA BIOS load */ |
634 |
if (cirrus_vga_enabled) { |
if (cirrus_vga_enabled) { |
747 |
register_ioport_write(0x92, 1, 1, ioport92_write, NULL); |
register_ioport_write(0x92, 1, 1, ioport92_write, NULL); |
748 |
|
|
749 |
if (pci_enabled) { |
if (pci_enabled) { |
|
apic_init(cpu_single_env); |
|
750 |
ioapic = ioapic_init(); |
ioapic = ioapic_init(); |
751 |
} |
} |
752 |
isa_pic = pic_init(pic_irq_request, cpu_single_env); |
isa_pic = pic_init(pic_irq_request, first_cpu); |
753 |
pit = pit_init(0x40, 0); |
pit = pit_init(0x40, 0); |
754 |
if (pci_enabled) { |
if (pci_enabled) { |
755 |
pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic); |
pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic); |