Re: [kvm-unit-tests PATCH] vmx_tests: Add vmfunc tests

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

 




On 07/07/2017 01:14, Bandan Das wrote:
> 
> Besides for the obvious vmfunc call in L2 for eptp switching,
> other tests are to check for valid error paths when L2 calls
> vmfunc when L1 hasn't enabled it in the secondary controls,
> L2 calls vmfunc with an invalid function number or calls it
> with an invalid field from the eptp list
> 
> Signed-off-by: Bandan Das <bsd@xxxxxxxxxx>
> ---
>  lib/x86/msr.h   |   1 +
>  x86/vmx.h       |   8 +++-
>  x86/vmx_tests.c | 146 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 154 insertions(+), 1 deletion(-)
> 
> diff --git a/lib/x86/msr.h b/lib/x86/msr.h
> index 2c0598c..41f75d9 100644
> --- a/lib/x86/msr.h
> +++ b/lib/x86/msr.h
> @@ -400,6 +400,7 @@
>  #define MSR_IA32_VMX_TRUE_PROC		0x0000048e
>  #define MSR_IA32_VMX_TRUE_EXIT		0x0000048f
>  #define MSR_IA32_VMX_TRUE_ENTRY		0x00000490
> +#define MSR_IA32_VMX_VMFUNC             0x00000491
>  
>  #define MSR_IA32_TSCDEADLINE		0x000006e0
>  
> diff --git a/x86/vmx.h b/x86/vmx.h
> index d12b9de..b424674 100644
> --- a/x86/vmx.h
> +++ b/x86/vmx.h
> @@ -138,11 +138,14 @@ enum Encoding {
>  	TSC_OFFSET_HI		= 0x2011ul,
>  	APIC_VIRT_ADDR		= 0x2012ul,
>  	APIC_ACCS_ADDR		= 0x2014ul,
> +	VMFUNC_CTRL             = 0x2018ul,
> +	VMFUNC_CTRL_HI          = 0x2019ul,
>  	EPTP			= 0x201aul,
>  	EPTP_HI			= 0x201bul,
>  	PMLADDR                 = 0x200eul,
>  	PMLADDR_HI              = 0x200ful,
> -
> +	EPTP_LIST_ADDR          = 0x2024ul,
> +	EPTP_LIST_ADDR_HI       = 0x2025ul,
>  
>  	/* 64-Bit Readonly Data Field */
>  	INFO_PHYS_ADDR		= 0x2400ul,
> @@ -394,6 +397,7 @@ enum Ctrl1 {
>  	CPU_URG			= 1ul << 7,
>  	CPU_WBINVD		= 1ul << 6,
>  	CPU_RDRAND		= 1ul << 11,
> +	CPU_VMFUNC              = 1ul << 13,
>  	CPU_PML                 = 1ul << 17,
>  };
>  
> @@ -405,6 +409,8 @@ enum Intr_type {
>  	VMX_INTR_TYPE_SOFT_EXCEPTION = 6,
>  };
>  
> +#define EPTP_SWITCHING 0x1
> +
>  /*
>   * Interruption-information format
>   */
> diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c
> index 2522d3a..01c58cc 100644
> --- a/x86/vmx_tests.c
> +++ b/x86/vmx_tests.c
> @@ -29,6 +29,9 @@ void *data_page1, *data_page2;
>  void *pml_log;
>  #define PML_INDEX 512
>  
> +void *vpage, *hpage1, *hpage2;
> +void *eptp_list;
> +
>  static inline unsigned ffs(unsigned x)
>  {
>  	int pos = -1;
> @@ -1332,6 +1335,148 @@ static int eptad_init()
>  	return r;
>  }
>  
> +static int vmfunc_init()
> +{
> +	eptp_list = alloc_page();
> +	u64 *buf = eptp_list;
> +
> +	vpage = alloc_page();
> +	hpage1 = alloc_page();
> +	hpage2 = alloc_page();
> +
> +	*((u32 *)vpage) = 0x1;
> +	*((u32 *)hpage1) = 0x2;
> +	*((u32 *)hpage2) = 0x3;
> +
> +	ept_init_common(false);
> +	buf[0] = (u64)pml4;
> +	install_ept(pml4, (unsigned long)hpage1, (unsigned long)vpage,
> +		    EPT_RA | EPT_WA | EPT_EA);
> +
> +	ept_init_common(false);
> +	buf[1] = (u64)pml4;
> +	install_ept(pml4, (unsigned long)hpage2, (unsigned long)vpage,
> +		    EPT_RA | EPT_WA | EPT_EA);
> +
> +	if (!(ctrl_cpu_rev[1].clr & CPU_VMFUNC)) {
> +		printf("\tVMFUNC is not supported");
> +		return VMX_TEST_EXIT;
> +	}
> +
> +	return VMX_TEST_START;
> +}
> +
> +static void vmfunc_ud_handler(struct ex_regs *regs)
> +{
> +	switch(vmx_get_test_stage()) {
> +	case 0:
> +	case 3:
> +		regs->rip += 3;
> +		vmx_inc_test_stage();
> +		vmx_inc_test_stage();
> +		break;
> +	default:
> +		printf("Unexpected #UD hit!\n");
> +		print_vmexit_info();
> +		exit(0);
> +	}
> +}
> +
> +static void vmfunc_main()
> +{
> +	int nr = 0, ept = 0;
> +
> +	handle_exception(UD_VECTOR, vmfunc_ud_handler);
> +	vmx_set_test_stage(0);
> +
> +	/* Call vmfunc when L1 hasn't enabled it' */
> +	asm volatile("vmfunc"
> +		     :
> +		     : "a"(nr), "c"(ept)
> +		     : "memory");
> +
> +	report("VMFUNC - Disabled VMFUNC in sec controls causes #UD",
> +	       vmx_get_test_stage() == 2);
> +
> +	vmcall();
> +	/* function > 64 causes #UD */
> +	nr = 64;
> +	asm volatile("vmfunc"
> +		     :
> +		     : "a"(nr), "c"(ept)
> +		     : "memory");
> +	report("VMFUNC - guest call with EAX > 63 causes #UD",
> +	       vmx_get_test_stage() == 5);
> +
> +	/* invalid vm function causes vmexit */
> +	nr = 1;
> +	asm volatile("vmfunc"
> +		     :
> +		     : "a"(nr), "c"(ept)
> +		     : "memory");
> +	report("VMFUNC - guest call with non-existant function",
> +	       vmx_get_test_stage() == 6);
> +
> +	/* invalid entry from the eptp list causes vmexit */
> +	nr = 0;
> +	ept = 512;
> +	asm volatile("vmfunc"
> +		     :
> +		     : "a"(nr), "c"(ept)
> +		     : "memory");
> +	report("VMFUNC - guest call with invalid entry in eptp list",
> +	       vmx_get_test_stage() == 7);
> +
> +	/*
> +	 * vpage points to hpage2 with value 0x3
> +	 * vmfunc with ecx = 0 should make vpage
> +	 * point to 0x2
> +	 */
> +	if (*((u32 *)vpage) != 0x3) {
> +		printf("Guest address points to unexpected page\n");
> +		exit(0);
> +	}
> +	ept = 0;
> +	asm volatile("vmfunc"
> +		     :
> +		     : "a"(nr), "c"(ept)
> +		     : "memory");
> +	report("VMFUNC - call to switch ept pointer without an exit",
> +	       (vmx_get_test_stage() == 7) && (*((u32 *)vpage) == 0x2));
> +}
> +
> +static int vmfunc_exit_handler(void)
> +{
> +	ulong reason = vmcs_read(EXI_REASON) & 0xff;
> +	u64 guest_rip = vmcs_read(GUEST_RIP);
> +	u32 insn_len = vmcs_read(EXI_INST_LEN);
> +	u32 ctrl_cpu;
> +	u64 controls;
> +
> +	switch (reason) {
> +	case VMX_VMCALL:
> +		ctrl_cpu = vmcs_read(CPU_EXEC_CTRL1) | CPU_VMFUNC;
> +		vmcs_write(CPU_EXEC_CTRL1, ctrl_cpu);
> +
> +		controls = rdmsr(MSR_IA32_VMX_VMFUNC) & 1;
> +		if (!(controls & EPTP_SWITCHING)) {
> +			printf("\tEPTP switching is not supported");
> +			return VMX_TEST_EXIT;
> +		}
> +
> +		vmcs_write(EPTP_LIST_ADDR, (u64)eptp_list);
> +		vmcs_write(VMFUNC_CTRL, controls);
> +	case VMX_VMFUNC:
> +		vmx_inc_test_stage();
> +		vmcs_write(GUEST_RIP, guest_rip + insn_len);
> +		return VMX_TEST_RESUME;
> +	default:
> +		report("Unknown exit reason, %ld", false, reason);
> +		print_vmexit_info();
> +	}
> +	return VMX_TEST_VMEXIT;
> +}
> +
>  static int pml_init()
>  {
>  	u32 ctrl_cpu;
> @@ -3173,6 +3318,7 @@ struct vmx_test vmx_tests[] = {
>  		disable_rdtscp_exit_handler, NULL, {0} },
>  	{ "int3", int3_init, int3_guest_main, int3_exit_handler, NULL, {0} },
>  	{ "into", into_init, into_guest_main, into_exit_handler, NULL, {0} },
> +	{ "vmfunc", vmfunc_init, vmfunc_main, vmfunc_exit_handler, NULL, {0} },
>  	{ "exit_monitor_from_l2_test", NULL, exit_monitor_from_l2_main,
>  		exit_monitor_from_l2_handler, NULL, {0} },
>  	/* Basic V2 tests. */
> 

Reviewed-by: Paolo Bonzini <pbonzini@xxxxxxxxxx>



[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