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;