aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel
diff options
context:
space:
mode:
authorAndi Kleen <ak@linux.intel.com>2009-04-29 13:31:00 -0400
committerH. Peter Anvin <hpa@zytor.com>2009-05-28 12:24:14 -0400
commitea149b36c7f511d17dd89fee734cb09778a91fa0 (patch)
tree04466a9b92dc5ce01c2ab8661165e3564d99f5c1 /arch/x86/kernel
parent5f8c1a54cab6f449fe04d42d0661bc796fa4e73e (diff)
x86, mce: add basic error injection infrastructure
Allow user programs to write mce records into /dev/mcelog. When they do that a fake machine check is triggered to test the machine check code. This uses the MCE MSR wrappers added earlier. The implementation is straight forward. There is a struct mce record per CPU and the MCE MSR accesses get data from there if there is valid data injected there. This allows to test the machine check code relatively realistically because only the lowest layer of hardware access is intercepted. The test suite and injector are available at git://git.kernel.org/pub/scm/utils/cpu/mce/mce-test.git git://git.kernel.org/pub/scm/utils/cpu/mce/mce-inject.git Signed-off-by: Andi Kleen <ak@linux.intel.com> Signed-off-by: H. Peter Anvin <hpa@zytor.com> Signed-off-by: Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com> Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'arch/x86/kernel')
-rw-r--r--arch/x86/kernel/cpu/mcheck/Makefile1
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce-inject.c126
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce.c39
3 files changed, 165 insertions, 1 deletions
diff --git a/arch/x86/kernel/cpu/mcheck/Makefile b/arch/x86/kernel/cpu/mcheck/Makefile
index 5f8b09425d39..60ee182c6c52 100644
--- a/arch/x86/kernel/cpu/mcheck/Makefile
+++ b/arch/x86/kernel/cpu/mcheck/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_X86_MCE_INTEL) += mce_intel_64.o mce_intel.o
7obj-$(CONFIG_X86_MCE_AMD) += mce_amd_64.o 7obj-$(CONFIG_X86_MCE_AMD) += mce_amd_64.o
8obj-$(CONFIG_X86_MCE_NONFATAL) += non-fatal.o 8obj-$(CONFIG_X86_MCE_NONFATAL) += non-fatal.o
9obj-$(CONFIG_X86_MCE_THRESHOLD) += threshold.o 9obj-$(CONFIG_X86_MCE_THRESHOLD) += threshold.o
10obj-$(CONFIG_X86_MCE_INJECT) += mce-inject.o
diff --git a/arch/x86/kernel/cpu/mcheck/mce-inject.c b/arch/x86/kernel/cpu/mcheck/mce-inject.c
new file mode 100644
index 000000000000..58afac4b5df5
--- /dev/null
+++ b/arch/x86/kernel/cpu/mcheck/mce-inject.c
@@ -0,0 +1,126 @@
1/*
2 * Machine check injection support.
3 * Copyright 2008 Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; version 2
8 * of the License.
9 *
10 * Authors:
11 * Andi Kleen
12 * Ying Huang
13 */
14#include <linux/module.h>
15#include <linux/timer.h>
16#include <linux/kernel.h>
17#include <linux/string.h>
18#include <linux/fs.h>
19#include <linux/smp.h>
20#include <asm/uaccess.h>
21#include <asm/mce.h>
22
23/* Update fake mce registers on current CPU. */
24static void inject_mce(struct mce *m)
25{
26 struct mce *i = &per_cpu(injectm, m->cpu);
27
28 /* Make sure noone reads partially written injectm */
29 i->finished = 0;
30 mb();
31 m->finished = 0;
32 /* First set the fields after finished */
33 i->cpu = m->cpu;
34 mb();
35 /* Now write record in order, finished last (except above) */
36 memcpy(i, m, sizeof(struct mce));
37 /* Finally activate it */
38 mb();
39 i->finished = 1;
40}
41
42struct delayed_mce {
43 struct timer_list timer;
44 struct mce m;
45};
46
47/* Inject mce on current CPU */
48static void raise_mce(unsigned long data)
49{
50 struct delayed_mce *dm = (struct delayed_mce *)data;
51 struct mce *m = &dm->m;
52 int cpu = m->cpu;
53
54 inject_mce(m);
55 if (m->status & MCI_STATUS_UC) {
56 struct pt_regs regs;
57 memset(&regs, 0, sizeof(struct pt_regs));
58 regs.ip = m->ip;
59 regs.cs = m->cs;
60 printk(KERN_INFO "Triggering MCE exception on CPU %d\n", cpu);
61 do_machine_check(&regs, 0);
62 printk(KERN_INFO "MCE exception done on CPU %d\n", cpu);
63 } else {
64 mce_banks_t b;
65 memset(&b, 0xff, sizeof(mce_banks_t));
66 printk(KERN_INFO "Starting machine check poll CPU %d\n", cpu);
67 machine_check_poll(0, &b);
68 mce_notify_user();
69 printk(KERN_INFO "Finished machine check poll on CPU %d\n",
70 cpu);
71 }
72 kfree(dm);
73}
74
75/* Error injection interface */
76static ssize_t mce_write(struct file *filp, const char __user *ubuf,
77 size_t usize, loff_t *off)
78{
79 struct delayed_mce *dm;
80 struct mce m;
81
82 if (!capable(CAP_SYS_ADMIN))
83 return -EPERM;
84 /*
85 * There are some cases where real MSR reads could slip
86 * through.
87 */
88 if (!boot_cpu_has(X86_FEATURE_MCE) || !boot_cpu_has(X86_FEATURE_MCA))
89 return -EIO;
90
91 if ((unsigned long)usize > sizeof(struct mce))
92 usize = sizeof(struct mce);
93 if (copy_from_user(&m, ubuf, usize))
94 return -EFAULT;
95
96 if (m.cpu >= NR_CPUS || !cpu_online(m.cpu))
97 return -EINVAL;
98
99 dm = kmalloc(sizeof(struct delayed_mce), GFP_KERNEL);
100 if (!dm)
101 return -ENOMEM;
102
103 /*
104 * Need to give user space some time to set everything up,
105 * so do it a jiffie or two later everywhere.
106 * Should we use a hrtimer here for better synchronization?
107 */
108 memcpy(&dm->m, &m, sizeof(struct mce));
109 setup_timer(&dm->timer, raise_mce, (unsigned long)dm);
110 dm->timer.expires = jiffies + 2;
111 add_timer_on(&dm->timer, m.cpu);
112 return usize;
113}
114
115static int inject_init(void)
116{
117 printk(KERN_INFO "Machine check injector initialized\n");
118 mce_chrdev_ops.write = mce_write;
119 return 0;
120}
121
122module_init(inject_init);
123/* Cannot tolerate unloading currently because we cannot
124 * guarantee all openers of mce_chrdev will get a reference to us.
125 */
126MODULE_LICENSE("GPL");
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index e755c95674dc..fe216bd10f43 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -98,6 +98,9 @@ void mce_setup(struct mce *m)
98 rdtscll(m->tsc); 98 rdtscll(m->tsc);
99} 99}
100 100
101DEFINE_PER_CPU(struct mce, injectm);
102EXPORT_PER_CPU_SYMBOL_GPL(injectm);
103
101/* 104/*
102 * Lockless MCE logging infrastructure. 105 * Lockless MCE logging infrastructure.
103 * This avoids deadlocks on printk locks without having to break locks. Also 106 * This avoids deadlocks on printk locks without having to break locks. Also
@@ -194,16 +197,46 @@ static void mce_panic(char *msg, struct mce *backup, u64 start)
194 panic(msg); 197 panic(msg);
195} 198}
196 199
200/* Support code for software error injection */
201
202static int msr_to_offset(u32 msr)
203{
204 unsigned bank = __get_cpu_var(injectm.bank);
205 if (msr == rip_msr)
206 return offsetof(struct mce, ip);
207 if (msr == MSR_IA32_MC0_STATUS + bank*4)
208 return offsetof(struct mce, status);
209 if (msr == MSR_IA32_MC0_ADDR + bank*4)
210 return offsetof(struct mce, addr);
211 if (msr == MSR_IA32_MC0_MISC + bank*4)
212 return offsetof(struct mce, misc);
213 if (msr == MSR_IA32_MCG_STATUS)
214 return offsetof(struct mce, mcgstatus);
215 return -1;
216}
217
197/* MSR access wrappers used for error injection */ 218/* MSR access wrappers used for error injection */
198static u64 mce_rdmsrl(u32 msr) 219static u64 mce_rdmsrl(u32 msr)
199{ 220{
200 u64 v; 221 u64 v;
222 if (__get_cpu_var(injectm).finished) {
223 int offset = msr_to_offset(msr);
224 if (offset < 0)
225 return 0;
226 return *(u64 *)((char *)&__get_cpu_var(injectm) + offset);
227 }
201 rdmsrl(msr, v); 228 rdmsrl(msr, v);
202 return v; 229 return v;
203} 230}
204 231
205static void mce_wrmsrl(u32 msr, u64 v) 232static void mce_wrmsrl(u32 msr, u64 v)
206{ 233{
234 if (__get_cpu_var(injectm).finished) {
235 int offset = msr_to_offset(msr);
236 if (offset >= 0)
237 *(u64 *)((char *)&__get_cpu_var(injectm) + offset) = v;
238 return;
239 }
207 wrmsrl(msr, v); 240 wrmsrl(msr, v);
208} 241}
209 242
@@ -296,6 +329,7 @@ void machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
296 * exceptions. 329 * exceptions.
297 */ 330 */
298} 331}
332EXPORT_SYMBOL_GPL(machine_check_poll);
299 333
300/* 334/*
301 * The actual machine check handler. This only handles real 335 * The actual machine check handler. This only handles real
@@ -468,6 +502,7 @@ void do_machine_check(struct pt_regs *regs, long error_code)
468 out2: 502 out2:
469 atomic_dec(&mce_entry); 503 atomic_dec(&mce_entry);
470} 504}
505EXPORT_SYMBOL_GPL(do_machine_check);
471 506
472#ifdef CONFIG_X86_MCE_INTEL 507#ifdef CONFIG_X86_MCE_INTEL
473/*** 508/***
@@ -568,6 +603,7 @@ int mce_notify_user(void)
568 } 603 }
569 return 0; 604 return 0;
570} 605}
606EXPORT_SYMBOL_GPL(mce_notify_user);
571 607
572/* 608/*
573 * Initialize Machine Checks for a CPU. 609 * Initialize Machine Checks for a CPU.
@@ -904,13 +940,14 @@ static long mce_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
904 } 940 }
905} 941}
906 942
907static const struct file_operations mce_chrdev_ops = { 943struct file_operations mce_chrdev_ops = {
908 .open = mce_open, 944 .open = mce_open,
909 .release = mce_release, 945 .release = mce_release,
910 .read = mce_read, 946 .read = mce_read,
911 .poll = mce_poll, 947 .poll = mce_poll,
912 .unlocked_ioctl = mce_ioctl, 948 .unlocked_ioctl = mce_ioctl,
913}; 949};
950EXPORT_SYMBOL_GPL(mce_chrdev_ops);
914 951
915static struct miscdevice mce_log_device = { 952static struct miscdevice mce_log_device = {
916 MISC_MCELOG_MINOR, 953 MISC_MCELOG_MINOR,