]> xenbits.xensource.com Git - xen.git/commitdiff
Implements Guest MCE# MSR read/write virtualization
authorKeir Fraser <keir.fraser@citrix.com>
Fri, 20 Mar 2009 17:24:53 +0000 (17:24 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Fri, 20 Mar 2009 17:24:53 +0000 (17:24 +0000)
Signed-off-by: Jiang, Yunhong <yunhong.jiang@intel.com>
Signed-off-by: Ke, Liping <liping.ke@intel.com>
xen/arch/x86/cpu/mcheck/mce_intel.c
xen/arch/x86/traps.c
xen/include/asm-x86/msr-index.h

index 5a9960fe6a0ea7f3994c39c3b6b2254e16e40187..1a95e3406f9075eae96de4a3b28a1a595f8c97a0 100644 (file)
@@ -812,3 +812,260 @@ int intel_mcheck_init(struct cpuinfo_x86 *c)
     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;
+}
+
+
index bf4dc8c52bb12dfa54e6e5e2d636c5aadcbc30f2..cdbb0868544b81c74a7cfde53a18ed1b64c84f1e 100644 (file)
@@ -728,8 +728,6 @@ static void pv_cpuid(struct cpu_user_regs *regs)
         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 )
@@ -1639,6 +1637,10 @@ static int is_cpufreq_controller(struct domain *d)
             (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;
@@ -2206,6 +2208,15 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
         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 cpu_user_regs *regs)
                         _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;
index 4f91ca152d553c8eb793ce7bbe9004354402b932..f6b3fd1ed1e0b5ca8350d62e38184f2ead6d3ddb 100644 (file)
 #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
 #define MSR_P6_EVNTSEL0                        0x00000186