diff mbox series

[kvm-unit-tests,14/14] x86: Add tests that run ac_test_run() in an L2 guest

Message ID 20211110212001.3745914-15-aaronlewis@google.com (mailing list archive)
State New, archived
Headers show
Series Run access test in an L2 guest | expand

Commit Message

Aaron Lewis Nov. 10, 2021, 9:20 p.m. UTC
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(+)
diff mbox series

Patch

diff --git a/x86/Makefile.common b/x86/Makefile.common
index a665854..461de51 100644
--- a/x86/Makefile.common
+++ b/x86/Makefile.common
@@ -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
diff --git a/x86/unittests.cfg b/x86/unittests.cfg
index dbeb8a2..4069e4c 100644
--- a/x86/unittests.cfg
+++ b/x86/unittests.cfg
@@ -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
diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c
index 9ee6653..8cf3543 100644
--- a/x86/vmx_tests.c
+++ b/x86/vmx_tests.c
@@ -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} },
 };