From 0098867364c187e4419101ca8156ac094808a25d Mon Sep 17 00:00:00 2001 From: Travis Geiselbrecht Date: Thu, 1 Mar 2007 08:09:28 +0000 Subject: [PATCH] this seems to solve the 'lock up on bootup on core 2' problem. Basically, there was a pretty subtle race between the cpus in main where if the main cpu released the AP cpus and then before the AP cpus had a chance to run the boot cpu started creating the main thread (which causes smp ici messages to be created) the system would livelock, where the boot cpu waited forever for the AP cpu to acknowledge the ICI (for a TLB flush when creating the kernel stack). Added smp_cpu_rendezvous(), used to synchronize all the cpus to a particular point, and used it a few times in main(). While i was at it i fixed another race that'll probably never happen, but what the hey. Make sure the kernel args are copied into kernel space by the main cpu before letting any other ones use it. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20269 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/kernel/smp.h | 2 +- src/system/kernel/main.c | 48 +++++++++++++++++++++++++----------- src/system/kernel/smp.c | 24 +++++------------- src/system/kernel/thread.c | 10 +++----- 4 files changed, 45 insertions(+), 39 deletions(-) diff --git a/headers/private/kernel/smp.h b/headers/private/kernel/smp.h index 5341897db8..80e6954fff 100644 --- a/headers/private/kernel/smp.h +++ b/headers/private/kernel/smp.h @@ -42,7 +42,7 @@ status_t smp_init(struct kernel_args *args); status_t smp_per_cpu_init(struct kernel_args *args, int32 cpu); bool smp_trap_non_boot_cpus(int32 cpu); void smp_wake_up_non_boot_cpus(void); -void smp_wait_for_non_boot_cpus(void); +void smp_cpu_rendezvous(volatile uint32 *var, int current_cpu); void smp_send_ici(int32 targetCPU, int32 message, uint32 data, uint32 data2, uint32 data3, void *data_ptr, uint32 flags); void smp_send_broadcast_ici(int32 message, uint32 data, uint32 data2, uint32 data3, diff --git a/src/system/kernel/main.c b/src/system/kernel/main.c index 69d75c8a2d..4156294164 100644 --- a/src/system/kernel/main.c +++ b/src/system/kernel/main.c @@ -40,26 +40,25 @@ #include -//#define TRACE_BOOT +#define TRACE_BOOT #ifdef TRACE_BOOT # define TRACE(x...) dprintf("INIT : " x) #else # define TRACE(x...) ; #endif -bool kernel_startup; +bool kernel_startup = true; static kernel_args sKernelArgs; +static uint32 sCpuRendezvous; +static uint32 sCpuRendezvous2; static int32 main2(void *); int _start(kernel_args *bootKernelArgs, int cpu); /* keep compiler happy */ - int _start(kernel_args *bootKernelArgs, int currentCPU) { - kernel_startup = true; - if (bootKernelArgs->kernel_args_size != sizeof(kernel_args) || bootKernelArgs->version != CURRENT_KERNEL_ARGS_VERSION) { // This is something we cannot handle right now - release kernels @@ -69,10 +68,16 @@ _start(kernel_args *bootKernelArgs, int currentCPU) return -1; } - memcpy(&sKernelArgs, bootKernelArgs, sizeof(kernel_args)); - // the passed in kernel args are in a non-allocated range of memory + smp_set_num_cpus(bootKernelArgs->num_cpus); - smp_set_num_cpus(sKernelArgs.num_cpus); + // wait for all the cpus to get here + smp_cpu_rendezvous(&sCpuRendezvous, currentCPU); + + // the passed in kernel args are in a non-allocated range of memory + if (currentCPU == 0) + memcpy(&sKernelArgs, bootKernelArgs, sizeof(kernel_args)); + + smp_cpu_rendezvous(&sCpuRendezvous2, currentCPU); // do any pre-booting cpu config cpu_preboot_init_percpu(&sKernelArgs, currentCPU); @@ -90,9 +95,6 @@ _start(kernel_args *bootKernelArgs, int currentCPU) set_dprintf_enabled(true); dprintf("Welcome to kernel debugger output!\n"); - // we're the boot processor, so wait for all of the APs to enter the kernel - smp_wait_for_non_boot_cpus(); - // init modules TRACE("init CPU\n"); cpu_init(&sKernelArgs); @@ -154,24 +156,42 @@ _start(kernel_args *bootKernelArgs, int currentCPU) TRACE("init VFS\n"); vfs_init(&sKernelArgs); - TRACE("enable interrupts, exit kernel startup\n"); + // bring up the AP cpus in a lock step fashion + TRACE("waking up AP cpus\n"); + sCpuRendezvous = sCpuRendezvous2 = 0; + smp_wake_up_non_boot_cpus(); + smp_cpu_rendezvous(&sCpuRendezvous, 0); // wait until they're booted + + // exit the kernel startup phase (mutexes, etc work from now on out) + TRACE("exiting kernel startup\n"); kernel_startup = false; - TRACE("waking up AP cpus\n"); - smp_wake_up_non_boot_cpus(); + smp_cpu_rendezvous(&sCpuRendezvous2, 0); // release the AP cpus to go enter the scheduler + TRACE("enabling interrupts and starting scheduler on cpu 0\n"); enable_interrupts(); scheduler_start(); // start a thread to finish initializing the rest of the system TRACE("starting main2 thread\n"); thread = spawn_kernel_thread(&main2, "main2", B_NORMAL_PRIORITY, NULL); + TRACE("resuming main2 thread...\n"); resume_thread(thread); } else { + // lets make sure we're in sync with the main cpu + // the boot processor has probably been sending us + // tlb sync messages all along the way, but we've + // been ignoring them + arch_cpu_global_TLB_invalidate(); + // this is run for each non boot processor after they've been set loose cpu_init_percpu(&sKernelArgs, currentCPU); smp_per_cpu_init(&sKernelArgs, currentCPU); + // wait for all other AP cpus to get to this point + smp_cpu_rendezvous(&sCpuRendezvous, currentCPU); + smp_cpu_rendezvous(&sCpuRendezvous2, currentCPU); + // welcome to the machine enable_interrupts(); scheduler_start(); diff --git a/src/system/kernel/smp.c b/src/system/kernel/smp.c index f484dd58a6..c0e6dc085c 100644 --- a/src/system/kernel/smp.c +++ b/src/system/kernel/smp.c @@ -553,12 +553,6 @@ smp_trap_non_boot_cpus(int32 cpu) boot_cpu_spin[cpu] = 1; acquire_spinlock_nocheck(&boot_cpu_spin[cpu]); - // lets make sure we're in sync with the main cpu - // the boot processor has probably been sending us - // tlb sync messages all along the way, but we've - // been ignoring them - arch_cpu_global_TLB_invalidate(); - return false; } @@ -581,21 +575,15 @@ smp_wake_up_non_boot_cpus() } } - +/* have all cpus spin until all have run */ void -smp_wait_for_non_boot_cpus(void) +smp_cpu_rendezvous(volatile uint32 *var, int current_cpu) { - bool retry; - int32 i; - do { - retry = false; - for (i = 1; i < sNumCPUs; i++) { - if (boot_cpu_spin[i] != 1) - retry = true; - } - } while (retry == true); -} + atomic_or(var, 1<id = threadID >= 0 ? threadID : allocate_thread_id(); thread->team = NULL; - // XXX terrible hack, this is to leave the early boot cpu pointers alone while being initialized -// thread->cpu = NULL; + thread->cpu = cpu; thread->sem.blocking = -1; thread->fault_handler = 0; thread->page_faults_allowed = 1; @@ -360,7 +359,7 @@ create_thread(const char *name, team_id teamID, thread_entry_func entry, TRACE(("create_thread(%s, id = %ld, %s)\n", name, threadID, kernel ? "kernel" : "user")); - thread = create_thread_struct(NULL, name, threadID); + thread = create_thread_struct(NULL, name, threadID, NULL); if (thread == NULL) return B_NO_MEMORY; @@ -1470,7 +1469,7 @@ thread_init(kernel_args *args) sprintf(name, "idle thread %lu", i + 1); thread = create_thread_struct(&sIdleThreads[i], name, - i == 0 ? team_get_kernel_team_id() : -1); + i == 0 ? team_get_kernel_team_id() : -1, &gCPU[i]); if (thread == NULL) { panic("error creating idle thread struct\n"); return B_NO_MEMORY; @@ -1491,7 +1490,6 @@ thread_init(kernel_args *args) hash_insert(sThreadHash, thread); insert_thread_into_team(thread->team, thread); - thread->cpu = &gCPU[i]; } sUsedThreads = args->num_cpus;