Commit 59b8ad81c45c3db028875476c46da7c29f6a9440
1 parent
c68ea704
SMP support - cpu_single_env usage fix - a20 helpers - dynamic Multi Processor BIOS table generation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1645 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
193 additions
and
6 deletions
hw/pc.c
| @@ -86,10 +86,11 @@ int cpu_get_pic_interrupt(CPUState *env) | @@ -86,10 +86,11 @@ int cpu_get_pic_interrupt(CPUState *env) | ||
| 86 | 86 | ||
| 87 | static void pic_irq_request(void *opaque, int level) | 87 | static void pic_irq_request(void *opaque, int level) |
| 88 | { | 88 | { |
| 89 | + CPUState *env = opaque; | ||
| 89 | if (level) | 90 | if (level) |
| 90 | - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); | 91 | + cpu_interrupt(env, CPU_INTERRUPT_HARD); |
| 91 | else | 92 | else |
| 92 | - cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); | 93 | + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); |
| 93 | } | 94 | } |
| 94 | 95 | ||
| 95 | /* PC cmos mappings */ | 96 | /* PC cmos mappings */ |
| @@ -287,15 +288,26 @@ static uint32_t speaker_ioport_read(void *opaque, uint32_t addr) | @@ -287,15 +288,26 @@ static uint32_t speaker_ioport_read(void *opaque, uint32_t addr) | ||
| 287 | (dummy_refresh_clock << 4); | 288 | (dummy_refresh_clock << 4); |
| 288 | } | 289 | } |
| 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 | + | ||
| 290 | static void ioport92_write(void *opaque, uint32_t addr, uint32_t val) | 302 | static void ioport92_write(void *opaque, uint32_t addr, uint32_t val) |
| 291 | { | 303 | { |
| 292 | - cpu_x86_set_a20(cpu_single_env, (val >> 1) & 1); | 304 | + ioport_set_a20((val >> 1) & 1); |
| 293 | /* XXX: bit 0 is fast reset */ | 305 | /* XXX: bit 0 is fast reset */ |
| 294 | } | 306 | } |
| 295 | 307 | ||
| 296 | static uint32_t ioport92_read(void *opaque, uint32_t addr) | 308 | static uint32_t ioport92_read(void *opaque, uint32_t addr) |
| 297 | { | 309 | { |
| 298 | - return ((cpu_single_env->a20_mask >> 20) & 1) << 1; | 310 | + return ioport_get_a20() << 1; |
| 299 | } | 311 | } |
| 300 | 312 | ||
| 301 | /***********************************************************/ | 313 | /***********************************************************/ |
| @@ -391,6 +403,162 @@ int load_kernel(const char *filename, uint8_t *addr, | @@ -391,6 +403,162 @@ int load_kernel(const char *filename, uint8_t *addr, | ||
| 391 | return -1; | 403 | return -1; |
| 392 | } | 404 | } |
| 393 | 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 | + | ||
| 394 | static const int ide_iobase[2] = { 0x1f0, 0x170 }; | 562 | static const int ide_iobase[2] = { 0x1f0, 0x170 }; |
| 395 | static const int ide_iobase2[2] = { 0x3f6, 0x376 }; | 563 | static const int ide_iobase2[2] = { 0x3f6, 0x376 }; |
| 396 | static const int ide_irq[2] = { 14, 15 }; | 564 | static const int ide_irq[2] = { 14, 15 }; |
| @@ -418,9 +586,26 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, | @@ -418,9 +586,26 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, | ||
| 418 | unsigned long bios_offset, vga_bios_offset; | 586 | unsigned long bios_offset, vga_bios_offset; |
| 419 | int bios_size, isa_bios_size; | 587 | int bios_size, isa_bios_size; |
| 420 | PCIBus *pci_bus; | 588 | PCIBus *pci_bus; |
| 589 | + CPUState *env; | ||
| 421 | 590 | ||
| 422 | linux_boot = (kernel_filename != NULL); | 591 | linux_boot = (kernel_filename != NULL); |
| 423 | 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 | + | ||
| 424 | /* allocate RAM */ | 609 | /* allocate RAM */ |
| 425 | cpu_register_physical_memory(0, ram_size, 0); | 610 | cpu_register_physical_memory(0, ram_size, 0); |
| 426 | 611 | ||
| @@ -441,6 +626,9 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, | @@ -441,6 +626,9 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, | ||
| 441 | fprintf(stderr, "qemu: could not load PC bios '%s'\n", buf); | 626 | fprintf(stderr, "qemu: could not load PC bios '%s'\n", buf); |
| 442 | exit(1); | 627 | exit(1); |
| 443 | } | 628 | } |
| 629 | + if (bios_size == 65536) { | ||
| 630 | + bios_add_mptable(phys_ram_base + bios_offset); | ||
| 631 | + } | ||
| 444 | 632 | ||
| 445 | /* VGA BIOS load */ | 633 | /* VGA BIOS load */ |
| 446 | if (cirrus_vga_enabled) { | 634 | if (cirrus_vga_enabled) { |
| @@ -559,10 +747,9 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, | @@ -559,10 +747,9 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, | ||
| 559 | register_ioport_write(0x92, 1, 1, ioport92_write, NULL); | 747 | register_ioport_write(0x92, 1, 1, ioport92_write, NULL); |
| 560 | 748 | ||
| 561 | if (pci_enabled) { | 749 | if (pci_enabled) { |
| 562 | - apic_init(cpu_single_env); | ||
| 563 | ioapic = ioapic_init(); | 750 | ioapic = ioapic_init(); |
| 564 | } | 751 | } |
| 565 | - isa_pic = pic_init(pic_irq_request, cpu_single_env); | 752 | + isa_pic = pic_init(pic_irq_request, first_cpu); |
| 566 | pit = pit_init(0x40, 0); | 753 | pit = pit_init(0x40, 0); |
| 567 | if (pci_enabled) { | 754 | if (pci_enabled) { |
| 568 | pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic); | 755 | pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic); |