SMP - BSP waits until the APs finish their booting
- APs configure local timers - while configuring local APIC timer the CPUs fiddle with the interrupt handlers. As the interrupt table is shared the BSP must not run
This commit is contained in:
parent
b7aed08e65
commit
9b6d66c787
@ -127,11 +127,7 @@ PRIVATE struct irq io_apic_irq[NR_IRQ_VECTORS];
|
||||
* to make APIC work if SMP is not configured, we need to set the maximal number
|
||||
* of CPUS to 1, cpuid to return 0 and the current cpu is always BSP
|
||||
*/
|
||||
#ifndef CONFIG_SMP
|
||||
/* this is always true on an uniprocessor */
|
||||
#define cpu_is_bsp(x) 1
|
||||
|
||||
#else
|
||||
#ifdef CONFIG_SMP
|
||||
|
||||
#include "kernel/smp.h"
|
||||
|
||||
|
@ -190,15 +190,35 @@ PRIVATE void ap_finish_booting(void)
|
||||
while(!i386_paging_enabled)
|
||||
arch_pause();
|
||||
|
||||
/*
|
||||
* Finish processor initialisation. CPUs must be excluded from running.
|
||||
* lapic timer calibration locks and unlocks the BKL because of the
|
||||
* nested interrupts used for calibration. Therefore BKL is not good
|
||||
* enough, the boot_lock must be held.
|
||||
*/
|
||||
spinlock_lock(&boot_lock);
|
||||
BKL_LOCK();
|
||||
|
||||
/*
|
||||
* we must load some page tables befre we turn paging on. As VM is
|
||||
* always present we use those
|
||||
*/
|
||||
segmentation2paging(proc_addr(VM_PROC_NR));
|
||||
|
||||
printf("CPU %d paging is on\n", cpu);
|
||||
|
||||
lapic_enable(cpu);
|
||||
|
||||
if (app_cpu_init_timer(system_hz)) {
|
||||
panic("FATAL : failed to initialize timer interrupts CPU %d, "
|
||||
"cannot continue without any clock source!", cpuid);
|
||||
}
|
||||
printf("CPU %d local APIC timer is ticking\n", cpu);
|
||||
|
||||
BKL_LOCK();
|
||||
printf("CPU %d is running\n", cpu);
|
||||
BKL_UNLOCK();
|
||||
|
||||
ap_boot_finished(cpu);
|
||||
spinlock_unlock(&boot_lock);
|
||||
for(;;);
|
||||
|
||||
/* finish processor initialisation. */
|
||||
|
@ -172,6 +172,9 @@ extern void * k_stacks;
|
||||
#define get_k_stack_top(cpu) ((void *)(((char*)(k_stacks)) \
|
||||
+ 2 * ((cpu) + 1) * K_STACK_SIZE))
|
||||
|
||||
#define barrier() do { mfence(); } while(0)
|
||||
|
||||
|
||||
#ifndef __GNUC__
|
||||
/* call a function to read the stack fram pointer (%ebp) */
|
||||
_PROTOTYPE(reg_t read_ebp, (void));
|
||||
|
@ -999,6 +999,8 @@ ENTRY(arch_spinlock_unlock)
|
||||
mfence
|
||||
ret
|
||||
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* mfence */
|
||||
/*===========================================================================*/
|
||||
@ -1008,8 +1010,6 @@ ENTRY(mfence)
|
||||
mfence
|
||||
ret
|
||||
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* arch_pause */
|
||||
/*===========================================================================*/
|
||||
|
@ -1083,12 +1083,15 @@ PUBLIC int arch_enable_paging(struct proc * caller, const message * m_ptr)
|
||||
io_apic[i].addr = io_apic[i].vaddr;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO APs are still waiting, release them */
|
||||
#endif
|
||||
#if CONFIG_SMP
|
||||
barrier();
|
||||
|
||||
i386_paging_enabled = 1;
|
||||
|
||||
wait_for_APs_to_finish_booting();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_WATCHDOG
|
||||
/*
|
||||
* We make sure that we don't enable the watchdog until paging is turned
|
||||
|
@ -61,6 +61,8 @@
|
||||
/* We only support 1 cpu now */
|
||||
#define CONFIG_MAX_CPUS 1
|
||||
#define cpuid 0
|
||||
/* this is always true on an uniprocessor */
|
||||
#define cpu_is_bsp(x) 1
|
||||
|
||||
#else
|
||||
|
||||
|
20
kernel/smp.c
20
kernel/smp.c
@ -6,4 +6,24 @@ unsigned bsp_cpu_id;
|
||||
|
||||
struct cpu cpus[CONFIG_MAX_CPUS];
|
||||
|
||||
static volatile unsigned ap_cpus_booted;
|
||||
|
||||
SPINLOCK_DEFINE(big_kernel_lock)
|
||||
SPINLOCK_DEFINE(boot_lock)
|
||||
|
||||
void wait_for_APs_to_finish_booting(void)
|
||||
{
|
||||
/* we must let the other CPUs to run in kernel mode first */
|
||||
BKL_UNLOCK();
|
||||
while (ap_cpus_booted != (ncpus - 1))
|
||||
arch_pause();
|
||||
/* now we have to take the lock again as we continu execution */
|
||||
BKL_LOCK();
|
||||
}
|
||||
|
||||
void ap_boot_finished(unsigned cpu)
|
||||
{
|
||||
printf("CPU %d is running\n", cpu);
|
||||
|
||||
ap_cpus_booted++;
|
||||
}
|
||||
|
10
kernel/smp.h
10
kernel/smp.h
@ -49,7 +49,17 @@ EXTERN struct cpu cpus[CONFIG_MAX_CPUS];
|
||||
#define cpu_test_flag(cpu, flag) (cpus[cpu].flags & (flag))
|
||||
#define cpu_is_ready(cpu) cpu_test_flag(cpu, CPU_IS_READY)
|
||||
|
||||
/*
|
||||
* Big Kernel Lock prevents more then one cpu executing the kernel code
|
||||
*/
|
||||
SPINLOCK_DECLARE(big_kernel_lock)
|
||||
/*
|
||||
* to sync the booting APs
|
||||
*/
|
||||
SPINLOCK_DECLARE(boot_lock)
|
||||
|
||||
_PROTOTYPE(void wait_for_APs_to_finish_booting, (void));
|
||||
_PROTOTYPE(void ap_boot_finished, (unsigned cpu));
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user