# Commit ce59e472b581e4923f6892172dde62b88c8aa8b7
# Date 2022-05-02 08:49:12 +0200
# Author Roger Pau Monné <roger.pau@citrix.com>
# Committer Jan Beulich <jbeulich@suse.com>
x86/msr: handle reads to MSR_P5_MC_{ADDR,TYPE}

Windows Server 2019 Essentials will unconditionally attempt to read
P5_MC_ADDR MSR at boot and throw a BSOD if injected a #GP.

Fix this by mapping MSR_P5_MC_{ADDR,TYPE} to
MSR_IA32_MCi_{ADDR,STATUS}, as reported also done by hardware in Intel
SDM "Mapping of the Pentium Processor Machine-Check Errors to the
Machine-Check Architecture" section.

Reported-by: Steffen Einsle <einsle@phptrix.de>
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>

--- a/xen/arch/x86/cpu/mcheck/mce.h
+++ b/xen/arch/x86/cpu/mcheck/mce.h
@@ -166,6 +166,11 @@ static inline int mce_vendor_bank_msr(co
         if (msr >= MSR_IA32_MC0_CTL2 &&
             msr < MSR_IA32_MCx_CTL2(v->arch.vmce.mcg_cap & MCG_CAP_COUNT) )
             return 1;
+        /* fallthrough */
+    case X86_VENDOR_CENTAUR:
+    case X86_VENDOR_SHANGHAI:
+        if (msr == MSR_IA32_P5_MC_ADDR || msr == MSR_IA32_P5_MC_TYPE)
+            return 1;
         break;
 
     case X86_VENDOR_AMD:
--- a/xen/arch/x86/cpu/mcheck/mce_intel.c
+++ b/xen/arch/x86/cpu/mcheck/mce_intel.c
@@ -955,8 +955,27 @@ int vmce_intel_wrmsr(struct vcpu *v, uin
 
 int vmce_intel_rdmsr(const struct vcpu *v, uint32_t msr, uint64_t *val)
 {
+    const struct cpuid_policy *cp = v->domain->arch.cpuid;
     unsigned int bank = msr - MSR_IA32_MC0_CTL2;
 
+    switch ( msr )
+    {
+    case MSR_IA32_P5_MC_ADDR:
+        /*
+         * Bank 0 is used for the 'bank 0 quirk' on older processors.
+         * See vcpu_fill_mc_msrs() for reference.
+         */
+        *val = v->arch.vmce.bank[1].mci_addr;
+        return 1;
+
+    case MSR_IA32_P5_MC_TYPE:
+        *val = v->arch.vmce.bank[1].mci_status;
+        return 1;
+    }
+
+    if ( cp->x86_vendor != X86_VENDOR_INTEL )
+        return 0;
+
     if ( bank < GUEST_MC_BANK_NUM )
     {
         *val = v->arch.vmce.bank[bank].mci_ctl2;
--- a/xen/arch/x86/cpu/mcheck/vmce.c
+++ b/xen/arch/x86/cpu/mcheck/vmce.c
@@ -149,6 +149,8 @@ static int bank_mce_rdmsr(const struct v
     default:
         switch ( boot_cpu_data.x86_vendor )
         {
+        case X86_VENDOR_CENTAUR:
+        case X86_VENDOR_SHANGHAI:
         case X86_VENDOR_INTEL:
             ret = vmce_intel_rdmsr(v, msr, val);
             break;
