]> xenbits.xensource.com Git - xen.git/commitdiff
hvmloader: Framework for multiprocessor initialisation.
authorKeir Fraser <keir.fraser@citrix.com>
Tue, 15 Apr 2008 15:39:00 +0000 (16:39 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Tue, 15 Apr 2008 15:39:00 +0000 (16:39 +0100)
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
tools/firmware/hvmloader/Makefile
tools/firmware/hvmloader/hvmloader.c
tools/firmware/hvmloader/smp.c [new file with mode: 0644]
tools/firmware/hvmloader/util.h

index 3a5b801335b83f16af5eb6cdb877470bcbf39c62..ae1fdc869da144ead6a5baedf54445651adb0226 100644 (file)
@@ -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
index 44104551342c9b9d6f45d81c8ab039e963284427..3bad1120ba36ecfee3473907eb4d0b7ff7a766bb 100644 (file)
@@ -32,7 +32,7 @@
 #include <xen/version.h>
 #include <xen/hvm/params.h>
 
-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 (file)
index 0000000..85f2a99
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * smp.c: Secondary processor bringup and initialisation.
+ *
+ * Copyright (c) 2008, Citrix Systems, Inc.
+ * 
+ * Authors:
+ *    Keir Fraser <keir.fraser@citrix.com>
+ * 
+ * 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);
+}
index 846335208f552decce497d6e4f38ee147412b47b..1d310c64e49246ce75b04c1c3a9aa94b3d78a217 100644 (file)
@@ -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.