diff options
-rw-r--r-- | arch/x86/machine/cpu.c | 38 | ||||
-rw-r--r-- | arch/x86/machine/cpu.h | 17 | ||||
-rw-r--r-- | arch/x86/machine/trap.c | 2 | ||||
-rw-r--r-- | arch/x86/machine/trap.h | 3 | ||||
-rw-r--r-- | arch/x86/machine/trap_asm.S | 1 | ||||
-rw-r--r-- | kern/panic.c | 19 |
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. + */ } |