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