Commit 15b24872 authored by Jan Kiszka's avatar Jan Kiszka Committed by Paolo Bonzini
Browse files

VMX: Extend preemption timer tests



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: default avatarJan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 17ba0dd0
......@@ -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
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment