aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel/apic.c
diff options
context:
space:
mode:
authorZwane Mwaikambo <zwane@arm.linux.org.uk>2005-11-07 03:58:33 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2005-11-07 10:53:28 -0500
commit77f72b192fd4624ad639dbf60c48be787c8aea59 (patch)
tree1d0d2d224dffad9f8c8e1e7cba0843d2d0899640 /arch/i386/kernel/apic.c
parent38e548ee1a79c8da7b3d9e26f2adce9b61413f84 (diff)
[PATCH] i386: LVT entries remaining unmasked on reboot
Excerpt from bugzilla entry http://bugzilla.kernel.org/show_bug.cgi?id=5518 "i386 version of Reboot-through-BIOS is unsafe: it forgets to mask APIC LVT interrupts before jumping to a BIOS entry point. As a result, BIOS ends up bombarded with interrupts early on boot. The BIOS does not expect it since following a "normal" hardware cpu reset, all APIC LVT registers have the Mask bit (16) set and can't generate interrupts. For example, the version of Phoenix BIOS used by VMware enables interrupts for the first time before masking/clearing APIC LVT. The APIC Timer LVT register is still set up for a timer interrupt delivery with a high vector from the previous Linux incarnation (0xef in our case). The BIOS has not fully initialized its IDT at this point and the real mode gate for 0xef remains all zeros. Vector 0xef dispatches BIOS to address 0:0, BIOS takes a #GP and eventually hangs. machine_shutdown() does attempt to shut down APIC before jumping to BIOS, but it is ineffective" Signed-off-by: Zwane Mwaikambo <zwane@arm.linux.org.uk> Cc: "Seth, Rohit" <rohit.seth@intel.com> Cc: Zachary Amsden <zach@vmware.com> Cc: "Eric W. Biederman" <ebiederm@xmission.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/i386/kernel/apic.c')
-rw-r--r--arch/i386/kernel/apic.c10
1 files changed, 8 insertions, 2 deletions
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index 7c724ffa08bb..496a2c9909fe 100644
--- a/arch/i386/kernel/apic.c
+++ b/arch/i386/kernel/apic.c
@@ -559,14 +559,20 @@ void __devinit setup_local_APIC(void)
559 * If Linux enabled the LAPIC against the BIOS default 559 * If Linux enabled the LAPIC against the BIOS default
560 * disable it down before re-entering the BIOS on shutdown. 560 * disable it down before re-entering the BIOS on shutdown.
561 * Otherwise the BIOS may get confused and not power-off. 561 * Otherwise the BIOS may get confused and not power-off.
562 * Additionally clear all LVT entries before disable_local_APIC
563 * for the case where Linux didn't enable the LAPIC.
562 */ 564 */
563void lapic_shutdown(void) 565void lapic_shutdown(void)
564{ 566{
565 if (!cpu_has_apic || !enabled_via_apicbase) 567 if (!cpu_has_apic)
566 return; 568 return;
567 569
568 local_irq_disable(); 570 local_irq_disable();
569 disable_local_APIC(); 571 clear_local_APIC();
572
573 if (enabled_via_apicbase)
574 disable_local_APIC();
575
570 local_irq_enable(); 576 local_irq_enable();
571} 577}
572 578