aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/Kconfig8
-rw-r--r--arch/x86/include/asm/mce.h3
-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
5 files changed, 176 insertions, 1 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index a148e7ac0d83..e25b6358fbe3 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -835,6 +835,14 @@ config X86_MCE_THRESHOLD
835 bool 835 bool
836 default y 836 default y
837 837
838config X86_MCE_INJECT
839 depends on X86_NEW_MCE
840 tristate "Machine check injector support"
841 ---help---
842 Provide support for injecting machine checks for testing purposes.
843 If you don't know what a machine check is and you don't do kernel
844 QA it is safe to say n.
845
838config X86_MCE_NONFATAL 846config X86_MCE_NONFATAL
839 tristate "Check for non-fatal errors on AMD Athlon/Duron / Intel Pentium 4" 847 tristate "Check for non-fatal errors on AMD Athlon/Duron / Intel Pentium 4"
840 depends on X86_OLD_MCE 848 depends on X86_OLD_MCE
diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h
index c3c7ee701753..e7d2372301ef 100644
--- a/arch/x86/include/asm/mce.h
+++ b/arch/x86/include/asm/mce.h
@@ -141,6 +141,9 @@ extern void machine_check_poll(enum mcp_flags flags, mce_banks_t *b);
141 141
142extern int mce_notify_user(void); 142extern int mce_notify_user(void);
143 143
144DECLARE_PER_CPU(struct mce, injectm);
145extern struct file_operations mce_chrdev_ops;
146
144#ifdef CONFIG_X86_MCE 147#ifdef CONFIG_X86_MCE
145extern void mcheck_init(struct cpuinfo_x86 *c); 148extern void mcheck_init(struct cpuinfo_x86 *c);
146#else 149#else
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,