diff options
author | Bryan O'Donoghue <bryan.odonoghue@linux.intel.com> | 2012-04-18 12:37:39 -0400 |
---|---|---|
committer | Luis Henriques <luis.henriques@canonical.com> | 2012-05-25 12:24:33 -0400 |
commit | 3377ca31f07eff747b7bc0ca526c9225fff1473a (patch) | |
tree | 68851fda95c02be08f88c68e1aaecd0887ad3054 | |
parent | a61de180d861cc17a9ea1e90aeab290c42aca565 (diff) |
x86, apic: APIC code touches invalid MSR on P5 class machines
BugLink: http://bugs.launchpad.net/bugs/996109
commit cbf2829b61c136edcba302a5e1b6b40e97d32c00 upstream.
Current APIC code assumes MSR_IA32_APICBASE is present for all systems.
Pentium Classic P5 and friends didn't have this MSR. MSR_IA32_APICBASE
was introduced as an architectural MSR by Intel @ P6.
Code paths that can touch this MSR invalidly are when vendor == Intel &&
cpu-family == 5 and APIC bit is set in CPUID - or when you simply pass
lapic on the kernel command line, on a P5.
The below patch stops Linux incorrectly interfering with the
MSR_IA32_APICBASE for P5 class machines. Other code paths exist that
touch the MSR - however those paths are not currently reachable for a
conformant P5.
Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linux.intel.com>
Link: http://lkml.kernel.org/r/4F8EEDD3.1080404@linux.intel.com
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | arch/x86/kernel/apic/apic.c | 34 |
1 files changed, 20 insertions, 14 deletions
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 9802bdf5298..4e8efd21671 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c | |||
@@ -1557,9 +1557,11 @@ static int __init apic_verify(void) | |||
1557 | mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; | 1557 | mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; |
1558 | 1558 | ||
1559 | /* The BIOS may have set up the APIC at some other address */ | 1559 | /* The BIOS may have set up the APIC at some other address */ |
1560 | rdmsr(MSR_IA32_APICBASE, l, h); | 1560 | if (boot_cpu_data.x86 >= 6) { |
1561 | if (l & MSR_IA32_APICBASE_ENABLE) | 1561 | rdmsr(MSR_IA32_APICBASE, l, h); |
1562 | mp_lapic_addr = l & MSR_IA32_APICBASE_BASE; | 1562 | if (l & MSR_IA32_APICBASE_ENABLE) |
1563 | mp_lapic_addr = l & MSR_IA32_APICBASE_BASE; | ||
1564 | } | ||
1563 | 1565 | ||
1564 | pr_info("Found and enabled local APIC!\n"); | 1566 | pr_info("Found and enabled local APIC!\n"); |
1565 | return 0; | 1567 | return 0; |
@@ -1577,13 +1579,15 @@ int __init apic_force_enable(unsigned long addr) | |||
1577 | * MSR. This can only be done in software for Intel P6 or later | 1579 | * MSR. This can only be done in software for Intel P6 or later |
1578 | * and AMD K7 (Model > 1) or later. | 1580 | * and AMD K7 (Model > 1) or later. |
1579 | */ | 1581 | */ |
1580 | rdmsr(MSR_IA32_APICBASE, l, h); | 1582 | if (boot_cpu_data.x86 >= 6) { |
1581 | if (!(l & MSR_IA32_APICBASE_ENABLE)) { | 1583 | rdmsr(MSR_IA32_APICBASE, l, h); |
1582 | pr_info("Local APIC disabled by BIOS -- reenabling.\n"); | 1584 | if (!(l & MSR_IA32_APICBASE_ENABLE)) { |
1583 | l &= ~MSR_IA32_APICBASE_BASE; | 1585 | pr_info("Local APIC disabled by BIOS -- reenabling.\n"); |
1584 | l |= MSR_IA32_APICBASE_ENABLE | addr; | 1586 | l &= ~MSR_IA32_APICBASE_BASE; |
1585 | wrmsr(MSR_IA32_APICBASE, l, h); | 1587 | l |= MSR_IA32_APICBASE_ENABLE | addr; |
1586 | enabled_via_apicbase = 1; | 1588 | wrmsr(MSR_IA32_APICBASE, l, h); |
1589 | enabled_via_apicbase = 1; | ||
1590 | } | ||
1587 | } | 1591 | } |
1588 | return apic_verify(); | 1592 | return apic_verify(); |
1589 | } | 1593 | } |
@@ -2111,10 +2115,12 @@ static void lapic_resume(void) | |||
2111 | * FIXME! This will be wrong if we ever support suspend on | 2115 | * FIXME! This will be wrong if we ever support suspend on |
2112 | * SMP! We'll need to do this as part of the CPU restore! | 2116 | * SMP! We'll need to do this as part of the CPU restore! |
2113 | */ | 2117 | */ |
2114 | rdmsr(MSR_IA32_APICBASE, l, h); | 2118 | if (boot_cpu_data.x86 >= 6) { |
2115 | l &= ~MSR_IA32_APICBASE_BASE; | 2119 | rdmsr(MSR_IA32_APICBASE, l, h); |
2116 | l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr; | 2120 | l &= ~MSR_IA32_APICBASE_BASE; |
2117 | wrmsr(MSR_IA32_APICBASE, l, h); | 2121 | l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr; |
2122 | wrmsr(MSR_IA32_APICBASE, l, h); | ||
2123 | } | ||
2118 | } | 2124 | } |
2119 | 2125 | ||
2120 | maxlvt = lapic_get_maxlvt(); | 2126 | maxlvt = lapic_get_maxlvt(); |