Refactoring core boot-up logic in kernel.
authorGerd Zellweger <mail@gerdzellweger.com>
Tue, 24 Sep 2013 11:30:19 +0000 (13:30 +0200)
committerGerd Zellweger <mail@gerdzellweger.com>
Thu, 24 Oct 2013 08:19:08 +0000 (10:19 +0200)
Move architecture independent logic into single arch-independent
syscall for all platforms. Handle arch specific boot-up with
specialized function (usually defined in start_aps.c).

25 files changed:
errors/errno.fugu
kernel/Hakefile
kernel/arch/armv7/irq.c
kernel/arch/armv7/syscall.c
kernel/arch/omap44xx/init.c
kernel/arch/omap44xx/start_aps.c
kernel/arch/x86/start_aps.c [deleted file]
kernel/arch/x86/syscall.c
kernel/arch/x86_32/init.c
kernel/arch/x86_32/init_ap_x86_32.S [moved from kernel/arch/x86/init_ap_x86_32.S with 100% similarity]
kernel/arch/x86_32/start_aps.c [new file with mode: 0644]
kernel/arch/x86_64/init.c
kernel/arch/x86_64/init_ap_x86_64.S [moved from kernel/arch/x86/init_ap_x86_64.S with 100% similarity]
kernel/arch/x86_64/start_aps.c [new file with mode: 0644]
kernel/arch/x86_64/startup_arch.c
kernel/coreboot.c [new file with mode: 0644]
kernel/include/arch/armv7-m/armv7_syscall.h
kernel/include/arch/armv7/armv7_syscall.h [deleted file]
kernel/include/arch/armv7/start_aps.h
kernel/include/arch/x86/cmos.h
kernel/include/arch/x86/start_aps.h
kernel/include/arch/x86/syscall.h
kernel/include/coreboot.h [new file with mode: 0644]
kernel/include/syscall.h
kernel/syscall.c

index 062baf0..5dcb5d2 100644 (file)
@@ -88,20 +88,21 @@ errors kernel SYS_ERR_ {
     failure IO_PORT_INVALID     "IO port out of range",
 
     // Dispatcher setup and spawn core invocations
-    failure DISP_CSPACE_ROOT    "Error setting CSpace root on dispatcher",
-    failure DISP_CSPACE_INVALID "Invalid capability type given for CSpace root on dispatcher",
-    failure DISP_VSPACE_ROOT    "Error setting VSpace root on dispatcher",
-    failure DISP_VSPACE_INVALID "Invalid capability type given for VSpace root on dispatcher",
-    failure DISP_FRAME          "Error setting dispatcher frame",
-    failure DISP_FRAME_INVALID  "Invalid capability type given for dispatcher frame",
-    failure DISP_NOT_RUNNABLE   "Cannot run dispatcher; it is not completely setup",
-    failure DISP_CAP_LOOKUP     "Error looking up dispatcher cap",
-    failure DISP_CAP_INVALID    "Invalid type capability given for dispatcher cap",
-    failure KERNEL_MEM_LOOKUP   "Error looking up capability for kernel memory",
-    failure KERNEL_MEM_INVALID  "Invalid capability type passed for kernel memory",
-    failure CORE_NOT_FOUND      "Unable to boot core: core ID does not exist",
-    failure INVALID_YIELD_TARGET "Target capability for directed yield is invalid",
-    failure DISP_OCAP_LOOKUP    "Error looking up other dispatcher cap",
+    failure DISP_CSPACE_ROOT            "Error setting CSpace root on dispatcher",
+    failure DISP_CSPACE_INVALID         "Invalid capability type given for CSpace root on dispatcher",
+    failure DISP_VSPACE_ROOT            "Error setting VSpace root on dispatcher",
+    failure DISP_VSPACE_INVALID         "Invalid capability type given for VSpace root on dispatcher",
+    failure DISP_FRAME                  "Error setting dispatcher frame",
+    failure DISP_FRAME_INVALID          "Invalid capability type given for dispatcher frame",
+    failure DISP_NOT_RUNNABLE           "Cannot run dispatcher; it is not completely setup",
+    failure DISP_CAP_LOOKUP             "Error looking up dispatcher cap",
+    failure DISP_CAP_INVALID            "Invalid type capability given for dispatcher cap",
+    failure KERNEL_MEM_LOOKUP           "Error looking up capability for kernel memory",
+    failure KERNEL_MEM_INVALID          "Invalid capability type passed for kernel memory",
+    failure CORE_NOT_FOUND              "Unable to boot core: core ID does not exist",
+    failure ARCHITECTURE_NOT_SUPPORTED  "Unable to boot core: specified architecture is not supported by kernel",
+    failure INVALID_YIELD_TARGET        "Target capability for directed yield is invalid",
+    failure DISP_OCAP_LOOKUP            "Error looking up other dispatcher cap",
 
     // VMKit specific errors
     failure VMKIT_UNAVAIL               "Virtualization extensions are unavailable",
index 7b1ee48..40fc9c7 100644 (file)
@@ -42,7 +42,8 @@ let
                "string.c", 
                "syscall.c",
                "wakeup.c", 
-               "useraccess.c" ]
+               "useraccess.c",
+               "coreboot.c" ]
              ++ (if Config.microbenchmarks then ["microbenchmarks.c"] else [])
              ++ (if Config.oneshot_timer then ["timer.c"] else [])
   common_libs = [ "getopt", "mdb_kernel" ]
@@ -91,8 +92,7 @@ let
      architectures = [ "x86_64" ],
      assemblyFiles = [ "arch/x86_64/boot.S", 
                        "arch/x86_64/entry.S", 
-                       "arch/x86/init_ap_x86_64.S", 
-                       "arch/x86/init_ap_x86_32.S" ],
+                       "arch/x86_64/init_ap_x86_64.S" ],
      cFiles = [ "arch/x86_64/debug.c", 
                 "arch/x86_64/gdb_arch.c", 
                 "arch/x86_64/init.c", 
@@ -103,9 +103,9 @@ let
                 "arch/x86_64/paging.c",
                 "arch/x86_64/vmkit.c" , 
                 "arch/x86_64/page_mappings_arch.c",
+                "arch/x86_64/start_aps.c",
                 "arch/x86/apic.c", 
                 "arch/x86/pic.c", 
-                "arch/x86/start_aps.c", 
                 "arch/x86/cmos.c", 
                 "arch/x86/misc.c",
                 "arch/x86/serial.c", 
@@ -140,8 +140,7 @@ let
      assemblyFiles = [ "arch/x86_32/boot.S", 
                        "arch/x86_32/entry.S", 
                        "arch/x86_32/pic.S",
-                       "arch/x86/init_ap_x86_64.S", 
-                       "arch/x86/init_ap_x86_32.S" ],
+                       "arch/x86_32/init_ap_x86_32.S" ],
      cFiles = [ "arch/x86_32/debug.c", 
                 "arch/x86_32/gdb_arch.c", 
                 "arch/x86_32/init.c", 
@@ -151,9 +150,9 @@ let
                 "arch/x86_32/syscall.c", 
                 "arch/x86_32/paging.c",
                 "arch/x86_32/page_mappings_arch.c",
+                "arch/x86_32/start_aps.c",
                 "arch/x86/apic.c", 
                 "arch/x86/pic.c", 
-                "arch/x86/start_aps.c", 
                 "arch/x86/cmos.c", 
                 "arch/x86/misc.c",
                 "arch/x86/serial.c", 
index 522dbfa..0a63204 100644 (file)
@@ -23,7 +23,6 @@
 #include <exec.h>
 #include <stdio.h>
 #include <syscall.h>
-#include <arch/armv7/armv7_syscall.h>
 #include <arch/armv7/start_aps.h>
 
 /*
index 76f600a..b7a1d38 100644 (file)
@@ -21,7 +21,6 @@
 #include <exec.h>
 #include <stdio.h>
 #include <syscall.h>
-#include <armv7_syscall.h>
 #include <start_aps.h>
 
 __attribute__((noreturn)) void sys_syscall_kernel(void);
@@ -33,33 +32,6 @@ void sys_syscall_kernel(void)
     panic("Why is the kernel making a system call?");
 }
 
-/**
- * \brief Spawn a new core
- */
-struct sysret sys_monitor_spawn_core(coreid_t core_id, enum cpu_type cpu_type,
-                                     genvaddr_t entry)
-{
-#ifdef __ARM_ARCH_7M__
-printf("armv7-m can not spawn new cores yet");
-#else
-       int r;
-       switch(cpu_type) {
-       case CPU_ARM:
-               r = start_aps_arm_start(core_id, (lvaddr_t)entry);
-               if(r != 0)
-               {
-                       return SYSRET(SYS_ERR_CORE_NOT_FOUND);
-               }
-               break;
-       default:
-        assert(!"Architecture not supported");
-        return SYSRET(SYS_ERR_CORE_NOT_FOUND);
-        break;
-       }
-#endif //defined(__ARM_ARCH_7M__)
-    return SYSRET(SYS_ERR_OK);
-}
-
 static struct sysret
 handle_dispatcher_setup(
     struct capability* to,
index cfcdc13..cea5490 100644 (file)
@@ -34,6 +34,7 @@
 #include <global.h>
 #include <arch/armv7/start_aps.h> // AP_WAIT_*, AUX_CORE_BOOT_*  and friends
 #include <cortexm3_heteropanda.h>
+#include <coreboot.h>
 
 #include <omap44xx_map.h>
 #include <dev/omap/omap44xx_id_dev.h>
@@ -801,6 +802,8 @@ static void __attribute__ ((noinline,noreturn)) text_init(void)
     reset_cycle_counter();
 #endif
 
+    coreboot_set_spawn_handler(CPU_ARM, start_aps_arm_start);
+
     arm_kernel_startup();
 }
 
index b90be59..6fc7842 100644 (file)
  *
  * \returns Zero on successful boot, non-zero (error code) on failure
  */
-int start_aps_arm_start(uint8_t core_id, lvaddr_t entry)
+int start_aps_arm_start(coreid_t core_id, genvaddr_t gen_entry)
 {
     //printf("----> %s (%s:%d): core_id=%u entry=0x%lx\n",
     //       __FUNCTION__, __FILE__, __LINE__,
     //       core_id, entry);
+    
+    lvaddr_t entry = (lvaddr_t) gen_entry;
 
     /* pointer to the pseudo-lock used to detect boot up of new core */
     volatile uint32_t *ap_wait = (uint32_t*)local_phys_to_mem(AP_WAIT_PHYS);
diff --git a/kernel/arch/x86/start_aps.c b/kernel/arch/x86/start_aps.c
deleted file mode 100644 (file)
index 47c9884..0000000
+++ /dev/null
@@ -1,238 +0,0 @@
-
-/**
- * \file
- * \brief Start the application processors
- *
- *  This file sends all needed IPIs to the other cores to start them.
- */
-
-/*
- * Copyright (c) 2007, 2008, 2010, ETH Zurich.
- * All rights reserved.
- *
- * This file is distributed under the terms in the attached LICENSE file.
- * If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
- */
-
-#include <kernel.h>
-#include <stdio.h>
-#include <string.h>
-#include <arch/x86/apic.h>
-#include <arch/x86/start_aps.h>
-#include <x86.h>
-#include <arch/x86/cmos.h>
-#include <init.h>
-#include <arch/x86/kputchar.h>
-#include "xapic_dev.h"
-#include <target/x86_64/offsets_target.h>
-#include <target/x86_32/offsets_target.h>
-
-#define STARTUP_TIMEOUT         0xffffff
-
-/**
- * start_ap and start_ap_end mark the start end the end point of the assembler
- * startup code to be copied
- */
-
-extern uint64_t x86_64_start_ap;
-extern uint64_t x86_64_start_ap_end;
-extern uint64_t x86_64_init_ap_absolute_entry;
-extern uint64_t x86_64_init_ap_wait;
-extern uint64_t x86_64_init_ap_lock;
-extern uint64_t x86_64_start;
-extern uint64_t x86_64_init_ap_global;
-
-extern uint64_t x86_32_start_ap;
-extern uint64_t x86_32_start_ap_end;
-extern uint64_t x86_32_init_ap_absolute_entry;
-extern uint64_t x86_32_init_ap_wait;
-extern uint64_t x86_32_init_ap_lock;
-extern uint64_t x86_32_start;
-extern uint64_t x86_32_init_ap_global;
-
-/**
- * \brief Boot a app core of x86_64 type
- *
- * The processors are started by a sequency of INIT and STARTUP IPIs
- * which are sent by this function. 
- *
- * \param core_id   APIC ID of the core to try booting
- * \param entry     Entry address for new kernel in the destination
- *                  architecture's lvaddr_t given in genvaddr_t
- *
- * \returns Zero on successful boot, non-zero (error code) on failure
- */
-int start_aps_x86_64_start(uint8_t core_id, genvaddr_t entry)
-{
-    /* Copy the startup code to the real-mode address */
-    uint8_t *real_dest = (uint8_t*) local_phys_to_mem(X86_64_REAL_MODE_LINEAR_OFFSET);
-    uint8_t *real_src = (uint8_t *) &x86_64_start_ap;
-    uint8_t *real_end = (uint8_t *) &x86_64_start_ap_end;
-    memcpy(real_dest, real_src, real_end - real_src);
-
-    /* Pointer to the entry point called from init_ap.S */
-    volatile uint64_t *absolute_entry_ptr = (volatile uint64_t *)
-        local_phys_to_mem((lpaddr_t) &x86_64_init_ap_absolute_entry - ((lpaddr_t) &x86_64_start_ap) +
-                          X86_64_REAL_MODE_LINEAR_OFFSET);
-    //copy the address of the function start (in boot.S) to the long-mode
-    //assembler code to be able to perform an absolute jump
-    *absolute_entry_ptr = entry;
-
-    /* pointer to the pseudo-lock used to detect boot up of new core */
-    volatile uint32_t *ap_wait = (volatile uint32_t *)
-        local_phys_to_mem((lpaddr_t) &x86_64_init_ap_wait - ((lpaddr_t) &x86_64_start_ap) +
-                          X86_64_REAL_MODE_LINEAR_OFFSET);
-
-    /* Pointer to the lock variable in the realmode code */
-    volatile uint8_t *ap_lock = (volatile uint8_t*)
-        local_phys_to_mem((lpaddr_t) &x86_64_init_ap_lock - ((lpaddr_t) &x86_64_start_ap) +
-                          X86_64_REAL_MODE_LINEAR_OFFSET);
-
-    /* pointer to the shared global variable amongst all kernels */
-    volatile uint64_t *ap_global = (volatile uint64_t *)
-        local_phys_to_mem((lpaddr_t) &x86_64_init_ap_global - ((lpaddr_t) &x86_64_start_ap) +
-                          X86_64_REAL_MODE_LINEAR_OFFSET);
-    *ap_global = (uint64_t)mem_to_local_phys((lvaddr_t)global);
-
-    lvaddr_t *init_vector;
-    init_vector = (lvaddr_t*)local_phys_to_mem(CMOS_RAM_BIOS_WARM_START_INIT_VECTOR);
-
-    *ap_wait = AP_STARTING_UP;
-
-    if (CPU_IS_M5_SIMULATOR) {
-        printk(LOG_WARN, "Warning: skipping shutdown/init of APs on M5\n");
-    } else {
-        //set shutdown status to WARM_SHUTDOWN and set start-vector
-        cmos_write( CMOS_RAM_SHUTDOWN_ADDR, CMOS_RAM_WARM_SHUTDOWN);
-        *init_vector = X86_64_REAL_MODE_ADDR_TO_REAL_MODE_VECTOR(X86_64_REAL_MODE_SEGMENT,
-                                                          X86_64_REAL_MODE_OFFSET);
-
-        //INIT 1 assert
-        apic_send_init_assert(core_id, xapic_none);
-
-        //set shutdown status to WARM_SHUTDOWN and set start-vector
-        cmos_write( CMOS_RAM_SHUTDOWN_ADDR, CMOS_RAM_WARM_SHUTDOWN);
-        *init_vector = X86_64_REAL_MODE_ADDR_TO_REAL_MODE_VECTOR(X86_64_REAL_MODE_SEGMENT,
-                                                          X86_64_REAL_MODE_OFFSET);
-
-        //INIT 2 de-assert
-        apic_send_init_deassert();
-    }
-
-    //SIPI1
-    apic_send_start_up(core_id, xapic_none,
-                       X86_64_REAL_MODE_SEGMENT_TO_REAL_MODE_PAGE(X86_64_REAL_MODE_SEGMENT));
-
-    //SIPI2
-    apic_send_start_up(core_id, xapic_none,
-                       X86_64_REAL_MODE_SEGMENT_TO_REAL_MODE_PAGE(X86_64_REAL_MODE_SEGMENT));
-
-    //give the new core a bit time to start-up and set the lock
-    for (uint64_t i = 0; i < STARTUP_TIMEOUT; i++) {
-        if (*ap_lock != 0) {
-            break;
-        }
-    }
-
-    //if the lock is set, the core has been started, otherwise assume, that
-    //a core with this APIC ID doesn't exist.
-    if (*ap_lock != 0) {
-        while (*ap_wait != AP_STARTED);
-        *ap_lock = 0;
-        debug(SUBSYS_STARTUP, "booted CPU%hhu\n", core_id);
-        return 0;
-    }
-    return -1;
-}
-
-/**
- * \brief Boot a app core of x86_32 type
- *
- * The processors are started by a sequency of INIT and STARTUP IPIs
- * which are sent by this function. 
- *
- * \param core_id   APIC ID of the core to try booting
- * \param entry     Entry address for new kernel in the destination
- *                  architecture's lvaddr_t given in genvaddr_t
- *
- * \returns Zero on successful boot, non-zero (error code) on failure
- */
-int start_aps_x86_32_start(uint8_t core_id, genvaddr_t entry)
-{
-    /* Copy the startup code to the real-mode address */
-    uint8_t *real_dest = (uint8_t*) local_phys_to_mem(X86_32_REAL_MODE_LINEAR_OFFSET);
-    uint8_t *real_src = (uint8_t *) &x86_32_start_ap;
-    uint8_t *real_end = (uint8_t *) &x86_32_start_ap_end;
-    memcpy(real_dest, real_src, real_end - real_src);
-
-    /* Pointer to the entry point called from init_ap.S */
-    volatile uint64_t *absolute_entry_ptr = (volatile uint64_t *)
-        local_phys_to_mem((lpaddr_t) &x86_32_init_ap_absolute_entry - ((lpaddr_t) &x86_32_start_ap) +
-                          X86_32_REAL_MODE_LINEAR_OFFSET);
-    //copy the address of the function start (in boot.S) to the long-mode
-    //assembler code to be able to perform an absolute jump
-    *absolute_entry_ptr = entry;
-
-    /* pointer to the pseudo-lock used to detect boot up of new core */
-    volatile uint32_t *ap_wait = (volatile uint32_t *)
-        local_phys_to_mem((lpaddr_t) &x86_32_init_ap_wait - ((lpaddr_t) &x86_32_start_ap) +
-                          X86_32_REAL_MODE_LINEAR_OFFSET);
-
-    /* Pointer to the lock variable in the realmode code */
-    volatile uint8_t *ap_lock = (volatile uint8_t*)
-        local_phys_to_mem((lpaddr_t) &x86_32_init_ap_lock - ((lpaddr_t) &x86_32_start_ap) +
-                          X86_32_REAL_MODE_LINEAR_OFFSET);
-
-    /* pointer to the shared global variable amongst all kernels */
-    volatile uint64_t *ap_global = (volatile uint64_t *)
-        local_phys_to_mem((lpaddr_t) &x86_32_init_ap_global - ((lpaddr_t) &x86_32_start_ap) +
-                          X86_32_REAL_MODE_LINEAR_OFFSET);
-    *ap_global = (uint64_t)mem_to_local_phys((lvaddr_t)global);
-
-    lvaddr_t *init_vector;
-    init_vector = (lvaddr_t*)local_phys_to_mem(CMOS_RAM_BIOS_WARM_START_INIT_VECTOR);
-
-    *ap_wait = AP_STARTING_UP;
-
-    //set shutdown status to WARM_SHUTDOWN and set start-vector
-    cmos_write( CMOS_RAM_SHUTDOWN_ADDR, CMOS_RAM_WARM_SHUTDOWN);
-    *init_vector = X86_32_REAL_MODE_ADDR_TO_REAL_MODE_VECTOR(X86_32_REAL_MODE_SEGMENT,
-                                                      X86_32_REAL_MODE_OFFSET);
-
-    //INIT 1 assert
-    apic_send_init_assert(core_id, xapic_none);
-
-    //set shutdown status to WARM_SHUTDOWN and set start-vector
-    cmos_write( CMOS_RAM_SHUTDOWN_ADDR, CMOS_RAM_WARM_SHUTDOWN);
-    *init_vector = X86_32_REAL_MODE_ADDR_TO_REAL_MODE_VECTOR(X86_32_REAL_MODE_SEGMENT,
-                                                      X86_32_REAL_MODE_OFFSET);
-
-    //INIT 2 de-assert
-    apic_send_init_deassert();
-
-    //SIPI1
-    apic_send_start_up(core_id, xapic_none,
-                       X86_32_REAL_MODE_SEGMENT_TO_REAL_MODE_PAGE(X86_32_REAL_MODE_SEGMENT));
-
-    //SIPI2
-    apic_send_start_up(core_id, xapic_none,
-                       X86_32_REAL_MODE_SEGMENT_TO_REAL_MODE_PAGE(X86_32_REAL_MODE_SEGMENT));
-
-    //give the new core a bit time to start-up and set the lock
-    for (uint64_t i = 0; i < STARTUP_TIMEOUT; i++) {
-        if (*ap_lock != 0) {
-            break;
-        }
-    }
-
-    //if the lock is set, the core has been started, otherwise assume, that
-    //a core with this APIC ID doesn't exist.
-    if (*ap_lock != 0) {
-        while (*ap_wait != AP_STARTED);
-        *ap_lock = 0;
-        debug(SUBSYS_STARTUP, "booted CPU%hhu\n", core_id);
-        return 0;
-    }
-    return -1;
-}
index 58a0aca..0c085ed 100644 (file)
  */
 uint64_t tsc_lasttime = 0;
 
-#ifndef __scc__
-/**
- * \brief Spawn a new core
- */
-struct sysret sys_monitor_spawn_core(coreid_t core_id, enum cpu_type cpu_type,
-                                     genvaddr_t entry)
-{
-    int r;
-    switch(cpu_type) {
-    case CPU_X86_64:
-        r = start_aps_x86_64_start(core_id, entry);
-        if (r != 0) {
-            return SYSRET(SYS_ERR_CORE_NOT_FOUND);
-        }
-        break;
-    case CPU_X86_32:
-        r = start_aps_x86_32_start(core_id, entry);
-        if (r != 0) {
-            return SYSRET(SYS_ERR_CORE_NOT_FOUND);
-        }
-        break;
-    default:
-        assert(!"Architecture not supported");
-        return SYSRET(SYS_ERR_CORE_NOT_FOUND);
-        break;
-    }
-
-    return SYSRET(SYS_ERR_OK);
-}
-#endif
-
 struct sysret sys_io(struct capability *to, enum io_cmd cmd,
                      uint16_t port, uint32_t data)
 {
index 4a69901..a9a6643 100644 (file)
@@ -626,6 +626,9 @@ static void  __attribute__ ((noreturn, noinline)) text_init(void)
     enable_monitor_mwait();
 #endif
 
+    /* Register start handler for other cores in the system */
+    set_spawn_core_handler(CPU_X86_64, start_aps_x86_32_start);
+
     // Call main kernel startup function -- this should never return
     kernel_startup();
 
diff --git a/kernel/arch/x86_32/start_aps.c b/kernel/arch/x86_32/start_aps.c
new file mode 100644 (file)
index 0000000..6c09018
--- /dev/null
@@ -0,0 +1,126 @@
+/**
+ * \file
+ * \brief Start the application processors
+ *
+ *  This file sends all needed IPIs to the other cores to start them.
+ */
+
+/*
+ * Copyright (c) 2007, 2008, 2010, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <kernel.h>
+#include <stdio.h>
+#include <string.h>
+#include <arch/x86/apic.h>
+#include <arch/x86/start_aps.h>
+#include <x86.h>
+#include <arch/x86/cmos.h>
+#include <init.h>
+#include <arch/x86/kputchar.h>
+#include "xapic_dev.h"
+#include <target/x86_32/offsets_target.h>
+
+extern uint64_t x86_32_start_ap;
+extern uint64_t x86_32_start_ap_end;
+extern uint64_t x86_32_init_ap_absolute_entry;
+extern uint64_t x86_32_init_ap_wait;
+extern uint64_t x86_32_init_ap_lock;
+extern uint64_t x86_32_start;
+extern uint64_t x86_32_init_ap_global;
+
+/**
+ * \brief Boot a app core of x86_32 type
+ *
+ * The processors are started by a sequency of INIT and STARTUP IPIs
+ * which are sent by this function. 
+ *
+ * \param core_id   APIC ID of the core to try booting
+ * \param entry     Entry address for new kernel in the destination
+ *                  architecture's lvaddr_t given in genvaddr_t
+ *
+ * \returns Zero on successful boot, non-zero (error code) on failure
+ */
+int start_aps_x86_32_start(uint8_t core_id, genvaddr_t entry)
+{
+    /* Copy the startup code to the real-mode address */
+    uint8_t *real_dest = (uint8_t*) local_phys_to_mem(X86_32_REAL_MODE_LINEAR_OFFSET);
+    uint8_t *real_src = (uint8_t *) &x86_32_start_ap;
+    uint8_t *real_end = (uint8_t *) &x86_32_start_ap_end;
+    memcpy(real_dest, real_src, real_end - real_src);
+
+    /* Pointer to the entry point called from init_ap.S */
+    volatile uint64_t *absolute_entry_ptr = (volatile uint64_t *)
+        local_phys_to_mem((lpaddr_t) &x86_32_init_ap_absolute_entry - ((lpaddr_t) &x86_32_start_ap) +
+                          X86_32_REAL_MODE_LINEAR_OFFSET);
+    //copy the address of the function start (in boot.S) to the long-mode
+    //assembler code to be able to perform an absolute jump
+    *absolute_entry_ptr = entry;
+
+    /* pointer to the pseudo-lock used to detect boot up of new core */
+    volatile uint32_t *ap_wait = (volatile uint32_t *)
+        local_phys_to_mem((lpaddr_t) &x86_32_init_ap_wait - ((lpaddr_t) &x86_32_start_ap) +
+                          X86_32_REAL_MODE_LINEAR_OFFSET);
+
+    /* Pointer to the lock variable in the realmode code */
+    volatile uint8_t *ap_lock = (volatile uint8_t*)
+        local_phys_to_mem((lpaddr_t) &x86_32_init_ap_lock - ((lpaddr_t) &x86_32_start_ap) +
+                          X86_32_REAL_MODE_LINEAR_OFFSET);
+
+    /* pointer to the shared global variable amongst all kernels */
+    volatile uint64_t *ap_global = (volatile uint64_t *)
+        local_phys_to_mem((lpaddr_t) &x86_32_init_ap_global - ((lpaddr_t) &x86_32_start_ap) +
+                          X86_32_REAL_MODE_LINEAR_OFFSET);
+    *ap_global = (uint64_t)mem_to_local_phys((lvaddr_t)global);
+
+    lvaddr_t *init_vector;
+    init_vector = (lvaddr_t*)local_phys_to_mem(CMOS_RAM_BIOS_WARM_START_INIT_VECTOR);
+
+    *ap_wait = AP_STARTING_UP;
+
+    //set shutdown status to WARM_SHUTDOWN and set start-vector
+    cmos_write( CMOS_RAM_SHUTDOWN_ADDR, CMOS_RAM_WARM_SHUTDOWN);
+    *init_vector = X86_32_REAL_MODE_ADDR_TO_REAL_MODE_VECTOR(X86_32_REAL_MODE_SEGMENT,
+                                                      X86_32_REAL_MODE_OFFSET);
+
+    //INIT 1 assert
+    apic_send_init_assert(core_id, xapic_none);
+
+    //set shutdown status to WARM_SHUTDOWN and set start-vector
+    cmos_write( CMOS_RAM_SHUTDOWN_ADDR, CMOS_RAM_WARM_SHUTDOWN);
+    *init_vector = X86_32_REAL_MODE_ADDR_TO_REAL_MODE_VECTOR(X86_32_REAL_MODE_SEGMENT,
+                                                      X86_32_REAL_MODE_OFFSET);
+
+    //INIT 2 de-assert
+    apic_send_init_deassert();
+
+    //SIPI1
+    apic_send_start_up(core_id, xapic_none,
+                       X86_32_REAL_MODE_SEGMENT_TO_REAL_MODE_PAGE(X86_32_REAL_MODE_SEGMENT));
+
+    //SIPI2
+    apic_send_start_up(core_id, xapic_none,
+                       X86_32_REAL_MODE_SEGMENT_TO_REAL_MODE_PAGE(X86_32_REAL_MODE_SEGMENT));
+
+    //give the new core a bit time to start-up and set the lock
+    for (uint64_t i = 0; i < STARTUP_TIMEOUT; i++) {
+        if (*ap_lock != 0) {
+            break;
+        }
+    }
+
+    //if the lock is set, the core has been started, otherwise assume, that
+    //a core with this APIC ID doesn't exist.
+    if (*ap_lock != 0) {
+        while (*ap_wait != AP_STARTED);
+        *ap_lock = 0;
+        debug(SUBSYS_STARTUP, "booted CPU%hhu\n", core_id);
+        return 0;
+    }
+    return -1;
+}
index 6cb6fb2..e88d459 100644 (file)
 #include <target/x86/barrelfish_kpi/coredata_target.h>
 #include <arch/x86/timing.h>
 #include <arch/x86/startup_x86.h>
+#include <arch/x86/start_aps.h>
 #include <arch/x86/ipi_notify.h>
 #include <barrelfish_kpi/cpu_arch.h>
 #include <target/x86_64/barrelfish_kpi/cpu_target.h>
+#include <coreboot.h>
 
 #include <dev/xapic_dev.h> // XXX
 #include <dev/ia32_dev.h>
@@ -527,6 +529,9 @@ static void  __attribute__ ((noreturn, noinline)) text_init(void)
     // Check/Enable MONITOR/MWAIT opcodes
     enable_monitor_mwait();
 
+    // Register start handler for other cores in the system
+    coreboot_set_spawn_handler(CPU_X86_64, start_aps_x86_64_start);
+
     // Call main kernel startup function -- this should never return
     kernel_startup();
 
diff --git a/kernel/arch/x86_64/start_aps.c b/kernel/arch/x86_64/start_aps.c
new file mode 100644 (file)
index 0000000..cff3749
--- /dev/null
@@ -0,0 +1,143 @@
+
+/**
+ * \file
+ * \brief Start the application processors
+ *
+ *  This file sends all needed IPIs to the other cores to start them.
+ */
+
+/*
+ * Copyright (c) 2007, 2008, 2010, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <kernel.h>
+#include <stdio.h>
+#include <string.h>
+#include <arch/x86/apic.h>
+#include <arch/x86/start_aps.h>
+#include <x86.h>
+#include <arch/x86/cmos.h>
+#include <init.h>
+#include <arch/x86/kputchar.h>
+#include "xapic_dev.h"
+#include <target/x86_64/offsets_target.h>
+
+/**
+ * start_ap and start_ap_end mark the start end the end point of the assembler
+ * startup code to be copied
+ */
+extern uint64_t x86_64_start_ap;
+extern uint64_t x86_64_start_ap_end;
+extern uint64_t x86_64_init_ap_absolute_entry;
+extern uint64_t x86_64_init_ap_wait;
+extern uint64_t x86_64_init_ap_lock;
+extern uint64_t x86_64_start;
+extern uint64_t x86_64_init_ap_global;
+
+/**
+ * \brief Boot a app core of x86_64 type
+ *
+ * The processors are started by a sequency of INIT and STARTUP IPIs
+ * which are sent by this function.
+ * CMOS writes to the shutdown status byte are used to execute
+ * different memory locations.
+ *
+ * \param core_id   APIC ID of the core to try booting
+ * \param entry     Entry address for new kernel in the destination
+ *                  architecture's lvaddr_t given in genvaddr_t
+ *
+ * \returns Zero on successful boot, non-zero (error code) on failure
+ */
+int start_aps_x86_64_start(uint8_t core_id, genvaddr_t entry)
+{
+    /* Copy the startup code to the real-mode address */
+    uint8_t *real_dest = (uint8_t *) local_phys_to_mem(X86_64_REAL_MODE_LINEAR_OFFSET);
+    uint8_t *real_src = (uint8_t *) &x86_64_start_ap;
+    uint8_t *real_end = (uint8_t *) &x86_64_start_ap_end;
+    memcpy(real_dest, real_src, real_end - real_src);
+
+    /* Pointer to the entry point called from init_ap.S */
+    volatile uint64_t *absolute_entry_ptr = (volatile uint64_t *)
+                                            local_phys_to_mem(
+                                                    (lpaddr_t) &x86_64_init_ap_absolute_entry -
+                                                    ((lpaddr_t) &x86_64_start_ap) +
+                                                    X86_64_REAL_MODE_LINEAR_OFFSET);
+    //copy the address of the function start (in boot.S) to the long-mode
+    //assembler code to be able to perform an absolute jump
+    *absolute_entry_ptr = entry;
+
+    /* pointer to the pseudo-lock used to detect boot up of new core */
+    volatile uint32_t *ap_wait = (volatile uint32_t *)
+                                 local_phys_to_mem((lpaddr_t) &x86_64_init_ap_wait -
+                                         ((lpaddr_t) &x86_64_start_ap) +
+                                         X86_64_REAL_MODE_LINEAR_OFFSET);
+
+    /* Pointer to the lock variable in the realmode code */
+    volatile uint8_t *ap_lock = (volatile uint8_t *)
+                                local_phys_to_mem((lpaddr_t) &x86_64_init_ap_lock -
+                                        ((lpaddr_t) &x86_64_start_ap) +
+                                        X86_64_REAL_MODE_LINEAR_OFFSET);
+
+    /* pointer to the shared global variable amongst all kernels */
+    volatile uint64_t *ap_global = (volatile uint64_t *)
+                                   local_phys_to_mem((lpaddr_t) &x86_64_init_ap_global -
+                                           ((lpaddr_t) &x86_64_start_ap) +
+                                           X86_64_REAL_MODE_LINEAR_OFFSET);
+    *ap_global = (uint64_t)mem_to_local_phys((lvaddr_t)global);
+
+    lvaddr_t *init_vector;
+    init_vector = (lvaddr_t *)local_phys_to_mem(CMOS_RAM_BIOS_WARM_START_INIT_VECTOR);
+
+    *ap_wait = AP_STARTING_UP;
+
+    if (CPU_IS_M5_SIMULATOR) {
+        printk(LOG_WARN, "Warning: skipping shutdown/init of APs on M5\n");
+    } else {
+        // set shutdown status to WARM_SHUTDOWN and set start-vector
+        cmos_write( CMOS_RAM_SHUTDOWN_ADDR, CMOS_RAM_WARM_SHUTDOWN);
+        *init_vector = X86_64_REAL_MODE_ADDR_TO_REAL_MODE_VECTOR(X86_64_REAL_MODE_SEGMENT,
+                       X86_64_REAL_MODE_OFFSET);
+
+        //INIT 1 assert
+        apic_send_init_assert(core_id, xapic_none);
+
+        //set shutdown status to WARM_SHUTDOWN and set start-vector
+        cmos_write( CMOS_RAM_SHUTDOWN_ADDR, CMOS_RAM_WARM_SHUTDOWN);
+        *init_vector = X86_64_REAL_MODE_ADDR_TO_REAL_MODE_VECTOR(X86_64_REAL_MODE_SEGMENT,
+                       X86_64_REAL_MODE_OFFSET);
+
+        //INIT 2 de-assert
+        apic_send_init_deassert();
+    }
+
+    //SIPI1
+    apic_send_start_up(core_id, xapic_none,
+                       X86_64_REAL_MODE_SEGMENT_TO_REAL_MODE_PAGE(X86_64_REAL_MODE_SEGMENT));
+
+    //SIPI2
+    apic_send_start_up(core_id, xapic_none,
+                       X86_64_REAL_MODE_SEGMENT_TO_REAL_MODE_PAGE(X86_64_REAL_MODE_SEGMENT));
+
+    //give the new core a bit time to start-up and set the lock
+    for (uint64_t i = 0; i < STARTUP_TIMEOUT; i++) {
+        if (*ap_lock != 0) {
+            break;
+        }
+    }
+
+    //if the lock is set, the core has been started, otherwise assume, that
+    //a core with this APIC ID doesn't exist.
+    if (*ap_lock != 0) {
+        while (*ap_wait != AP_STARTED);
+        *ap_lock = 0;
+        debug(SUBSYS_STARTUP, "booted CPU%hhu\n", core_id);
+        return 0;
+    }
+    return -1;
+}
+
index 0d268e6..9d4366a 100644 (file)
@@ -31,6 +31,7 @@
 #include <kputchar.h>
 #include <startup.h>
 #include <arch/x86/startup_x86.h>
+#include <arch/x86/start_aps.h>
 
 /// Quick way to find the base address of a cnode capability
 #define CNODE(cte)     (cte)->cap.u.cnode.cnode
diff --git a/kernel/coreboot.c b/kernel/coreboot.c
new file mode 100644 (file)
index 0000000..d2904e3
--- /dev/null
@@ -0,0 +1,52 @@
+/**
+ * \file
+ * \brief Registering for handler functions to manage cores
+ */
+/*
+ * Copyright (c) 2013, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <coreboot.h>
+#include <barrelfish_kpi/types.h>
+#include <barrelfish_kpi/cpu.h>
+
+static start_core_fn spawn_core_handlers[CPU_TYPE_NUM];
+
+/**
+ * Register spawn core handler function for specific cpu type.
+ * 
+ * \param type CPU type
+ * \param handler Handler functions
+ */
+void coreboot_set_spawn_handler(enum cpu_type type, start_core_fn handler) 
+{
+    assert(type < CPU_TYPE_NUM);
+    assert(handler != NULL);
+    assert(spawn_core_handlers[type] == NULL);
+
+    if (type < CPU_TYPE_NUM) {
+        spawn_core_handlers[type] = handler;
+    }
+}
+
+/**
+ * \param  cpu_type Get handler for specific cpu type
+ * \return Core boot handler function or NULL in case none was registered
+ * for that type
+ */
+start_core_fn coreboot_get_spawn_handler(enum cpu_type type) {
+    assert(type < CPU_TYPE_NUM);
+    
+    if (type >= CPU_TYPE_NUM) {
+        return NULL;
+    }
+    return spawn_core_handlers[type];
+}
\ No newline at end of file
index 70a3178..9110d29 100644 (file)
 
 #include <capabilities.h>
 
-struct sysret sys_monitor_spawn_core(coreid_t core_id, enum cpu_type cpu_type,
-                                     genvaddr_t entry);
-
-
-//needed because to resume an interrupted IT block, there literally is only one way:
-//exiting handler mode, restoring the context
-//if the dispatcher has to restore a context with IT-bits set, it can only do so with help
-//from the kernel. 
-//XXX: registers is an area in the userspace of the currently executing process,
-//it is NOT the set of arguments given to the syscall
-errval_t sys_resume_context(arch_registers_state_t* registers);
+// needed because to resume an interrupted IT block, there literally is only one way:
+// exiting handler mode, restoring the context
+// if the dispatcher has to restore a context with IT-bits set, it can only do so with help
+// from the kernel.
+// XXX: registers is an area in the userspace of the currently executing process,
+// it is NOT the set of arguments given to the syscall
+errval_t sys_resume_context(arch_registers_state_t *registers);
 
 #endif // ARMV7_SYSCALL_H
diff --git a/kernel/include/arch/armv7/armv7_syscall.h b/kernel/include/arch/armv7/armv7_syscall.h
deleted file mode 100644 (file)
index ea432ce..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/**
- * \file
- * \brief armv7-specific system calls implementation.
- */
-
-/*
- * Copyright (c) 2007, 2008, 2009, 2010, ETH Zurich.
- * All rights reserved.
- *
- * This file is distributed under the terms in the attached LICENSE file.
- * If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
- */
-
-#ifndef ARMV7_SYSCALL_H
-#define ARMV7_SYSCALL_H
-
-#include <capabilities.h>
-
-struct sysret sys_monitor_spawn_core(coreid_t core_id, enum cpu_type cpu_type,
-                                     genvaddr_t entry);
-
-#endif // ARMV7_SYSCALL_H
index e9bf2b5..e1d9f43 100644 (file)
@@ -47,6 +47,6 @@
     #error "Unknown ARM arch"
 #endif
 
-int start_aps_arm_start(uint8_t core_id, lvaddr_t entry);
+int start_aps_arm_start(coreid_t core_id, genvaddr_t entry);
 
 #endif // START_APS_H_
index ace2538..5b37558 100644 (file)
 
 #include <stdint.h>
 
+/**
+ * This byte is read upon startup after CPU reset in order to determine if
+ * the reset was used as a way to get out of 80286 protected mode.
+ */
 #define CMOS_RAM_SHUTDOWN_ADDR 0x0f
+
+/** 
+ * Shutdown with FAR JMP (immediate jmp to address at 0:[0467H]) 
+ * \sa CMOS_RAM_BIOS_WARM_START_INIT_VECTOR
+ **/
 #define CMOS_RAM_WARM_SHUTDOWN 0x0a
 #define CMOS_RAM_BIOS_WARM_START_INIT_VECTOR 0x467
 
index 4a0a742..4f8780f 100644 (file)
 #ifndef START_APS_H_
 #define START_APS_H_
 
+#include <stdint.h>
+#include <barrelfish_kpi/types.h>
+
 #define AP_STARTING_UP 1
 #define AP_STARTED     2
 
-int start_aps_x86_64_start(uint8_t core_id, genvaddr_t entry);
-int start_aps_x86_32_start(uint8_t core_id, genvaddr_t entry);
+#define STARTUP_TIMEOUT         0xffffff
+
+int start_aps_x86_64_start(coreid_t core_id, genvaddr_t entry);
+int start_aps_x86_32_start(coreid_t core_id, genvaddr_t entry);
 
 #endif // START_APS_H_
index 3229dd4..322805e 100644 (file)
@@ -17,8 +17,6 @@
 
 #include <capabilities.h>
 
-struct sysret sys_monitor_spawn_core(coreid_t core_id, enum cpu_type cpu_type,
-                                     genvaddr_t entry);
 struct sysret sys_io(struct capability *to, enum io_cmd cmd,
                      uint16_t port, uint32_t data);
 struct sysret sys_monitor_handle_sync_timer(uint64_t synctime);
diff --git a/kernel/include/coreboot.h b/kernel/include/coreboot.h
new file mode 100644 (file)
index 0000000..f43f80e
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2013, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef COREBOOT_H
+#define COREBOOT_H
+
+#include <assert.h>
+#include <barrelfish_kpi/types.h>
+#include <barrelfish_kpi/cpu.h>
+
+typedef int(*start_core_fn)(coreid_t coreid, genvaddr_t entry);
+
+void coreboot_set_spawn_handler(enum cpu_type type, start_core_fn handler);
+start_core_fn coreboot_get_spawn_handler(enum cpu_type);
+
+#endif // COREBOOT_H
\ No newline at end of file
index b126e9a..278fbd6 100644 (file)
@@ -18,6 +18,7 @@
 #include <kernel.h>
 #include <barrelfish_kpi/cpu.h>
 #include <barrelfish_kpi/dispatcher_shared_target.h>
+#include <barrelfish_kpi/types.h>
 #include <capabilities.h>
 
 errval_t sys_print(const char *str, size_t length);
@@ -61,5 +62,8 @@ sys_dispatcher_setup_guest (struct capability *to,
 struct sysret sys_monitor_domain_id(capaddr_t cptr, domainid_t domain_id);
 struct sysret sys_trace_setup(struct capability *cap, capaddr_t cptr);
 struct sysret sys_idcap_identify(struct capability *cap, idcap_id_t *id);
+struct sysret sys_monitor_spawn_core(coreid_t core_id, enum cpu_type cpu_type,
+                                     genvaddr_t entry);
+
 
 #endif
index cc333ec..a8b3616 100644 (file)
@@ -19,6 +19,7 @@
 #include <barrelfish_kpi/syscalls.h>
 #include <capabilities.h>
 #include <cap_predicates.h>
+#include <coreboot.h>
 #include <mdb/mdb.h>
 #include <dispatch.h>
 #include <wakeup.h>
@@ -540,3 +541,44 @@ struct sysret sys_idcap_identify(struct capability *cap, idcap_id_t *id)
 
     return SYSRET(SYS_ERR_OK);
 }
+
+/**
+ * Calls correct handler function to spawn an app core.
+ *
+ * At the moment spawn_core_handlers is set-up per 
+ * architecture inside text_init() usually found in init.c.
+ * 
+ * \note Generally the x86 terms of BSP and APP core are used
+ * throughout Barrelfish to distinguish between bootstrap core (BSP)
+ * and application cores (APP).
+ * 
+ * \param  core_id  Identifier of the core which we want to boot
+ * \param  cpu_type Architecture of the core.
+ * \param  entry    Entry point for code to start execution.
+ * 
+ * \retval SYS_ERR_OK Core successfully booted.
+ * \retval SYS_ERR_ARCHITECTURE_NOT_SUPPORTED No handler registered for
+ *     the specified cpu_type.
+ * \retval SYS_ERR_CORE_NOT_FOUND Core failed to boot.
+ */
+struct sysret sys_monitor_spawn_core(coreid_t core_id, enum cpu_type cpu_type,
+                                     genvaddr_t entry)
+{
+    assert(cpu_type < CPU_TYPE_NUM);
+    // TODO(gz): assert core_id valid
+    // TODO(gz): assert entry range?
+
+    if (cpu_type < CPU_TYPE_NUM &&
+        coreboot_get_spawn_handler(cpu_type) == NULL) {
+        assert(!"Architecture not supported -- " \
+               "or you failed to register spawn handler?");
+        return SYSRET(SYS_ERR_ARCHITECTURE_NOT_SUPPORTED);
+    }
+
+    int r = (coreboot_get_spawn_handler(cpu_type))(core_id, entry);
+    if (r != 0) {
+        return SYSRET(SYS_ERR_CORE_NOT_FOUND);
+    }
+
+    return SYSRET(SYS_ERR_OK);
+}
\ No newline at end of file