@@ -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