Commit 59b8ad81c45c3db028875476c46da7c29f6a9440

Authored by bellard
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
... ... @@ -86,10 +86,11 @@ int cpu_get_pic_interrupt(CPUState *env)
86 86  
87 87 static void pic_irq_request(void *opaque, int level)
88 88 {
  89 + CPUState *env = opaque;
89 90 if (level)
90   - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
  91 + cpu_interrupt(env, CPU_INTERRUPT_HARD);
91 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 96 /* PC cmos mappings */
... ... @@ -287,15 +288,26 @@ static uint32_t speaker_ioport_read(void *opaque, uint32_t addr)
287 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 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 305 /* XXX: bit 0 is fast reset */
294 306 }
295 307  
296 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 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 562 static const int ide_iobase[2] = { 0x1f0, 0x170 };
395 563 static const int ide_iobase2[2] = { 0x3f6, 0x376 };
396 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 586 unsigned long bios_offset, vga_bios_offset;
419 587 int bios_size, isa_bios_size;
420 588 PCIBus *pci_bus;
  589 + CPUState *env;
421 590  
422 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 609 /* allocate RAM */
425 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 626 fprintf(stderr, "qemu: could not load PC bios '%s'\n", buf);
442 627 exit(1);
443 628 }
  629 + if (bios_size == 65536) {
  630 + bios_add_mptable(phys_ram_base + bios_offset);
  631 + }
444 632  
445 633 /* VGA BIOS load */
446 634 if (cirrus_vga_enabled) {
... ... @@ -559,10 +747,9 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
559 747 register_ioport_write(0x92, 1, 1, ioport92_write, NULL);
560 748  
561 749 if (pci_enabled) {
562   - apic_init(cpu_single_env);
563 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 753 pit = pit_init(0x40, 0);
567 754 if (pci_enabled) {
568 755 pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic);
... ...