[PATCH 02/13] VMX: Extend preemption timer tests

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Jan Kiszka <jan.kiszka@xxxxxxxxxxx>

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@xxxxxxxxxxx>
---
 x86/vmx_tests.c | 84 +++++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 64 insertions(+), 20 deletions(-)

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
-- 
1.8.1.1.298.ge7eed54

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux