| 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); |