diff --git a/common/include/arch/i386/interrupt.h b/common/include/arch/i386/interrupt.h index 86b9447ff..c13a1e422 100644 --- a/common/include/arch/i386/interrupt.h +++ b/common/include/arch/i386/interrupt.h @@ -49,6 +49,7 @@ #define XT_WINI_IRQ 5 /* xt winchester */ #define FLOPPY_IRQ 6 /* floppy disk */ #define PRINTER_IRQ 7 +#define SPURIOUS_IRQ 7 #define CMOS_CLOCK_IRQ 8 #define KBD_AUX_IRQ 12 /* AUX (PS/2 mouse) port in kbd controller */ #define AT_WINI_0_IRQ 14 /* at winchester controller 0 */ diff --git a/kernel/arch/i386/apic.c b/kernel/arch/i386/apic.c index b73b98f1a..05602da62 100644 --- a/kernel/arch/i386/apic.c +++ b/kernel/arch/i386/apic.c @@ -428,13 +428,22 @@ PRIVATE int calib_clk_handler(irq_hook_t * UNUSED(hook)) return 1; } +PRIVATE int spurious_irq_handler(irq_hook_t * UNUSED(hook)) +{ + /* + * Do nothing, only unlock the kernel so we do not deadlock! + */ + BKL_UNLOCK(); + return 1; +} + PRIVATE void apic_calibrate_clocks(unsigned cpu) { u32_t lvtt, val, lapic_delta; u64_t tsc_delta; u64_t cpu_freq; - irq_hook_t calib_clk; + irq_hook_t calib_clk, spurious_irq; BOOT_VERBOSE(printf("Calibrating clock\n")); /* @@ -467,6 +476,14 @@ PRIVATE void apic_calibrate_clocks(unsigned cpu) /* set the probe, we use the legacy timer, IRQ 0 */ put_irq_handler(&calib_clk, CLOCK_IRQ, calib_clk_handler); + /* + * A spurious interrupt may occur during the clock calibration. Since we + * do this calibration in kernel, we need a special handler which will + * leave the BKL unlocked like the clock handler. This is a corner case, + * boot time only situation + */ + put_irq_handler(&spurious_irq, SPURIOUS_IRQ, spurious_irq_handler); + /* set the PIC timer to get some time */ init_8253A_timer(system_hz); @@ -489,6 +506,7 @@ PRIVATE void apic_calibrate_clocks(unsigned cpu) /* remove the probe */ rm_irq_handler(&calib_clk); + rm_irq_handler(&spurious_irq); lapic_delta = lapic_tctr0 - lapic_tctr1; tsc_delta = sub64(tsc1, tsc0);