Il 31/05/2014 18:18, Kevin O'Connor ha scritto:
> Change the multi-processor init code to trampoline into 32bit mode on
> each of the additional processors. Implement an atomic lock so that
> each processor performs its initialization serially.
>
> Signed-off-by: Kevin O'Connor <kevin(a)koconnor.net>
> ---
>
> Changed since v2:
> * Use "lock btsl" instead of "lock cmpxchgl" as suggested by Paolo.
> * Enable CPU caching on the APs
> * Report the apic_id in debug messages for each AP
Reviewed-by: Paolo Bonzini <pbonzini(a)redhat.com>
> ---
> Makefile | 3 +-
> src/config.h | 1 +
> src/fw/smp.c | 102 ++++++++++++++++++++++++++++----------------------------
> src/romlayout.S | 20 +++++++++++
> src/util.h | 1 -
> 5 files changed, 73 insertions(+), 54 deletions(-)
>
> diff --git a/Makefile b/Makefile
> index 78b598e..fb4e683 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -29,7 +29,6 @@ LD32BIT_FLAG:=-melf_i386
> # Source files
> SRCBOTH=misc.c stacks.c output.c string.c x86.c block.c cdrom.c mouse.c kbd.c \
> serial.c clock.c resume.c pnpbios.c vgahooks.c pcibios.c apm.c \
> - fw/smp.c \
> hw/pci.c hw/timer.c hw/rtc.c hw/dma.c hw/pic.c hw/ps2port.c hw/serialio.c \
> hw/usb.c hw/usb-uhci.c hw/usb-ohci.c hw/usb-ehci.c \
> hw/usb-hid.c hw/usb-msc.c hw/usb-uas.c \
> @@ -41,7 +40,7 @@ SRC32FLAT=$(SRCBOTH) post.c memmap.c malloc.c pmm.c romfile.c optionroms.c \
> boot.c bootsplash.c jpeg.c bmp.c \
> hw/ahci.c hw/pvscsi.c hw/usb-xhci.c hw/usb-hub.c \
> fw/coreboot.c fw/lzmadecode.c fw/csm.c fw/biostables.c \
> - fw/paravirt.c fw/shadow.c fw/pciinit.c fw/smm.c fw/mtrr.c fw/xen.c \
> + fw/paravirt.c fw/shadow.c fw/pciinit.c fw/smm.c fw/smp.c fw/mtrr.c fw/xen.c \
> fw/acpi.c fw/mptable.c fw/pirtable.c fw/smbios.c fw/romfile_loader.c
> SRC32SEG=string.c output.c pcibios.c apm.c stacks.c hw/pci.c hw/serialio.c
> DIRS=src src/hw src/fw vgasrc
> diff --git a/src/config.h b/src/config.h
> index 6f1a5b9..6da067d 100644
> --- a/src/config.h
> +++ b/src/config.h
> @@ -95,6 +95,7 @@
> #define DEBUG_ISR_hwpic1 5
> #define DEBUG_ISR_hwpic2 5
> #define DEBUG_HDL_smi 9
> +#define DEBUG_HDL_smp 1
> #define DEBUG_HDL_pnp 1
> #define DEBUG_HDL_pmm 1
> #define DEBUG_HDL_pcibios 9
> diff --git a/src/fw/smp.c b/src/fw/smp.c
> index 38fe383..51c0cae 100644
> --- a/src/fw/smp.c
> +++ b/src/fw/smp.c
> @@ -1,4 +1,4 @@
> -// CPU count detection
> +// QEMU multi-CPU initialization code
> //
> // Copyright (C) 2008 Kevin O'Connor <kevin(a)koconnor.net>
> // Copyright (C) 2006 Fabrice Bellard
> @@ -20,8 +20,8 @@
>
> #define APIC_ENABLED 0x0100
>
> -struct { u32 ecx, eax, edx; } smp_mtrr[32] VARFSEG;
> -u32 smp_mtrr_count VARFSEG;
> +static struct { u32 index; u64 val; } smp_mtrr[32];
> +static u32 smp_mtrr_count;
>
> void
> wrmsr_smp(u32 index, u64 val)
> @@ -31,52 +31,40 @@ wrmsr_smp(u32 index, u64 val)
> warn_noalloc();
> return;
> }
> - smp_mtrr[smp_mtrr_count].ecx = index;
> - smp_mtrr[smp_mtrr_count].eax = val;
> - smp_mtrr[smp_mtrr_count].edx = val >> 32;
> + smp_mtrr[smp_mtrr_count].index = index;
> + smp_mtrr[smp_mtrr_count].val = val;
> smp_mtrr_count++;
> }
>
> -u32 CountCPUs VARFSEG;
> u32 MaxCountCPUs;
> +static u32 CountCPUs;
> +u32 SMPLock __VISIBLE;
> +u32 SMPStack __VISIBLE;
> // 256 bits for the found APIC IDs
> -u32 FoundAPICIDs[256/32] VARFSEG;
> -extern void smp_ap_boot_code(void);
> -ASM16(
> - " .global smp_ap_boot_code\n"
> - "smp_ap_boot_code:\n"
> +static u32 FoundAPICIDs[256/32];
>
> - // Setup data segment
> - " movw $" __stringify(SEG_BIOS) ", %ax\n"
> - " movw %ax, %ds\n"
> +void VISIBLE32FLAT
> +handle_smp(void)
> +{
> + // Enable CPU caching
> + setcr0(getcr0() & ~(CR0_CD|CR0_NW));
> +
> + // Detect apic_id
> + u32 eax, ebx, ecx, cpuid_features;
> + cpuid(1, &eax, &ebx, &ecx, &cpuid_features);
> + u8 apic_id = ebx>>24;
> + dprintf(DEBUG_HDL_smp, "handle_smp: apic_id=%d\n", apic_id);
>
> // MTRR setup
> - " movl $smp_mtrr, %esi\n"
> - " movl smp_mtrr_count, %ebx\n"
> - "1:testl %ebx, %ebx\n"
> - " jz 2f\n"
> - " movl 0(%esi), %ecx\n"
> - " movl 4(%esi), %eax\n"
> - " movl 8(%esi), %edx\n"
> - " wrmsr\n"
> - " addl $12, %esi\n"
> - " decl %ebx\n"
> - " jmp 1b\n"
> - "2:\n"
> -
> - // get apic ID on EBX, set bit on FoundAPICIDs
> - " movl $1, %eax\n"
> - " cpuid\n"
> - " shrl $24, %ebx\n"
> - " lock btsl %ebx, FoundAPICIDs\n"
> -
> - // Increment the cpu counter
> - " lock incl CountCPUs\n"
> -
> - // Halt the processor.
> - "1:hlt\n"
> - " jmp 1b\n"
> - );
> + int i;
> + for (i=0; i<smp_mtrr_count; i++)
> + wrmsr(smp_mtrr[i].index, smp_mtrr[i].val);
> +
> + // Set bit on FoundAPICIDs
> + FoundAPICIDs[apic_id/32] |= (1 << (apic_id % 32));
> +
> + CountCPUs++;
> +}
>
> int apic_id_is_present(u8 apic_id)
> {
> @@ -104,15 +92,14 @@ smp_setup(void)
> // mark the BSP initial APIC ID as found, too:
> u8 apic_id = ebx>>24;
> FoundAPICIDs[apic_id/32] |= (1 << (apic_id % 32));
> -
> - // Init the counter.
> - writel(&CountCPUs, 1);
> + CountCPUs = 1;
>
> // Setup jump trampoline to counter code.
> u64 old = *(u64*)BUILD_AP_BOOT_ADDR;
> - // ljmpw $SEG_BIOS, $(smp_ap_boot_code - BUILD_BIOS_ADDR)
> + // ljmpw $SEG_BIOS, $(entry_smp - BUILD_BIOS_ADDR)
> + extern void entry_smp(void);
> u64 new = (0xea | ((u64)SEG_BIOS<<24)
> - | (((u32)smp_ap_boot_code - BUILD_BIOS_ADDR) << 8));
> + | (((u32)entry_smp - BUILD_BIOS_ADDR) << 8));
> *(u64*)BUILD_AP_BOOT_ADDR = new;
>
> // enable local APIC
> @@ -125,6 +112,9 @@ smp_setup(void)
> /* Set LINT1 as NMI, level triggered */
> writel(APIC_LINT1, 0x8400);
>
> + // Init the lock.
> + writel(&SMPLock, 1);
> +
> // broadcast SIPI
> barrier();
> writel(APIC_ICR_LOW, 0x000C4500);
> @@ -132,9 +122,19 @@ smp_setup(void)
> writel(APIC_ICR_LOW, 0x000C4600 | sipi_vector);
>
> // Wait for other CPUs to process the SIPI.
> - u8 cmos_smp_count = rtc_read(CMOS_BIOS_SMP_COUNT);
> - while (cmos_smp_count + 1 != readl(&CountCPUs))
> - yield();
> + u8 cmos_smp_count = rtc_read(CMOS_BIOS_SMP_COUNT) + 1;
> + while (cmos_smp_count != CountCPUs)
> + asm volatile(
> + // Release lock and allow other processors to use the stack.
> + " movl %%esp, %1\n"
> + " movl $0, %0\n"
> + // Reacquire lock and take back ownership of stack.
> + "1:rep ; nop\n"
> + " lock btsl $0, %0\n"
> + " jc 1b\n"
> + : "+m" (SMPLock), "+m" (SMPStack)
> + : : "cc", "memory");
> + yield();
>
> // Restore memory.
> *(u64*)BUILD_AP_BOOT_ADDR = old;
> @@ -143,6 +143,6 @@ smp_setup(void)
> if (!MaxCountCPUs || MaxCountCPUs < CountCPUs)
> MaxCountCPUs = CountCPUs;
>
> - dprintf(1, "Found %d cpu(s) max supported %d cpu(s)\n", readl(&CountCPUs),
> - MaxCountCPUs);
> + dprintf(1, "Found %d cpu(s) max supported %d cpu(s)\n", CountCPUs,
> + MaxCountCPUs);
> }
> diff --git a/src/romlayout.S b/src/romlayout.S
> index 0d6af39..4922279 100644
> --- a/src/romlayout.S
> +++ b/src/romlayout.S
> @@ -274,6 +274,26 @@ entry_smi:
> rsm
> .code16gcc
>
> +// Entry point for QEMU smp sipi interrupts.
> + DECLFUNC entry_smp
> +entry_smp:
> + // Transition to 32bit mode.
> + movl $2f + BUILD_BIOS_ADDR, %edx
> + jmp transition32
> + .code32
> + // Acquire lock and take ownership of shared stack
> +1: rep nop
> +2: lock btsl $0, SMPLock
> + jc 1b
> + movl SMPStack, %esp
> + // Call handle_smp
> + calll _cfunc32flat_handle_smp - BUILD_BIOS_ADDR
> + // Release lock and halt processor.
> + movl $0, SMPLock
> +3: hlt
> + jmp 3b
> + .code16gcc
> +
> // Resume (and reboot) entry point - called from entry_post
> DECLFUNC entry_resume
> entry_resume:
> diff --git a/src/util.h b/src/util.h
> index b54271b..8c794c4 100644
> --- a/src/util.h
> +++ b/src/util.h
> @@ -126,7 +126,6 @@ void smm_device_setup(void);
> void smm_setup(void);
>
> // fw/smp.c
> -extern u32 CountCPUs;
> extern u32 MaxCountCPUs;
> void wrmsr_smp(u32 index, u64 val);
> void smp_setup(void);
>