# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1237569893 0
# Node ID cc60defe5b9697ab0e068caa4fd1f8798bfe5104
# Parent c44c963ea1625314aef37487f0bc9e0924f39614
Implements Guest MCE# MSR read/write virtualization
Signed-off-by: Jiang, Yunhong <yunhong.jiang@xxxxxxxxx>
Signed-off-by: Ke, Liping <liping.ke@xxxxxxxxx>
---
xen/arch/x86/cpu/mcheck/mce_intel.c | 257 ++++++++++++++++++++++++++++++++++++
xen/arch/x86/traps.c | 21 ++
xen/include/asm-x86/msr-index.h | 24 +++
3 files changed, 300 insertions(+), 2 deletions(-)
diff -r c44c963ea162 -r cc60defe5b96 xen/arch/x86/cpu/mcheck/mce_intel.c
--- a/xen/arch/x86/cpu/mcheck/mce_intel.c Fri Mar 20 17:24:29 2009 +0000
+++ b/xen/arch/x86/cpu/mcheck/mce_intel.c Fri Mar 20 17:24:53 2009 +0000
@@ -812,3 +812,260 @@ int intel_mcheck_init(struct cpuinfo_x86
open_softirq(MACHINE_CHECK_SOFTIRQ, mce_softirq);
return 1;
}
+
+/* Guest vMCE# MSRs virtualization ops (rdmsr/wrmsr) */
+int intel_mce_wrmsr(u32 msr, u32 lo, u32 hi)
+{
+ struct domain *d = current->domain;
+ struct bank_entry *entry = NULL;
+ uint64_t value = (u64)hi << 32 | lo;
+ int ret = 0;
+
+ spin_lock(&mce_locks);
+ switch(msr)
+ {
+ case MSR_IA32_MCG_CTL:
+ if (value != (u64)~0x0 && value != 0x0) {
+ printk(KERN_ERR "MCE: value writen to MCG_CTL"
+ "should be all 0s or 1s\n");
+ ret = -1;
+ break;
+ }
+ if (!d || is_idle_domain(d)) {
+ printk(KERN_ERR "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)) {
+ printk(KERN_ERR "MCE: wrmsr not in DOM context, skip\n");
+ break;
+ }
+ d->arch.vmca_msrs.mcg_status = value;
+ printk(KERN_DEBUG "MCE: wrmsr MCG_CTL %lx\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:
+ printk(KERN_ERR "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) {
+ printk(KERN_ERR "MCE: value writen to MCi_CTL"
+ "should be all 0s or 1s\n");
+ ret = -1;
+ break;
+ }
+ if (!d || is_idle_domain(d)) {
+ printk(KERN_ERR "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 */
+ printk(KERN_ERR "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;
+ }
+ printk(KERN_DEBUG "MCE: wmrsr mci_status in vMCE# context\n");
+ }
+ printk(KERN_DEBUG "MCE: wrmsr mci_status val:%lx\n", value);
+ break;
+ }
+ spin_unlock(&mce_locks);
+ return ret;
+}
+
+int intel_mce_rdmsr(u32 msr, u32 *lo, u32 *hi)
+{
+ struct domain *d = current->domain;
+ int ret = 0;
+ struct bank_entry *entry = NULL;
+
+ *lo = *hi = 0x0;
+ spin_lock(&mce_locks);
+ switch(msr)
+ {
+ case MSR_IA32_MCG_STATUS:
+ if (!d || is_idle_domain(d)) {
+ printk(KERN_ERR "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);
+ printk(KERN_DEBUG "MCE: rd MCG_STATUS lo %x hi %x\n", *lo, *hi);
+ break;
+ case MSR_IA32_MCG_CAP:
+ if (!d || is_idle_domain(d)) {
+ printk(KERN_ERR "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);
+ printk(KERN_DEBUG "MCE: rdmsr MCG_CAP lo %x hi %x\n", *lo, *hi);
+ break;
+ case MSR_IA32_MCG_CTL:
+ if (!d || is_idle_domain(d)) {
+ printk(KERN_ERR "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);
+ printk(KERN_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:
+ printk(KERN_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)) {
+ printk(KERN_ERR "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);
+ printk(KERN_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;
+ printk(KERN_DEBUG "MCE: rdmsr mci_status\n");
+ if (!d || is_idle_domain(d)) {
+ printk(KERN_ERR "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;
+ printk(KERN_DEBUG "MCE: rdmsr MCi_STATUS in vmCE# context "
+ "lo %x hi %x\n", *lo, *hi);
+ }
+ }
+ 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)) {
+ printk(KERN_ERR "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;
+ printk(KERN_DEBUG "MCE: rdmsr MCi_ADDR in vMCE# context "
+ "lo %x hi %x\n", *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)) {
+ printk(KERN_ERR "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;
+ printk(KERN_DEBUG "MCE: rdmsr MCi_MISC in vMCE# context "
+ " lo %x hi %x\n", *lo, *hi);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ spin_unlock(&mce_locks);
+ return ret;
+}
+
+
diff -r c44c963ea162 -r cc60defe5b96 xen/arch/x86/traps.c
--- a/xen/arch/x86/traps.c Fri Mar 20 17:24:29 2009 +0000
+++ b/xen/arch/x86/traps.c Fri Mar 20 17:24:53 2009 +0000
@@ -728,8 +728,6 @@ static void pv_cpuid(struct cpu_user_reg
if ( !opt_allow_hugepage )
__clear_bit(X86_FEATURE_PSE, &d);
__clear_bit(X86_FEATURE_PGE, &d);
- __clear_bit(X86_FEATURE_MCE, &d);
- __clear_bit(X86_FEATURE_MCA, &d);
__clear_bit(X86_FEATURE_PSE36, &d);
}
switch ( (uint32_t)regs->eax )
@@ -1638,6 +1636,10 @@ static int is_cpufreq_controller(struct
return ((cpufreq_controller == FREQCTL_dom0_kernel) &&
(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)
{
@@ -2206,6 +2208,15 @@ static int emulate_privileged_op(struct
default:
if ( wrmsr_hypervisor_regs(regs->ecx, eax, edx) )
break;
+ if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
+ if ( intel_mce_wrmsr(regs->ecx, eax, edx) != 0) {
+ gdprintk(XENLOG_ERR, "MCE: vMCE MSRS(%lx) Write"
+ " (%x:%x) Fails! ", regs->ecx, edx, eax);
+ goto fail;
+ }
+ break;
+ }
+
if ( (rdmsr_safe(regs->ecx, l, h) != 0) ||
(eax != l) || (edx != h) )
invalid:
@@ -2289,6 +2300,12 @@ static int emulate_privileged_op(struct
_p(regs->ecx));*/
if ( rdmsr_safe(regs->ecx, regs->eax, regs->edx) )
goto fail;
+
+ if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
+ if ( intel_mce_rdmsr(regs->ecx, &eax, &edx) != 0)
+ printk(KERN_ERR "MCE: Not MCE MSRs %lx\n", regs->ecx);
+ }
+
break;
}
break;
diff -r c44c963ea162 -r cc60defe5b96 xen/include/asm-x86/msr-index.h
--- a/xen/include/asm-x86/msr-index.h Fri Mar 20 17:24:29 2009 +0000
+++ b/xen/include/asm-x86/msr-index.h Fri Mar 20 17:24:53 2009 +0000
@@ -96,29 +96,53 @@
#define CMCI_EN (1UL<<30)
#define CMCI_THRESHOLD_MASK 0x7FFF
+#define MSR_IA32_MC1_CTL 0x00000404
+#define MSR_IA32_MC1_CTL2 0x00000281
#define MSR_IA32_MC1_STATUS 0x00000405
#define MSR_IA32_MC1_ADDR 0x00000406
#define MSR_IA32_MC1_MISC 0x00000407
#define MSR_IA32_MC2_CTL 0x00000408
+#define MSR_IA32_MC2_CTL2 0x00000282
#define MSR_IA32_MC2_STATUS 0x00000409
#define MSR_IA32_MC2_ADDR 0x0000040A
#define MSR_IA32_MC2_MISC 0x0000040B
+#define MSR_IA32_MC3_CTL2 0x00000283
#define MSR_IA32_MC3_CTL 0x0000040C
#define MSR_IA32_MC3_STATUS 0x0000040D
#define MSR_IA32_MC3_ADDR 0x0000040E
#define MSR_IA32_MC3_MISC 0x0000040F
+#define MSR_IA32_MC4_CTL2 0x00000284
#define MSR_IA32_MC4_CTL 0x00000410
#define MSR_IA32_MC4_STATUS 0x00000411
#define MSR_IA32_MC4_ADDR 0x00000412
#define MSR_IA32_MC4_MISC 0x00000413
+#define MSR_IA32_MC5_CTL2 0x00000285
#define MSR_IA32_MC5_CTL 0x00000414
#define MSR_IA32_MC5_STATUS 0x00000415
#define MSR_IA32_MC5_ADDR 0x00000416
#define MSR_IA32_MC5_MISC 0x00000417
+
+#define MSR_IA32_MC6_CTL2 0x00000286
+#define MSR_IA32_MC6_CTL 0x00000418
+#define MSR_IA32_MC6_STATUS 0x00000419
+#define MSR_IA32_MC6_ADDR 0x0000041A
+#define MSR_IA32_MC6_MISC 0x0000041B
+
+#define MSR_IA32_MC7_CTL2 0x00000287
+#define MSR_IA32_MC7_CTL 0x0000041C
+#define MSR_IA32_MC7_STATUS 0x0000041D
+#define MSR_IA32_MC7_ADDR 0x0000041E
+#define MSR_IA32_MC7_MISC 0x0000041F
+
+#define MSR_IA32_MC8_CTL2 0x00000288
+#define MSR_IA32_MC8_CTL 0x00000420
+#define MSR_IA32_MC8_STATUS 0x00000421
+#define MSR_IA32_MC8_ADDR 0x00000422
+#define MSR_IA32_MC8_MISC 0x00000423
#define MSR_P6_PERFCTR0 0x000000c1
#define MSR_P6_PERFCTR1 0x000000c2
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|