aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/cpu
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2009-09-23 11:49:55 -0400
committerIngo Molnar <mingo@elte.hu>2009-09-23 12:08:26 -0400
commit11868a2dc4f5e4f2f652bfd259e1360193fcee62 (patch)
tree54c83a3acde4931a1aa93e7b9231f0ad87668f2d /arch/x86/kernel/cpu
parent14c93e8eba70c3c85d8f8acc6cfdc728aef92076 (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/x86/kernel/cpu')
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce.c23
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 2f5aab26320e..4b2af86e3e8d 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)
305static u64 mce_rdmsrl(u32 msr) 305static 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 }