Skip to contentSkip to conversation

VMX preemption timer: Make test case more robust

PATCH In review Jan Kiszka 2 participants 2 messages Oct 23, 2013 – Oct 28, 2013 KVM

lore
Share & tools
lore

Jan Kiszka

author
#0 lore raw

PATCH 1/1 VMX preemption timer: Make test case more robust

If we both print from L2 and, on timer expiry, from L1, we risk a deadlock in L1 on the printf lock that is held by L2 then. Avoid this by only printing from L1.

Furthermore, if the timer fails to fire in time, disable it before continuing to avoid that it fire later on in different contexts.

---
 x86/vmx_tests.c | 26 ++++++++++++++++----------
 1 file changed, 16 insertions(+), 10 deletions(-)
x86/vmx_tests.c +16 -10
index 8d47bcd..7893a6c 100644
@@ -128,6 +128,9 @@ void preemption_timer_init()
 	preempt_val = 10000000;
 	vmcs_write(PREEMPT_TIMER_VALUE, preempt_val);
 	preempt_scale = rdmsr(MSR_IA32_VMX_MISC) & 0x1F;
+
+	if (!(ctrl_exit_rev.clr & EXI_SAVE_PREEMPT))
+		printf("\tSave preemption value is not supported\n");
 }
 
 void preemption_timer_main()
@@ -137,9 +140,7 @@ void preemption_timer_main()
 		printf("\tPreemption timer is not supported\n");
 		return;
 	}
-	if (!(ctrl_exit_rev.clr & EXI_SAVE_PREEMPT))
-		printf("\tSave preemption value is not supported\n");
-	else {
+	if (ctrl_exit_rev.clr & EXI_SAVE_PREEMPT) {
 		set_stage(0);
 		vmcall();
 		if (get_stage() == 1)
@@ -148,8 +149,8 @@ void preemption_timer_main()
 	while (1) {
 		if (((rdtsc() - tsc_val) >> preempt_scale)
 				> 10 * preempt_val) {
-			report("Preemption timer", 0);
-			break;
+			set_stage(2);
+			vmcall();
 		}
 	}
 }
@@ -170,7 +171,7 @@ int preemption_timer_exit_handler()
 			report("Preemption timer", 0);
 		else
 			report("Preemption timer", 1);
-		return VMX_TEST_VMEXIT;
+		break;
 	case VMX_VMCALL:
 		switch (get_stage()) {
 		case 0:
@@ -182,24 +183,29 @@ int preemption_timer_exit_handler()
 					EXI_SAVE_PREEMPT) & ctrl_exit_rev.clr;
 				vmcs_write(EXI_CONTROLS, ctrl_exit);
 			}
-			break;
+			vmcs_write(GUEST_RIP, guest_rip + insn_len);
+			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);
+			return VMX_TEST_RESUME;
+		case 2:
+			report("Preemption timer", 0);
 			break;
 		default:
 			printf("Invalid stage.\n");
 			print_vmexit_info();
-			return VMX_TEST_VMEXIT;
+			break;
 		}
-		vmcs_write(GUEST_RIP, guest_rip + insn_len);
-		return VMX_TEST_RESUME;
+		break;
 	default:
 		printf("Unknown exit reason, %d\n", reason);
 		print_vmexit_info();
 	}
+	vmcs_write(PIN_CONTROLS, vmcs_read(PIN_CONTROLS) & ~PIN_PREEMPT);
 	return VMX_TEST_VMEXIT;
 }
 
Signature · 1 line
1.8.1.1.298.ge7eed54
maintainer
#1 lore raw

Il 23/10/2013 16:21, Jan Kiszka ha scritto:

Quoted 82 lines

If we both print from L2 and, on timer expiry, from L1, we risk a deadlock in L1 on the printf lock that is held by L2 then. Avoid this by only printing from L1.

Furthermore, if the timer fails to fire in time, disable it before continuing to avoid that it fire later on in different contexts.

---
 x86/vmx_tests.c | 26 ++++++++++++++++----------
 1 file changed, 16 insertions(+), 10 deletions(-)
x86/vmx_tests.c +14 -9
index 8d47bcd..7893a6c 100644
@@ -128,6 +128,9 @@ void preemption_timer_init()
 	preempt_val = 10000000;
 	vmcs_write(PREEMPT_TIMER_VALUE, preempt_val);
 	preempt_scale = rdmsr(MSR_IA32_VMX_MISC) & 0x1F;
+
+	if (!(ctrl_exit_rev.clr & EXI_SAVE_PREEMPT))
+		printf("\tSave preemption value is not supported\n");
 }
 
 void preemption_timer_main()
@@ -137,9 +140,7 @@ void preemption_timer_main()
 		printf("\tPreemption timer is not supported\n");
 		return;
 	}
-	if (!(ctrl_exit_rev.clr & EXI_SAVE_PREEMPT))
-		printf("\tSave preemption value is not supported\n");
-	else {
+	if (ctrl_exit_rev.clr & EXI_SAVE_PREEMPT) {
 		set_stage(0);
 		vmcall();
 		if (get_stage() == 1)
@@ -148,8 +149,8 @@ void preemption_timer_main()
 	while (1) {
 		if (((rdtsc() - tsc_val) >> preempt_scale)
 				> 10 * preempt_val) {
-			report("Preemption timer", 0);
-			break;
+			set_stage(2);
+			vmcall();
 		}
 	}
 }
@@ -170,7 +171,7 @@ int preemption_timer_exit_handler()
 			report("Preemption timer", 0);
 		else
 			report("Preemption timer", 1);
-		return VMX_TEST_VMEXIT;
+		break;
 	case VMX_VMCALL:
 		switch (get_stage()) {
 		case 0:
@@ -182,24 +183,29 @@ int preemption_timer_exit_handler()
 					EXI_SAVE_PREEMPT) & ctrl_exit_rev.clr;
 				vmcs_write(EXI_CONTROLS, ctrl_exit);
 			}
-			break;
+			vmcs_write(GUEST_RIP, guest_rip + insn_len);
+			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);
+			return VMX_TEST_RESUME;
+		case 2:
+			report("Preemption timer", 0);
 			break;
 		default:
 			printf("Invalid stage.\n");
 			print_vmexit_info();
-			return VMX_TEST_VMEXIT;
+			break;
 		}
-		vmcs_write(GUEST_RIP, guest_rip + insn_len);

x86/vmx_tests.c int preemption_timer_exit_handler() · line 211

Quoted 10 lines
x86/vmx_tests.c +2 -1
-		return VMX_TEST_RESUME;
+		break;
 	default:
 		printf("Unknown exit reason, %d\n", reason);
 		print_vmexit_info();
 	}
+	vmcs_write(PIN_CONTROLS, vmcs_read(PIN_CONTROLS) & ~PIN_PREEMPT);
 	return VMX_TEST_VMEXIT;
 }
 

Applied to kvm-unit-tests.git vmx.

Paolo