]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
KVM: SVM: Disable x2AVIC RDMSR interception for MSRs KVM actually supports
authorSean Christopherson <seanjc@google.com>
Thu, 14 May 2026 21:31:14 +0000 (14:31 -0700)
committerSean Christopherson <seanjc@google.com>
Fri, 22 May 2026 23:28:30 +0000 (16:28 -0700)
When toggling x2AVIC on/off, use KVM's curated mask of x2APIC MSRs that
can/should be passed through to the guest (or not) when 2AVIC is enabled.
Using the effective list provided by the local APIC emulation fixes
multiple (classes of) bugs, as the existing hand-coded list of MSRs is
wrong on multiple fronts:

 - ARBPRI isn't supported by KVM, isn't accelerated by AVIC (for read or
   write), and its #VMEXIT is fault-like, i.e. requires decoding the
   instruction.  Disabling interception is nonsensical and suboptimal.

 - DFR and ICR2 aren't supported by x2APIC and so don't need their
   intercepts disabled for performance reasons.  While the #GP due to
   x2APIC being abled has higher priority than the trap-like #VMEXIT,
   disabling interception of unsupported MSRs is confusing and unnecessary.

 - RRR is completely unsupported.

 - AVIC currently fails to pass through the "range of vectors" registers,
   IRR, ISR, and TMR, as e.g. X2APIC_MSR(APIC_IRR) only affects IRR0, and
   thus only disables intercept for vectors 31:0 (which are the *least*
   interesting registers).

 - TMCCT (the current APIC timer count) isn't accelerated by hardware, and
   generates a fault-like AVIC_UNACCELERATED_ACCESS #VMEXIT, i.e. requires
   KVM to decode the instruction to figure out what the guest was trying to
   access.  Note, the only reason this isn't a fatal bug is that the AVIC
   architecture had the foresight to guard against buggy hypervisors.  E.g.
   if hardware simply read from the virtual APIC page, the guest would get
   garbage (because the timer is emulated in software).

Fixes: 4d1d7942e36a ("KVM: SVM: Introduce logic to (de)activate x2AVIC mode")
Cc: stable@vger.kernel.org
Reviewed-by: Naveen N Rao (AMD) <naveen@kernel.org>
Link: https://patch.msgid.link/20260514213115.1637082-3-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
arch/x86/kvm/svm/avic.c

index adf211860949a205820f73fe023fa01c3d86f205..8e4926c7b8dcdc9c3336d64341f19b20fd8924c0 100644 (file)
@@ -122,6 +122,9 @@ static u32 x2avic_max_physical_id;
 static void avic_set_x2apic_msr_interception(struct vcpu_svm *svm,
                                             bool intercept)
 {
+       struct kvm_vcpu *vcpu = &svm->vcpu;
+       u64 rd_regs;
+
        static const u32 x2avic_passthrough_msrs[] = {
                X2APIC_MSR(APIC_ID),
                X2APIC_MSR(APIC_LVR),
@@ -162,9 +165,15 @@ static void avic_set_x2apic_msr_interception(struct vcpu_svm *svm,
        if (!x2avic_enabled)
                return;
 
+       rd_regs = kvm_x2apic_disable_read_intercept_reg_mask(vcpu);
+
+       for_each_set_bit(i, (unsigned long *)&rd_regs, BITS_PER_TYPE(rd_regs))
+               svm_set_intercept_for_msr(vcpu, APIC_BASE_MSR + i,
+                                         MSR_TYPE_R, intercept);
+
        for (i = 0; i < ARRAY_SIZE(x2avic_passthrough_msrs); i++)
-               svm_set_intercept_for_msr(&svm->vcpu, x2avic_passthrough_msrs[i],
-                                         MSR_TYPE_RW, intercept);
+               svm_set_intercept_for_msr(vcpu, x2avic_passthrough_msrs[i],
+                                         MSR_TYPE_W, intercept);
 
        svm->x2avic_msrs_intercepted = intercept;
 }