@@ -74,6 +74,8 @@ $(TEST_DIR)/realmode.o: bits = $(if $(call cc-option,-m16,""),16,32)
$(TEST_DIR)/access_test.elf: $(TEST_DIR)/access.o
+$(TEST_DIR)/vmx.elf: $(TEST_DIR)/access.o
+
$(TEST_DIR)/kvmclock_test.elf: $(TEST_DIR)/kvmclock.o
$(TEST_DIR)/hyperv_synic.elf: $(TEST_DIR)/hyperv.o
@@ -347,6 +347,19 @@ extra_params = -cpu max,+vmx -append vmx_vmcs_shadow_test
arch = x86_64
groups = vmx
+[vmx_pf_exception_test]
+file = vmx.flat
+extra_params = -cpu max,+vmx -append vmx_pf_exception_test
+arch = x86_64
+groups = vmx nested_exception
+
+[vmx_pf_exception_test_reduced_maxphyaddr]
+file = vmx.flat
+extra_params = -cpu IvyBridge,phys-bits=36,host-phys-bits=off,+vmx -append vmx_pf_exception_test
+arch = x86_64
+groups = vmx nested_exception
+check = /sys/module/kvm_intel/parameters/allow_smaller_maxphyaddr=Y
+
[debug]
file = debug.flat
arch = x86_64
@@ -20,6 +20,7 @@
#include "alloc_page.h"
#include "smp.h"
#include "delay.h"
+#include "access.h"
#define VPID_CAP_INVVPID_TYPES_SHIFT 40
@@ -10658,6 +10659,53 @@ static void atomic_switch_overflow_msrs_test(void)
test_skip("Test is only supported on KVM");
}
+static void vmx_pf_exception_test_guest(void)
+{
+ ac_test_run(PT_LEVEL_PML4);
+}
+
+static void vmx_pf_exception_test(void)
+{
+ u64 efer;
+ struct cpuid cpuid;
+
+ test_set_guest(vmx_pf_exception_test_guest);
+
+ enter_guest();
+
+ while (vmcs_read(EXI_REASON) != VMX_VMCALL) {
+ switch (vmcs_read(EXI_REASON)) {
+ case VMX_RDMSR:
+ assert(regs.rcx == MSR_EFER);
+ efer = vmcs_read(GUEST_EFER);
+ regs.rdx = efer >> 32;
+ regs.rax = efer & 0xffffffff;
+ break;
+ case VMX_WRMSR:
+ assert(regs.rcx == MSR_EFER);
+ efer = regs.rdx << 32 | (regs.rax & 0xffffffff);
+ vmcs_write(GUEST_EFER, efer);
+ break;
+ case VMX_CPUID:
+ cpuid = (struct cpuid) {0, 0, 0, 0};
+ cpuid = raw_cpuid(regs.rax, regs.rcx);
+ regs.rax = cpuid.a;
+ regs.rbx = cpuid.b;
+ regs.rcx = cpuid.c;
+ regs.rdx = cpuid.d;
+ break;
+ default:
+ assert_msg(false,
+ "Unexpected exit to L1, exit_reason: %s (0x%lx)",
+ exit_reason_description(vmcs_read(EXI_REASON)),
+ vmcs_read(EXI_REASON));
+ }
+ skip_exit_insn();
+ enter_guest();
+ }
+
+ assert_exit_reason(VMX_VMCALL);
+}
#define TEST(name) { #name, .v2 = name }
/* name/init/guest_main/exit_handler/syscall_handler/guest_regs */
@@ -10763,5 +10811,6 @@ struct vmx_test vmx_tests[] = {
TEST(rdtsc_vmexit_diff_test),
TEST(vmx_mtf_test),
TEST(vmx_mtf_pdpte_test),
+ TEST(vmx_pf_exception_test),
{ NULL, NULL, NULL, NULL, NULL, {0} },
};
Add tests vmx_pf_exception_test and vmx_pf_exception_test_reduced_maxphyaddr to vmx_tests.c. The purpose of these tests are to test the reflection logic in KVM to ensure exceptions are being routed to were they are intended to go. For example, it will test that we are not accidentally reflecting exceptions into L1 when L1 isn't expecting them. Commit 18712c13709d ("KVM: nVMX: Use vmx_need_pf_intercept() when deciding if L0 wants a #PF") fixed an issue related to this which went undetected because there was no testing in place. This adds testing to ensure there is coverage for such issues. Signed-off-by: Aaron Lewis <aaronlewis@google.com> --- x86/Makefile.common | 2 ++ x86/unittests.cfg | 13 ++++++++++++ x86/vmx_tests.c | 49 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+)