Skip to content

Commit c39857c

Browse files
committed
KVM: VMX: Always intercept accesses to unsupported "extended" x2APIC regs
Don't clear the "read" bits for x2APIC registers above SELF_IPI (APIC regs 0x400 - 0xff0, MSRs 0x840 - 0x8ff). KVM doesn't emulate registers in that space (there are a smattering of AMD-only extensions) and so should intercept reads in order to inject #GP. When APICv is fully enabled, Intel hardware doesn't validate the registers on RDMSR and instead blindly retrieves data from the vAPIC page, i.e. it's software's responsibility to intercept reads to non-existent MSRs. Fixes: 8d14695 ("x86, apicv: add virtual x2apic support") Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com> Reviewed-by: Jim Mattson <jmattson@google.com> Link: https://lore.kernel.org/r/20230107011025.565472-6-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent b5fcc59 commit c39857c

1 file changed

Lines changed: 20 additions & 18 deletions

File tree

arch/x86/kvm/vmx/vmx.c

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4018,26 +4018,17 @@ void vmx_enable_intercept_for_msr(struct kvm_vcpu *vcpu, u32 msr, int type)
40184018
vmx_set_msr_bitmap_write(msr_bitmap, msr);
40194019
}
40204020

4021-
static void vmx_reset_x2apic_msrs(struct kvm_vcpu *vcpu, u8 mode)
4022-
{
4023-
unsigned long *msr_bitmap = to_vmx(vcpu)->vmcs01.msr_bitmap;
4024-
unsigned long read_intercept;
4025-
int msr;
4026-
4027-
read_intercept = (mode & MSR_BITMAP_MODE_X2APIC_APICV) ? 0 : ~0;
4028-
4029-
for (msr = 0x800; msr <= 0x8ff; msr += BITS_PER_LONG) {
4030-
unsigned int read_idx = msr / BITS_PER_LONG;
4031-
unsigned int write_idx = read_idx + (0x800 / sizeof(long));
4032-
4033-
msr_bitmap[read_idx] = read_intercept;
4034-
msr_bitmap[write_idx] = ~0ul;
4035-
}
4036-
}
4037-
40384021
static void vmx_update_msr_bitmap_x2apic(struct kvm_vcpu *vcpu)
40394022
{
4023+
/*
4024+
* x2APIC indices for 64-bit accesses into the RDMSR and WRMSR halves
4025+
* of the MSR bitmap. KVM emulates APIC registers up through 0x3f0,
4026+
* i.e. MSR 0x83f, and so only needs to dynamically manipulate 64 bits.
4027+
*/
4028+
const int read_idx = APIC_BASE_MSR / BITS_PER_LONG_LONG;
4029+
const int write_idx = read_idx + (0x800 / sizeof(u64));
40404030
struct vcpu_vmx *vmx = to_vmx(vcpu);
4031+
u64 *msr_bitmap = (u64 *)vmx->vmcs01.msr_bitmap;
40414032
u8 mode;
40424033

40434034
if (!cpu_has_vmx_msr_bitmap())
@@ -4058,7 +4049,18 @@ static void vmx_update_msr_bitmap_x2apic(struct kvm_vcpu *vcpu)
40584049

40594050
vmx->x2apic_msr_bitmap_mode = mode;
40604051

4061-
vmx_reset_x2apic_msrs(vcpu, mode);
4052+
/*
4053+
* Reset the bitmap for MSRs 0x800 - 0x83f. Leave AMD's uber-extended
4054+
* registers (0x840 and above) intercepted, KVM doesn't support them.
4055+
* Intercept all writes by default and poke holes as needed. Pass
4056+
* through all reads by default in x2APIC+APICv mode, as all registers
4057+
* except the current timer count are passed through for read.
4058+
*/
4059+
if (mode & MSR_BITMAP_MODE_X2APIC_APICV)
4060+
msr_bitmap[read_idx] = 0;
4061+
else
4062+
msr_bitmap[read_idx] = ~0ull;
4063+
msr_bitmap[write_idx] = ~0ull;
40624064

40634065
/*
40644066
* TPR reads and writes can be virtualized even if virtual interrupt

0 commit comments

Comments
 (0)