Commit 77f72b19 authored by Zwane Mwaikambo's avatar Zwane Mwaikambo Committed by Linus Torvalds

[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: default avatarZwane 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: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 38e548ee
...@@ -559,14 +559,20 @@ void __devinit setup_local_APIC(void) ...@@ -559,14 +559,20 @@ void __devinit setup_local_APIC(void)
* If Linux enabled the LAPIC against the BIOS default * If Linux enabled the LAPIC against the BIOS default
* disable it down before re-entering the BIOS on shutdown. * disable it down before re-entering the BIOS on shutdown.
* Otherwise the BIOS may get confused and not power-off. * Otherwise the BIOS may get confused and not power-off.
* Additionally clear all LVT entries before disable_local_APIC
* for the case where Linux didn't enable the LAPIC.
*/ */
void lapic_shutdown(void) void lapic_shutdown(void)
{ {
if (!cpu_has_apic || !enabled_via_apicbase) if (!cpu_has_apic)
return; return;
local_irq_disable(); local_irq_disable();
disable_local_APIC(); clear_local_APIC();
if (enabled_via_apicbase)
disable_local_APIC();
local_irq_enable(); local_irq_enable();
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment