Re: [kvm-unit-tests PATCH] x86: VMX: Add a VMX-preemption timer expiration test

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 08/05/20 22:39, Jim Mattson wrote:
> When the VMX-preemption timer is activated, code executing in VMX
> non-root operation should never be able to record a TSC value beyond
> the deadline imposed by adding the scaled VMX-preemption timer value
> to the first TSC value observed by the guest after VM-entry.
> 
> Signed-off-by: Jim Mattson <jmattson@xxxxxxxxxx>
> Reviewed-by: Peter Shier <pshier@xxxxxxxxxx>
> ---
>  lib/x86/processor.h | 23 +++++++++++++
>  x86/vmx.h           | 21 ++++++++++++
>  x86/vmx_tests.c     | 81 +++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 125 insertions(+)
> 
> diff --git a/lib/x86/processor.h b/lib/x86/processor.h
> index 804673b..cf3acf6 100644
> --- a/lib/x86/processor.h
> +++ b/lib/x86/processor.h
> @@ -479,6 +479,29 @@ static inline unsigned long long rdtsc(void)
>  	return r;
>  }
>  
> +/*
> + * Per the advice in the SDM, volume 2, the sequence "mfence; lfence"
> + * executed immediately before rdtsc ensures that rdtsc will be
> + * executed only after all previous instructions have executed and all
> + * previous loads and stores are globally visible. In addition, the
> + * lfence immediately after rdtsc ensures that rdtsc will be executed
> + * prior to the execution of any subsequent instruction.
> + */
> +static inline unsigned long long fenced_rdtsc(void)
> +{
> +	unsigned long long tsc;
> +
> +#ifdef __x86_64__
> +	unsigned int eax, edx;
> +
> +	asm volatile ("mfence; lfence; rdtsc; lfence" : "=a"(eax), "=d"(edx));
> +	tsc = eax | ((unsigned long long)edx << 32);
> +#else
> +	asm volatile ("mfence; lfence; rdtsc; lfence" : "=A"(tsc));
> +#endif
> +	return tsc;
> +}
> +
>  static inline unsigned long long rdtscp(u32 *aux)
>  {
>         long long r;
> diff --git a/x86/vmx.h b/x86/vmx.h
> index 08b354d..71fdaa0 100644
> --- a/x86/vmx.h
> +++ b/x86/vmx.h
> @@ -118,6 +118,27 @@ union vmx_ctrl_msr {
>  	};
>  };
>  
> +union vmx_misc {
> +	u64 val;
> +	struct {
> +		u32 pt_bit:5,
> +		    stores_lma:1,
> +		    act_hlt:1,
> +		    act_shutdown:1,
> +		    act_wfsipi:1,
> +		    :5,
> +		    vmx_pt:1,
> +		    smm_smbase:1,
> +		    cr3_targets:9,
> +		    msr_list_size:3,
> +		    smm_mon_ctl:1,
> +		    vmwrite_any:1,
> +		    inject_len0:1,
> +		    :1;
> +		u32 mseg_revision;
> +	};
> +};
> +
>  union vmx_ept_vpid {
>  	u64 val;
>  	struct {
> diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c
> index 0909adb..991c317 100644
> --- a/x86/vmx_tests.c
> +++ b/x86/vmx_tests.c
> @@ -8555,6 +8555,86 @@ static void vmx_preemption_timer_tf_test(void)
>  	handle_exception(DB_VECTOR, old_db);
>  }
>  
> +#define VMX_PREEMPTION_TIMER_EXPIRY_CYCLES 1000000
> +
> +static u64 vmx_preemption_timer_expiry_start;
> +static u64 vmx_preemption_timer_expiry_finish;
> +
> +static void vmx_preemption_timer_expiry_test_guest(void)
> +{
> +	vmcall();
> +	vmx_preemption_timer_expiry_start = fenced_rdtsc();
> +
> +	while (vmx_get_test_stage() == 0)
> +		vmx_preemption_timer_expiry_finish = fenced_rdtsc();
> +}
> +
> +/*
> + * Test that the VMX-preemption timer is not excessively delayed.
> + *
> + * Per the SDM, volume 3, VM-entry starts the VMX-preemption timer
> + * with the unsigned value in the VMX-preemption timer-value field,
> + * and the VMX-preemption timer counts down by 1 every time bit X in
> + * the TSC changes due to a TSC increment (where X is
> + * IA32_VMX_MISC[4:0]). If the timer counts down to zero in any state
> + * other than the wait-for-SIPI state, the logical processor
> + * transitions to the C0 C-state and causes a VM-exit.
> + *
> + * The guest code above reads the starting TSC after VM-entry. At this
> + * point, the VMX-preemption timer has already been activated. Next,
> + * the guest code reads the current TSC in a loop, storing the value
> + * read to memory.
> + *
> + * If the RDTSC in the loop reads a value past the VMX-preemption
> + * timer deadline, then the VMX-preemption timer VM-exit must be
> + * delivered before the next instruction retires. Even if a higher
> + * priority SMI is delivered first, the VMX-preemption timer VM-exit
> + * must be delivered before the next instruction retires. Hence, a TSC
> + * value past the VMX-preemption timer deadline might be read, but it
> + * cannot be stored. If a TSC value past the deadline *is* stored,
> + * then the architectural specification has been violated.
> + */
> +static void vmx_preemption_timer_expiry_test(void)
> +{
> +	u32 preemption_timer_value;
> +	union vmx_misc misc;
> +	u64 tsc_deadline;
> +	u32 reason;
> +
> +	if (!(ctrl_pin_rev.clr & PIN_PREEMPT)) {
> +		report_skip("'Activate VMX-preemption timer' not supported");
> +		return;
> +	}
> +
> +	test_set_guest(vmx_preemption_timer_expiry_test_guest);
> +
> +	enter_guest();
> +	skip_exit_vmcall();
> +
> +	misc.val = rdmsr(MSR_IA32_VMX_MISC);
> +	preemption_timer_value =
> +		VMX_PREEMPTION_TIMER_EXPIRY_CYCLES >> misc.pt_bit;
> +
> +	vmcs_set_bits(PIN_CONTROLS, PIN_PREEMPT);
> +	vmcs_write(PREEMPT_TIMER_VALUE, preemption_timer_value);
> +	vmx_set_test_stage(0);
> +
> +	enter_guest();
> +	reason = (u32)vmcs_read(EXI_REASON);
> +	TEST_ASSERT(reason == VMX_PREEMPT);
> +
> +	vmcs_clear_bits(PIN_CONTROLS, PIN_PREEMPT);
> +	vmx_set_test_stage(1);
> +	enter_guest();
> +
> +	tsc_deadline = ((vmx_preemption_timer_expiry_start >> misc.pt_bit) <<
> +			misc.pt_bit) + (preemption_timer_value << misc.pt_bit);
> +
> +	report(vmx_preemption_timer_expiry_finish < tsc_deadline,
> +	       "Last stored guest TSC (%lu) < TSC deadline (%lu)",
> +	       vmx_preemption_timer_expiry_finish, tsc_deadline);
> +}
> +
>  static void vmx_db_test_guest(void)
>  {
>  	/*
> @@ -9861,6 +9941,7 @@ struct vmx_test vmx_tests[] = {
>  	TEST(vmx_store_tsc_test),
>  	TEST(vmx_preemption_timer_zero_test),
>  	TEST(vmx_preemption_timer_tf_test),
> +	TEST(vmx_preemption_timer_expiry_test),
>  	/* EPT access tests. */
>  	TEST(ept_access_test_not_present),
>  	TEST(ept_access_test_read_only),
> 

Queued, thanks.

Paolo




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux