[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] x86 mce: fix and clean up c/s 19423
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1238501868 -3600 # Node ID f9501b0bcc1b421a7add49dfefce5cc448df3b8d # Parent cc4a2290c22487477a4ff5fbda05b349efb89319 x86 mce: fix and clean up c/s 19423 - fix inverted return value check for intel_mce_{rd,wr}msr() - fix broken initialization of d->arch.vmca_msrs.mci_ctl - remove pointless (!d || is_idle_domain(d)) checks - eliminate hard-coded limit to 9 banks - avoid redundant gdprintk()s Signed-off-by: Jan Beulich <jbeulich@xxxxxxxxxx> --- xen/arch/x86/cpu/mcheck/mce_intel.c | 306 ++++++++++++++---------------------- xen/arch/x86/domain.c | 12 - xen/arch/x86/traps.c | 32 +-- xen/include/asm-x86/traps.h | 5 4 files changed, 146 insertions(+), 209 deletions(-) diff -r cc4a2290c224 -r f9501b0bcc1b xen/arch/x86/cpu/mcheck/mce_intel.c --- a/xen/arch/x86/cpu/mcheck/mce_intel.c Tue Mar 31 13:14:10 2009 +0100 +++ b/xen/arch/x86/cpu/mcheck/mce_intel.c Tue Mar 31 13:17:48 2009 +0100 @@ -742,7 +742,7 @@ void mce_intel_feature_init(struct cpuin intel_init_cmci(c); } -uint64_t g_mcg_cap; +static uint64_t g_mcg_cap; static void mce_cap_init(struct cpuinfo_x86 *c) { u32 l, h; @@ -754,9 +754,12 @@ static void mce_cap_init(struct cpuinfo_ if ((l & MCG_CMCI_P) && cpu_has_apic) cmci_support = 1; - nr_mce_banks = l & 0xff; + nr_mce_banks = l & MCG_CAP_COUNT; if (nr_mce_banks > MAX_NR_BANKS) + { printk(KERN_WARNING "MCE: exceed max mce banks\n"); + g_mcg_cap = (g_mcg_cap & ~MCG_CAP_COUNT) | MAX_NR_BANKS; + } if (l & MCG_EXT_P) { nr_intel_ext_msrs = (l >> MCG_EXT_CNT) & 0xff; @@ -828,11 +831,22 @@ int intel_mcheck_init(struct cpuinfo_x86 } /* Guest vMCE# MSRs virtualization ops (rdmsr/wrmsr) */ -int intel_mce_wrmsr(u32 msr, u32 lo, u32 hi) +void intel_mce_init_msr(struct domain *d) +{ + d->arch.vmca_msrs.mcg_status = 0x0; + d->arch.vmca_msrs.mcg_cap = g_mcg_cap; + d->arch.vmca_msrs.mcg_ctl = (uint64_t)~0x0; + d->arch.vmca_msrs.nr_injection = 0; + memset(d->arch.vmca_msrs.mci_ctl, ~0, + sizeof(d->arch.vmca_msrs.mci_ctl)); + INIT_LIST_HEAD(&d->arch.vmca_msrs.impact_header); +} + +int intel_mce_wrmsr(u32 msr, u64 value) { struct domain *d = current->domain; struct bank_entry *entry = NULL; - uint64_t value = (u64)hi << 32 | lo; + unsigned int bank; int ret = 1; spin_lock(&mce_locks); @@ -840,86 +854,71 @@ int intel_mce_wrmsr(u32 msr, u32 lo, u32 { case MSR_IA32_MCG_CTL: if (value != (u64)~0x0 && value != 0x0) { - gdprintk(XENLOG_WARNING, "MCE: value writen to MCG_CTL" + gdprintk(XENLOG_WARNING, "MCE: value written to MCG_CTL" "should be all 0s or 1s\n"); ret = -1; break; } - if (!d || is_idle_domain(d)) { - gdprintk(XENLOG_WARNING, "MCE: wrmsr not in DOM context, skip\n"); - break; - } d->arch.vmca_msrs.mcg_ctl = value; break; case MSR_IA32_MCG_STATUS: - if (!d || is_idle_domain(d)) { - gdprintk(XENLOG_WARNING, "MCE: wrmsr not in DOM context, skip\n"); - break; - } d->arch.vmca_msrs.mcg_status = value; gdprintk(XENLOG_DEBUG, "MCE: wrmsr MCG_CTL %"PRIx64"\n", value); break; - case MSR_IA32_MC0_CTL2: - case MSR_IA32_MC1_CTL2: - case MSR_IA32_MC2_CTL2: - case MSR_IA32_MC3_CTL2: - case MSR_IA32_MC4_CTL2: - case MSR_IA32_MC5_CTL2: - case MSR_IA32_MC6_CTL2: - case MSR_IA32_MC7_CTL2: - case MSR_IA32_MC8_CTL2: + case MSR_IA32_MCG_CAP: + gdprintk(XENLOG_WARNING, "MCE: MCG_CAP is read-only\n"); + ret = -1; + break; + case MSR_IA32_MC0_CTL2 ... MSR_IA32_MC0_CTL2 + MAX_NR_BANKS - 1: gdprintk(XENLOG_WARNING, "We have disabled CMCI capability, " "Guest should not write this MSR!\n"); break; - case MSR_IA32_MC0_CTL: - case MSR_IA32_MC1_CTL: - case MSR_IA32_MC2_CTL: - case MSR_IA32_MC3_CTL: - case MSR_IA32_MC4_CTL: - case MSR_IA32_MC5_CTL: - case MSR_IA32_MC6_CTL: - case MSR_IA32_MC7_CTL: - case MSR_IA32_MC8_CTL: - if (value != (u64)~0x0 && value != 0x0) { - gdprintk(XENLOG_WARNING, "MCE: value writen to MCi_CTL" - "should be all 0s or 1s\n"); + case MSR_IA32_MC0_CTL ... MSR_IA32_MC0_CTL + 4 * MAX_NR_BANKS - 1: + bank = (msr - MSR_IA32_MC0_CTL) / 4; + if (bank >= (d->arch.vmca_msrs.mcg_cap & MCG_CAP_COUNT)) { + gdprintk(XENLOG_WARNING, "MCE: bank %u does not exist\n", bank); ret = -1; break; } - if (!d || is_idle_domain(d)) { - gdprintk(XENLOG_WARNING, "MCE: wrmsr not in DOM context, skip\n"); - break; - } - d->arch.vmca_msrs.mci_ctl[(msr - MSR_IA32_MC0_CTL)/4] = value; - break; - case MSR_IA32_MC0_STATUS: - case MSR_IA32_MC1_STATUS: - case MSR_IA32_MC2_STATUS: - case MSR_IA32_MC3_STATUS: - case MSR_IA32_MC4_STATUS: - case MSR_IA32_MC5_STATUS: - case MSR_IA32_MC6_STATUS: - case MSR_IA32_MC7_STATUS: - case MSR_IA32_MC8_STATUS: - if (!d || is_idle_domain(d)) { - /* Just skip */ - gdprintk(XENLOG_WARNING, "mce wrmsr: not in domain context!\n"); - break; - } - /* Give the first entry of the list, it corresponds to current - * vMCE# injection. When vMCE# is finished processing by the - * the guest, this node will be deleted. - * Only error bank is written. Non-error bank simply return. - */ - if ( !list_empty(&d->arch.vmca_msrs.impact_header) ) { - entry = list_entry(d->arch.vmca_msrs.impact_header.next, - struct bank_entry, list); - if ( entry->bank == (msr - MSR_IA32_MC0_STATUS)/4 ) { - entry->mci_status = value; + switch (msr & (MSR_IA32_MC0_CTL | 3)) + { + case MSR_IA32_MC0_CTL: + if (value != (u64)~0x0 && value != 0x0) { + gdprintk(XENLOG_WARNING, "MCE: value written to MC%u_CTL" + "should be all 0s or 1s (is %"PRIx64")\n", + bank, value); + ret = -1; + break; } - gdprintk(XENLOG_DEBUG, "MCE: wmrsr mci_status in vMCE# context\n"); - } - gdprintk(XENLOG_DEBUG, "MCE: wrmsr mci_status val:%"PRIx64"\n", value); + d->arch.vmca_msrs.mci_ctl[(msr - MSR_IA32_MC0_CTL)/4] = value; + break; + case MSR_IA32_MC0_STATUS: + /* Give the first entry of the list, it corresponds to current + * vMCE# injection. When vMCE# is finished processing by the + * the guest, this node will be deleted. + * Only error bank is written. Non-error banks simply return. + */ + if (!list_empty(&d->arch.vmca_msrs.impact_header)) { + entry = list_entry(d->arch.vmca_msrs.impact_header.next, + struct bank_entry, list); + if ( entry->bank == bank ) + entry->mci_status = value; + gdprintk(XENLOG_DEBUG, + "MCE: wr MC%u_STATUS %"PRIx64" in vMCE#\n", + bank, value); + } else + gdprintk(XENLOG_DEBUG, + "MCE: wr MC%u_STATUS %"PRIx64"\n", bank, value); + break; + case MSR_IA32_MC0_ADDR: + gdprintk(XENLOG_WARNING, "MCE: MC%u_ADDR is read-only\n", bank); + ret = -1; + break; + case MSR_IA32_MC0_MISC: + gdprintk(XENLOG_WARNING, "MCE: MC%u_MISC is read-only\n", bank); + ret = -1; + break; + } break; default: ret = 0; @@ -933,6 +932,7 @@ int intel_mce_rdmsr(u32 msr, u32 *lo, u3 { struct domain *d = current->domain; int ret = 1; + unsigned int bank; struct bank_entry *entry = NULL; *lo = *hi = 0x0; @@ -940,142 +940,82 @@ int intel_mce_rdmsr(u32 msr, u32 *lo, u3 switch(msr) { case MSR_IA32_MCG_STATUS: - if (!d || is_idle_domain(d)) { - gdprintk(XENLOG_WARNING, "MCE: rdmsr not in domain context!\n"); - *lo = *hi = 0x0; - break; - } *lo = (u32)d->arch.vmca_msrs.mcg_status; *hi = (u32)(d->arch.vmca_msrs.mcg_status >> 32); gdprintk(XENLOG_DEBUG, "MCE: rd MCG_STATUS lo %x hi %x\n", *lo, *hi); break; case MSR_IA32_MCG_CAP: - if (!d || is_idle_domain(d)) { - gdprintk(XENLOG_WARNING, "MCE: rdmsr not in domain context!\n"); - *lo = *hi = 0x0; - break; - } *lo = (u32)d->arch.vmca_msrs.mcg_cap; *hi = (u32)(d->arch.vmca_msrs.mcg_cap >> 32); gdprintk(XENLOG_DEBUG, "MCE: rdmsr MCG_CAP lo %x hi %x\n", *lo, *hi); break; case MSR_IA32_MCG_CTL: - if (!d || is_idle_domain(d)) { - gdprintk(XENLOG_WARNING, "MCE: rdmsr not in domain context!\n"); - *lo = *hi = 0x0; - break; - } *lo = (u32)d->arch.vmca_msrs.mcg_ctl; *hi = (u32)(d->arch.vmca_msrs.mcg_ctl >> 32); gdprintk(XENLOG_DEBUG, "MCE: rdmsr MCG_CTL lo %x hi %x\n", *lo, *hi); break; - case MSR_IA32_MC0_CTL2: - case MSR_IA32_MC1_CTL2: - case MSR_IA32_MC2_CTL2: - case MSR_IA32_MC3_CTL2: - case MSR_IA32_MC4_CTL2: - case MSR_IA32_MC5_CTL2: - case MSR_IA32_MC6_CTL2: - case MSR_IA32_MC7_CTL2: - case MSR_IA32_MC8_CTL2: + case MSR_IA32_MC0_CTL2 ... MSR_IA32_MC0_CTL2 + MAX_NR_BANKS - 1: gdprintk(XENLOG_WARNING, "We have disabled CMCI capability, " "Guest should not read this MSR!\n"); break; - case MSR_IA32_MC0_CTL: - case MSR_IA32_MC1_CTL: - case MSR_IA32_MC2_CTL: - case MSR_IA32_MC3_CTL: - case MSR_IA32_MC4_CTL: - case MSR_IA32_MC5_CTL: - case MSR_IA32_MC6_CTL: - case MSR_IA32_MC7_CTL: - case MSR_IA32_MC8_CTL: - if (!d || is_idle_domain(d)) { - gdprintk(XENLOG_WARNING, "MCE: rdmsr not in domain context!\n"); - *lo = *hi = 0x0; - break; - } - *lo = (u32)d->arch.vmca_msrs.mci_ctl[(msr - MSR_IA32_MC0_CTL)/4]; - *hi = - (u32)(d->arch.vmca_msrs.mci_ctl[(msr - MSR_IA32_MC0_CTL)/4] - >> 32); - gdprintk(XENLOG_DEBUG, "MCE: rdmsr MCi_CTL lo %x hi %x\n", *lo, *hi); - break; - case MSR_IA32_MC0_STATUS: - case MSR_IA32_MC1_STATUS: - case MSR_IA32_MC2_STATUS: - case MSR_IA32_MC3_STATUS: - case MSR_IA32_MC4_STATUS: - case MSR_IA32_MC5_STATUS: - case MSR_IA32_MC6_STATUS: - case MSR_IA32_MC7_STATUS: - case MSR_IA32_MC8_STATUS: - /* Only error bank is read. Non-error bank simply return */ - *lo = *hi = 0x0; - gdprintk(XENLOG_DEBUG, "MCE: rdmsr mci_status\n"); - if (!d || is_idle_domain(d)) { - gdprintk(XENLOG_WARNING, "mce_rdmsr: not in domain context!\n"); - break; - } - if (!list_empty(&d->arch.vmca_msrs.impact_header)) { - entry = list_entry(d->arch.vmca_msrs.impact_header.next, - struct bank_entry, list); - if ( entry->bank == (msr - MSR_IA32_MC0_STATUS)/4 ) { - *lo = entry->mci_status; - *hi = entry->mci_status >> 32; - gdprintk(XENLOG_DEBUG, "MCE: rdmsr MCi_STATUS in vmCE# context " - "lo %x hi %x\n", *lo, *hi); + case MSR_IA32_MC0_CTL ... MSR_IA32_MC0_CTL + 4 * MAX_NR_BANKS - 1: + bank = (msr - MSR_IA32_MC0_CTL) / 4; + if (bank >= (d->arch.vmca_msrs.mcg_cap & MCG_CAP_COUNT)) { + gdprintk(XENLOG_WARNING, "MCE: bank %u does not exist\n", bank); + ret = -1; + break; + } + switch (msr & (MSR_IA32_MC0_CTL | 3)) + { + case MSR_IA32_MC0_CTL: + *lo = (u32)d->arch.vmca_msrs.mci_ctl[bank]; + *hi = (u32)(d->arch.vmca_msrs.mci_ctl[bank] >> 32); + gdprintk(XENLOG_DEBUG, "MCE: rd MC%u_CTL lo %x hi %x\n", + bank, *lo, *hi); + break; + case MSR_IA32_MC0_STATUS: + /* Only error bank is read. Non-error banks simply return. */ + if (!list_empty(&d->arch.vmca_msrs.impact_header)) { + entry = list_entry(d->arch.vmca_msrs.impact_header.next, + struct bank_entry, list); + if (entry->bank == bank) { + *lo = entry->mci_status; + *hi = entry->mci_status >> 32; + gdprintk(XENLOG_DEBUG, + "MCE: rd MC%u_STATUS in vmCE# context " + "lo %x hi %x\n", bank, *lo, *hi); + } else + entry = NULL; } - } - break; - case MSR_IA32_MC0_ADDR: - case MSR_IA32_MC1_ADDR: - case MSR_IA32_MC2_ADDR: - case MSR_IA32_MC3_ADDR: - case MSR_IA32_MC4_ADDR: - case MSR_IA32_MC5_ADDR: - case MSR_IA32_MC6_ADDR: - case MSR_IA32_MC7_ADDR: - case MSR_IA32_MC8_ADDR: - *lo = *hi = 0x0; - if (!d || is_idle_domain(d)) { - gdprintk(XENLOG_WARNING, "mce_rdmsr: not in domain context!\n"); - break; - } - if (!list_empty(&d->arch.vmca_msrs.impact_header)) { - entry = list_entry(d->arch.vmca_msrs.impact_header.next, - struct bank_entry, list); - if ( entry->bank == (msr - MSR_IA32_MC0_ADDR)/4 ) { - *lo = entry->mci_addr; - *hi = entry->mci_addr >> 32; - gdprintk(XENLOG_DEBUG, "MCE: rdmsr MCi_ADDR in vMCE# context " - "lo %x hi %x\n", *lo, *hi); + if (!entry) + gdprintk(XENLOG_DEBUG, "MCE: rd MC%u_STATUS\n", bank); + break; + case MSR_IA32_MC0_ADDR: + if (!list_empty(&d->arch.vmca_msrs.impact_header)) { + entry = list_entry(d->arch.vmca_msrs.impact_header.next, + struct bank_entry, list); + if (entry->bank == bank) { + *lo = entry->mci_addr; + *hi = entry->mci_addr >> 32; + gdprintk(XENLOG_DEBUG, + "MCE: rd MC%u_ADDR in vMCE# context lo %x hi %x\n", + bank, *lo, *hi); + } } - } - break; - case MSR_IA32_MC0_MISC: - case MSR_IA32_MC1_MISC: - case MSR_IA32_MC2_MISC: - case MSR_IA32_MC3_MISC: - case MSR_IA32_MC4_MISC: - case MSR_IA32_MC5_MISC: - case MSR_IA32_MC6_MISC: - case MSR_IA32_MC7_MISC: - case MSR_IA32_MC8_MISC: - *lo = *hi = 0x0; - if (!d || is_idle_domain(d)) { - gdprintk(XENLOG_WARNING, "MCE: rdmsr not in domain context!\n"); - break; - } - if (!list_empty(&d->arch.vmca_msrs.impact_header)) { - entry = list_entry(d->arch.vmca_msrs.impact_header.next, - struct bank_entry, list); - if ( entry->bank == (msr - MSR_IA32_MC0_MISC)/4 ) { - *lo = entry->mci_misc; - *hi = entry->mci_misc >> 32; - gdprintk(XENLOG_DEBUG, "MCE: rdmsr MCi_MISC in vMCE# context " - " lo %x hi %x\n", *lo, *hi); + break; + case MSR_IA32_MC0_MISC: + if (!list_empty(&d->arch.vmca_msrs.impact_header)) { + entry = list_entry(d->arch.vmca_msrs.impact_header.next, + struct bank_entry, list); + if (entry->bank == bank) { + *lo = entry->mci_misc; + *hi = entry->mci_misc >> 32; + gdprintk(XENLOG_DEBUG, + "MCE: rd MC%u_MISC in vMCE# context lo %x hi %x\n", + bank, *lo, *hi); + } } + break; } break; default: diff -r cc4a2290c224 -r f9501b0bcc1b xen/arch/x86/domain.c --- a/xen/arch/x86/domain.c Tue Mar 31 13:14:10 2009 +0100 +++ b/xen/arch/x86/domain.c Tue Mar 31 13:17:48 2009 +0100 @@ -46,6 +46,7 @@ #include <asm/hvm/support.h> #include <asm/debugreg.h> #include <asm/msr.h> +#include <asm/traps.h> #include <asm/nmi.h> #include <xen/numa.h> #include <xen/iommu.h> @@ -373,7 +374,6 @@ void vcpu_destroy(struct vcpu *v) hvm_vcpu_destroy(v); } -extern uint64_t g_mcg_cap; int arch_domain_create(struct domain *d, unsigned int domcr_flags) { #ifdef __x86_64__ @@ -458,14 +458,8 @@ int arch_domain_create(struct domain *d, goto fail; /* For Guest vMCE MSRs virtualization */ - d->arch.vmca_msrs.mcg_status = 0x0; - d->arch.vmca_msrs.mcg_cap = g_mcg_cap; - d->arch.vmca_msrs.mcg_ctl = (uint64_t)~0x0; - d->arch.vmca_msrs.nr_injection = 0; - memset(d->arch.vmca_msrs.mci_ctl, 0x1, - sizeof(d->arch.vmca_msrs.mci_ctl)); - INIT_LIST_HEAD(&d->arch.vmca_msrs.impact_header); - + if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL ) + intel_mce_init_msr(d); } if ( is_hvm_domain(d) ) diff -r cc4a2290c224 -r f9501b0bcc1b xen/arch/x86/traps.c --- a/xen/arch/x86/traps.c Tue Mar 31 13:14:10 2009 +0100 +++ b/xen/arch/x86/traps.c Tue Mar 31 13:17:48 2009 +0100 @@ -1637,10 +1637,6 @@ static int is_cpufreq_controller(struct (d->domain_id == 0)); } -/*Intel vMCE MSRs virtualization*/ -extern int intel_mce_wrmsr(u32 msr, u32 lo, u32 hi); -extern int intel_mce_rdmsr(u32 msr, u32 *lo, u32 *hi); - static int emulate_privileged_op(struct cpu_user_regs *regs) { struct vcpu *v = current; @@ -2210,10 +2206,10 @@ static int emulate_privileged_op(struct break; if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL ) { - int rc = intel_mce_wrmsr(regs->ecx, eax, edx); - if ( rc == -1 ) + int rc = intel_mce_wrmsr(regs->ecx, res); + if ( rc < 0 ) goto fail; - if ( rc == 0 ) + if ( rc ) break; } @@ -2291,25 +2287,27 @@ static int emulate_privileged_op(struct default: if ( rdmsr_hypervisor_regs(regs->ecx, &l, &h) ) { + rdmsr_writeback: regs->eax = l; regs->edx = h; break; } + + if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL ) + { + int rc = intel_mce_rdmsr(regs->ecx, &l, &h); + + if ( rc < 0 ) + goto fail; + if ( rc ) + goto rdmsr_writeback; + } + /* Everyone can read the MSR space. */ /* gdprintk(XENLOG_WARNING,"Domain attempted RDMSR %p.\n", _p(regs->ecx));*/ if ( rdmsr_safe(regs->ecx, regs->eax, regs->edx) ) goto fail; - - if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL ) - { - int rc = intel_mce_rdmsr(regs->ecx, &eax, &edx); - if ( rc == -1 ) - goto fail; - if ( rc == 0 ) - break; - } - break; } break; diff -r cc4a2290c224 -r f9501b0bcc1b xen/include/asm-x86/traps.h --- a/xen/include/asm-x86/traps.h Tue Mar 31 13:14:10 2009 +0100 +++ b/xen/include/asm-x86/traps.h Tue Mar 31 13:17:48 2009 +0100 @@ -47,4 +47,9 @@ extern int send_guest_trap(struct domain extern int send_guest_trap(struct domain *d, uint16_t vcpuid, unsigned int trap_nr); +/* Intel vMCE MSRs virtualization */ +extern void intel_mce_init_msr(struct domain *d); +extern int intel_mce_wrmsr(u32 msr, u64 value); +extern int intel_mce_rdmsr(u32 msr, u32 *lo, u32 *hi); + #endif /* ASM_TRAP_H */ _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |