aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSean Christopherson <sean.j.christopherson@intel.com>2020-03-12 16:27:42 -0700
committerPaolo Bonzini <pbonzini@redhat.com>2020-03-14 11:34:00 +0100
commitfdd5a3944e9b87055b45d3eaedcb58b085794594 (patch)
treecf48c57c8e211c57dced6ee361acc3c0226c0c49
parent782985f1b69b3ff06d228b3bb115242a7203b38f (diff)
downloadkvm-unit-tests-fdd5a3944e9b87055b45d3eaedcb58b085794594.tar.gz
nVMX: Expose __enter_guest() and consolidate guest state test code
Expose __enter_guest() outside of vmx.c and use it in a new wrapper for testing guest state. Handling both success and failure paths in a common helper eliminates a lot of boilerplate code in the tests themselves. Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--x86/vmx.c12
-rw-r--r--x86/vmx.h5
-rw-r--r--x86/vmx_tests.c115
3 files changed, 40 insertions, 92 deletions
diff --git a/x86/vmx.c b/x86/vmx.c
index d92350d..1c837f0 100644
--- a/x86/vmx.c
+++ b/x86/vmx.c
@@ -1840,14 +1840,11 @@ static void check_for_guest_termination(void)
}
}
-#define ABORT_ON_EARLY_VMENTRY_FAIL 0x1
-#define ABORT_ON_INVALID_GUEST_STATE 0x2
-
/*
* Enters the guest (or launches it for the first time). Error to call once the
* guest has returned (i.e., run past the end of its guest() function).
*/
-static void __enter_guest(u8 abort_flag, struct vmentry_result *result)
+void __enter_guest(u8 abort_flag, struct vmentry_result *result)
{
TEST_ASSERT_MSG(v2_guest_main,
"Never called test_set_guest_func!");
@@ -1905,13 +1902,6 @@ void enter_guest(void)
ABORT_ON_INVALID_GUEST_STATE, &result);
}
-void enter_guest_with_invalid_guest_state(void)
-{
- struct vmentry_result result;
-
- __enter_guest(ABORT_ON_EARLY_VMENTRY_FAIL, &result);
-}
-
extern struct vmx_test vmx_tests[];
static bool
diff --git a/x86/vmx.h b/x86/vmx.h
index c4a0fb4..73979f7 100644
--- a/x86/vmx.h
+++ b/x86/vmx.h
@@ -855,9 +855,12 @@ bool ept_huge_pages_supported(int level);
bool ept_execute_only_supported(void);
bool ept_ad_bits_supported(void);
+#define ABORT_ON_EARLY_VMENTRY_FAIL 0x1
+#define ABORT_ON_INVALID_GUEST_STATE 0x2
+
+void __enter_guest(u8 abort_flag, struct vmentry_result *result);
void enter_guest(void);
void enter_guest_with_bad_controls(void);
-void enter_guest_with_invalid_guest_state(void);
typedef void (*test_guest_func)(void);
typedef void (*test_teardown_func)(void *data);
diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c
index 3fda00c..61769db 100644
--- a/x86/vmx_tests.c
+++ b/x86/vmx_tests.c
@@ -5239,23 +5239,25 @@ static void guest_state_test_main(void)
asm volatile("fnop");
}
-static void advance_guest_state_test(void)
+static void test_guest_state(const char *test, bool xfail, u64 field,
+ const char * field_name)
{
- u32 reason = vmcs_read(EXI_REASON);
- if (! (reason & 0x80000000)) {
- u64 guest_rip = vmcs_read(GUEST_RIP);
- u32 insn_len = vmcs_read(EXI_INST_LEN);
- vmcs_write(GUEST_RIP, guest_rip + insn_len);
- }
-}
+ struct vmentry_result result;
+ u8 abort_flags;
-static void report_guest_state_test(const char *test, u32 xreason,
- u64 field, const char * field_name)
-{
- u32 reason = vmcs_read(EXI_REASON);
+ abort_flags = ABORT_ON_EARLY_VMENTRY_FAIL;
+ if (!xfail)
+ abort_flags = ABORT_ON_INVALID_GUEST_STATE;
+
+ __enter_guest(abort_flags, &result);
- report(reason == xreason, "%s, %s %lx", test, field_name, field);
- advance_guest_state_test();
+ report(result.exit_reason.failed_vmentry == xfail &&
+ ((xfail && result.exit_reason.basic == VMX_FAIL_STATE) ||
+ (!xfail && result.exit_reason.basic == VMX_VMCALL)),
+ "%s, %s %lx", test, field_name, field);
+
+ if (!result.exit_reason.failed_vmentry)
+ skip_exit_insn();
}
/*
@@ -6911,16 +6913,7 @@ static void test_efer_vmlaunch(u32 fld, bool ok)
else
test_vmx_vmlaunch(VMXERR_ENTRY_INVALID_HOST_STATE_FIELD);
} else {
- if (ok) {
- enter_guest();
- report(vmcs_read(EXI_REASON) == VMX_VMCALL,
- "vmlaunch succeeds");
- } else {
- enter_guest_with_invalid_guest_state();
- report(vmcs_read(EXI_REASON) == (VMX_ENTRY_FAILURE | VMX_FAIL_STATE),
- "vmlaunch fails");
- }
- advance_guest_state_test();
+ test_guest_state("EFER test", !ok, GUEST_EFER, "GUEST_EFER");
}
}
@@ -7124,10 +7117,8 @@ static void test_pat(u32 field, const char * field_name, u32 ctrl_field,
report_prefix_pop();
} else { // GUEST_PAT
- enter_guest();
- report_guest_state_test("ENT_LOAD_PAT enabled",
- VMX_VMCALL, val,
- "GUEST_PAT");
+ test_guest_state("ENT_LOAD_PAT enabled", false,
+ val, "GUEST_PAT");
}
}
}
@@ -7151,21 +7142,9 @@ static void test_pat(u32 field, const char * field_name, u32 ctrl_field,
report_prefix_pop();
} else { // GUEST_PAT
- if (i == 0x2 || i == 0x3 || i >= 0x8) {
- enter_guest_with_invalid_guest_state();
- report_guest_state_test("ENT_LOAD_PAT "
- "enabled",
- VMX_FAIL_STATE | VMX_ENTRY_FAILURE,
- val,
- "GUEST_PAT");
- } else {
- enter_guest();
- report_guest_state_test("ENT_LOAD_PAT "
- "enabled",
- VMX_VMCALL,
- val,
- "GUEST_PAT");
- }
+ error = (i == 0x2 || i == 0x3 || i >= 0x8);
+ test_guest_state("ENT_LOAD_PAT enabled", !!error,
+ val, "GUEST_PAT");
}
}
@@ -7254,14 +7233,9 @@ static void test_pgc_vmlaunch(u32 xerror, u32 xreason, bool xfail, bool host)
report(success != xfail, "vmlaunch succeeded");
}
} else {
- if (xfail) {
- enter_guest_with_invalid_guest_state();
- } else {
- enter_guest();
- }
- report_guest_state_test("load GUEST_PERF_GLOBAL_CTRL",
- xreason, GUEST_PERF_GLOBAL_CTRL,
- "GUEST_PERF_GLOBAL_CTRL");
+ test_guest_state("load GUEST_PERF_GLOBAL_CTRL", xfail,
+ GUEST_PERF_GLOBAL_CTRL,
+ "GUEST_PERF_GLOBAL_CTRL");
}
}
@@ -7422,10 +7396,8 @@ static void test_canonical(u64 field, const char * field_name, bool host)
test_vmx_vmlaunch(0);
report_prefix_pop();
} else {
- enter_guest();
- report_guest_state_test("Test canonical address",
- VMX_VMCALL, addr_saved,
- field_name);
+ test_guest_state("Test canonical address", false,
+ addr_saved, field_name);
}
}
@@ -7436,10 +7408,8 @@ static void test_canonical(u64 field, const char * field_name, bool host)
test_vmx_vmlaunch(VMXERR_ENTRY_INVALID_HOST_STATE_FIELD);
report_prefix_pop();
} else {
- enter_guest_with_invalid_guest_state();
- report_guest_state_test("Test non-canonical address",
- VMX_FAIL_STATE | VMX_ENTRY_FAILURE,
- NONCANONICAL, field_name);
+ test_guest_state("Test non-canonical address", true,
+ NONCANONICAL, field_name);
}
vmcs_write(field, addr_saved);
@@ -7626,9 +7596,8 @@ static void test_guest_dr7(void)
for (i = 0; i < 64; i++) {
val = 1ull << i;
vmcs_write(GUEST_DR7, val);
- enter_guest();
- report_guest_state_test("ENT_LOAD_DBGCTLS disabled",
- VMX_VMCALL, val, "GUEST_DR7");
+ test_guest_state("ENT_LOAD_DBGCTLS disabled", false,
+ val, "GUEST_DR7");
}
}
if (ctrl_enter_rev.clr & ENT_LOAD_DBGCTLS) {
@@ -7636,15 +7605,8 @@ static void test_guest_dr7(void)
for (i = 0; i < 64; i++) {
val = 1ull << i;
vmcs_write(GUEST_DR7, val);
- if (i < 32)
- enter_guest();
- else
- enter_guest_with_invalid_guest_state();
- report_guest_state_test("ENT_LOAD_DBGCTLS enabled",
- i < 32 ? VMX_VMCALL :
- VMX_ENTRY_FAILURE |
- VMX_FAIL_STATE,
- val, "GUEST_DR7");
+ test_guest_state("ENT_LOAD_DBGCTLS enabled", i >= 32,
+ val, "GUEST_DR7");
}
}
vmcs_write(GUEST_DR7, dr7_saved);
@@ -9516,17 +9478,10 @@ static void atomic_switch_msrs_test(int count)
assert_exit_reason(VMX_VMCALL);
skip_exit_vmcall();
} else {
- u32 exit_reason;
- u32 exit_reason_want;
u32 exit_qual;
- enter_guest_with_invalid_guest_state();
-
- exit_reason = vmcs_read(EXI_REASON);
- exit_reason_want = VMX_FAIL_MSR | VMX_ENTRY_FAILURE;
- report(exit_reason == exit_reason_want,
- "exit_reason, %u, is %u.", exit_reason,
- exit_reason_want);
+ test_guest_state("Invalid MSR Load Count", true, count,
+ "ENT_MSR_LD_CNT");
exit_qual = vmcs_read(EXI_QUALIFICATION);
report(exit_qual == max_allowed + 1, "exit_qual, %u, is %u.",