diff mbox series

[3/3] nSVM: Test effect of host RFLAGS.TF on VMRUN

Message ID 20210203012842.101447-4-krish.sadhukhan@oracle.com (mailing list archive)
State New, archived
Headers show
Series nSVM: Test host RFLAGS.TF on VMRUN | expand

Commit Message

Krish Sadhukhan Feb. 3, 2021, 1:28 a.m. UTC
According to section "VMRUN and TF/RF Bits in EFLAGS" in AMD APM vol 2,

	"From the host point of view, VMRUN acts like a single instruction,
	 even though an arbitrary number of guest instructions may execute
	 before a #VMEXIT effectively completes the VMRUN. As a single
	 host instruction, VMRUN interacts with EFLAGS.TF like ordinary
	 instructions. EFLAGS.TF causes a #DB trap after the VMRUN completes
	 on the host side (i.e., after the #VMEXIT from the guest).

Signed-off-by: Krish Sadhukhan <krish.sadhukhan@oracle.com>
---
 x86/svm_tests.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 93 insertions(+)
diff mbox series

Patch

diff --git a/x86/svm_tests.c b/x86/svm_tests.c
index 7bf3624..73bffe6 100644
--- a/x86/svm_tests.c
+++ b/x86/svm_tests.c
@@ -2002,6 +2002,96 @@  static bool init_intercept_check(struct svm_test *test)
     return init_intercept;
 }
 
+/*
+ * Setting host EFLAGS.TF causes a #DB trap after the VMRUN completes on the
+ * host side (i.e., after the #VMEXIT from the guest).
+ *
+ * [AMD APM]
+ */
+static volatile u8 host_rflags_guest_flag = 0;
+static volatile u8 host_rflags_isr_flag = 0;
+static void ss_bp_isr(struct ex_regs *r)
+{
+	host_rflags_isr_flag = (host_rflags_guest_flag == 1) ? 2 : 1;
+	r->rflags &= ~X86_EFLAGS_TF;
+}
+
+static void host_rflags_prepare(struct svm_test *test)
+{
+	default_prepare(test);
+	handle_exception(DB_VECTOR, ss_bp_isr);
+	host_rflags_guest_flag = host_rflags_isr_flag = 0;
+	set_test_stage(test, 0);
+}
+
+static void host_rflags_test(struct svm_test *test)
+{
+	while (1) {
+		if (get_test_stage(test) > 0)
+			host_rflags_guest_flag =
+			    (host_rflags_isr_flag == 1) ? 2 : 1;
+		vmmcall();
+		if (get_test_stage(test) == 3)
+			break;
+	}
+}
+
+static bool host_rflags_finished(struct svm_test *test)
+{
+	switch (get_test_stage(test)) {
+	case 0:
+		if (vmcb->control.exit_code != SVM_EXIT_VMMCALL &&
+		    host_rflags_isr_flag != 0 && host_rflags_guest_flag != 0) {
+			report(false, "Unexpected VMEXIT. Exit reason 0x%x",
+			    vmcb->control.exit_code);
+			return true;
+		}
+		/*
+		 * Setting host EFLAGS.TF not immediately before VMRUN, causes
+		 * #DB trap before first guest instruction is executed
+		 */
+		write_rflags(read_rflags() | X86_EFLAGS_TF);
+		vmcb->save.rip += 3;
+		break;
+	case 1:
+		if (vmcb->control.exit_code != SVM_EXIT_VMMCALL &&
+		    host_rflags_isr_flag != 1 && host_rflags_guest_flag != 2) {
+			report(false, "Unexpected VMEXIT. Exit reason 0x%x",
+			    vmcb->control.exit_code);
+			return true;
+		}
+		host_rflags_guest_flag = host_rflags_isr_flag = 0;
+		vmcb->save.rip += 3;
+		/*
+		 * Setting host EFLAGS.TF immediately before VMRUN, causes #DB
+		 * trap after VMRUN completes on the host side (i.e., after
+		 * VMEXIT from guest).
+		 */
+		set_ss_bp_on_vmrun();
+		break;
+	case 2:
+		if (vmcb->control.exit_code != SVM_EXIT_VMMCALL &&
+		    host_rflags_isr_flag != 2 && host_rflags_guest_flag != 1) {
+			report(false, "Unexpected VMEXIT. Exit reason 0x%x",
+			    vmcb->control.exit_code);
+			return true;
+		}
+		host_rflags_guest_flag = host_rflags_isr_flag = 0;
+		vmcb->save.rip += 3;
+		unset_ss_bp_on_vmrun();
+		break;
+	default:
+		return true;
+	}
+	inc_test_stage(test);
+	return get_test_stage(test) == 4;
+}
+
+static bool host_rflags_check(struct svm_test *test)
+{
+	return get_test_stage(test) == 3;
+}
+
 #define TEST(name) { #name, .v2 = name }
 
 /*
@@ -2491,6 +2581,9 @@  struct svm_test svm_tests[] = {
     { "svm_init_intercept_test", smp_supported, init_intercept_prepare,
       default_prepare_gif_clear, init_intercept_test,
       init_intercept_finished, init_intercept_check, .on_vcpu = 2 },
+    { "host_rflags", default_supported, host_rflags_prepare,
+      default_prepare_gif_clear, host_rflags_test,
+      host_rflags_finished, host_rflags_check },
     TEST(svm_cr4_osxsave_test),
     TEST(svm_guest_state_test),
     TEST(svm_vmrun_errata_test),