kvm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Paolo Bonzini <pbonzini@redhat.com>
To: Arthur Chunqi Li <yzt356@gmail.com>
Cc: kvm@vger.kernel.org, jan.kiszka@web.de, gleb@redhat.com
Subject: Re: [PATCH v2] kvm-unit-tests: VMX: Test suite for preemption timer
Date: Mon, 09 Sep 2013 15:59:27 +0200	[thread overview]
Message-ID: <522DD43F.5010407@redhat.com> (raw)
In-Reply-To: <1378433506-18401-1-git-send-email-yzt356@gmail.com>

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@gmail.com>
> ---
> 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} },
>  };
> 


      reply	other threads:[~2013-09-09 13:59 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-09-06  2:11 [PATCH v2] kvm-unit-tests: VMX: Test suite for preemption timer Arthur Chunqi Li
2013-09-09 13:59 ` Paolo Bonzini [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=522DD43F.5010407@redhat.com \
    --to=pbonzini@redhat.com \
    --cc=gleb@redhat.com \
    --cc=jan.kiszka@web.de \
    --cc=kvm@vger.kernel.org \
    --cc=yzt356@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).