Commit b00471a5 authored by Paolo Bonzini's avatar Paolo Bonzini

Merge tag 'kvm-x86-vmx-6.9' of https://github.com/kvm-x86/linux into HEAD

KVM VMX changes for 6.9:

 - Fix a bug where KVM would report stale/bogus exit qualification information
   when exiting to userspace due to an unexpected VM-Exit while the CPU was
   vectoring an exception.

 - Add a VMX flag in /proc/cpuinfo to report 5-level EPT support.

 - Clean up the logic for massaging the passthrough MSR bitmaps when userspace
   changes its MSR filter.
parents 41ebae2e 259720c3
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#define VMX_FEATURE_EPT_EXECUTE_ONLY ( 0*32+ 17) /* "ept_x_only" EPT entries can be execute only */ #define VMX_FEATURE_EPT_EXECUTE_ONLY ( 0*32+ 17) /* "ept_x_only" EPT entries can be execute only */
#define VMX_FEATURE_EPT_AD ( 0*32+ 18) /* EPT Accessed/Dirty bits */ #define VMX_FEATURE_EPT_AD ( 0*32+ 18) /* EPT Accessed/Dirty bits */
#define VMX_FEATURE_EPT_1GB ( 0*32+ 19) /* 1GB EPT pages */ #define VMX_FEATURE_EPT_1GB ( 0*32+ 19) /* 1GB EPT pages */
#define VMX_FEATURE_EPT_5LEVEL ( 0*32+ 20) /* 5-level EPT paging */
/* Aggregated APIC features 24-27 */ /* Aggregated APIC features 24-27 */
#define VMX_FEATURE_FLEXPRIORITY ( 0*32+ 24) /* TPR shadow + virt APIC */ #define VMX_FEATURE_FLEXPRIORITY ( 0*32+ 24) /* TPR shadow + virt APIC */
......
...@@ -72,6 +72,8 @@ static void init_vmx_capabilities(struct cpuinfo_x86 *c) ...@@ -72,6 +72,8 @@ static void init_vmx_capabilities(struct cpuinfo_x86 *c)
c->vmx_capability[MISC_FEATURES] |= VMX_F(EPT_AD); c->vmx_capability[MISC_FEATURES] |= VMX_F(EPT_AD);
if (ept & VMX_EPT_1GB_PAGE_BIT) if (ept & VMX_EPT_1GB_PAGE_BIT)
c->vmx_capability[MISC_FEATURES] |= VMX_F(EPT_1GB); c->vmx_capability[MISC_FEATURES] |= VMX_F(EPT_1GB);
if (ept & VMX_EPT_PAGE_WALK_5_BIT)
c->vmx_capability[MISC_FEATURES] |= VMX_F(EPT_5LEVEL);
/* Synthetic APIC features that are aggregates of multiple features. */ /* Synthetic APIC features that are aggregates of multiple features. */
if ((c->vmx_capability[PRIMARY_CTLS] & VMX_F(VIRTUAL_TPR)) && if ((c->vmx_capability[PRIMARY_CTLS] & VMX_F(VIRTUAL_TPR)) &&
......
...@@ -161,7 +161,7 @@ module_param(allow_smaller_maxphyaddr, bool, S_IRUGO); ...@@ -161,7 +161,7 @@ module_param(allow_smaller_maxphyaddr, bool, S_IRUGO);
/* /*
* List of MSRs that can be directly passed to the guest. * List of MSRs that can be directly passed to the guest.
* In addition to these x2apic and PT MSRs are handled specially. * In addition to these x2apic, PT and LBR MSRs are handled specially.
*/ */
static u32 vmx_possible_passthrough_msrs[MAX_POSSIBLE_PASSTHROUGH_MSRS] = { static u32 vmx_possible_passthrough_msrs[MAX_POSSIBLE_PASSTHROUGH_MSRS] = {
MSR_IA32_SPEC_CTRL, MSR_IA32_SPEC_CTRL,
...@@ -669,25 +669,14 @@ static inline bool cpu_need_virtualize_apic_accesses(struct kvm_vcpu *vcpu) ...@@ -669,25 +669,14 @@ static inline bool cpu_need_virtualize_apic_accesses(struct kvm_vcpu *vcpu)
return flexpriority_enabled && lapic_in_kernel(vcpu); return flexpriority_enabled && lapic_in_kernel(vcpu);
} }
static int possible_passthrough_msr_slot(u32 msr) static int vmx_get_passthrough_msr_slot(u32 msr)
{ {
u32 i; int i;
for (i = 0; i < ARRAY_SIZE(vmx_possible_passthrough_msrs); i++)
if (vmx_possible_passthrough_msrs[i] == msr)
return i;
return -ENOENT;
}
static bool is_valid_passthrough_msr(u32 msr)
{
bool r;
switch (msr) { switch (msr) {
case 0x800 ... 0x8ff: case 0x800 ... 0x8ff:
/* x2APIC MSRs. These are handled in vmx_update_msr_bitmap_x2apic() */ /* x2APIC MSRs. These are handled in vmx_update_msr_bitmap_x2apic() */
return true; return -ENOENT;
case MSR_IA32_RTIT_STATUS: case MSR_IA32_RTIT_STATUS:
case MSR_IA32_RTIT_OUTPUT_BASE: case MSR_IA32_RTIT_OUTPUT_BASE:
case MSR_IA32_RTIT_OUTPUT_MASK: case MSR_IA32_RTIT_OUTPUT_MASK:
...@@ -702,14 +691,16 @@ static bool is_valid_passthrough_msr(u32 msr) ...@@ -702,14 +691,16 @@ static bool is_valid_passthrough_msr(u32 msr)
case MSR_LBR_CORE_FROM ... MSR_LBR_CORE_FROM + 8: case MSR_LBR_CORE_FROM ... MSR_LBR_CORE_FROM + 8:
case MSR_LBR_CORE_TO ... MSR_LBR_CORE_TO + 8: case MSR_LBR_CORE_TO ... MSR_LBR_CORE_TO + 8:
/* LBR MSRs. These are handled in vmx_update_intercept_for_lbr_msrs() */ /* LBR MSRs. These are handled in vmx_update_intercept_for_lbr_msrs() */
return true; return -ENOENT;
} }
r = possible_passthrough_msr_slot(msr) != -ENOENT; for (i = 0; i < ARRAY_SIZE(vmx_possible_passthrough_msrs); i++) {
if (vmx_possible_passthrough_msrs[i] == msr)
WARN(!r, "Invalid MSR %x, please adapt vmx_possible_passthrough_msrs[]", msr); return i;
}
return r; WARN(1, "Invalid MSR %x, please adapt vmx_possible_passthrough_msrs[]", msr);
return -ENOENT;
} }
struct vmx_uret_msr *vmx_find_uret_msr(struct vcpu_vmx *vmx, u32 msr) struct vmx_uret_msr *vmx_find_uret_msr(struct vcpu_vmx *vmx, u32 msr)
...@@ -3963,6 +3954,7 @@ void vmx_disable_intercept_for_msr(struct kvm_vcpu *vcpu, u32 msr, int type) ...@@ -3963,6 +3954,7 @@ void vmx_disable_intercept_for_msr(struct kvm_vcpu *vcpu, u32 msr, int type)
{ {
struct vcpu_vmx *vmx = to_vmx(vcpu); struct vcpu_vmx *vmx = to_vmx(vcpu);
unsigned long *msr_bitmap = vmx->vmcs01.msr_bitmap; unsigned long *msr_bitmap = vmx->vmcs01.msr_bitmap;
int idx;
if (!cpu_has_vmx_msr_bitmap()) if (!cpu_has_vmx_msr_bitmap())
return; return;
...@@ -3973,16 +3965,13 @@ void vmx_disable_intercept_for_msr(struct kvm_vcpu *vcpu, u32 msr, int type) ...@@ -3973,16 +3965,13 @@ void vmx_disable_intercept_for_msr(struct kvm_vcpu *vcpu, u32 msr, int type)
* Mark the desired intercept state in shadow bitmap, this is needed * Mark the desired intercept state in shadow bitmap, this is needed
* for resync when the MSR filters change. * for resync when the MSR filters change.
*/ */
if (is_valid_passthrough_msr(msr)) { idx = vmx_get_passthrough_msr_slot(msr);
int idx = possible_passthrough_msr_slot(msr); if (idx >= 0) {
if (idx != -ENOENT) {
if (type & MSR_TYPE_R) if (type & MSR_TYPE_R)
clear_bit(idx, vmx->shadow_msr_intercept.read); clear_bit(idx, vmx->shadow_msr_intercept.read);
if (type & MSR_TYPE_W) if (type & MSR_TYPE_W)
clear_bit(idx, vmx->shadow_msr_intercept.write); clear_bit(idx, vmx->shadow_msr_intercept.write);
} }
}
if ((type & MSR_TYPE_R) && if ((type & MSR_TYPE_R) &&
!kvm_msr_allowed(vcpu, msr, KVM_MSR_FILTER_READ)) { !kvm_msr_allowed(vcpu, msr, KVM_MSR_FILTER_READ)) {
...@@ -4007,6 +3996,7 @@ void vmx_enable_intercept_for_msr(struct kvm_vcpu *vcpu, u32 msr, int type) ...@@ -4007,6 +3996,7 @@ void vmx_enable_intercept_for_msr(struct kvm_vcpu *vcpu, u32 msr, int type)
{ {
struct vcpu_vmx *vmx = to_vmx(vcpu); struct vcpu_vmx *vmx = to_vmx(vcpu);
unsigned long *msr_bitmap = vmx->vmcs01.msr_bitmap; unsigned long *msr_bitmap = vmx->vmcs01.msr_bitmap;
int idx;
if (!cpu_has_vmx_msr_bitmap()) if (!cpu_has_vmx_msr_bitmap())
return; return;
...@@ -4017,16 +4007,13 @@ void vmx_enable_intercept_for_msr(struct kvm_vcpu *vcpu, u32 msr, int type) ...@@ -4017,16 +4007,13 @@ void vmx_enable_intercept_for_msr(struct kvm_vcpu *vcpu, u32 msr, int type)
* Mark the desired intercept state in shadow bitmap, this is needed * Mark the desired intercept state in shadow bitmap, this is needed
* for resync when the MSR filter changes. * for resync when the MSR filter changes.
*/ */
if (is_valid_passthrough_msr(msr)) { idx = vmx_get_passthrough_msr_slot(msr);
int idx = possible_passthrough_msr_slot(msr); if (idx >= 0) {
if (idx != -ENOENT) {
if (type & MSR_TYPE_R) if (type & MSR_TYPE_R)
set_bit(idx, vmx->shadow_msr_intercept.read); set_bit(idx, vmx->shadow_msr_intercept.read);
if (type & MSR_TYPE_W) if (type & MSR_TYPE_W)
set_bit(idx, vmx->shadow_msr_intercept.write); set_bit(idx, vmx->shadow_msr_intercept.write);
} }
}
if (type & MSR_TYPE_R) if (type & MSR_TYPE_R)
vmx_set_msr_bitmap_read(msr_bitmap, msr); vmx_set_msr_bitmap_read(msr_bitmap, msr);
...@@ -4136,6 +4123,9 @@ static void vmx_msr_filter_changed(struct kvm_vcpu *vcpu) ...@@ -4136,6 +4123,9 @@ static void vmx_msr_filter_changed(struct kvm_vcpu *vcpu)
struct vcpu_vmx *vmx = to_vmx(vcpu); struct vcpu_vmx *vmx = to_vmx(vcpu);
u32 i; u32 i;
if (!cpu_has_vmx_msr_bitmap())
return;
/* /*
* Redo intercept permissions for MSRs that KVM is passing through to * Redo intercept permissions for MSRs that KVM is passing through to
* the guest. Disabling interception will check the new MSR filter and * the guest. Disabling interception will check the new MSR filter and
...@@ -6539,7 +6529,7 @@ static int __vmx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath) ...@@ -6539,7 +6529,7 @@ static int __vmx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)
vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_DELIVERY_EV; vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_DELIVERY_EV;
vcpu->run->internal.data[0] = vectoring_info; vcpu->run->internal.data[0] = vectoring_info;
vcpu->run->internal.data[1] = exit_reason.full; vcpu->run->internal.data[1] = exit_reason.full;
vcpu->run->internal.data[2] = vcpu->arch.exit_qualification; vcpu->run->internal.data[2] = vmx_get_exit_qual(vcpu);
if (exit_reason.basic == EXIT_REASON_EPT_MISCONFIG) { if (exit_reason.basic == EXIT_REASON_EPT_MISCONFIG) {
vcpu->run->internal.data[ndata++] = vcpu->run->internal.data[ndata++] =
vmcs_read64(GUEST_PHYSICAL_ADDRESS); vmcs_read64(GUEST_PHYSICAL_ADDRESS);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment