Modify the APIC register mask infrastructure to support both standard APIC registers (0x0-0x3f0) and extended APIC registers (0x400-0x530). This refactoring: - Replaces the single u64 bitmask with a u64[2] array to accommodate the extended register range(128 bitmask) - Updates the APIC_REG_MASK macro to handle both standard and extended register spaces - Adapts kvm_lapic_readable_reg_mask() to use the new approach - Adds APIC_REG_TEST macro to check register validity for standard APIC registers and Exended APIC registers - Updates all callers to use the new interface This is purely an infrastructure change to support the upcoming extended APIC register emulation. Suggested-by: Dapeng Mi Signed-off-by: Manali Shukla --- arch/x86/kvm/lapic.c | 99 ++++++++++++++++++++++++++---------------- arch/x86/kvm/lapic.h | 2 +- arch/x86/kvm/vmx/vmx.c | 10 +++-- 3 files changed, 70 insertions(+), 41 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index e19545b8cc98..f92e3f53ee75 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -1587,53 +1587,77 @@ static inline struct kvm_lapic *to_lapic(struct kvm_io_device *dev) return container_of(dev, struct kvm_lapic, dev); } -#define APIC_REG_MASK(reg) (1ull << ((reg) >> 4)) -#define APIC_REGS_MASK(first, count) \ - (APIC_REG_MASK(first) * ((1ull << (count)) - 1)) - -u64 kvm_lapic_readable_reg_mask(struct kvm_lapic *apic) -{ - /* Leave bits '0' for reserved and write-only registers. */ - u64 valid_reg_mask = - APIC_REG_MASK(APIC_ID) | - APIC_REG_MASK(APIC_LVR) | - APIC_REG_MASK(APIC_TASKPRI) | - APIC_REG_MASK(APIC_PROCPRI) | - APIC_REG_MASK(APIC_LDR) | - APIC_REG_MASK(APIC_SPIV) | - APIC_REGS_MASK(APIC_ISR, APIC_ISR_NR) | - APIC_REGS_MASK(APIC_TMR, APIC_ISR_NR) | - APIC_REGS_MASK(APIC_IRR, APIC_ISR_NR) | - APIC_REG_MASK(APIC_ESR) | - APIC_REG_MASK(APIC_ICR) | - APIC_REG_MASK(APIC_LVTT) | - APIC_REG_MASK(APIC_LVTTHMR) | - APIC_REG_MASK(APIC_LVTPC) | - APIC_REG_MASK(APIC_LVT0) | - APIC_REG_MASK(APIC_LVT1) | - APIC_REG_MASK(APIC_LVTERR) | - APIC_REG_MASK(APIC_TMICT) | - APIC_REG_MASK(APIC_TMCCT) | - APIC_REG_MASK(APIC_TDCR); +/* + * Helper macros for APIC register bitmask handling + * 2 element array is being used to represent 128-bit mask, where: + * - mask[0] tracks standard APIC registers (0x0-0x3f0) + * - mask[1] tracks extended APIC registers (0x400-0x530) + */ + +#define APIC_REG_INDEX(reg) (((reg) < 0x400) ? 0 : 1) +#define APIC_REG_BIT(reg) (((reg) < 0x400) ? ((reg) >> 4) : (((reg) - 0x400) >> 4)) + +/* Set a bit in the mask for a single APIC register. */ +#define APIC_REG_MASK(reg, mask) do { \ + (mask)[APIC_REG_INDEX(reg)] |= (1ULL << APIC_REG_BIT(reg)); \ +} while (0) + +/* Set bits in the mask for a range of consecutive APIC registers. */ +#define APIC_REGS_MASK(first, count, mask) do { \ + (mask)[APIC_REG_INDEX(first)] |= ((1ULL << (count)) - 1) << APIC_REG_BIT(first); \ +} while (0) + +/* Macro to check whether the an APIC register bit is set in the mask. */ +#define APIC_REG_TEST(reg, mask) \ + ((mask)[APIC_REG_INDEX(reg)] & (1ULL << APIC_REG_BIT(reg))) + +#define APIC_LAST_REG_OFFSET 0x3f0 +#define APIC_EXT_LAST_REG_OFFSET 0x530 + +void kvm_lapic_readable_reg_mask(struct kvm_lapic *apic, u64 mask[2]) +{ + mask[0] = 0; + mask[1] = 0; + + APIC_REG_MASK(APIC_ID, mask); + APIC_REG_MASK(APIC_LVR, mask); + APIC_REG_MASK(APIC_TASKPRI, mask); + APIC_REG_MASK(APIC_PROCPRI, mask); + APIC_REG_MASK(APIC_LDR, mask); + APIC_REG_MASK(APIC_SPIV, mask); + APIC_REGS_MASK(APIC_ISR, APIC_ISR_NR, mask); + APIC_REGS_MASK(APIC_TMR, APIC_ISR_NR, mask); + APIC_REGS_MASK(APIC_IRR, APIC_ISR_NR, mask); + APIC_REG_MASK(APIC_ESR, mask); + APIC_REG_MASK(APIC_ICR, mask); + APIC_REG_MASK(APIC_LVTT, mask); + APIC_REG_MASK(APIC_LVTTHMR, mask); + APIC_REG_MASK(APIC_LVTPC, mask); + APIC_REG_MASK(APIC_LVT0, mask); + APIC_REG_MASK(APIC_LVT1, mask); + APIC_REG_MASK(APIC_LVTERR, mask); + APIC_REG_MASK(APIC_TMICT, mask); + APIC_REG_MASK(APIC_TMCCT, mask); if (kvm_lapic_lvt_supported(apic, LVT_CMCI)) - valid_reg_mask |= APIC_REG_MASK(APIC_LVTCMCI); + APIC_REG_MASK(APIC_LVTCMCI, mask); /* 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); - - return valid_reg_mask; + if (!apic_x2apic_mode(apic)) { + APIC_REG_MASK(APIC_ARBPRI, mask); + APIC_REG_MASK(APIC_DFR, mask); + APIC_REG_MASK(APIC_ICR2, 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 int last_reg = APIC_LAST_REG_OFFSET; unsigned char alignment = offset & 0xf; u32 result; + u64 mask[2]; /* * WARN if KVM reads ICR in x2APIC mode, as it's an 8-byte register in @@ -1644,8 +1668,9 @@ static int kvm_lapic_reg_read(struct kvm_lapic *apic, u32 offset, int len, if (alignment + len > 4) return 1; - if (offset > 0x3f0 || - !(kvm_lapic_readable_reg_mask(apic) & APIC_REG_MASK(offset))) + kvm_lapic_readable_reg_mask(apic, mask); + + if (offset > last_reg || !APIC_REG_TEST(offset, mask)) return 1; result = __apic_read(apic, offset & ~0xf); diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index 8b00e29741de..a07f8524d04a 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h @@ -147,7 +147,7 @@ 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); +void kvm_lapic_readable_reg_mask(struct kvm_lapic *apic, u64 mask[2]); static inline void kvm_lapic_set_irr(int vec, struct kvm_lapic *apic) { diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 4a4691beba55..b13a20c9787e 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -4032,10 +4032,14 @@ static void vmx_update_msr_bitmap_x2apic(struct kvm_vcpu *vcpu) * through reads for all valid registers by default in x2APIC+APICv * mode, only the current timer count needs on-demand emulation by KVM. */ - if (mode & MSR_BITMAP_MODE_X2APIC_APICV) - msr_bitmap[read_idx] = ~kvm_lapic_readable_reg_mask(vcpu->arch.apic); - else + if (mode & MSR_BITMAP_MODE_X2APIC_APICV) { + u64 mask[2]; + + kvm_lapic_readable_reg_mask(vcpu->arch.apic, mask); + msr_bitmap[read_idx] = ~mask[0]; + } else { msr_bitmap[read_idx] = ~0ull; + } msr_bitmap[write_idx] = ~0ull; /* -- 2.43.0