summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/x86/machine/cpu.c38
-rw-r--r--arch/x86/machine/cpu.h17
-rw-r--r--arch/x86/machine/trap.c2
-rw-r--r--arch/x86/machine/trap.h3
-rw-r--r--arch/x86/machine/trap_asm.S1
-rw-r--r--kern/panic.c19
6 files changed, 70 insertions, 10 deletions
diff --git a/arch/x86/machine/cpu.c b/arch/x86/machine/cpu.c
index f8a21685..1c306a60 100644
--- a/arch/x86/machine/cpu.c
+++ b/arch/x86/machine/cpu.c
@@ -25,6 +25,7 @@
#include <kern/stdint.h>
#include <kern/string.h>
#include <machine/acpimp.h>
+#include <machine/atomic.h>
#include <machine/biosmem.h>
#include <machine/boot.h>
#include <machine/cpu.h>
@@ -89,6 +90,8 @@ static struct cpu_gate_desc cpu_idt[CPU_IDT_SIZE] __aligned(8);
static unsigned long cpu_double_fault_handler;
static char cpu_double_fault_stack[STACK_SIZE] __aligned(DATA_ALIGN);
+static volatile unsigned long cpu_nr_halts;
+
static void
cpu_seg_set_null(char *table, unsigned int selector)
{
@@ -568,3 +571,38 @@ cpu_ap_sync(void)
while (cpu_count() == 1)
cpu_pause();
}
+
+void
+cpu_halt_broadcast(void)
+{
+ unsigned long nr_halts;
+ unsigned int nr_cpus;
+
+ nr_cpus = cpu_count();
+
+ if (nr_cpus == 1)
+ return;
+
+ nr_halts = atomic_cas(&cpu_nr_halts, 0, nr_cpus - 1);
+
+ /* Another CPU has started a halt, wait for the IPI */
+ if (nr_halts != 0)
+ for (;;)
+ cpu_idle();
+
+ lapic_ipi_broadcast(TRAP_CPU_HALT);
+
+ while (cpu_nr_halts != 0)
+ cpu_pause();
+}
+
+void
+cpu_halt_intr(struct trap_frame *frame)
+{
+ (void)frame;
+
+ lapic_eoi();
+
+ atomic_add(&cpu_nr_halts, -1);
+ cpu_halt();
+}
diff --git a/arch/x86/machine/cpu.h b/arch/x86/machine/cpu.h
index 774f76da..d1a8b68e 100644
--- a/arch/x86/machine/cpu.h
+++ b/arch/x86/machine/cpu.h
@@ -95,6 +95,11 @@
#include <kern/stdint.h>
#include <machine/pit.h>
+/*
+ * Forward declaration.
+ */
+struct trap_frame;
+
#define CPU_VENDOR_ID_SIZE 13
#define CPU_MODEL_NAME_SIZE 49
@@ -403,6 +408,8 @@ cpu_idle(void)
/*
* Halt the CPU.
+ *
+ * Implies a compiler barrier.
*/
static __noreturn __always_inline void
cpu_halt(void)
@@ -414,6 +421,16 @@ cpu_halt(void)
}
/*
+ * Halt all other processors.
+ */
+void cpu_halt_broadcast(void);
+
+/*
+ * Interrupt handler for inter-processor halt requests.
+ */
+void cpu_halt_intr(struct trap_frame *frame);
+
+/*
* Macros to create access functions for per-CPU pointers.
*
* Changing such a pointer should only be done by low level scheduling
diff --git a/arch/x86/machine/trap.c b/arch/x86/machine/trap.c
index aabf418b..9e4d63d5 100644
--- a/arch/x86/machine/trap.c
+++ b/arch/x86/machine/trap.c
@@ -65,6 +65,7 @@ void trap_isr_simd_fp_exception(void);
void trap_isr_pic_int7(void);
void trap_isr_pic_int15(void);
void trap_isr_pmap_update(void);
+void trap_isr_cpu_halt(void);
void trap_isr_lapic_timer(void);
void trap_isr_lapic_error(void);
void trap_isr_lapic_spurious(void);
@@ -183,6 +184,7 @@ trap_setup(void)
/* System defined traps */
trap_install(TRAP_PMAP_UPDATE, trap_isr_pmap_update, pmap_update_intr);
+ trap_install(TRAP_CPU_HALT, trap_isr_cpu_halt, cpu_halt_intr);
trap_install(TRAP_LAPIC_TIMER, trap_isr_lapic_timer, lapic_intr_timer);
trap_install(TRAP_LAPIC_ERROR, trap_isr_lapic_error, lapic_intr_error);
trap_install(TRAP_LAPIC_SPURIOUS, trap_isr_lapic_spurious,
diff --git a/arch/x86/machine/trap.h b/arch/x86/machine/trap.h
index 96ba61f4..4a6a4861 100644
--- a/arch/x86/machine/trap.h
+++ b/arch/x86/machine/trap.h
@@ -53,7 +53,8 @@
*
* The local APIC assigns one priority every 16 vectors.
*/
-#define TRAP_PMAP_UPDATE 240
+#define TRAP_PMAP_UPDATE 239
+#define TRAP_CPU_HALT 240
#define TRAP_LAPIC_TIMER 253
#define TRAP_LAPIC_ERROR 254
#define TRAP_LAPIC_SPURIOUS 255
diff --git a/arch/x86/machine/trap_asm.S b/arch/x86/machine/trap_asm.S
index 594ba92e..5831a0db 100644
--- a/arch/x86/machine/trap_asm.S
+++ b/arch/x86/machine/trap_asm.S
@@ -170,6 +170,7 @@ TRAP(TRAP_PIC_BASE + 15, pic_int15)
/* System defined traps */
TRAP(TRAP_PMAP_UPDATE, pmap_update)
+TRAP(TRAP_CPU_HALT, cpu_halt)
TRAP(TRAP_LAPIC_TIMER, lapic_timer)
TRAP(TRAP_LAPIC_ERROR, lapic_error)
TRAP(TRAP_LAPIC_SPURIOUS, lapic_spurious)
diff --git a/kern/panic.c b/kern/panic.c
index 7615850e..95b55de2 100644
--- a/kern/panic.c
+++ b/kern/panic.c
@@ -24,17 +24,18 @@
void
panic(const char *format, ...)
{
- va_list list;
+ va_list list;
- cpu_intr_disable();
+ cpu_intr_disable();
+ cpu_halt_broadcast();
- printk("\nkernel panic: ");
- va_start(list, format);
- vprintk(format, list);
+ printk("\nkernel panic: ");
+ va_start(list, format);
+ vprintk(format, list);
- cpu_halt();
+ cpu_halt();
- /*
- * Never reached.
- */
+ /*
+ * Never reached.
+ */
}