Skip to content

Commit

Permalink
KVM: VMX: Always intercept accesses to unsupported "extended" x2APIC …
Browse files Browse the repository at this point in the history
…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>
  • Loading branch information
sean-jc committed Jan 19, 2023
1 parent 1088d5e commit cbb3f75
Showing 1 changed file with 20 additions and 18 deletions.
38 changes: 20 additions & 18 deletions arch/x86/kvm/vmx/vmx.c
Original file line number Diff line number Diff line change
Expand Up @@ -4018,26 +4018,17 @@ void vmx_enable_intercept_for_msr(struct kvm_vcpu *vcpu, u32 msr, int type)
vmx_set_msr_bitmap_write(msr_bitmap, msr);
}

static void vmx_reset_x2apic_msrs(struct kvm_vcpu *vcpu, u8 mode)
{
unsigned long *msr_bitmap = to_vmx(vcpu)->vmcs01.msr_bitmap;
unsigned long read_intercept;
int msr;

read_intercept = (mode & MSR_BITMAP_MODE_X2APIC_APICV) ? 0 : ~0;

for (msr = 0x800; msr <= 0x8ff; msr += BITS_PER_LONG) {
unsigned int read_idx = msr / BITS_PER_LONG;
unsigned int write_idx = read_idx + (0x800 / sizeof(long));

msr_bitmap[read_idx] = read_intercept;
msr_bitmap[write_idx] = ~0ul;
}
}

static void vmx_update_msr_bitmap_x2apic(struct kvm_vcpu *vcpu)
{
/*
* x2APIC indices for 64-bit accesses into the RDMSR and WRMSR halves
* of the MSR bitmap. KVM emulates APIC registers up through 0x3f0,
* i.e. MSR 0x83f, and so only needs to dynamically manipulate 64 bits.
*/
const int read_idx = APIC_BASE_MSR / BITS_PER_LONG_LONG;
const int write_idx = read_idx + (0x800 / sizeof(u64));
struct vcpu_vmx *vmx = to_vmx(vcpu);
u64 *msr_bitmap = (u64 *)vmx->vmcs01.msr_bitmap;
u8 mode;

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

vmx->x2apic_msr_bitmap_mode = mode;

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

/*
* TPR reads and writes can be virtualized even if virtual interrupt
Expand Down

0 comments on commit cbb3f75

Please sign in to comment.