[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>
This commit is contained in:
Zwane Mwaikambo 2005-11-07 00:58:33 -08:00 committed by Linus Torvalds
parent 38e548ee1a
commit 77f72b192f
1 changed files with 8 additions and 2 deletions

View File

@ -559,14 +559,20 @@ void __devinit setup_local_APIC(void)
* If Linux enabled the LAPIC against the BIOS default
* disable it down before re-entering the BIOS on shutdown.
* 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)
{
if (!cpu_has_apic || !enabled_via_apicbase)
if (!cpu_has_apic)
return;
local_irq_disable();
disable_local_APIC();
clear_local_APIC();
if (enabled_via_apicbase)
disable_local_APIC();
local_irq_enable();
}