From 3fa048c0a641db7b58d69c9629cb714de60d221c Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Thu, 31 Jan 2008 22:15:52 +0000 Subject: [PATCH] When starting the other CPUs from the bootloader we did not wait for any confirmation after sending off the startup IPIs. We simply moved on and setup the temporary stack address for the next CPU to be started. With this it was possible that the trampoline code did not manage to load the address before we overwrote it. So for configurations with more than two CPUs it was possible that two CPUs were setup to the same kernel stack which could have caused all sorts of things - most likely a tripple fault and a reboot. On real hardware this seems very unlikely but it was easily reproducible with QEMU and -smp >2. We now use the shared trampoline stack to implement a notification mechanism. The trampoline code will clear the stack location variable once it has loaded everything it needs from the trampoline stack. On the other side smp_boot_other_cpus() will wait for this variable to be cleared after it sent the startup IPIs so that it knows when it can safely move on and overwrite the area to boot the next CPU. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23800 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/system/boot/platform/bios_ia32/smp.cpp | 7 +++++++ src/system/boot/platform/bios_ia32/smp_trampoline.S | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/src/system/boot/platform/bios_ia32/smp.cpp b/src/system/boot/platform/bios_ia32/smp.cpp index fc2b766167..105bc7e945 100644 --- a/src/system/boot/platform/bios_ia32/smp.cpp +++ b/src/system/boot/platform/bios_ia32/smp.cpp @@ -565,6 +565,13 @@ dprintf("wait for delivery\n"); while ((apic_read(APIC_INTR_COMMAND_1) & APIC_DELIVERY_STATUS) != 0) asm volatile ("pause;"); } + + // Wait for the trampoline code to clear the final stack location. + // This serves as a notification for us that it has loaded the address + // and it is safe for us to overwrite it to trampoline the next CPU. + tempStack++; + while (*tempStack != 0) + spin(1000); } TRACE(("done trampolining\n")); diff --git a/src/system/boot/platform/bios_ia32/smp_trampoline.S b/src/system/boot/platform/bios_ia32/smp_trampoline.S index 480f453b57..33a5ced675 100644 --- a/src/system/boot/platform/bios_ia32/smp_trampoline.S +++ b/src/system/boot/platform/bios_ia32/smp_trampoline.S @@ -47,6 +47,11 @@ trampoline_32: movl %eax,%cr3 # set the page dir popl %eax # get the final stack location + + // Clear the final stack location to notify the startup code that + // we loaded the address and it is now safe to be overwritten. + pushl $0x00000000 + movl %eax,%esp // load an address for an indirect jump