This feature is only enabled when the vCPU has opted in to enable MCG_CMCI_P. Signed-off-by: Jue Wang <juew@xxxxxxxxxx> --- arch/x86/kvm/lapic.c | 33 ++++++++++++++++++++++++++------- arch/x86/kvm/lapic.h | 7 ++++++- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 2c770e4c0e6c..0b370ccd11a1 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -27,6 +27,7 @@ #include <linux/math64.h> #include <linux/slab.h> #include <asm/processor.h> +#include <asm/mce.h> #include <asm/msr.h> #include <asm/page.h> #include <asm/current.h> @@ -364,9 +365,14 @@ static inline int apic_lvt_nmi_mode(u32 lvt_val) return (lvt_val & (APIC_MODE_MASK | APIC_LVT_MASKED)) == APIC_DM_NMI; } +static inline bool kvm_is_cmci_supported(struct kvm_vcpu *vcpu) +{ + return vcpu->arch.mcg_cap & MCG_CMCI_P; +} + static inline int kvm_apic_get_nr_lvt_entries(struct kvm_vcpu *vcpu) { - return KVM_APIC_MAX_NR_LVT_ENTRIES; + return KVM_APIC_MAX_NR_LVT_ENTRIES - !kvm_is_cmci_supported(vcpu); } void kvm_apic_set_version(struct kvm_vcpu *vcpu) @@ -396,7 +402,8 @@ static const unsigned int apic_lvt_mask[KVM_APIC_MAX_NR_LVT_ENTRIES] = { [LVT_PERFORMANCE_COUNTER] = LVT_MASK | APIC_MODE_MASK, [LVT_LINT0] = LINT_MASK, [LVT_LINT1] = LINT_MASK, - [LVT_ERROR] = LVT_MASK + [LVT_ERROR] = LVT_MASK, + [LVT_CMCI] = LVT_MASK | APIC_MODE_MASK }; static int find_highest_vector(void *bitmap) @@ -1411,6 +1418,9 @@ int kvm_lapic_reg_read(struct kvm_lapic *apic, u32 offset, int len, APIC_REG_MASK(APIC_TMCCT) | APIC_REG_MASK(APIC_TDCR); + if (kvm_is_cmci_supported(apic->vcpu)) + valid_reg_mask |= APIC_REG_MASK(APIC_LVTCMCI); + /* ARBPRI is not valid on x2APIC */ if (!apic_x2apic_mode(apic)) valid_reg_mask |= APIC_REG_MASK(APIC_ARBPRI); @@ -2043,12 +2053,10 @@ int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) apic_set_spiv(apic, val & mask); if (!(val & APIC_SPIV_APIC_ENABLED)) { int i; - u32 lvt_val; - for (i = 0; i < KVM_APIC_MAX_NR_LVT_ENTRIES; i++) { - lvt_val = kvm_lapic_get_reg(apic, APIC_LVTx(i)); + for (i = 0; i < kvm_apic_get_nr_lvt_entries(apic->vcpu); i++) { kvm_lapic_set_reg(apic, APIC_LVTx(i), - lvt_val | APIC_LVT_MASKED); + kvm_lapic_get_reg(apic, APIC_LVTx(i)) | APIC_LVT_MASKED); } apic_update_lvtt(apic); atomic_set(&apic->lapic_timer.pending, 0); @@ -2098,6 +2106,17 @@ int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) apic_update_lvtt(apic); break; + case APIC_LVTCMCI: + if (!kvm_is_cmci_supported(apic->vcpu)) { + ret = 1; + break; + } + if (!kvm_apic_sw_enabled(apic)) + val |= APIC_LVT_MASKED; + val &= apic_lvt_mask[LVT_CMCI]; + kvm_lapic_set_reg(apic, APIC_LVTCMCI, val); + break; + case APIC_TMICT: if (apic_lvtt_tscdeadline(apic)) break; @@ -2346,7 +2365,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event) kvm_apic_set_xapic_id(apic, vcpu->vcpu_id); kvm_apic_set_version(apic->vcpu); - for (i = 0; i < KVM_APIC_MAX_NR_LVT_ENTRIES; i++) + for (i = 0; i < kvm_apic_get_nr_lvt_entries(vcpu); i++) kvm_lapic_set_reg(apic, APIC_LVTx(i), APIC_LVT_MASKED); apic_update_lvtt(apic); if (kvm_vcpu_is_reset_bsp(vcpu) && diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index 5666441d5d1b..9f9f74b17918 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h @@ -35,6 +35,7 @@ enum lapic_lvt_entry { LVT_LINT0, LVT_LINT1, LVT_ERROR, + LVT_CMCI, KVM_APIC_MAX_NR_LVT_ENTRIES, }; @@ -42,7 +43,11 @@ enum lapic_lvt_entry { #define APIC_LVTx(x) \ ({ \ - int __apic_reg = APIC_LVTT + 0x10 * (x); \ + int __apic_reg; \ + if ((x) == LVT_CMCI) \ + __apic_reg = APIC_LVTCMCI; \ + else \ + __apic_reg = APIC_LVTT + 0x10 * (x); \ __apic_reg; \ }) -- 2.35.1.1178.g4f1659d476-goog