KVM: x86: Split out logic to generate "readable" APIC regs mask to helper
authorSean Christopherson <seanjc@google.com>
Sat, 7 Jan 2023 01:10:23 +0000 (01:10 +0000)
committerSean Christopherson <seanjc@google.com>
Tue, 24 Jan 2023 18:04:35 +0000 (10:04 -0800)
Move the generation of the readable APIC regs bitmask to a standalone
helper so that VMX can use the mask for its MSR interception bitmaps.

No functional change intended.

Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
Link: https://lore.kernel.org/r/20230107011025.565472-5-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
arch/x86/kvm/lapic.c
arch/x86/kvm/lapic.h

index 91e6f958d4b2fee6cb82635560b5b9b05ad5be0a..d2ad5e8b63a4405981780ced94c4bcb96116bd15 100644 (file)
@@ -1561,12 +1561,9 @@ static inline struct kvm_lapic *to_lapic(struct kvm_io_device *dev)
 #define APIC_REGS_MASK(first, count) \
        (APIC_REG_MASK(first) * ((1ull << (count)) - 1))
 
-static int kvm_lapic_reg_read(struct kvm_lapic *apic, u32 offset, int len,
-                             void *data)
+u64 kvm_lapic_readable_reg_mask(struct kvm_lapic *apic)
 {
-       unsigned char alignment = offset & 0xf;
-       u32 result;
-       /* this bitmask has a bit cleared for each reserved register */
+       /* Leave bits '0' for reserved and write-only registers. */
        u64 valid_reg_mask =
                APIC_REG_MASK(APIC_ID) |
                APIC_REG_MASK(APIC_LVR) |
@@ -1592,22 +1589,33 @@ static int kvm_lapic_reg_read(struct kvm_lapic *apic, u32 offset, int len,
        if (kvm_lapic_lvt_supported(apic, LVT_CMCI))
                valid_reg_mask |= APIC_REG_MASK(APIC_LVTCMCI);
 
-       /*
-        * ARBPRI, DFR, and ICR2 are not valid in x2APIC mode.  WARN if KVM
-        * reads ICR in x2APIC mode as it's an 8-byte register in x2APIC and
-        * needs to be manually handled by the caller.
-        */
+       /* ARBPRI, DFR, and ICR2 are not valid in x2APIC mode. */
        if (!apic_x2apic_mode(apic))
                valid_reg_mask |= APIC_REG_MASK(APIC_ARBPRI) |
                                  APIC_REG_MASK(APIC_DFR) |
                                  APIC_REG_MASK(APIC_ICR2);
-       else
-               WARN_ON_ONCE(offset == APIC_ICR);
+
+       return valid_reg_mask;
+}
+EXPORT_SYMBOL_GPL(kvm_lapic_readable_reg_mask);
+
+static int kvm_lapic_reg_read(struct kvm_lapic *apic, u32 offset, int len,
+                             void *data)
+{
+       unsigned char alignment = offset & 0xf;
+       u32 result;
+
+       /*
+        * WARN if KVM reads ICR in x2APIC mode, as it's an 8-byte register in
+        * x2APIC and needs to be manually handled by the caller.
+        */
+       WARN_ON_ONCE(apic_x2apic_mode(apic) && offset == APIC_ICR);
 
        if (alignment + len > 4)
                return 1;
 
-       if (offset > 0x3f0 || !(valid_reg_mask & APIC_REG_MASK(offset)))
+       if (offset > 0x3f0 ||
+           !(kvm_lapic_readable_reg_mask(apic) & APIC_REG_MASK(offset)))
                return 1;
 
        result = __apic_read(apic, offset & ~0xf);
index df316ede7546597e477cff6c471cd1818468a2a4..0a0ea4b5dd8ce7239b85f5d054828fd5f0eedb6b 100644 (file)
@@ -146,6 +146,8 @@ int kvm_hv_vapic_msr_read(struct kvm_vcpu *vcpu, u32 msr, u64 *data);
 int kvm_lapic_set_pv_eoi(struct kvm_vcpu *vcpu, u64 data, unsigned long len);
 void kvm_lapic_exit(void);
 
+u64 kvm_lapic_readable_reg_mask(struct kvm_lapic *apic);
+
 #define VEC_POS(v) ((v) & (32 - 1))
 #define REG_POS(v) (((v) >> 5) << 4)