From: Keir Fraser Date: Tue, 15 Apr 2008 15:39:00 +0000 (+0100) Subject: hvmloader: Framework for multiprocessor initialisation. X-Git-Tag: 3.3.0-rc1~243^2 X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=1eaea3f0b675f67f9ce3dc9a6f9e4b272c9d75aa;p=xen.git hvmloader: Framework for multiprocessor initialisation. Signed-off-by: Keir Fraser --- diff --git a/tools/firmware/hvmloader/Makefile b/tools/firmware/hvmloader/Makefile index 3a5b801335..ae1fdc869d 100644 --- a/tools/firmware/hvmloader/Makefile +++ b/tools/firmware/hvmloader/Makefile @@ -28,7 +28,7 @@ LOADADDR = 0x100000 CFLAGS += $(CFLAGS_include) -I. -SRCS = hvmloader.c mp_tables.c util.c smbios.c 32bitbios_support.c +SRCS = hvmloader.c mp_tables.c util.c smbios.c 32bitbios_support.c smp.c OBJS = $(patsubst %.c,%.o,$(SRCS)) .PHONY: all diff --git a/tools/firmware/hvmloader/hvmloader.c b/tools/firmware/hvmloader/hvmloader.c index 4410455134..3bad1120ba 100644 --- a/tools/firmware/hvmloader/hvmloader.c +++ b/tools/firmware/hvmloader/hvmloader.c @@ -32,7 +32,7 @@ #include #include -asm( +asm ( " .text \n" " .globl _start \n" "_start: \n" @@ -98,6 +98,7 @@ asm( "stack_top: \n" ); +void smp_initialise(void); void create_mp_tables(void); int hvm_write_smbios_tables(void); @@ -444,6 +445,8 @@ int main(void) printf("CPU speed is %u MHz\n", get_cpu_mhz()); + smp_initialise(); + printf("Writing SMBIOS tables ...\n"); smbios_sz = hvm_write_smbios_tables(); diff --git a/tools/firmware/hvmloader/smp.c b/tools/firmware/hvmloader/smp.c new file mode 100644 index 0000000000..85f2a99103 --- /dev/null +++ b/tools/firmware/hvmloader/smp.c @@ -0,0 +1,132 @@ +/* + * smp.c: Secondary processor bringup and initialisation. + * + * Copyright (c) 2008, Citrix Systems, Inc. + * + * Authors: + * Keir Fraser + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "util.h" +#include "config.h" +#include "apic_regs.h" + +#define AP_BOOT_EIP 0x1000 +extern char ap_boot_start[], ap_boot_end[]; + +static int ap_callin, ap_cpuid; + +asm ( + " .text \n" + " .code16 \n" + "ap_boot_start: .code16 \n" + " mov %cs,%ax \n" + " mov %ax,%ds \n" + " lgdt gdt_desr-ap_boot_start\n" + " xor %ax, %ax \n" + " inc %ax \n" + " lmsw %ax \n" + " ljmpl $0x08,$1f \n" + "gdt_desr: \n" + " .word gdt_end - gdt - 1 \n" + " .long gdt \n" + "ap_boot_end: .code32 \n" + "1: mov $0x10,%eax \n" + " mov %eax,%ds \n" + " mov %eax,%es \n" + " mov %eax,%ss \n" + " movl $stack_top,%esp \n" + " movl %esp,%ebp \n" + " call ap_start \n" + "1: hlt \n" + " jmp 1b \n" + " \n" + " .align 8 \n" + "gdt: \n" + " .quad 0x0000000000000000 \n" + " .quad 0x00cf9a000000ffff \n" /* 0x08: Flat code segment */ + " .quad 0x00cf92000000ffff \n" /* 0x10: Flat data segment */ + "gdt_end: \n" + " \n" + " .bss \n" + " .align 8 \n" + "stack: \n" + " .skip 0x4000 \n" + "stack_top: \n" + ); + +/*static*/ void ap_start(void) +{ + printf(" - CPU%d ... ", ap_cpuid); + + printf("done.\n"); + wmb(); + ap_callin = 1; +} + +static void lapic_wait_ready(void) +{ + while ( lapic_read(APIC_ICR) & APIC_ICR_BUSY ) + cpu_relax(); +} + +static void boot_cpu(unsigned int cpu) +{ + unsigned int icr2 = SET_APIC_DEST_FIELD(LAPIC_ID(cpu)); + + /* Initialise shared variables. */ + ap_cpuid = cpu; + ap_callin = 0; + wmb(); + + /* Wake up the secondary processor: INIT-SIPI-SIPI... */ + lapic_wait_ready(); + lapic_write(APIC_ICR2, icr2); + lapic_write(APIC_ICR, APIC_DM_INIT); + lapic_wait_ready(); + lapic_write(APIC_ICR2, icr2); + lapic_write(APIC_ICR, APIC_DM_STARTUP | (AP_BOOT_EIP >> 12)); + lapic_wait_ready(); + lapic_write(APIC_ICR2, icr2); + lapic_write(APIC_ICR, APIC_DM_STARTUP | (AP_BOOT_EIP >> 12)); + lapic_wait_ready(); + + /* + * Wait for the secondary processor to complete initialisation. + * Do not touch shared resources meanwhile. + */ + while ( !ap_callin ) + cpu_relax(); + + /* Take the secondary processor offline. */ + lapic_write(APIC_ICR2, icr2); + lapic_write(APIC_ICR, APIC_DM_INIT); + lapic_wait_ready(); +} + +void smp_initialise(void) +{ + unsigned int i, nr_cpus = get_vcpu_nr(); + + if ( nr_cpus <= 1 ) + return; + + memcpy((void *)AP_BOOT_EIP, ap_boot_start, ap_boot_end - ap_boot_start); + + printf("Multiprocessor initialisation:\n"); + for ( i = 1; i < nr_cpus; i++ ) + boot_cpu(i); +} diff --git a/tools/firmware/hvmloader/util.h b/tools/firmware/hvmloader/util.h index 846335208f..1d310c64e4 100644 --- a/tools/firmware/hvmloader/util.h +++ b/tools/firmware/hvmloader/util.h @@ -78,6 +78,7 @@ static inline void cpu_relax(void) #define barrier() asm volatile ( "" : : : "memory" ) #define rmb() barrier() #define wmb() barrier() +#define mb() asm volatile ( "lock; addl $0,0(%%esp)" : : : "memory" ) /* * Divide a 64-bit dividend by a 32-bit divisor.