kvm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [kvm-unit-tests PATCH] vmx_tests: Add vmfunc tests
@ 2017-07-06 23:14 Bandan Das
  2017-07-07  8:46 ` Paolo Bonzini
  2017-07-28 19:59 ` [kvm-unit-tests PATCH v2] " Bandan Das
  0 siblings, 2 replies; 3+ messages in thread
From: Bandan Das @ 2017-07-06 23:14 UTC (permalink / raw)
  To: kvm; +Cc: Paolo Bonzini


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@redhat.com>
---
 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. */
-- 
2.9.4

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [kvm-unit-tests PATCH] vmx_tests: Add vmfunc tests
  2017-07-06 23:14 [kvm-unit-tests PATCH] vmx_tests: Add vmfunc tests Bandan Das
@ 2017-07-07  8:46 ` Paolo Bonzini
  2017-07-28 19:59 ` [kvm-unit-tests PATCH v2] " Bandan Das
  1 sibling, 0 replies; 3+ messages in thread
From: Paolo Bonzini @ 2017-07-07  8:46 UTC (permalink / raw)
  To: Bandan Das, kvm



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@redhat.com>
> ---
>  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@redhat.com>

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [kvm-unit-tests PATCH v2] vmx_tests: Add vmfunc tests
  2017-07-06 23:14 [kvm-unit-tests PATCH] vmx_tests: Add vmfunc tests Bandan Das
  2017-07-07  8:46 ` Paolo Bonzini
@ 2017-07-28 19:59 ` Bandan Das
  1 sibling, 0 replies; 3+ messages in thread
From: Bandan Das @ 2017-07-28 19:59 UTC (permalink / raw)
  To: kvm; +Cc: Paolo Bonzini


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@redhat.com>
---
v2:
 Use eptp instead of pml4 in the eptp_list buffer because
 That would have the necessary bits set for eptp validity
 
 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..c97aad4 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] = eptp;
+	install_ept(pml4, (unsigned long)hpage1, (unsigned long)vpage,
+		    EPT_RA | EPT_WA | EPT_EA);
+
+	ept_init_common(false);
+	buf[1] = eptp;
+	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. */
-- 
2.9.4

^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2017-07-28 19:59 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-07-06 23:14 [kvm-unit-tests PATCH] vmx_tests: Add vmfunc tests Bandan Das
2017-07-07  8:46 ` Paolo Bonzini
2017-07-28 19:59 ` [kvm-unit-tests PATCH v2] " Bandan Das

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).