Il 06/09/2013 04:11, Arthur Chunqi Li ha scritto: > Test cases for preemption timer in nested VMX. Two aspects are tested: > 1. Save preemption timer on VMEXIT if relevant bit set in EXIT_CONTROL > 2. Test a relevant bug of KVM. The bug will not save preemption timer > value if exit L2->L0 for some reason and enter L0->L2. Thus preemption > timer will never trigger if the value is large enough. > 3. Some other aspects are tested, e.g. preempt without save, preempt > when value is 0. > > Signed-off-by: Arthur Chunqi Li <yzt356@xxxxxxxxx> > --- > ChangeLog to v1: > 1. Add test of EXI_SAVE_PREEMPT enable and PIN_PREEMPT disable > 2. Add test of PIN_PREEMPT enable and EXI_SAVE_PREEMPT enable/disable > 3. Add test of preemption value is 0 The patch looks good, however we have now 3 series that are conflicting (basic tests, EPT, preemption timer). I ordered them and pushed them to "vmx" branch of kvm-unit-tests.git. Can you send them as a single series from now on? Thanks, Paolo > x86/vmx.h | 3 + > x86/vmx_tests.c | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 178 insertions(+) > > diff --git a/x86/vmx.h b/x86/vmx.h > index 28595d8..ebc8cfd 100644 > --- a/x86/vmx.h > +++ b/x86/vmx.h > @@ -210,6 +210,7 @@ enum Encoding { > GUEST_ACTV_STATE = 0x4826ul, > GUEST_SMBASE = 0x4828ul, > GUEST_SYSENTER_CS = 0x482aul, > + PREEMPT_TIMER_VALUE = 0x482eul, > > /* 32-Bit Host State Fields */ > HOST_SYSENTER_CS = 0x4c00ul, > @@ -331,6 +332,7 @@ enum Ctrl_exi { > EXI_LOAD_PERF = 1UL << 12, > EXI_INTA = 1UL << 15, > EXI_LOAD_EFER = 1UL << 21, > + EXI_SAVE_PREEMPT = 1UL << 22, > }; > > enum Ctrl_ent { > @@ -342,6 +344,7 @@ enum Ctrl_pin { > PIN_EXTINT = 1ul << 0, > PIN_NMI = 1ul << 3, > PIN_VIRT_NMI = 1ul << 5, > + PIN_PREEMPT = 1ul << 6, > }; > > enum Ctrl0 { > diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c > index c1b39f4..2e32031 100644 > --- a/x86/vmx_tests.c > +++ b/x86/vmx_tests.c > @@ -1,4 +1,30 @@ > #include "vmx.h" > +#include "msr.h" > +#include "processor.h" > + > +volatile u32 stage; > + > +static inline void vmcall() > +{ > + asm volatile("vmcall"); > +} > + > +static inline void set_stage(u32 s) > +{ > + barrier(); > + stage = s; > + barrier(); > +} > + > +static inline u32 get_stage() > +{ > + u32 s; > + > + barrier(); > + s = stage; > + barrier(); > + return s; > +} > > void basic_init() > { > @@ -76,6 +102,153 @@ int vmenter_exit_handler() > return VMX_TEST_VMEXIT; > } > > +u32 preempt_scale; > +volatile unsigned long long tsc_val; > +volatile u32 preempt_val; > + > +void preemption_timer_init() > +{ > + u32 ctrl_exit; > + > + // Enable EXI_SAVE_PREEMPT with PIN_PREEMPT dieabled > + ctrl_exit = (vmcs_read(EXI_CONTROLS) | > + EXI_SAVE_PREEMPT) & ctrl_exit_rev.clr; > + vmcs_write(EXI_CONTROLS, ctrl_exit); > + preempt_val = 10000000; > + vmcs_write(PREEMPT_TIMER_VALUE, preempt_val); > + set_stage(0); > + preempt_scale = rdmsr(MSR_IA32_VMX_MISC) & 0x1F; > +} > + > +void preemption_timer_main() > +{ > + int i, j; > + > + if (!(ctrl_pin_rev.clr & PIN_PREEMPT)) { > + 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 { > + // Test EXI_SAVE_PREEMPT enable and PIN_PREEMPT disable > + set_stage(0); > + // Consume enough time to let L2->L0->L2 occurs > + for(i = 0; i < 100000; i++) > + for (j = 0; j < 10000; j++); > + vmcall(); > + // Test PIN_PREEMPT enable and EXI_SAVE_PREEMPT enable/disable > + set_stage(1); > + vmcall(); > + // Test both enable > + if (get_stage() == 2) > + vmcall(); > + } > + // Test the bug of reseting preempt value when L2->L0->L2 > + set_stage(3); > + vmcall(); > + tsc_val = rdtsc(); > + while (1) { > + if (((rdtsc() - tsc_val) >> preempt_scale) > + > 10 * preempt_val) { > + report("Preemption timer timeout", 0); > + break; > + } > + if (get_stage() == 4) > + break; > + } > + // Test preempt val is 0 > + set_stage(4); > + report("Preemption timer, val=0", 0); > +} > + > +int preemption_timer_exit_handler() > +{ > + u64 guest_rip; > + ulong reason; > + u32 insn_len; > + u32 ctrl_exit; > + u32 ctrl_pin; > + > + guest_rip = vmcs_read(GUEST_RIP); > + reason = vmcs_read(EXI_REASON) & 0xff; > + insn_len = vmcs_read(EXI_INST_LEN); > + switch (reason) { > + case VMX_PREEMPT: > + switch (get_stage()) { > + case 3: > + if (((rdtsc() - tsc_val) >> preempt_scale) < preempt_val) > + report("Preemption timer timeout", 0); > + else > + report("Preemption timer timeout", 1); > + set_stage(get_stage() + 1); > + break; > + case 4: > + if (vmcs_read(PREEMPT_TIMER_VALUE) == 0) > + report("Preemption timer, val=0", 1); > + else > + report("Preemption timer, val=0", 0); > + return VMX_TEST_VMEXIT; > + } > + return VMX_TEST_RESUME; > + case VMX_VMCALL: > + switch (get_stage()) { > + case 0: > + if (vmcs_read(PREEMPT_TIMER_VALUE) != preempt_val) > + report("Preemption timer off", 0); > + else > + report("Preemption timer off", 1); > + // Enable PIN_PREEMPT and disable EXI_SAVE_PREEMPT > + ctrl_pin = (vmcs_read(PIN_CONTROLS) | PIN_PREEMPT) & > + ctrl_pin_rev.clr; > + vmcs_write(PIN_CONTROLS, ctrl_pin); > + ctrl_exit = (vmcs_read(EXI_CONTROLS) & > + ~EXI_SAVE_PREEMPT) & ctrl_exit_rev.clr; > + vmcs_write(EXI_CONTROLS, ctrl_exit); > + vmcs_write(PREEMPT_TIMER_VALUE, preempt_val); > + break; > + case 1: > + if (vmcs_read(PREEMPT_TIMER_VALUE) != preempt_val) > + report("Save preemption value", 0); > + else { > + set_stage(get_stage() + 1); > + // Enable EXI_SAVE_PREEMPT with PIN_PREEMPT > + // already enabled > + ctrl_exit = (vmcs_read(EXI_CONTROLS) | > + EXI_SAVE_PREEMPT) & ctrl_exit_rev.clr; > + vmcs_write(EXI_CONTROLS, ctrl_exit); > + } > + vmcs_write(PREEMPT_TIMER_VALUE, preempt_val); > + break; > + case 2: > + if (vmcs_read(PREEMPT_TIMER_VALUE) >= preempt_val) > + report("Save preemption value", 0); > + else > + report("Save preemption value", 1); > + break; > + case 3: > + vmcs_write(PREEMPT_TIMER_VALUE, preempt_val); > + ctrl_pin = (vmcs_read(PIN_CONTROLS) | PIN_PREEMPT) & > + ctrl_pin_rev.clr; > + vmcs_write(PIN_CONTROLS, ctrl_pin); > + ctrl_exit = (vmcs_read(EXI_CONTROLS) | > + EXI_SAVE_PREEMPT) & ctrl_exit_rev.clr; > + vmcs_write(EXI_CONTROLS, ctrl_exit); > + break; > + default: > + printf("Invalid stage.\n"); > + print_vmexit_info(); > + return VMX_TEST_VMEXIT; > + } > + vmcs_write(GUEST_RIP, guest_rip + insn_len); > + return VMX_TEST_RESUME; > + default: > + printf("Unknown exit reason, %d\n", reason); > + print_vmexit_info(); > + } > + return VMX_TEST_VMEXIT; > +} > + > /* name/init/guest_main/exit_handler/syscall_handler/guest_regs > basic_* just implement some basic functions */ > struct vmx_test vmx_tests[] = { > @@ -83,5 +256,7 @@ struct vmx_test vmx_tests[] = { > basic_syscall_handler, {0} }, > { "vmenter", basic_init, vmenter_main, vmenter_exit_handler, > basic_syscall_handler, {0} }, > + { "preemption timer", preemption_timer_init, preemption_timer_main, > + preemption_timer_exit_handler, basic_syscall_handler, {0} }, > { NULL, NULL, NULL, NULL, NULL, {0} }, > }; > -- 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