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
This commit is contained in:
Travis Geiselbrecht
2007-03-01 08:09:28 +00:00
parent 8d7966617a
commit 0098867364
4 changed files with 45 additions and 39 deletions
+1 -1
View File
@@ -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,
+34 -14
View File
@@ -40,26 +40,25 @@
#include <string.h>
//#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();
+6 -18
View File
@@ -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<<current_cpu);
while (*var != ((1<<sNumCPUs) - 1))
;
}
status_t
smp_init(kernel_args *args)
+4 -6
View File
@@ -170,7 +170,7 @@ thread_struct_hash(void *_t, const void *_key, uint32 range)
*/
static struct thread *
create_thread_struct(struct thread *inthread, const char *name, thread_id threadID)
create_thread_struct(struct thread *inthread, const char *name, thread_id threadID, struct cpu_ent *cpu)
{
struct thread *thread;
cpu_status state;
@@ -201,8 +201,7 @@ create_thread_struct(struct thread *inthread, const char *name, thread_id thread
thread->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;