Test that the default behavior of KVM is to ignore userspace MSR writes and conditionally expose the "{load,clear} IA32_BNDCFGS" bits in the VMX control MSRs if the guest CPUID exposes MPX. Additionally, test that when the corresponding quirk is disabled, userspace can still clear these bits regardless of what is exposed in CPUID. Signed-off-by: Oliver Upton <oupton@xxxxxxxxxx> --- .../selftests/kvm/include/x86_64/vmx.h | 2 + .../kvm/x86_64/vmx_control_msrs_test.c | 97 +++++++++++++++++++ 2 files changed, 99 insertions(+) diff --git a/tools/testing/selftests/kvm/include/x86_64/vmx.h b/tools/testing/selftests/kvm/include/x86_64/vmx.h index 583ceb0d1457..811c66d9be74 100644 --- a/tools/testing/selftests/kvm/include/x86_64/vmx.h +++ b/tools/testing/selftests/kvm/include/x86_64/vmx.h @@ -80,6 +80,7 @@ #define VM_EXIT_SAVE_IA32_EFER 0x00100000 #define VM_EXIT_LOAD_IA32_EFER 0x00200000 #define VM_EXIT_SAVE_VMX_PREEMPTION_TIMER 0x00400000 +#define VM_EXIT_CLEAR_BNDCFGS 0x00800000 #define VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR 0x00036dff @@ -90,6 +91,7 @@ #define VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL 0x00002000 #define VM_ENTRY_LOAD_IA32_PAT 0x00004000 #define VM_ENTRY_LOAD_IA32_EFER 0x00008000 +#define VM_ENTRY_LOAD_BNDCFGS 0x00010000 #define VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR 0x000011ff diff --git a/tools/testing/selftests/kvm/x86_64/vmx_control_msrs_test.c b/tools/testing/selftests/kvm/x86_64/vmx_control_msrs_test.c index 4ab780483e15..132e7e435bfa 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_control_msrs_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_control_msrs_test.c @@ -138,6 +138,102 @@ static void load_perf_global_ctrl_test(struct kvm_vm *vm) VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL, /* clear */ 0, /* exp_set */ VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL); /* exp_clear */ + + /* cleanup, enable the quirk again */ + cap.args[0] = 0; + vm_enable_cap(vm, &cap); +} + +static void clear_mpx_bit(struct kvm_cpuid2 *cpuid) +{ + struct kvm_cpuid_entry2 ent; + + ent = *kvm_get_supported_cpuid_index(0x7, 0x0); + ent.ebx &= ~(1u << 14); + + TEST_ASSERT(set_cpuid(cpuid, &ent), + "failed to clear CPUID.07H:EBX[14] (MPX)"); +} + +static void bndcfgs_test(struct kvm_vm *vm) +{ + uint32_t entry_low, entry_high, exit_low, exit_high; + struct kvm_enable_cap cap = {0}; + struct kvm_cpuid2 *cpuid; + + get_vmx_control_msr(vm, MSR_IA32_VMX_TRUE_ENTRY_CTLS, &entry_low, &entry_high); + get_vmx_control_msr(vm, MSR_IA32_VMX_TRUE_EXIT_CTLS, &exit_low, &exit_high); + + if (!(entry_high & VM_ENTRY_LOAD_BNDCFGS) || + !(exit_high & VM_EXIT_CLEAR_BNDCFGS)) { + print_skip("\"load/clear IA32_BNDCFGS\" VM-{Entry,Exit} controls not supported"); + return; + } + + /* + * Test that KVM will set these bits regardless of userspace if the + * guest CPUID exposes MPX. + */ + test_vmx_control_msr(vm, MSR_IA32_VMX_TRUE_ENTRY_CTLS, + 0, /* set */ + VM_ENTRY_LOAD_BNDCFGS, /* clear */ + VM_ENTRY_LOAD_BNDCFGS, /* exp_set */ + 0); /* exp_clear */ + test_vmx_control_msr(vm, MSR_IA32_VMX_TRUE_EXIT_CTLS, + 0, /* set */ + VM_EXIT_CLEAR_BNDCFGS, /* clear */ + VM_EXIT_CLEAR_BNDCFGS, /* exp_set */ + 0); /* exp_clear */ + + /* + * Hide MPX in CPUID + */ + cpuid = _kvm_get_supported_cpuid(); + clear_mpx_bit(cpuid); + vcpu_set_cpuid(vm, VCPU_ID, cpuid); + free(cpuid); + + /* + * Test that KVM will clear these bits if the guest CPUID does not + * expose MPX + */ + test_vmx_control_msr(vm, MSR_IA32_VMX_TRUE_ENTRY_CTLS, + 0, /* set */ + 0, /* clear */ + 0, /* exp_set */ + VM_ENTRY_LOAD_BNDCFGS); /* exp_clear */ + test_vmx_control_msr(vm, MSR_IA32_VMX_TRUE_EXIT_CTLS, + 0, /* set */ + 0, /* clear */ + 0, /* exp_set */ + VM_EXIT_CLEAR_BNDCFGS); /* exp_clear */ + + /* + * Re-enable MPX in CPUID + */ + vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); + + /* + * Disable the quirk, giving userspace control of the VMX capability + * MSRs. + */ + cap.cap = KVM_CAP_DISABLE_QUIRKS2; + cap.args[0] = KVM_X86_QUIRK_TWEAK_VMX_CTRL_MSRS; + vm_enable_cap(vm, &cap); + + /* + * Test that userspace can clear these bits, even if it exposes MPX. + */ + test_vmx_control_msr(vm, MSR_IA32_VMX_TRUE_ENTRY_CTLS, + 0, /* set */ + VM_ENTRY_LOAD_BNDCFGS, /* clear */ + 0, /* exp_set */ + VM_ENTRY_LOAD_BNDCFGS); /* exp_clear */ + test_vmx_control_msr(vm, MSR_IA32_VMX_TRUE_EXIT_CTLS, + 0, /* set */ + VM_EXIT_CLEAR_BNDCFGS, /* clear */ + 0, /* exp_set */ + VM_EXIT_CLEAR_BNDCFGS); /* exp_clear */ } int main(void) @@ -155,6 +251,7 @@ int main(void) vm = vm_create_default(VCPU_ID, 0, NULL); load_perf_global_ctrl_test(vm); + bndcfgs_test(vm); kvm_vm_free(vm); } -- 2.35.1.574.g5d30c73bfb-goog