In VMX non-root operation, new behavior applies to virtualize WRMSR to vICR in x2APIC mode. Depending on settings of the VM-execution controls, CPU would produce APIC-write VM-exit following the 64-bit value written to offset 300H on the virtual-APIC page(vICR). KVM needs to retrieve the value written by CPU and emulate the vICR write to deliver an interrupt. Current KVM doesn't consider to handle the 64-bit setting on vICR in trap-like APIC-write VM-exit. Because using kvm_lapic_reg_write() to emulate writes to APIC_ICR requires the APIC_ICR2 is already programmed correctly. But in the above APIC-write VM-exit, CPU writes the whole 64 bits to APIC_ICR rather than program higher 32 bits and lower 32 bits to APIC_ICR2 and APIC_ICR respectively. So, KVM needs to retrieve the whole 64-bit value and program higher 32 bits to APIC_ICR2 first. Signed-off-by: Zeng Guang <guang.zeng@xxxxxxxxx> --- arch/x86/kvm/lapic.c | 12 +++++++++--- arch/x86/kvm/lapic.h | 5 +++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index f206fc35deff..3ce7142ba00e 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -2186,15 +2186,21 @@ EXPORT_SYMBOL_GPL(kvm_lapic_set_eoi); /* emulate APIC access in a trap manner */ void kvm_apic_write_nodecode(struct kvm_vcpu *vcpu, u32 offset) { - u32 val = 0; + struct kvm_lapic *apic = vcpu->arch.apic; + u64 val = 0; /* hw has done the conditional check and inst decode */ offset &= 0xff0; - kvm_lapic_reg_read(vcpu->arch.apic, offset, 4, &val); + /* exception dealing with 64bit data on vICR in x2apic mode */ + if ((offset == APIC_ICR) && apic_x2apic_mode(apic)) { + val = kvm_lapic_get_reg64(apic, offset); + kvm_lapic_reg_write(apic, APIC_ICR2, (u32)(val>>32)); + } else + kvm_lapic_reg_read(apic, offset, 4, &val); /* TODO: optimize to just emulate side effect w/o one more write */ - kvm_lapic_reg_write(vcpu->arch.apic, offset, val); + kvm_lapic_reg_write(apic, offset, (u32)val); } EXPORT_SYMBOL_GPL(kvm_apic_write_nodecode); diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index 2b44e533fc8d..91864e401a64 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h @@ -158,6 +158,11 @@ static inline u32 kvm_lapic_get_reg(struct kvm_lapic *apic, int reg_off) return *((u32 *) (apic->regs + reg_off)); } +static inline u64 kvm_lapic_get_reg64(struct kvm_lapic *apic, int reg_off) +{ + return *((u64 *) (apic->regs + reg_off)); +} + static inline void __kvm_lapic_set_reg(char *regs, int reg_off, u32 val) { *((u32 *) (regs + reg_off)) = val; -- 2.27.0