x86, MCE, AMD: Hardware MCE injection
Subsystems (3)
cover x86, MCE, AMD: Hardware MCE injection
From: Borislav Petkov <[email protected]>
Hi,
this new set version moves the whole interface to debugfs since it belongs there in the first place. Remaining functionality unchanged.
Changelog:
v2: only small changes from the last submission
(http://lkml.org/lkml/2011/4/15/171) so that we can have valid MCG_STATUS values and don't choke on severity sanity checking.
v1: Initial submission.
Thanks.
PATCH 1/6 x86, MCE: Add a HW injection flag
From: Borislav Petkov <[email protected]>
Add an mce->inject_flag to denote that we're doing HW injection.
--- arch/x86/include/asm/mce.h | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
arch/x86/include/asm/mce.h +1 -0
@@ -49,6 +49,7 @@#define MCJ_CTX_IRQ 2/* inject context: IRQ */ #define MCJ_NMI_BROADCAST 4/* do NMI broadcasting */ #define MCJ_EXCEPTION 8/* raise as exception */ +#define MCJ_HW_INJECT 16/* do a HW MCE inject, i.e. INT18 */ /* Fields are zero when not available */ struct mce {
Signature · 1 line
1.7.4.rc2
Re: [PATCH -v3 1/6] x86, MCE: Add a HW injection flag
Quoted 15 lines · Borislav Petkov
From: Borislav Petkov <[email protected]>
Add an
mce->inject_flagto denote that we're doing HW injection.Signed-off-by Borislav Petkov <[email protected]>Acked-by Ingo Molnar <[email protected]>--- arch/x86/include/asm/mce.h | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)arch/x86/include/asm/mce.h +0
-0
arch/x86/include/asm/mce.h line 55
Quoted 7 lines
arch/x86/include/asm/mce.h +1
-0@@ -49,6 +49,7 @@#define MCJ_CTX_IRQ 2/* inject context: IRQ */ #define MCJ_NMI_BROADCAST 4/* do NMI broadcasting */ #define MCJ_EXCEPTION 8/* raise as exception */ +#define MCJ_HW_INJECT 16/* do a HW MCE inject, i.e. INT18 */ /* Fields are zero when not available */ struct mce {
IMHO, we should have better name for this feature; using wrmsr + int$18 is not the only way to inject mce event to HW. I'd like to suggest MCJ_AMD_HW_INJECT, MCJ_USE_WRMSR or so instead. Then we can have MCJ_USE_APEI_EINJ and so on, for various way of MCE injection.
Thanks,
H.Seto
Re: [PATCH -v3 1/6] x86, MCE: Add a HW injection flag
Quoted 21 lines · Hidetoshi Seto
Quoted 20 lines · Borislav Petkov
From: Borislav Petkov <[email protected]>
Add an
mce->inject_flagto denote that we're doing HW injection.Signed-off-by Borislav Petkov <[email protected]>Acked-by Ingo Molnar <[email protected]>--- arch/x86/include/asm/mce.h | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)arch/x86/include/asm/mce.h +1
-0@@ -49,6 +49,7 @@#define MCJ_CTX_IRQ 2/* inject context: IRQ */ #define MCJ_NMI_BROADCAST 4/* do NMI broadcasting */ #define MCJ_EXCEPTION 8/* raise as exception */ +#define MCJ_HW_INJECT 16/* do a HW MCE inject, i.e. INT18 */
Quoted 7 lines
arch/x86/include/asm/mce.h line 55
Quoted 2 lines
arch/x86/include/asm/mce.h +0
-0/* Fields are zero when not available */ struct mce {IMHO, we should have better name for this feature; using wrmsr + int$18 is not the only way to inject mce event to HW. I'd like to suggest
MCJ_AMD_HW_INJECT,MCJ_USE_WRMSRor so instead. Then we can haveMCJ_USE_APEI_EINJand so on, for various way of MCE injection.
Fair enough, the name might be too generic. Maybe I should change it to MCJ_HW_MSR_INJECT to denote injecting of hw errors through the MCA MSRs.
Signature · 8 lines
Regards/Gruss, Boris. Advanced Micro Devices GmbH Einsteinring 24, 85609 Dornach General Managers: Alberto Bozzo, Andrew Bowd Registration: Dornach, Gemeinde Aschheim, Landkreis Muenchen Registergericht Muenchen, HRB Nr. 43632
PATCH 2/6 x86, MCE: Export mce_get_debugfs_dir
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
This is needed for external users of the same debugfs toplevel dir.
--- arch/x86/include/asm/mce.h | 1 + arch/x86/kernel/cpu/mcheck/mce-internal.h | 1 - arch/x86/kernel/cpu/mcheck/mce.c | 1 + 3 files changed, 2 insertions(+), 1 deletions(-)
arch/x86/include/asm/mce.h +1 -0
@@ -241,5 +241,6 @@ struct cper_sec_mem_err;extern void apei_mce_report_mem_error (int corrected,struct cper_sec_mem_err *mem_err); +struct dentry *mce_get_debugfs_dir (void );#endif /* __KERNEL__ */ #endif /* _ASM_X86_MCE_H */
arch/x86/kernel/cpu/mcheck/mce-internal.h +0 -1
@@ -22,7 +22,6 @@ struct mce_bank { };int mce_severity (struct mce *a,int tolerant,char **msg); -struct dentry *mce_get_debugfs_dir (void );extern int mce_ser;
arch/x86/kernel/cpu/mcheck/mce.c +1 -0
@@ -2170,6 +2170,7 @@ struct dentry *mce_get_debugfs_dir(void)return dmce; } +EXPORT_SYMBOL_GPL (mce_get_debugfs_dir);static void mce_reset (void ) {
Signature · 1 line
1.7.4.rc2
PATCH 3/6 EDAC, MCE, AMD: Add function to enable direct write to MCE MSRs
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
Normally, writing to MCE MSRs causes a #GP. Add a function to enable direct access to those MSRs.
--- drivers/edac/mce_amd_inj.c | 24 ++++++++++++++++++++++++ 1 files changed, 24 insertions(+), 0 deletions(-)
drivers/edac/mce_amd_inj.c +24 -0
@@ -30,6 +30,30 @@ static struct edac_mce_attr mce_attr_##_name = __ATTR(_name, _mode, _show, _storstatic struct kobject *mce_kobj;/* +* Caller needs to be make sure this cpu doesn't disappear +* from under us, i.e.: get_cpu/put_cpu. +*/ +static int toggle_hw_mce_inject (unsigned int cpu,bool enable) +{ +u32 l, h; +int err; + + err =rdmsr_on_cpu (cpu,MSR_K7_HWCR , &l, &h); +if (err) { +printk (KERN_ERR "%s: error reading HWCR\n" , __func__); +return err; + } + + enable ? (l |=BIT (18 )) : (l &= ~BIT (18 )); + + err =wrmsr_on_cpu (cpu,MSR_K7_HWCR , l, h); +if (err) +printk (KERN_ERR "%s: error writing HWCR\n" , __func__); + +return err; +} + +/* * Collect all the MCi_XXX settings */ static struct mce i_mce;
Signature · 1 line
1.7.4.rc2
PATCH 4/6 EDAC, MCE, AMD: Convert to debugfs
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
This is a module which is used for debugging MCE decoding paths so its userspace interface should go to debugfs, where it belongs conceptually.
While at it, add a warning to the Kconfig text that this interface is unstable and no userspace scripts should rely all too much on it.
Make it so.
--- drivers/edac/Kconfig | 8 +- drivers/edac/mce_amd_inj.c | 191 ++++++++++++++++++++------------------------ 2 files changed, 91 insertions(+), 108 deletions(-)
drivers/edac/Kconfig +5 -3
@@ -52,15 +52,17 @@ config EDAC_DECODE_MCE has been initialized. config EDAC_MCE_INJ - tristate "Simple MCE injection interface over /sysfs" - depends on EDAC_DECODE_MCE + tristate "Simple debugfs MCE injection interface" + depends on EDAC_DECODE_MCE && DEBUG_FS default n help - This is a simple interface to inject MCEs over /sysfs and test + This is a simple interface to inject MCEs over debugfs and test the MCE decoding code in EDAC. This is currently AMD-only. + WARNING: Do not even assume that this interface is staying stable! + config EDAC_MM_EDAC tristate "Main Memory EDAC (Error Detection And Correction) reporting" help
drivers/edac/mce_amd_inj.c +86 -105
247 lines not on this page · raw message
Signature · 1 line
1.7.4.rc2
PATCH 5/6 EDAC, MCE, AMD: Add attributes needed for HW injection
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
hw_inject denotes whether we want to do a hardware or a software injection and, in the case of hardware injection, we want to do that on a particular cpu, thus the second 'cpu' attribute.
--- drivers/edac/mce_amd_inj.c | 57 ++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 57 insertions(+), 0 deletions(-)
drivers/edac/mce_amd_inj.c +57 -0
@@ -77,6 +77,61 @@ static int toggle_hw_mce_inject(unsigned int cpu, bool enable) }/* +* HW or SW injection +*/ +static int hw_inj_get (void *data,u64 *val) +{ +struct mce *m = (struct mce *)data; + + *val = !!(m->inject_flags &MCJ_HW_INJECT ); + +return 0 ; +} + +static int hw_inj_set (void *data,u64 val) +{ +struct mce *m = (struct mce *)data; + +switch (val) { +case 0 : + m->inject_flags &= (u8 )~MCJ_HW_INJECT ; +break ; + +case 1 : + m->inject_flags |=MCJ_HW_INJECT ; +break ; + +default : +printk (KERN_ERR "%s: Only 0 or 1 allowed!\n" , __func__); +return -EINVAL ; + } +return 0 ; +} + +DEFINE_SIMPLE_ATTRIBUTE (hw_inj_fops, hw_inj_get, hw_inj_set,"%llu\n" ); + +/* +* On which CPU to inject? +*/ + +MCE_INJECT_GET (extcpu); + + +static int inj_extcpu_set (void *data,u64 val) +{ +struct mce *m = (struct mce *)data; + +if (val >=num_online_cpus ()) { +printk (KERN_ERR "%s: Non-existent CPU: %llu\n" , __func__, val); +return -EINVAL ; + } + m->extcpu = val; +return 0 ; +} + +DEFINE_SIMPLE_ATTRIBUTE (extcpu_fops, inj_extcpu_get, inj_extcpu_set,"%llu\n" ); + +/* * This denotes into which bank we're injecting and triggers * the injection, at the same time. */
@@ -116,6 +171,8 @@ struct dfs_node { { .name = "misc", .fops = &misc_fops }, { .name = "addr", .fops = &addr_fops }, { .name = "bank", .fops = &bank_fops }, + { .name = "hw_inject", .fops = &hw_inj_fops }, + { .name = "cpu", .fops = &extcpu_fops }, };static int __init edac_init_mce_inject (void )
Signature · 1 line
1.7.4.rc2
PATCH 6/6 EDAC, MCE, AMD: Add an injector function
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
Selectively inject either a real MCE or a sw-only version which exercises the decoding code only. The hardware-injected MCE triggers a machine check exception (#MC) so that the MCE handler can be bothered to do something too.
--- drivers/edac/mce_amd_inj.c | 50 ++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 48 insertions(+), 2 deletions(-)
drivers/edac/mce_amd_inj.c +48 -2
@@ -131,6 +131,53 @@ static int inj_extcpu_set(void *data, u64 val)DEFINE_SIMPLE_ATTRIBUTE (extcpu_fops, inj_extcpu_get, inj_extcpu_set,"%llu\n" ); +static void trigger_mce (void *info) +{ + asmvolatile ("int $18" ); +} + +static void do_inject (void ) +{ +u64 mcg_status =0 ; +unsigned int cpu = i_mce.extcpu; +int this_cpu; +u8 b = i_mce.bank; + +if (!(i_mce.inject_flags &MCJ_HW_INJECT )) { +amd_decode_mce (NULL ,0 , &i_mce); +return ; + } + +/* prep MCE global settings for the injection */ + mcg_status =MCG_STATUS_MCIP |MCG_STATUS_EIPV ; + +if (!(i_mce.status &MCI_STATUS_PCC )) + mcg_status |=MCG_STATUS_RIPV ; + + this_cpu =get_cpu (); + +toggle_hw_mce_inject (cpu, true); + +wrmsr_on_cpu (cpu,MSR_IA32_MCG_STATUS , + (u32 )mcg_status, (u32)(mcg_status >>32 )); + +wrmsr_on_cpu (cpu,MSR_IA32_MCx_STATUS (b), + (u32 )i_mce.status, (u32)(i_mce.status >>32 )); + +wrmsr_on_cpu (cpu,MSR_IA32_MCx_ADDR (b), + (u32 )i_mce.addr, (u32)(i_mce.addr >>32 )); + +wrmsr_on_cpu (cpu,MSR_IA32_MCx_MISC (b), + (u32 )i_mce.misc, (u32)(i_mce.misc >>32 )); + +toggle_hw_mce_inject (cpu, false); + +smp_call_function_single (cpu, trigger_mce,NULL ,0 ); + +put_cpu (); + +} +/* * This denotes into which bank we're injecting and triggers * the injection, at the same time.
@@ -146,8 +193,7 @@ static int inj_bank_set(void *data, u64 val) } m->bank = val; - -amd_decode_mce (NULL ,0 , m); +do_inject ();return 0 ; }
Signature · 1 line
1.7.4.rc2