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 /arch/x86/kernel | |
| 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>
Diffstat (limited to 'arch/x86/kernel')
| -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(); |
