KVM: x86: Add helpers to handle 64-bit APIC MSR read/writes
authorSean Christopherson <seanjc@google.com>
Fri, 4 Feb 2022 21:42:02 +0000 (21:42 +0000)
committerPaolo Bonzini <pbonzini@redhat.com>
Tue, 1 Mar 2022 13:50:47 +0000 (08:50 -0500)
Add helpers to handle 64-bit APIC read/writes via MSRs to deduplicate the
x2APIC and Hyper-V code needed to service reads/writes to ICR.  Future
support for IPI virtualization will add yet another path where KVM must
handle 64-bit APIC MSR reads/write (to ICR).

Opportunistically fix the comment in the write path; ICR2 holds the
destination (if there's no shorthand), not the vector.

No functional change intended.

Signed-off-by: Sean Christopherson <seanjc@google.com>
Message-Id: <20220204214205.3306634-9-seanjc@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/kvm/lapic.c

index 90b49f9..05a6f69 100644 (file)
@@ -2774,6 +2774,30 @@ int kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr)
        return 0;
 }
 
+static int kvm_lapic_msr_read(struct kvm_lapic *apic, u32 reg, u64 *data)
+{
+       u32 low, high = 0;
+
+       if (kvm_lapic_reg_read(apic, reg, 4, &low))
+               return 1;
+
+       if (reg == APIC_ICR &&
+           WARN_ON_ONCE(kvm_lapic_reg_read(apic, APIC_ICR2, 4, &high)))
+               return 1;
+
+       *data = (((u64)high) << 32) | low;
+
+       return 0;
+}
+
+static int kvm_lapic_msr_write(struct kvm_lapic *apic, u32 reg, u64 data)
+{
+       /* For 64-bit ICR writes, set ICR2 (dest) before ICR (command). */
+       if (reg == APIC_ICR)
+               kvm_lapic_reg_write(apic, APIC_ICR2, (u32)(data >> 32));
+       return kvm_lapic_reg_write(apic, reg, (u32)data);
+}
+
 int kvm_x2apic_msr_write(struct kvm_vcpu *vcpu, u32 msr, u64 data)
 {
        struct kvm_lapic *apic = vcpu->arch.apic;
@@ -2785,16 +2809,13 @@ int kvm_x2apic_msr_write(struct kvm_vcpu *vcpu, u32 msr, u64 data)
        if (reg == APIC_ICR2)
                return 1;
 
-       /* if this is ICR write vector before command */
-       if (reg == APIC_ICR)
-               kvm_lapic_reg_write(apic, APIC_ICR2, (u32)(data >> 32));
-       return kvm_lapic_reg_write(apic, reg, (u32)data);
+       return kvm_lapic_msr_write(apic, reg, data);
 }
 
 int kvm_x2apic_msr_read(struct kvm_vcpu *vcpu, u32 msr, u64 *data)
 {
        struct kvm_lapic *apic = vcpu->arch.apic;
-       u32 reg = (msr - APIC_BASE_MSR) << 4, low, high = 0;
+       u32 reg = (msr - APIC_BASE_MSR) << 4;
 
        if (!lapic_in_kernel(vcpu) || !apic_x2apic_mode(apic))
                return 1;
@@ -2802,45 +2823,23 @@ int kvm_x2apic_msr_read(struct kvm_vcpu *vcpu, u32 msr, u64 *data)
        if (reg == APIC_DFR || reg == APIC_ICR2)
                return 1;
 
-       if (kvm_lapic_reg_read(apic, reg, 4, &low))
-               return 1;
-       if (reg == APIC_ICR)
-               kvm_lapic_reg_read(apic, APIC_ICR2, 4, &high);
-
-       *data = (((u64)high) << 32) | low;
-
-       return 0;
+       return kvm_lapic_msr_read(apic, reg, data);
 }
 
 int kvm_hv_vapic_msr_write(struct kvm_vcpu *vcpu, u32 reg, u64 data)
 {
-       struct kvm_lapic *apic = vcpu->arch.apic;
-
        if (!lapic_in_kernel(vcpu))
                return 1;
 
-       /* if this is ICR write vector before command */
-       if (reg == APIC_ICR)
-               kvm_lapic_reg_write(apic, APIC_ICR2, (u32)(data >> 32));
-       return kvm_lapic_reg_write(apic, reg, (u32)data);
+       return kvm_lapic_msr_write(vcpu->arch.apic, reg, data);
 }
 
 int kvm_hv_vapic_msr_read(struct kvm_vcpu *vcpu, u32 reg, u64 *data)
 {
-       struct kvm_lapic *apic = vcpu->arch.apic;
-       u32 low, high = 0;
-
        if (!lapic_in_kernel(vcpu))
                return 1;
 
-       if (kvm_lapic_reg_read(apic, reg, 4, &low))
-               return 1;
-       if (reg == APIC_ICR)
-               kvm_lapic_reg_read(apic, APIC_ICR2, 4, &high);
-
-       *data = (((u64)high) << 32) | low;
-
-       return 0;
+       return kvm_lapic_msr_read(vcpu->arch.apic, reg, data);
 }
 
 int kvm_lapic_set_pv_eoi(struct kvm_vcpu *vcpu, u64 data, unsigned long len)