diff options
author | Ingo Molnar <mingo@elte.hu> | 2009-09-23 11:49:55 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-09-23 12:08:26 -0400 |
commit | 11868a2dc4f5e4f2f652bfd259e1360193fcee62 (patch) | |
tree | 54c83a3acde4931a1aa93e7b9231f0ad87668f2d /arch | |
parent | 14c93e8eba70c3c85d8f8acc6cfdc728aef92076 (diff) |
x86: mce: Use safer ways to access MCE registers
Use rdmsrl_safe() when accessing MCE registers. While in
theory we always 'know' which ones are safe to access from
the capability bits, there's a lot of hardware variations
and reality might differ from theory, as it did in this case:
http://bugzilla.kernel.org/show_bug.cgi?id=14204
[ 0.010016] mce: CPU supports 5 MCE banks
[ 0.011029] general protection fault: 0000 [#1]
[ 0.011998] last sysfs file:
[ 0.011998] Modules linked in:
[ 0.011998]
[ 0.011998] Pid: 0, comm: swapper Not tainted (2.6.31_router #1) HP Vectra
[ 0.011998] EIP: 0060:[<c100d9b9>] EFLAGS: 00010246 CPU: 0
[ 0.011998] EIP is at mce_rdmsrl+0x19/0x60
[ 0.011998] EAX: 00000000 EBX: 00000001 ECX: 00000407 EDX: 08000000
[ 0.011998] ESI: 00000000 EDI: 8c000000 EBP: 00000405 ESP: c17d5eac
So WARN_ONCE() instead of crashing the box.
( also fix a number of stylistic inconsistencies in the code. )
Note, we might still crash in wrmsrl() if we get that far, but
we shouldnt if the registers are truly inaccessible.
Reported-by: GNUtoo <GNUtoo@no-log.org>
Cc: Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com>
Cc: Huang Ying <ying.huang@intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
LKML-Reference: <bug-14204-5438@http.bugzilla.kernel.org/>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/kernel/cpu/mcheck/mce.c | 23 |
1 files changed, 21 insertions, 2 deletions
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 2f5aab26320..4b2af86e3e8 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c | |||
@@ -305,13 +305,25 @@ static int msr_to_offset(u32 msr) | |||
305 | static u64 mce_rdmsrl(u32 msr) | 305 | static u64 mce_rdmsrl(u32 msr) |
306 | { | 306 | { |
307 | u64 v; | 307 | u64 v; |
308 | |||
308 | if (__get_cpu_var(injectm).finished) { | 309 | if (__get_cpu_var(injectm).finished) { |
309 | int offset = msr_to_offset(msr); | 310 | int offset = msr_to_offset(msr); |
311 | |||
310 | if (offset < 0) | 312 | if (offset < 0) |
311 | return 0; | 313 | return 0; |
312 | return *(u64 *)((char *)&__get_cpu_var(injectm) + offset); | 314 | return *(u64 *)((char *)&__get_cpu_var(injectm) + offset); |
313 | } | 315 | } |
314 | rdmsrl(msr, v); | 316 | |
317 | if (rdmsrl_safe(msr, &v)) { | ||
318 | WARN_ONCE(1, "mce: Unable to read msr %d!\n", msr); | ||
319 | /* | ||
320 | * Return zero in case the access faulted. This should | ||
321 | * not happen normally but can happen if the CPU does | ||
322 | * something weird, or if the code is buggy. | ||
323 | */ | ||
324 | v = 0; | ||
325 | } | ||
326 | |||
315 | return v; | 327 | return v; |
316 | } | 328 | } |
317 | 329 | ||
@@ -319,6 +331,7 @@ static void mce_wrmsrl(u32 msr, u64 v) | |||
319 | { | 331 | { |
320 | if (__get_cpu_var(injectm).finished) { | 332 | if (__get_cpu_var(injectm).finished) { |
321 | int offset = msr_to_offset(msr); | 333 | int offset = msr_to_offset(msr); |
334 | |||
322 | if (offset >= 0) | 335 | if (offset >= 0) |
323 | *(u64 *)((char *)&__get_cpu_var(injectm) + offset) = v; | 336 | *(u64 *)((char *)&__get_cpu_var(injectm) + offset) = v; |
324 | return; | 337 | return; |
@@ -415,7 +428,7 @@ static inline void mce_get_rip(struct mce *m, struct pt_regs *regs) | |||
415 | m->ip = mce_rdmsrl(rip_msr); | 428 | m->ip = mce_rdmsrl(rip_msr); |
416 | } | 429 | } |
417 | 430 | ||
418 | #ifdef CONFIG_X86_LOCAL_APIC | 431 | #ifdef CONFIG_X86_LOCAL_APIC |
419 | /* | 432 | /* |
420 | * Called after interrupts have been reenabled again | 433 | * Called after interrupts have been reenabled again |
421 | * when a MCE happened during an interrupts off region | 434 | * when a MCE happened during an interrupts off region |
@@ -1172,6 +1185,7 @@ static int mce_banks_init(void) | |||
1172 | return -ENOMEM; | 1185 | return -ENOMEM; |
1173 | for (i = 0; i < banks; i++) { | 1186 | for (i = 0; i < banks; i++) { |
1174 | struct mce_bank *b = &mce_banks[i]; | 1187 | struct mce_bank *b = &mce_banks[i]; |
1188 | |||
1175 | b->ctl = -1ULL; | 1189 | b->ctl = -1ULL; |
1176 | b->init = 1; | 1190 | b->init = 1; |
1177 | } | 1191 | } |
@@ -1203,6 +1217,7 @@ static int __cpuinit mce_cap_init(void) | |||
1203 | banks = b; | 1217 | banks = b; |
1204 | if (!mce_banks) { | 1218 | if (!mce_banks) { |
1205 | int err = mce_banks_init(); | 1219 | int err = mce_banks_init(); |
1220 | |||
1206 | if (err) | 1221 | if (err) |
1207 | return err; | 1222 | return err; |
1208 | } | 1223 | } |
@@ -1237,6 +1252,7 @@ static void mce_init(void) | |||
1237 | 1252 | ||
1238 | for (i = 0; i < banks; i++) { | 1253 | for (i = 0; i < banks; i++) { |
1239 | struct mce_bank *b = &mce_banks[i]; | 1254 | struct mce_bank *b = &mce_banks[i]; |
1255 | |||
1240 | if (!b->init) | 1256 | if (!b->init) |
1241 | continue; | 1257 | continue; |
1242 | wrmsrl(MSR_IA32_MCx_CTL(i), b->ctl); | 1258 | wrmsrl(MSR_IA32_MCx_CTL(i), b->ctl); |
@@ -1626,6 +1642,7 @@ static int mce_disable(void) | |||
1626 | 1642 | ||
1627 | for (i = 0; i < banks; i++) { | 1643 | for (i = 0; i < banks; i++) { |
1628 | struct mce_bank *b = &mce_banks[i]; | 1644 | struct mce_bank *b = &mce_banks[i]; |
1645 | |||
1629 | if (b->init) | 1646 | if (b->init) |
1630 | wrmsrl(MSR_IA32_MCx_CTL(i), 0); | 1647 | wrmsrl(MSR_IA32_MCx_CTL(i), 0); |
1631 | } | 1648 | } |
@@ -1911,6 +1928,7 @@ static void mce_disable_cpu(void *h) | |||
1911 | cmci_clear(); | 1928 | cmci_clear(); |
1912 | for (i = 0; i < banks; i++) { | 1929 | for (i = 0; i < banks; i++) { |
1913 | struct mce_bank *b = &mce_banks[i]; | 1930 | struct mce_bank *b = &mce_banks[i]; |
1931 | |||
1914 | if (b->init) | 1932 | if (b->init) |
1915 | wrmsrl(MSR_IA32_MCx_CTL(i), 0); | 1933 | wrmsrl(MSR_IA32_MCx_CTL(i), 0); |
1916 | } | 1934 | } |
@@ -1928,6 +1946,7 @@ static void mce_reenable_cpu(void *h) | |||
1928 | cmci_reenable(); | 1946 | cmci_reenable(); |
1929 | for (i = 0; i < banks; i++) { | 1947 | for (i = 0; i < banks; i++) { |
1930 | struct mce_bank *b = &mce_banks[i]; | 1948 | struct mce_bank *b = &mce_banks[i]; |
1949 | |||
1931 | if (b->init) | 1950 | if (b->init) |
1932 | wrmsrl(MSR_IA32_MCx_CTL(i), b->ctl); | 1951 | wrmsrl(MSR_IA32_MCx_CTL(i), b->ctl); |
1933 | } | 1952 | } |