diff mbox

[02/13] VMX: Extend preemption timer tests

Message ID 0a5a011b73361a016243fd436726995f63e511cb.1388858359.git.jan.kiszka@web.de (mailing list archive)
State New, archived
Headers show

Commit Message

Jan Kiszka Jan. 4, 2014, 5:59 p.m. UTC
From: Jan Kiszka <jan.kiszka@siemens.com>

This checks that we properly expire the preemption timer while the guest
is in HLT state and that we do not progress guest execution of the
preemption timer is activated with a timer value of 0.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 x86/vmx_tests.c | 84 +++++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 64 insertions(+), 20 deletions(-)
diff mbox

Patch

diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c
index 70efb50..0077f3f 100644
--- a/x86/vmx_tests.c
+++ b/x86/vmx_tests.c
@@ -99,6 +99,7 @@  int vmenter_exit_handler()
 u32 preempt_scale;
 volatile unsigned long long tsc_val;
 volatile u32 preempt_val;
+u64 saved_rip;
 
 int preemption_timer_init()
 {
@@ -126,17 +127,24 @@  void preemption_timer_main()
 		if (get_stage() == 1)
 			vmcall();
 	}
-	while (1) {
+	set_stage(1);
+	while (get_stage() == 1) {
 		if (((rdtsc() - tsc_val) >> preempt_scale)
 				> 10 * preempt_val) {
 			set_stage(2);
 			vmcall();
 		}
 	}
+	tsc_val = rdtsc();
+	asm volatile ("hlt");
+	vmcall();
+	set_stage(5);
+	vmcall();
 }
 
 int preemption_timer_exit_handler()
 {
+	bool guest_halted;
 	u64 guest_rip;
 	ulong reason;
 	u32 insn_len;
@@ -147,33 +155,69 @@  int preemption_timer_exit_handler()
 	insn_len = vmcs_read(EXI_INST_LEN);
 	switch (reason) {
 	case VMX_PREEMPT:
-		if (((rdtsc() - tsc_val) >> preempt_scale) < preempt_val)
-			report("Preemption timer", 0);
-		else
-			report("Preemption timer", 1);
+		switch (get_stage()) {
+		case 1:
+		case 2:
+			report("busy-wait for preemption timer",
+			       ((rdtsc() - tsc_val) >> preempt_scale) >=
+			       preempt_val);
+			set_stage(3);
+			vmcs_write(PREEMPT_TIMER_VALUE, preempt_val);
+			return VMX_TEST_RESUME;
+		case 3:
+			guest_halted =
+				(vmcs_read(GUEST_ACTV_STATE) == ACTV_HLT);
+			report("preemption timer during hlt",
+			       ((rdtsc() - tsc_val) >> preempt_scale) >=
+			       preempt_val && guest_halted);
+			set_stage(4);
+			vmcs_write(PIN_CONTROLS,
+				   vmcs_read(PIN_CONTROLS) & ~PIN_PREEMPT);
+			vmcs_write(GUEST_ACTV_STATE, ACTV_ACTIVE);
+			return VMX_TEST_RESUME;
+		case 4:
+			report("preemption timer with 0 value",
+			       saved_rip == guest_rip);
+			break;
+		default:
+			printf("Invalid stage.\n");
+			print_vmexit_info();
+			break;
+		}
 		break;
 	case VMX_VMCALL:
+		vmcs_write(GUEST_RIP, guest_rip + insn_len);
 		switch (get_stage()) {
 		case 0:
-			if (vmcs_read(PREEMPT_TIMER_VALUE) != preempt_val)
-				report("Save preemption value", 0);
-			else {
-				set_stage(get_stage() + 1);
-				ctrl_exit = (vmcs_read(EXI_CONTROLS) |
-					EXI_SAVE_PREEMPT) & ctrl_exit_rev.clr;
-				vmcs_write(EXI_CONTROLS, ctrl_exit);
-			}
-			vmcs_write(GUEST_RIP, guest_rip + insn_len);
+			report("Keep preemption value",
+			       vmcs_read(PREEMPT_TIMER_VALUE) == preempt_val);
+			set_stage(1);
+			vmcs_write(PREEMPT_TIMER_VALUE, preempt_val);
+			ctrl_exit = (vmcs_read(EXI_CONTROLS) |
+				EXI_SAVE_PREEMPT) & ctrl_exit_rev.clr;
+			vmcs_write(EXI_CONTROLS, ctrl_exit);
 			return VMX_TEST_RESUME;
 		case 1:
-			if (vmcs_read(PREEMPT_TIMER_VALUE) >= preempt_val)
-				report("Save preemption value", 0);
-			else
-				report("Save preemption value", 1);
-			vmcs_write(GUEST_RIP, guest_rip + insn_len);
+			report("Save preemption value",
+			       vmcs_read(PREEMPT_TIMER_VALUE) < preempt_val);
 			return VMX_TEST_RESUME;
 		case 2:
-			report("Preemption timer", 0);
+			report("busy-wait for preemption timer", 0);
+			set_stage(3);
+			vmcs_write(PREEMPT_TIMER_VALUE, preempt_val);
+			return VMX_TEST_RESUME;
+		case 3:
+			report("preemption timer during hlt", 0);
+			set_stage(4);
+			/* fall through */
+		case 4:
+			vmcs_write(PIN_CONTROLS,
+				   vmcs_read(PIN_CONTROLS) | PIN_PREEMPT);
+			vmcs_write(PREEMPT_TIMER_VALUE, 0);
+			saved_rip = guest_rip + insn_len;
+			return VMX_TEST_RESUME;
+		case 5:
+			report("preemption timer with 0 value (vmcall stage 5)", 0);
 			break;
 		default:
 			// Should not reach here