This series adds the Corrected Machine Check Interrupt (CMCI) and Uncorrectable Error No Action required (UCNA) emulation to KVM. The former is implemented as a LVT CMCI vector. The emulation of UCNA share the MCE emulation infrastructure. Both CMCI and UCNA emulation do not depend on hardware. CMCI emulation only depends on vcpu's lapic being available. Signed-off-by: Jue Wang <juew@xxxxxxxxxx> --- arch/x86/kvm/vmx/vmx.c | 1 + arch/x86/kvm/x86.c | 50 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index b730d799c26e..63aa2b3d30ca 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -8035,6 +8035,7 @@ static __init int hardware_setup(void) } kvm_mce_cap_supported |= MCG_LMCE_P; + kvm_mce_cap_supported |= MCG_CMCI_P; if (pt_mode != PT_MODE_SYSTEM && pt_mode != PT_MODE_HOST_GUEST) return -EINVAL; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index eab1398cefa5..77b51c781998 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4797,6 +4797,52 @@ static int kvm_vcpu_ioctl_x86_setup_mce(struct kvm_vcpu *vcpu, return r; } +/* + * Validate this is an UCNA error by checking the MCG_STATUS and MCi_STATUS + * registers that none of the bits for Machine Check Exceptions are set and + * both the VAL (valid) and UC (uncorrectable) bits are set. + * UCNA - UnCorrectable No Action required + * SRAR - Software Recoverable Action Required + * MCI_STATUS_PCC - Processor Context Corrupted + * MCI_STATUS_S - Signaled as a Machine Check Exception + * MCI_STATUS_AR - This MCE is "software recoverable action required" + */ +static bool is_ucna(struct kvm_x86_mce *mce) +{ + return !mce->mcg_status && + !(mce->status & (MCI_STATUS_PCC | MCI_STATUS_S | MCI_STATUS_AR)) && + (mce->status & MCI_STATUS_VAL) && + (mce->status & MCI_STATUS_UC); +} + +static int kvm_vcpu_x86_set_ucna(struct kvm_vcpu *vcpu, struct kvm_x86_mce *mce) +{ + u64 mcg_cap = vcpu->arch.mcg_cap; + unsigned int bank_num = mcg_cap & 0xff; + u64 *banks = vcpu->arch.mce_banks; + + if (mce->bank >= bank_num) + return -EINVAL; + + if (!is_ucna(mce)) + return -EINVAL; + + banks += 4 * mce->bank; + banks[1] = mce->status; + banks[2] = mce->addr; + banks[3] = mce->misc; + vcpu->arch.mcg_status = mce->mcg_status; + + if (!(mcg_cap & MCG_CMCI_P) || + !(vcpu->arch.mci_ctl2_banks[mce->bank] & MCI_CTL2_CMCI_EN)) + return 0; + + if (lapic_in_kernel(vcpu)) + kvm_apic_local_deliver(vcpu->arch.apic, APIC_LVTCMCI); + + return 0; +} + static int kvm_vcpu_ioctl_x86_set_mce(struct kvm_vcpu *vcpu, struct kvm_x86_mce *mce) { @@ -4806,6 +4852,10 @@ static int kvm_vcpu_ioctl_x86_set_mce(struct kvm_vcpu *vcpu, if (mce->bank >= bank_num || !(mce->status & MCI_STATUS_VAL)) return -EINVAL; + + if (is_ucna(mce)) + return kvm_vcpu_x86_set_ucna(vcpu, mce); + /* * if IA32_MCG_CTL is not all 1s, the uncorrected error * reporting is disabled -- 2.36.0.550.gb090851708-goog