summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/x86/machine/cpu.c30
-rw-r--r--arch/x86/machine/cpu.h15
-rw-r--r--arch/x86/machine/pmap.c23
-rw-r--r--arch/x86/machine/pmap.h7
-rw-r--r--kern/kernel.c7
-rw-r--r--kern/kernel.h4
6 files changed, 42 insertions, 44 deletions
diff --git a/arch/x86/machine/cpu.c b/arch/x86/machine/cpu.c
index 82af7c30..b0567943 100644
--- a/arch/x86/machine/cpu.c
+++ b/arch/x86/machine/cpu.c
@@ -70,7 +70,12 @@ struct cpu cpu_array[MAX_CPUS];
/*
* Number of configured processors.
+ *
+ * The boot version is used until all processors are configured, since some
+ * modules depend on cpu_count() to adjust their behaviour when several
+ * processors are present.
*/
+static unsigned int cpu_boot_array_size;
unsigned int cpu_array_size;
/*
@@ -298,6 +303,7 @@ cpu_setup(void)
cpu_array[i].state = CPU_STATE_OFF;
}
+ cpu_boot_array_size = 1;
cpu_array_size = 1;
cpu_init(&cpu_array[0]);
}
@@ -341,13 +347,13 @@ cpu_mp_register_lapic(unsigned int apic_id, int is_bsp)
return;
}
- if (cpu_array_size == ARRAY_SIZE(cpu_array)) {
+ if (cpu_boot_array_size == ARRAY_SIZE(cpu_array)) {
printk("cpu: ignoring processor beyond id %u\n", MAX_CPUS - 1);
return;
}
- cpu_array[cpu_array_size].apic_id = apic_id;
- cpu_array_size++;
+ cpu_array[cpu_boot_array_size].apic_id = apic_id;
+ cpu_boot_array_size++;
}
static void __init
@@ -360,7 +366,7 @@ cpu_mp_start_aps(void)
size_t map_size;
unsigned int i;
- if (cpu_array_size == 1)
+ if (cpu_boot_array_size == 1)
return;
assert(BOOT_MP_TRAMPOLINE_ADDR < BIOSMEM_BASE);
@@ -396,7 +402,7 @@ cpu_mp_start_aps(void)
* Preallocate stacks now, as the kernel mappings shouldn't change while
* the APs are bootstrapping.
*/
- for (i = 1; i < cpu_array_size; i++) {
+ for (i = 1; i < cpu_boot_array_size; i++) {
cpu = &cpu_array[i];
cpu->boot_stack = vm_kmem_alloc(BOOT_STACK_SIZE);
@@ -405,7 +411,7 @@ cpu_mp_start_aps(void)
}
/* Perform the "Universal Start-up Algorithm" */
- for (i = 1; i < cpu_array_size; i++) {
+ for (i = 1; i < cpu_boot_array_size; i++) {
cpu = &cpu_array[i];
boot_ap_id = i;
@@ -424,6 +430,8 @@ cpu_mp_start_aps(void)
while (cpu->state == CPU_STATE_OFF)
cpu_pause();
}
+
+ cpu_array_size = cpu_boot_array_size;
}
static void __init
@@ -437,8 +445,6 @@ cpu_mp_setup(void)
{
acpimp_setup();
cpu_mp_start_aps();
- cpu_intr_enable();
- pmap_mp_setup();
cpu_mp_info();
}
@@ -448,5 +454,11 @@ cpu_ap_setup(void)
cpu_init(&cpu_array[boot_ap_id]);
cpu_check(cpu_current());
lapic_ap_setup();
- cpu_intr_enable();
+}
+
+void __init
+cpu_ap_sync(void)
+{
+ while (cpu_count() == 1)
+ cpu_pause();
}
diff --git a/arch/x86/machine/cpu.h b/arch/x86/machine/cpu.h
index 674892ad..66376e3a 100644
--- a/arch/x86/machine/cpu.h
+++ b/arch/x86/machine/cpu.h
@@ -436,18 +436,25 @@ void cpu_mp_register_lapic(unsigned int apic_id, int is_bsp);
/*
* Probe application processors and start them.
- *
- * This function enables interrupts.
*/
void cpu_mp_setup(void);
/*
* CPU initialization on APs.
- *
- * This function enables interrupts.
*/
void cpu_ap_setup(void);
+/*
+ * Synchronize processors on kernel entry.
+ *
+ * Wait for all processors to reach a proper state when entering the kernel,
+ * so that memory allocations can proceed and thread scheduling started.
+ *
+ * Once this function returns, cpu_count can be used reliably to know if there
+ * are more than one processors, and how many.
+ */
+void cpu_ap_sync(void);
+
#endif /* __ASSEMBLER__ */
#endif /* _X86_CPU_H */
diff --git a/arch/x86/machine/pmap.c b/arch/x86/machine/pmap.c
index cbd08b59..65f9708a 100644
--- a/arch/x86/machine/pmap.c
+++ b/arch/x86/machine/pmap.c
@@ -148,11 +148,6 @@ static unsigned long pmap_zero_va;
static struct spinlock pmap_zero_va_lock;
/*
- * True if running on multiple processors (TLB flushes must be propagated).
- */
-static volatile int pmap_mp_mode;
-
-/*
* Shared variables used by the inter-processor update functions.
*/
static unsigned long pmap_update_start;
@@ -364,6 +359,7 @@ pmap_bootstrap(void)
cpu_tlb_flush();
+ spinlock_init(&pmap_update_lock);
pmap_kernel_limit = VM_MIN_KERNEL_ADDRESS;
}
@@ -372,9 +368,6 @@ pmap_ap_bootstrap(void)
{
if (cpu_has_global_pages())
cpu_enable_global_pages();
-
- while (!pmap_mp_mode)
- cpu_pause();
}
unsigned long __init
@@ -507,10 +500,7 @@ pmap_kupdate(unsigned long start, unsigned long end)
{
unsigned int nr_cpus;
- if (pmap_mp_mode)
- nr_cpus = cpu_count();
- else
- nr_cpus = 1;
+ nr_cpus = cpu_count();
if (nr_cpus == 1) {
pmap_kupdate_local(start, end);
@@ -556,15 +546,6 @@ pmap_kextract(unsigned long va)
}
void
-pmap_mp_setup(void)
-{
- assert(cpu_intr_enabled());
-
- spinlock_init(&pmap_update_lock);
- pmap_mp_mode = 1;
-}
-
-void
pmap_update_intr(struct trap_frame *frame)
{
(void)frame;
diff --git a/arch/x86/machine/pmap.h b/arch/x86/machine/pmap.h
index 89b36b52..018bf900 100644
--- a/arch/x86/machine/pmap.h
+++ b/arch/x86/machine/pmap.h
@@ -176,13 +176,6 @@ void pmap_kupdate(unsigned long start, unsigned long end);
phys_addr_t pmap_kextract(unsigned long va);
/*
- * Prepare the pmap module for a multiprocessor environment.
- *
- * Interrupts must be enabled when calling this function.
- */
-void pmap_mp_setup(void);
-
-/*
* Interrupt handler for inter-processor update requests.
*/
void pmap_update_intr(struct trap_frame *frame);
diff --git a/kern/kernel.c b/kern/kernel.c
index 760f68e8..07a0f660 100644
--- a/kern/kernel.c
+++ b/kern/kernel.c
@@ -30,7 +30,7 @@ kernel_main(void)
task_setup();
thread_setup();
- /* Interrupts are enabled by this call */
+ cpu_intr_enable();
cpu_mp_setup();
thread_run();
@@ -41,7 +41,10 @@ kernel_main(void)
void __init
kernel_ap_main(void)
{
- assert(cpu_intr_enabled());
+ assert(!cpu_intr_enabled());
+
+ cpu_intr_enable();
+ cpu_ap_sync();
thread_run();
diff --git a/kern/kernel.h b/kern/kernel.h
index 22d5714b..f5821ca6 100644
--- a/kern/kernel.h
+++ b/kern/kernel.h
@@ -26,13 +26,15 @@
/*
* Machine-independent entry point.
+ *
+ * Interrupts must be disabled when calling this function.
*/
void kernel_main(void);
/*
* Entry point for APs.
*
- * Interrupts must be enabled when calling this function.
+ * Interrupts must be disabled when calling this function.
*/
void kernel_ap_main(void);