From: Paolo Bonzini Subject: Re: [PATCH] kvm-unit-tests: VMX: Test suite for preemption timer Date: Mon, 09 Sep 2013 14:47:11 +0200 Message-ID: <522DC34F.60708@redhat.com> References: <1378308395-3209-1-git-send-email-yzt356@gmail.com> Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Cc: kvm@vger.kernel.org, jan.kiszka@web.de, gleb@redhat.com To: Arthur Chunqi Li Return-path: Received: from mail-qa0-f54.google.com ([209.85.216.54]:40585 "EHLO mail-qa0-f54.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753001Ab3IIMrI (ORCPT ); Mon, 9 Sep 2013 08:47:08 -0400 Received: by mail-qa0-f54.google.com with SMTP id i13so122871qae.6 for ; Mon, 09 Sep 2013 05:47:08 -0700 (PDT) In-Reply-To: <1378308395-3209-1-git-send-email-yzt356@gmail.com> Sender: kvm-owner@vger.kernel.org List-ID: Il 04/09/2013 17:26, 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. > > Signed-off-by: Arthur Chunqi Li > --- > x86/vmx.h | 3 ++ > x86/vmx_tests.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 120 insertions(+) Please rebase your other four patches on top of this one, since this one is good to go! Reviewed-by: Paolo Bonzini Paolo > +void preemption_timer_init() > +{ > + u32 ctrl_pin; > + > + ctrl_pin = vmcs_read(PIN_CONTROLS) | PIN_PREEMPT; > + ctrl_pin &= ctrl_pin_rev.clr; > + vmcs_write(PIN_CONTROLS, ctrl_pin); > + preempt_val = 10000000; > + vmcs_write(PREEMPT_TIMER_VALUE, preempt_val); > + preempt_scale = rdmsr(MSR_IA32_VMX_MISC) & 0x1F; > +} > + > +void preemption_timer_main() > +{ > + tsc_val = rdtsc(); > + 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 { > + set_stage(0); > + vmcall(); > + if (get_stage() == 1) > + vmcall(); > + } > + while (1) { > + if (((rdtsc() - tsc_val) >> preempt_scale) > + > 10 * preempt_val) { > + report("Preemption timer", 0); > + break; > + } > + } > +} > + > +int preemption_timer_exit_handler() > +{ > + u64 guest_rip; > + ulong reason; > + u32 insn_len; > + u32 ctrl_exit; > + > + guest_rip = vmcs_read(GUEST_RIP); > + reason = vmcs_read(EXI_REASON) & 0xff; > + 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); > + return VMX_TEST_VMEXIT; > + case VMX_VMCALL: > + 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); > + } > + break; > + case 1: > + if (vmcs_read(PREEMPT_TIMER_VALUE) >= preempt_val) > + report("Save preemption value", 0); > + else > + report("Save preemption value", 1); > + 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 +198,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} }, > }; >