public inbox for kvm@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] kvm-unit-tests: VMX: Test nested EPT features
@ 2013-09-09  4:57 Arthur Chunqi Li
  2013-09-09  4:57 ` [PATCH 1/2] kvm-unit-tests: VMX: The framework of EPT for nested VMX testing Arthur Chunqi Li
                   ` (2 more replies)
  0 siblings, 3 replies; 11+ messages in thread
From: Arthur Chunqi Li @ 2013-09-09  4:57 UTC (permalink / raw)
  To: kvm; +Cc: jan.kiszka, gleb, pbonzini, Arthur Chunqi Li

This series of patches provide the framework of nested EPT and some test
cases for nested EPT features.

Arthur Chunqi Li (2):
  kvm-unit-tests: VMX: The framework of EPT for nested VMX testing
  kvm-unit-tests: VMX: Test cases for nested EPT

 x86/vmx.c       |  159 ++++++++++++++++++++++++++++++++-
 x86/vmx.h       |   76 ++++++++++++++++
 x86/vmx_tests.c |  266 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 497 insertions(+), 4 deletions(-)

-- 
1.7.9.5


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

* [PATCH 1/2] kvm-unit-tests: VMX: The framework of EPT for nested VMX testing
  2013-09-09  4:57 [PATCH 0/2] kvm-unit-tests: VMX: Test nested EPT features Arthur Chunqi Li
@ 2013-09-09  4:57 ` Arthur Chunqi Li
  2013-09-09 13:45   ` Paolo Bonzini
  2013-09-09  4:57 ` [PATCH 2/2] kvm-unit-tests: VMX: Test cases for nested EPT Arthur Chunqi Li
  2013-09-09  7:17 ` [PATCH 0/2] kvm-unit-tests: VMX: Test nested EPT features Jan Kiszka
  2 siblings, 1 reply; 11+ messages in thread
From: Arthur Chunqi Li @ 2013-09-09  4:57 UTC (permalink / raw)
  To: kvm; +Cc: jan.kiszka, gleb, pbonzini, Arthur Chunqi Li

The framework of EPT for nested VMX, including functions to build up
EPT paging structures, read/set EPT PTEs and setup a range of 1:1 map
EPT.

Signed-off-by: Arthur Chunqi Li <yzt356@gmail.com>
---
 x86/vmx.c |  159 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 x86/vmx.h |   76 +++++++++++++++++++++++++++++
 2 files changed, 231 insertions(+), 4 deletions(-)

diff --git a/x86/vmx.c b/x86/vmx.c
index ca36d35..87d1d55 100644
--- a/x86/vmx.c
+++ b/x86/vmx.c
@@ -143,6 +143,159 @@ asm(
 	"	call hypercall\n\t"
 );
 
+/* EPT paging structure related functions */
+/* install_ept_entry : Install a page to a given level in EPT
+		@pml4 : addr of pml4 table
+		@pte_level : level of PTE to set
+		@guest_addr : physical address of guest
+		@pte : pte value to set
+		@pt_page : address of page table, NULL for a new page
+ */
+void install_ept_entry(unsigned long *pml4,
+		int pte_level,
+		unsigned long guest_addr,
+		unsigned long pte,
+		unsigned long *pt_page)
+{
+	int level;
+	unsigned long *pt = pml4;
+	unsigned offset;
+
+	for (level = EPT_PAGE_LEVEL; level > pte_level; --level) {
+		offset = (guest_addr >> ((level-1) * EPT_PGDIR_WIDTH + 12))
+				& EPT_PGDIR_MASK;
+		if (!(pt[offset] & (EPT_PRESENT))) {
+			unsigned long *new_pt = pt_page;
+			if (!new_pt)
+				new_pt = alloc_page();
+			else
+				pt_page = 0;
+			memset(new_pt, 0, PAGE_SIZE);
+			pt[offset] = virt_to_phys(new_pt)
+					| EPT_RA | EPT_WA | EPT_EA;
+		}
+		pt = phys_to_virt(pt[offset] & 0xffffffffff000ull);
+	}
+	offset = ((unsigned long)guest_addr >> ((level-1) *
+			EPT_PGDIR_WIDTH + 12)) & EPT_PGDIR_MASK;
+	pt[offset] = pte;
+}
+
+/* Map a page, @perm is the permission of the page */
+void install_ept(unsigned long *pml4,
+		unsigned long phys,
+		unsigned long guest_addr,
+		u64 perm)
+{
+	install_ept_entry(pml4, 1, guest_addr, (phys & PAGE_MASK) | perm, 0);
+}
+
+/* Map a 1G-size page */
+void install_1g_ept(unsigned long *pml4,
+		unsigned long phys,
+		unsigned long guest_addr,
+		u64 perm)
+{
+	install_ept_entry(pml4, 3, guest_addr,
+			(phys & PAGE_MASK) | perm | EPT_LARGE_PAGE, 0);
+}
+
+/* Map a 2M-size page */
+void install_2m_ept(unsigned long *pml4,
+		unsigned long phys,
+		unsigned long guest_addr,
+		u64 perm)
+{
+	install_ept_entry(pml4, 2, guest_addr,
+			(phys & PAGE_MASK) | perm | EPT_LARGE_PAGE, 0);
+}
+
+/* setup_ept_range : Setup a range of 1:1 mapped page to EPT paging structure.
+		@start : start address of guest page
+		@len : length of address to be mapped
+		@map_1g : whether 1G page map is used
+		@map_2m : whether 2M page map is used
+		@perm : permission for every page
+ */
+int setup_ept_range(unsigned long *pml4, unsigned long start,
+		unsigned long len, int map_1g, int map_2m, u64 perm)
+{
+	u64 phys = start;
+	u64 max = (u64)len + (u64)start;
+
+	if (map_1g) {
+		while (phys + PAGE_SIZE_1G <= max) {
+			install_1g_ept(pml4, phys, phys, perm);
+			phys += PAGE_SIZE_1G;
+		}
+	}
+	if (map_2m) {
+		while (phys + PAGE_SIZE_2M <= max) {
+			install_2m_ept(pml4, phys, phys, perm);
+			phys += PAGE_SIZE_2M;
+		}
+	}
+	while (phys + PAGE_SIZE <= max) {
+		install_ept(pml4, phys, phys, perm);
+		phys += PAGE_SIZE;
+	}
+	return 0;
+}
+
+/* get_ept_pte : Get the PTE of a given level in EPT,
+    @level == 1 means get the latest level*/
+unsigned long get_ept_pte(unsigned long *pml4,
+		unsigned long guest_addr, int level)
+{
+	int l;
+	unsigned long *pt = pml4, pte;
+	unsigned offset;
+
+	for (l = EPT_PAGE_LEVEL; l > 1; --l) {
+		offset = (guest_addr >> (((l-1) * EPT_PGDIR_WIDTH) + 12))
+				& EPT_PGDIR_MASK;
+		pte = pt[offset];
+		if (!(pte & (EPT_PRESENT)))
+			return 0;
+		if (l == level)
+			return pte;
+		if (l < 4 && (pte & EPT_LARGE_PAGE))
+			return pte;
+		pt = (unsigned long *)(pte & 0xffffffffff000ull);
+	}
+	offset = (guest_addr >> (((l-1) * EPT_PGDIR_WIDTH) + 12))
+			& EPT_PGDIR_MASK;
+	pte = pt[offset];
+	return pte;
+}
+
+int set_ept_pte(unsigned long *pml4, unsigned long guest_addr,
+		int level, u64 pte_val)
+{
+	int l;
+	unsigned long *pt = pml4;
+	unsigned offset;
+
+	if (level < 1 || level > 3)
+		return -1;
+	for (l = EPT_PAGE_LEVEL; l > 1; --l) {
+		offset = (guest_addr >> (((l-1) * EPT_PGDIR_WIDTH) + 12))
+				& EPT_PGDIR_MASK;
+		if (l == level) {
+			pt[offset] = pte_val;
+			return 0;
+		}
+		if (!(pt[offset] & (EPT_PRESENT)))
+			return -1;
+		pt = (unsigned long *)(pt[offset] & 0xffffffffff000ull);
+	}
+	offset = (guest_addr >> (((l-1) * EPT_PGDIR_WIDTH) + 12))
+			& EPT_PGDIR_MASK;
+	pt[offset] = pte_val;
+	return 0;
+}
+
+
 static void init_vmcs_ctrl(void)
 {
 	/* 26.2 CHECKS ON VMX CONTROLS AND HOST-STATE AREA */
@@ -336,10 +489,8 @@ static void init_vmx(void)
 			: MSR_IA32_VMX_ENTRY_CTLS);
 	ctrl_cpu_rev[0].val = rdmsr(basic.ctrl ? MSR_IA32_VMX_TRUE_PROC
 			: MSR_IA32_VMX_PROCBASED_CTLS);
-	if (ctrl_cpu_rev[0].set & CPU_SECONDARY)
-		ctrl_cpu_rev[1].val = rdmsr(MSR_IA32_VMX_PROCBASED_CTLS2);
-	if (ctrl_cpu_rev[1].set & CPU_EPT || ctrl_cpu_rev[1].set & CPU_VPID)
-		ept_vpid.val = rdmsr(MSR_IA32_VMX_EPT_VPID_CAP);
+	ctrl_cpu_rev[1].val = rdmsr(MSR_IA32_VMX_PROCBASED_CTLS2);
+	ept_vpid.val = rdmsr(MSR_IA32_VMX_EPT_VPID_CAP);
 
 	write_cr0((read_cr0() & fix_cr0_clr) | fix_cr0_set);
 	write_cr4((read_cr4() & fix_cr4_clr) | fix_cr4_set | X86_CR4_VMXE);
diff --git a/x86/vmx.h b/x86/vmx.h
index 28595d8..742c2b2 100644
--- a/x86/vmx.h
+++ b/x86/vmx.h
@@ -432,6 +432,59 @@ enum Ctrl1 {
 #define HYPERCALL_MASK		0xFFF
 #define HYPERCALL_VMEXIT	0x1
 
+#define EPTP_PG_WALK_LEN_SHIFT	3ul
+#define EPTP_AD_FLAG			(1ul << 6)
+
+#define EPT_MEM_TYPE_UC	0ul
+#define EPT_MEM_TYPE_WC	1ul
+#define EPT_MEM_TYPE_WT	4ul
+#define EPT_MEM_TYPE_WP	5ul
+#define EPT_MEM_TYPE_WB	6ul
+
+#define EPT_RA			1ul
+#define EPT_WA			2ul
+#define EPT_EA			4ul
+#define EPT_PRESENT		(EPT_RA | EPT_WA | EPT_EA)	
+#define EPT_ACCESS_FLAG	(1ul << 8)
+#define EPT_DIRTY_FLAG		(1ul << 9)
+#define EPT_LARGE_PAGE		(1ul << 7)
+#define EPT_MEM_TYPE_SHIFT	3ul
+#define EPT_IGNORE_PAT		(1ul << 6)
+#define EPT_SUPPRESS_VE	(1ull << 63)
+
+#define EPT_CAP_WT		1ull
+#define EPT_CAP_PWL4		(1ull << 6)
+#define EPT_CAP_UC		(1ull << 8)
+#define EPT_CAP_WB		(1ull << 14)
+#define EPT_CAP_2M_PAGE	(1ull << 16)
+#define EPT_CAP_1G_PAGE	(1ull << 17)
+#define EPT_CAP_INVEPT		(1ull << 20)
+#define EPT_CAP_INVEPT_SINGLE	(1ull << 25)
+#define EPT_CAP_INVEPT_ALL	(1ull << 26)
+#define EPT_CAP_AD_FLAG	(1ull << 21)
+
+#define PAGE_SIZE_2M		(512 * PAGE_SIZE)
+#define PAGE_SIZE_1G		(512 * PAGE_SIZE_2M)
+#define	EPT_PAGE_LEVEL	4
+#define	EPT_PGDIR_WIDTH	9
+#define	EPT_PGDIR_MASK	511
+#define PAGE_MASK (~(PAGE_SIZE-1))
+
+#define EPT_VLT_RD		1
+#define EPT_VLT_WR		(1 << 1)
+#define EPT_VLT_FETCH		(1 << 2)
+#define EPT_VLT_PERM_RD	(1 << 3)
+#define EPT_VLT_PERM_WR	(1 << 4)
+#define EPT_VLT_PERM_EX	(1 << 5)
+#define EPT_VLT_LADDR_VLD	(1 << 7)
+#define EPT_VLT_PADDR		(1 << 8)
+
+#define MAGIC_VAL_1		0x12345678ul
+#define MAGIC_VAL_2		0x87654321ul
+#define MAGIC_VAL_3		0xfffffffful
+
+#define INVEPT_SINGLE		1
+#define INVEPT_GLOBAL		2
 
 extern struct regs regs;
 
@@ -472,8 +525,31 @@ static inline int vmcs_save(struct vmcs **vmcs)
 	return ret;
 }
 
+static inline void invept(unsigned long type, u64 eptp)
+{
+	struct {
+		u64 eptp, gpa;
+	} operand = {eptp, 0};
+	asm volatile("invept %0, %1\n" ::"m"(operand),"r"(type));
+}
+
 void report(const char *name, int result);
 void print_vmexit_info();
+void install_ept_entry(unsigned long *pml4, int pte_level,
+		unsigned long guest_addr, unsigned long pte,
+		unsigned long *pt_page);
+void install_1g_ept(unsigned long *pml4, unsigned long phys,
+		unsigned long guest_addr, u64 perm);
+void install_2m_ept(unsigned long *pml4, unsigned long phys,
+		unsigned long guest_addr, u64 perm);
+void install_ept(unsigned long *pml4, unsigned long phys,
+		unsigned long guest_addr, u64 perm);
+int setup_ept_range(unsigned long *pml4, unsigned long start,
+		unsigned long len, int map_1g, int map_2m, u64 perm);
+unsigned long get_ept_pte(unsigned long *pml4,
+		unsigned long guest_addr, int level);
+int set_ept_pte(unsigned long *pml4, unsigned long guest_addr,
+		int level, u64 pte_val);
 
 #endif
 
-- 
1.7.9.5


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

* [PATCH 2/2] kvm-unit-tests: VMX: Test cases for nested EPT
  2013-09-09  4:57 [PATCH 0/2] kvm-unit-tests: VMX: Test nested EPT features Arthur Chunqi Li
  2013-09-09  4:57 ` [PATCH 1/2] kvm-unit-tests: VMX: The framework of EPT for nested VMX testing Arthur Chunqi Li
@ 2013-09-09  4:57 ` Arthur Chunqi Li
  2013-09-09 13:56   ` Paolo Bonzini
  2013-09-09 15:29   ` Arthur Chunqi Li
  2013-09-09  7:17 ` [PATCH 0/2] kvm-unit-tests: VMX: Test nested EPT features Jan Kiszka
  2 siblings, 2 replies; 11+ messages in thread
From: Arthur Chunqi Li @ 2013-09-09  4:57 UTC (permalink / raw)
  To: kvm; +Cc: jan.kiszka, gleb, pbonzini, Arthur Chunqi Li

Some test cases for nested EPT features, including:
1. EPT basic framework tests: read, write and remap.
2. EPT misconfigurations test cases: page permission mieconfiguration
and memory type misconfiguration
3. EPT violations test cases: page permission violation and paging
structure violation

Signed-off-by: Arthur Chunqi Li <yzt356@gmail.com>
---
 x86/vmx_tests.c |  266 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 266 insertions(+)

diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c
index c1b39f4..a0b9824 100644
--- a/x86/vmx_tests.c
+++ b/x86/vmx_tests.c
@@ -1,4 +1,36 @@
 #include "vmx.h"
+#include "processor.h"
+#include "vm.h"
+#include "msr.h"
+#include "fwcfg.h"
+
+volatile u32 stage;
+volatile bool init_fail;
+unsigned long *pml4;
+u64 eptp;
+void *data_page1, *data_page2;
+
+static inline void set_stage(u32 s)
+{
+	barrier();
+	stage = s;
+	barrier();
+}
+
+static inline u32 get_stage()
+{
+	u32 s;
+
+	barrier();
+	s = stage;
+	barrier();
+	return s;
+}
+
+static inline void vmcall()
+{
+	asm volatile ("vmcall");
+}
 
 void basic_init()
 {
@@ -76,6 +108,238 @@ int vmenter_exit_handler()
 	return VMX_TEST_VMEXIT;
 }
 
+static int setup_ept()
+{
+	int support_2m;
+	unsigned long end_of_memory;
+
+	if (!(ept_vpid.val & EPT_CAP_UC) &&
+			!(ept_vpid.val & EPT_CAP_WB)) {
+		printf("\tEPT paging-structure memory type "
+				"UC&WB are not supported\n");
+		return 1;
+	}
+	if (ept_vpid.val & EPT_CAP_UC)
+		eptp = EPT_MEM_TYPE_UC;
+	else
+		eptp = EPT_MEM_TYPE_WB;
+	if (!(ept_vpid.val & EPT_CAP_PWL4)) {
+		printf("\tPWL4 is not supported\n");
+		return 1;
+	}
+	eptp |= (3 << EPTP_PG_WALK_LEN_SHIFT);
+	pml4 = alloc_page();
+	memset(pml4, 0, PAGE_SIZE);
+	eptp |= virt_to_phys(pml4);
+	vmcs_write(EPTP, eptp);
+	support_2m = !!(ept_vpid.val & EPT_CAP_2M_PAGE);
+	end_of_memory = fwcfg_get_u64(FW_CFG_RAM_SIZE);
+	if (end_of_memory < (1ul << 32))
+		end_of_memory = (1ul << 32);
+	if (setup_ept_range(pml4, 0, end_of_memory,
+			0, support_2m, EPT_WA | EPT_RA | EPT_EA)) {
+		printf("\tSet ept tables failed.\n");
+		return 1;
+	}
+	return 0;
+}
+
+static void ept_init()
+{
+	u32 ctrl_cpu[2];
+
+	init_fail = false;
+	ctrl_cpu[0] = vmcs_read(CPU_EXEC_CTRL0);
+	ctrl_cpu[1] = vmcs_read(CPU_EXEC_CTRL1);
+	ctrl_cpu[0] = (ctrl_cpu[0] | CPU_SECONDARY)
+		& ctrl_cpu_rev[0].clr;
+	ctrl_cpu[1] = (ctrl_cpu[1] | CPU_EPT)
+		& ctrl_cpu_rev[1].clr;
+	vmcs_write(CPU_EXEC_CTRL0, ctrl_cpu[0]);
+	vmcs_write(CPU_EXEC_CTRL1, ctrl_cpu[1] | CPU_EPT);
+	if (setup_ept())
+		init_fail = true;
+	data_page1 = alloc_page();
+	data_page2 = alloc_page();
+	memset(data_page1, 0x0, PAGE_SIZE);
+	memset(data_page2, 0x0, PAGE_SIZE);
+	*((u32 *)data_page1) = MAGIC_VAL_1;
+	*((u32 *)data_page2) = MAGIC_VAL_2;
+	install_ept(pml4, (unsigned long)data_page1, (unsigned long)data_page2,
+			EPT_RA | EPT_WA | EPT_EA);
+}
+
+static void ept_main()
+{
+	if (init_fail)
+		return;
+	if (!(ctrl_cpu_rev[0].clr & CPU_SECONDARY)
+		&& !(ctrl_cpu_rev[1].clr & CPU_EPT)) {
+		printf("\tEPT is not supported");
+		return;
+	}
+	set_stage(0);
+	if (*((u32 *)data_page2) != MAGIC_VAL_1 &&
+			*((u32 *)data_page1) != MAGIC_VAL_1)
+		report("EPT basic framework - read", 0);
+	else {
+		*((u32 *)data_page2) = MAGIC_VAL_3;
+		vmcall();
+		if (get_stage() == 1) {
+			if (*((u32 *)data_page1) == MAGIC_VAL_3 &&
+					*((u32 *)data_page2) == MAGIC_VAL_2)
+				report("EPT basic framework", 1);
+			else
+				report("EPT basic framework - remap", 1);
+		}
+	}
+	// Test EPT Misconfigurations
+	set_stage(1);
+	vmcall();
+	*((u32 *)data_page1) = MAGIC_VAL_1;
+	if (get_stage() != 2) {
+		report("EPT misconfigurations", 0);
+		goto t1;
+	}
+	set_stage(2);
+	vmcall();
+	*((u32 *)data_page1) = MAGIC_VAL_1;
+	if (get_stage() != 3) {
+		report("EPT misconfigurations", 0);
+		goto t1;
+	}
+	report("EPT misconfigurations", 1);
+t1:
+	// Test EPT violation
+	set_stage(3);
+	vmcall();
+	*((u32 *)data_page1) = MAGIC_VAL_1;
+	if (get_stage() == 4)
+		report("EPT violation - page permission", 1);
+	else
+		report("EPT violation - page permission", 0);
+	// Violation caused by EPT paging structure
+	set_stage(4);
+	vmcall();
+	*((u32 *)data_page1) = MAGIC_VAL_2;
+	if (get_stage() == 5)
+		report("EPT violation - paging structure", 1);
+	else
+		report("EPT violation - paging structure", 0);
+	return;
+}
+
+static int ept_exit_handler()
+{
+	u64 guest_rip;
+	ulong reason;
+	u32 insn_len;
+	u32 exit_qual;
+	static unsigned long data_page1_pte, data_page1_pte_pte;
+
+	guest_rip = vmcs_read(GUEST_RIP);
+	reason = vmcs_read(EXI_REASON) & 0xff;
+	insn_len = vmcs_read(EXI_INST_LEN);
+	exit_qual = vmcs_read(EXI_QUALIFICATION);
+	switch (reason) {
+	case VMX_VMCALL:
+		switch (get_stage()) {
+		case 0:
+			if (*((u32 *)data_page1) == MAGIC_VAL_3 &&
+					*((u32 *)data_page2) == MAGIC_VAL_2) {
+				set_stage(get_stage() + 1);
+				install_ept(pml4, (unsigned long)data_page2,
+						(unsigned long)data_page2,
+						EPT_RA | EPT_WA | EPT_EA);
+			} else
+				report("EPT basic framework - write\n", 0);
+			break;
+		case 1:
+			install_ept(pml4, (unsigned long)data_page1,
+ 				(unsigned long)data_page1, EPT_WA);
+			invept(INVEPT_SINGLE, eptp);
+			break;
+		case 2:
+			install_ept(pml4, (unsigned long)data_page1,
+ 				(unsigned long)data_page1,
+ 				EPT_RA | EPT_WA | EPT_EA |
+ 				(2 << EPT_MEM_TYPE_SHIFT));
+			invept(INVEPT_SINGLE, eptp);
+			break;
+		case 3:
+			data_page1_pte = get_ept_pte(pml4,
+				(unsigned long)data_page1, 1);
+			set_ept_pte(pml4, (unsigned long)data_page1, 
+				1, data_page1_pte & (~EPT_PRESENT));
+			invept(INVEPT_SINGLE, eptp);
+			break;
+		case 4:
+			data_page1_pte = get_ept_pte(pml4,
+				(unsigned long)data_page1, 2);
+			data_page1_pte &= PAGE_MASK;
+			data_page1_pte_pte = get_ept_pte(pml4, data_page1_pte, 2);
+			set_ept_pte(pml4, data_page1_pte, 2,
+				data_page1_pte_pte & (~EPT_PRESENT));
+			invept(INVEPT_SINGLE, eptp);
+			break;
+		// Should not reach here
+		default:
+			printf("ERROR - unknown stage, %d.\n", get_stage());
+			print_vmexit_info();
+			return VMX_TEST_VMEXIT;
+		}
+		vmcs_write(GUEST_RIP, guest_rip + insn_len);
+		return VMX_TEST_RESUME;
+	case VMX_EPT_MISCONFIG:
+		switch (get_stage()) {
+		case 1:
+		case 2:
+			set_stage(get_stage() + 1);
+			install_ept(pml4, (unsigned long)data_page1,
+ 				(unsigned long)data_page1,
+ 				EPT_RA | EPT_WA | EPT_EA);
+			invept(INVEPT_SINGLE, eptp);
+			break;
+		// Should not reach here
+		default:
+			printf("ERROR - unknown stage, %d.\n", get_stage());
+			print_vmexit_info();
+			return VMX_TEST_VMEXIT;
+		}
+		vmcs_write(GUEST_RIP, guest_rip + insn_len);
+		return VMX_TEST_RESUME;
+	case VMX_EPT_VIOLATION:
+		switch(get_stage()) {
+		case 3:
+			if (exit_qual == (EPT_VLT_WR | EPT_VLT_LADDR_VLD |
+					EPT_VLT_PADDR))
+				set_stage(get_stage() + 1);
+			set_ept_pte(pml4, (unsigned long)data_page1, 
+				1, data_page1_pte | (EPT_PRESENT));
+			invept(INVEPT_SINGLE, eptp);
+			break;
+		case 4:
+			if (exit_qual == (EPT_VLT_RD | EPT_VLT_LADDR_VLD))
+				set_stage(get_stage() + 1);
+			set_ept_pte(pml4, data_page1_pte, 2,
+				data_page1_pte_pte | (EPT_PRESENT));
+			invept(INVEPT_SINGLE, eptp);
+			break;
+		default:
+			// Should not reach here
+			printf("ERROR : unknown stage, %d\n", get_stage());
+			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 +347,7 @@ struct vmx_test vmx_tests[] = {
 		basic_syscall_handler, {0} },
 	{ "vmenter", basic_init, vmenter_main, vmenter_exit_handler,
 		basic_syscall_handler, {0} },
+	{ "EPT framework", ept_init, ept_main, ept_exit_handler,
+		basic_syscall_handler, {0} },
 	{ NULL, NULL, NULL, NULL, NULL, {0} },
 };
-- 
1.7.9.5


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

* Re: [PATCH 0/2] kvm-unit-tests: VMX: Test nested EPT features
  2013-09-09  4:57 [PATCH 0/2] kvm-unit-tests: VMX: Test nested EPT features Arthur Chunqi Li
  2013-09-09  4:57 ` [PATCH 1/2] kvm-unit-tests: VMX: The framework of EPT for nested VMX testing Arthur Chunqi Li
  2013-09-09  4:57 ` [PATCH 2/2] kvm-unit-tests: VMX: Test cases for nested EPT Arthur Chunqi Li
@ 2013-09-09  7:17 ` Jan Kiszka
  2013-09-09  7:44   ` Arthur Chunqi Li
  2 siblings, 1 reply; 11+ messages in thread
From: Jan Kiszka @ 2013-09-09  7:17 UTC (permalink / raw)
  To: Arthur Chunqi Li; +Cc: kvm, gleb, pbonzini

[-- Attachment #1: Type: text/plain, Size: 666 bytes --]

On 2013-09-09 06:57, Arthur Chunqi Li wrote:
> This series of patches provide the framework of nested EPT and some test
> cases for nested EPT features.
> 
> Arthur Chunqi Li (2):
>   kvm-unit-tests: VMX: The framework of EPT for nested VMX testing
>   kvm-unit-tests: VMX: Test cases for nested EPT
> 
>  x86/vmx.c       |  159 ++++++++++++++++++++++++++++++++-
>  x86/vmx.h       |   76 ++++++++++++++++
>  x86/vmx_tests.c |  266 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 497 insertions(+), 4 deletions(-)
> 

I suppose this is v2 of the previous patch? What is the delta? A meta
changelog could go here.

Jan


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 263 bytes --]

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

* Re: [PATCH 0/2] kvm-unit-tests: VMX: Test nested EPT features
  2013-09-09  7:17 ` [PATCH 0/2] kvm-unit-tests: VMX: Test nested EPT features Jan Kiszka
@ 2013-09-09  7:44   ` Arthur Chunqi Li
  0 siblings, 0 replies; 11+ messages in thread
From: Arthur Chunqi Li @ 2013-09-09  7:44 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: kvm, Gleb Natapov, Paolo Bonzini

On Mon, Sep 9, 2013 at 3:17 PM, Jan Kiszka <jan.kiszka@web.de> wrote:
> On 2013-09-09 06:57, Arthur Chunqi Li wrote:
>> This series of patches provide the framework of nested EPT and some test
>> cases for nested EPT features.
>>
>> Arthur Chunqi Li (2):
>>   kvm-unit-tests: VMX: The framework of EPT for nested VMX testing
>>   kvm-unit-tests: VMX: Test cases for nested EPT
>>
>>  x86/vmx.c       |  159 ++++++++++++++++++++++++++++++++-
>>  x86/vmx.h       |   76 ++++++++++++++++
>>  x86/vmx_tests.c |  266 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 497 insertions(+), 4 deletions(-)
>>
>
> I suppose this is v2 of the previous patch? What is the delta? A meta
> changelog could go here.
Yes, v1 just provide the framework of EPT (similar to the first patch
of this series), and some more tests about nested EPT is added in this
series (the second patch).

Arthur
>
> Jan
>

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

* Re: [PATCH 1/2] kvm-unit-tests: VMX: The framework of EPT for nested VMX testing
  2013-09-09  4:57 ` [PATCH 1/2] kvm-unit-tests: VMX: The framework of EPT for nested VMX testing Arthur Chunqi Li
@ 2013-09-09 13:45   ` Paolo Bonzini
  0 siblings, 0 replies; 11+ messages in thread
From: Paolo Bonzini @ 2013-09-09 13:45 UTC (permalink / raw)
  To: Arthur Chunqi Li; +Cc: kvm, jan.kiszka, gleb

Il 09/09/2013 06:57, Arthur Chunqi Li ha scritto:
> The framework of EPT for nested VMX, including functions to build up
> EPT paging structures, read/set EPT PTEs and setup a range of 1:1 map
> EPT.
> 
> Signed-off-by: Arthur Chunqi Li <yzt356@gmail.com>
> ---
>  x86/vmx.c |  159 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
>  x86/vmx.h |   76 +++++++++++++++++++++++++++++
>  2 files changed, 231 insertions(+), 4 deletions(-)
> 
> @@ -336,10 +489,8 @@ static void init_vmx(void)
>  			: MSR_IA32_VMX_ENTRY_CTLS);
>  	ctrl_cpu_rev[0].val = rdmsr(basic.ctrl ? MSR_IA32_VMX_TRUE_PROC
>  			: MSR_IA32_VMX_PROCBASED_CTLS);
> -	if (ctrl_cpu_rev[0].set & CPU_SECONDARY)
> -		ctrl_cpu_rev[1].val = rdmsr(MSR_IA32_VMX_PROCBASED_CTLS2);
> -	if (ctrl_cpu_rev[1].set & CPU_EPT || ctrl_cpu_rev[1].set & CPU_VPID)
> -		ept_vpid.val = rdmsr(MSR_IA32_VMX_EPT_VPID_CAP);
> +	ctrl_cpu_rev[1].val = rdmsr(MSR_IA32_VMX_PROCBASED_CTLS2);
> +	ept_vpid.val = rdmsr(MSR_IA32_VMX_EPT_VPID_CAP);

This is because these MSRs are confusing.

Your definitions are:

union vmx_ctrl_cpu {
        u64 val;
        struct { 
                u32 set, clr; 
        };
};

so "set" are the low 32-bit and "clr" are the high 32-bits.

This is how the SDM's description should be read:

set    clr
0      0          if bit is 0, ok. if bit is 1, fail
			=> reserved, must be 0
0      1          if bit is 0, ok. if bit is 1, ok
			=> supported by processor
1      0          if bit is 0, fail. if bit is 1, fail
			=> impossible
1      1	  if bit is 0, fail. if bit is 1, ok
			=> reserved, must be 1
So the right fix is:

        if ((ctrl_cpu_rev[0].clr & CPU_SECONDARY) != 0)
                ctrl_cpu_rev[1].val = rdmsr(MSR_IA32_VMX_PROCBASED_CTLS2);
        if ((ctrl_cpu_rev[1].clr & (CPU_EPT | CPU_VPID)) != 0)
                ept_vpid.val = rdmsr(MSR_IA32_VMX_EPT_VPID_CAP);

While looking at this I found another related bug.  This line:

	ctrl_cpu[1] |= ctrl_cpu_rev[1].set & ctrl_cpu_rev[1].clr;

should be

	ctrl_cpu[1] = (ctrl_cpu[1] | ctrl_cpu_rev[1].set) & ctrl_cpu_rev[1].clr;

which is the same as other lines using the MSRs.

Paolo

>  	write_cr0((read_cr0() & fix_cr0_clr) | fix_cr0_set);
>  	write_cr4((read_cr4() & fix_cr4_clr) | fix_cr4_set | X86_CR4_VMXE);
> diff --git a/x86/vmx.h b/x86/vmx.h
> index 28595d8..742c2b2 100644
> --- a/x86/vmx.h
> +++ b/x86/vmx.h
> @@ -432,6 +432,59 @@ enum Ctrl1 {
>  #define HYPERCALL_MASK		0xFFF
>  #define HYPERCALL_VMEXIT	0x1
>  
> +#define EPTP_PG_WALK_LEN_SHIFT	3ul
> +#define EPTP_AD_FLAG			(1ul << 6)
> +
> +#define EPT_MEM_TYPE_UC	0ul
> +#define EPT_MEM_TYPE_WC	1ul
> +#define EPT_MEM_TYPE_WT	4ul
> +#define EPT_MEM_TYPE_WP	5ul
> +#define EPT_MEM_TYPE_WB	6ul
> +
> +#define EPT_RA			1ul
> +#define EPT_WA			2ul
> +#define EPT_EA			4ul
> +#define EPT_PRESENT		(EPT_RA | EPT_WA | EPT_EA)	
> +#define EPT_ACCESS_FLAG	(1ul << 8)
> +#define EPT_DIRTY_FLAG		(1ul << 9)
> +#define EPT_LARGE_PAGE		(1ul << 7)
> +#define EPT_MEM_TYPE_SHIFT	3ul
> +#define EPT_IGNORE_PAT		(1ul << 6)
> +#define EPT_SUPPRESS_VE	(1ull << 63)
> +
> +#define EPT_CAP_WT		1ull
> +#define EPT_CAP_PWL4		(1ull << 6)
> +#define EPT_CAP_UC		(1ull << 8)
> +#define EPT_CAP_WB		(1ull << 14)
> +#define EPT_CAP_2M_PAGE	(1ull << 16)
> +#define EPT_CAP_1G_PAGE	(1ull << 17)
> +#define EPT_CAP_INVEPT		(1ull << 20)
> +#define EPT_CAP_INVEPT_SINGLE	(1ull << 25)
> +#define EPT_CAP_INVEPT_ALL	(1ull << 26)
> +#define EPT_CAP_AD_FLAG	(1ull << 21)
> +
> +#define PAGE_SIZE_2M		(512 * PAGE_SIZE)
> +#define PAGE_SIZE_1G		(512 * PAGE_SIZE_2M)
> +#define	EPT_PAGE_LEVEL	4
> +#define	EPT_PGDIR_WIDTH	9
> +#define	EPT_PGDIR_MASK	511
> +#define PAGE_MASK (~(PAGE_SIZE-1))
> +
> +#define EPT_VLT_RD		1
> +#define EPT_VLT_WR		(1 << 1)
> +#define EPT_VLT_FETCH		(1 << 2)
> +#define EPT_VLT_PERM_RD	(1 << 3)
> +#define EPT_VLT_PERM_WR	(1 << 4)
> +#define EPT_VLT_PERM_EX	(1 << 5)
> +#define EPT_VLT_LADDR_VLD	(1 << 7)
> +#define EPT_VLT_PADDR		(1 << 8)
> +
> +#define MAGIC_VAL_1		0x12345678ul
> +#define MAGIC_VAL_2		0x87654321ul
> +#define MAGIC_VAL_3		0xfffffffful
> +
> +#define INVEPT_SINGLE		1
> +#define INVEPT_GLOBAL		2
>  
>  extern struct regs regs;
>  
> @@ -472,8 +525,31 @@ static inline int vmcs_save(struct vmcs **vmcs)
>  	return ret;
>  }
>  
> +static inline void invept(unsigned long type, u64 eptp)
> +{
> +	struct {
> +		u64 eptp, gpa;
> +	} operand = {eptp, 0};
> +	asm volatile("invept %0, %1\n" ::"m"(operand),"r"(type));
> +}
> +
>  void report(const char *name, int result);
>  void print_vmexit_info();
> +void install_ept_entry(unsigned long *pml4, int pte_level,
> +		unsigned long guest_addr, unsigned long pte,
> +		unsigned long *pt_page);
> +void install_1g_ept(unsigned long *pml4, unsigned long phys,
> +		unsigned long guest_addr, u64 perm);
> +void install_2m_ept(unsigned long *pml4, unsigned long phys,
> +		unsigned long guest_addr, u64 perm);
> +void install_ept(unsigned long *pml4, unsigned long phys,
> +		unsigned long guest_addr, u64 perm);
> +int setup_ept_range(unsigned long *pml4, unsigned long start,
> +		unsigned long len, int map_1g, int map_2m, u64 perm);
> +unsigned long get_ept_pte(unsigned long *pml4,
> +		unsigned long guest_addr, int level);
> +int set_ept_pte(unsigned long *pml4, unsigned long guest_addr,
> +		int level, u64 pte_val);
>  
>  #endif
>  
> 


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

* Re: [PATCH 2/2] kvm-unit-tests: VMX: Test cases for nested EPT
  2013-09-09  4:57 ` [PATCH 2/2] kvm-unit-tests: VMX: Test cases for nested EPT Arthur Chunqi Li
@ 2013-09-09 13:56   ` Paolo Bonzini
  2013-09-09 14:11     ` Arthur Chunqi Li
  2013-09-09 15:29   ` Arthur Chunqi Li
  1 sibling, 1 reply; 11+ messages in thread
From: Paolo Bonzini @ 2013-09-09 13:56 UTC (permalink / raw)
  To: Arthur Chunqi Li; +Cc: kvm, jan.kiszka, gleb

Il 09/09/2013 06:57, Arthur Chunqi Li ha scritto:
> Some test cases for nested EPT features, including:
> 1. EPT basic framework tests: read, write and remap.
> 2. EPT misconfigurations test cases: page permission mieconfiguration
> and memory type misconfiguration
> 3. EPT violations test cases: page permission violation and paging
> structure violation
> 
> Signed-off-by: Arthur Chunqi Li <yzt356@gmail.com>
> ---
>  x86/vmx_tests.c |  266 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 266 insertions(+)
> 
> diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c
> index c1b39f4..a0b9824 100644
> --- a/x86/vmx_tests.c
> +++ b/x86/vmx_tests.c
> @@ -1,4 +1,36 @@
>  #include "vmx.h"
> +#include "processor.h"
> +#include "vm.h"
> +#include "msr.h"
> +#include "fwcfg.h"
> +
> +volatile u32 stage;
> +volatile bool init_fail;

Why volatile?

The patch looks good.

> +unsigned long *pml4;
> +u64 eptp;
> +void *data_page1, *data_page2;
> +
> +static inline void set_stage(u32 s)
> +{
> +	barrier();
> +	stage = s;
> +	barrier();
> +}
> +
> +static inline u32 get_stage()
> +{
> +	u32 s;
> +
> +	barrier();
> +	s = stage;
> +	barrier();
> +	return s;
> +}
> +
> +static inline void vmcall()
> +{
> +	asm volatile ("vmcall");
> +}
>  
>  void basic_init()
>  {
> @@ -76,6 +108,238 @@ int vmenter_exit_handler()
>  	return VMX_TEST_VMEXIT;
>  }
>  
> +static int setup_ept()
> +{
> +	int support_2m;
> +	unsigned long end_of_memory;
> +
> +	if (!(ept_vpid.val & EPT_CAP_UC) &&
> +			!(ept_vpid.val & EPT_CAP_WB)) {
> +		printf("\tEPT paging-structure memory type "
> +				"UC&WB are not supported\n");
> +		return 1;
> +	}
> +	if (ept_vpid.val & EPT_CAP_UC)
> +		eptp = EPT_MEM_TYPE_UC;
> +	else
> +		eptp = EPT_MEM_TYPE_WB;
> +	if (!(ept_vpid.val & EPT_CAP_PWL4)) {
> +		printf("\tPWL4 is not supported\n");
> +		return 1;
> +	}
> +	eptp |= (3 << EPTP_PG_WALK_LEN_SHIFT);
> +	pml4 = alloc_page();
> +	memset(pml4, 0, PAGE_SIZE);
> +	eptp |= virt_to_phys(pml4);
> +	vmcs_write(EPTP, eptp);
> +	support_2m = !!(ept_vpid.val & EPT_CAP_2M_PAGE);
> +	end_of_memory = fwcfg_get_u64(FW_CFG_RAM_SIZE);
> +	if (end_of_memory < (1ul << 32))
> +		end_of_memory = (1ul << 32);
> +	if (setup_ept_range(pml4, 0, end_of_memory,
> +			0, support_2m, EPT_WA | EPT_RA | EPT_EA)) {
> +		printf("\tSet ept tables failed.\n");
> +		return 1;
> +	}
> +	return 0;
> +}
> +
> +static void ept_init()
> +{
> +	u32 ctrl_cpu[2];
> +
> +	init_fail = false;
> +	ctrl_cpu[0] = vmcs_read(CPU_EXEC_CTRL0);
> +	ctrl_cpu[1] = vmcs_read(CPU_EXEC_CTRL1);
> +	ctrl_cpu[0] = (ctrl_cpu[0] | CPU_SECONDARY)
> +		& ctrl_cpu_rev[0].clr;
> +	ctrl_cpu[1] = (ctrl_cpu[1] | CPU_EPT)
> +		& ctrl_cpu_rev[1].clr;
> +	vmcs_write(CPU_EXEC_CTRL0, ctrl_cpu[0]);
> +	vmcs_write(CPU_EXEC_CTRL1, ctrl_cpu[1] | CPU_EPT);
> +	if (setup_ept())
> +		init_fail = true;
> +	data_page1 = alloc_page();
> +	data_page2 = alloc_page();
> +	memset(data_page1, 0x0, PAGE_SIZE);
> +	memset(data_page2, 0x0, PAGE_SIZE);
> +	*((u32 *)data_page1) = MAGIC_VAL_1;
> +	*((u32 *)data_page2) = MAGIC_VAL_2;
> +	install_ept(pml4, (unsigned long)data_page1, (unsigned long)data_page2,
> +			EPT_RA | EPT_WA | EPT_EA);
> +}
> +
> +static void ept_main()
> +{
> +	if (init_fail)
> +		return;
> +	if (!(ctrl_cpu_rev[0].clr & CPU_SECONDARY)
> +		&& !(ctrl_cpu_rev[1].clr & CPU_EPT)) {
> +		printf("\tEPT is not supported");
> +		return;
> +	}
> +	set_stage(0);
> +	if (*((u32 *)data_page2) != MAGIC_VAL_1 &&
> +			*((u32 *)data_page1) != MAGIC_VAL_1)
> +		report("EPT basic framework - read", 0);
> +	else {
> +		*((u32 *)data_page2) = MAGIC_VAL_3;
> +		vmcall();
> +		if (get_stage() == 1) {
> +			if (*((u32 *)data_page1) == MAGIC_VAL_3 &&
> +					*((u32 *)data_page2) == MAGIC_VAL_2)
> +				report("EPT basic framework", 1);
> +			else
> +				report("EPT basic framework - remap", 1);
> +		}
> +	}
> +	// Test EPT Misconfigurations
> +	set_stage(1);
> +	vmcall();
> +	*((u32 *)data_page1) = MAGIC_VAL_1;
> +	if (get_stage() != 2) {
> +		report("EPT misconfigurations", 0);
> +		goto t1;
> +	}
> +	set_stage(2);
> +	vmcall();
> +	*((u32 *)data_page1) = MAGIC_VAL_1;
> +	if (get_stage() != 3) {
> +		report("EPT misconfigurations", 0);
> +		goto t1;
> +	}
> +	report("EPT misconfigurations", 1);
> +t1:
> +	// Test EPT violation
> +	set_stage(3);
> +	vmcall();
> +	*((u32 *)data_page1) = MAGIC_VAL_1;
> +	if (get_stage() == 4)
> +		report("EPT violation - page permission", 1);
> +	else
> +		report("EPT violation - page permission", 0);
> +	// Violation caused by EPT paging structure
> +	set_stage(4);
> +	vmcall();
> +	*((u32 *)data_page1) = MAGIC_VAL_2;
> +	if (get_stage() == 5)
> +		report("EPT violation - paging structure", 1);
> +	else
> +		report("EPT violation - paging structure", 0);
> +	return;
> +}
> +
> +static int ept_exit_handler()
> +{
> +	u64 guest_rip;
> +	ulong reason;
> +	u32 insn_len;
> +	u32 exit_qual;
> +	static unsigned long data_page1_pte, data_page1_pte_pte;
> +
> +	guest_rip = vmcs_read(GUEST_RIP);
> +	reason = vmcs_read(EXI_REASON) & 0xff;
> +	insn_len = vmcs_read(EXI_INST_LEN);
> +	exit_qual = vmcs_read(EXI_QUALIFICATION);
> +	switch (reason) {
> +	case VMX_VMCALL:
> +		switch (get_stage()) {
> +		case 0:
> +			if (*((u32 *)data_page1) == MAGIC_VAL_3 &&
> +					*((u32 *)data_page2) == MAGIC_VAL_2) {
> +				set_stage(get_stage() + 1);
> +				install_ept(pml4, (unsigned long)data_page2,
> +						(unsigned long)data_page2,
> +						EPT_RA | EPT_WA | EPT_EA);
> +			} else
> +				report("EPT basic framework - write\n", 0);
> +			break;
> +		case 1:
> +			install_ept(pml4, (unsigned long)data_page1,
> + 				(unsigned long)data_page1, EPT_WA);
> +			invept(INVEPT_SINGLE, eptp);
> +			break;
> +		case 2:
> +			install_ept(pml4, (unsigned long)data_page1,
> + 				(unsigned long)data_page1,
> + 				EPT_RA | EPT_WA | EPT_EA |
> + 				(2 << EPT_MEM_TYPE_SHIFT));
> +			invept(INVEPT_SINGLE, eptp);
> +			break;
> +		case 3:
> +			data_page1_pte = get_ept_pte(pml4,
> +				(unsigned long)data_page1, 1);
> +			set_ept_pte(pml4, (unsigned long)data_page1, 
> +				1, data_page1_pte & (~EPT_PRESENT));
> +			invept(INVEPT_SINGLE, eptp);
> +			break;
> +		case 4:
> +			data_page1_pte = get_ept_pte(pml4,
> +				(unsigned long)data_page1, 2);
> +			data_page1_pte &= PAGE_MASK;
> +			data_page1_pte_pte = get_ept_pte(pml4, data_page1_pte, 2);
> +			set_ept_pte(pml4, data_page1_pte, 2,
> +				data_page1_pte_pte & (~EPT_PRESENT));
> +			invept(INVEPT_SINGLE, eptp);
> +			break;
> +		// Should not reach here
> +		default:
> +			printf("ERROR - unknown stage, %d.\n", get_stage());
> +			print_vmexit_info();
> +			return VMX_TEST_VMEXIT;
> +		}
> +		vmcs_write(GUEST_RIP, guest_rip + insn_len);
> +		return VMX_TEST_RESUME;
> +	case VMX_EPT_MISCONFIG:
> +		switch (get_stage()) {
> +		case 1:
> +		case 2:
> +			set_stage(get_stage() + 1);
> +			install_ept(pml4, (unsigned long)data_page1,
> + 				(unsigned long)data_page1,
> + 				EPT_RA | EPT_WA | EPT_EA);
> +			invept(INVEPT_SINGLE, eptp);
> +			break;
> +		// Should not reach here
> +		default:
> +			printf("ERROR - unknown stage, %d.\n", get_stage());
> +			print_vmexit_info();
> +			return VMX_TEST_VMEXIT;
> +		}
> +		vmcs_write(GUEST_RIP, guest_rip + insn_len);
> +		return VMX_TEST_RESUME;
> +	case VMX_EPT_VIOLATION:
> +		switch(get_stage()) {
> +		case 3:
> +			if (exit_qual == (EPT_VLT_WR | EPT_VLT_LADDR_VLD |
> +					EPT_VLT_PADDR))
> +				set_stage(get_stage() + 1);
> +			set_ept_pte(pml4, (unsigned long)data_page1, 
> +				1, data_page1_pte | (EPT_PRESENT));
> +			invept(INVEPT_SINGLE, eptp);
> +			break;
> +		case 4:
> +			if (exit_qual == (EPT_VLT_RD | EPT_VLT_LADDR_VLD))
> +				set_stage(get_stage() + 1);
> +			set_ept_pte(pml4, data_page1_pte, 2,
> +				data_page1_pte_pte | (EPT_PRESENT));
> +			invept(INVEPT_SINGLE, eptp);
> +			break;
> +		default:
> +			// Should not reach here
> +			printf("ERROR : unknown stage, %d\n", get_stage());
> +			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 +347,7 @@ struct vmx_test vmx_tests[] = {
>  		basic_syscall_handler, {0} },
>  	{ "vmenter", basic_init, vmenter_main, vmenter_exit_handler,
>  		basic_syscall_handler, {0} },
> +	{ "EPT framework", ept_init, ept_main, ept_exit_handler,
> +		basic_syscall_handler, {0} },
>  	{ NULL, NULL, NULL, NULL, NULL, {0} },
>  };
> 


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

* Re: [PATCH 2/2] kvm-unit-tests: VMX: Test cases for nested EPT
  2013-09-09 13:56   ` Paolo Bonzini
@ 2013-09-09 14:11     ` Arthur Chunqi Li
  2013-09-09 14:26       ` Paolo Bonzini
  0 siblings, 1 reply; 11+ messages in thread
From: Arthur Chunqi Li @ 2013-09-09 14:11 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: kvm, Jan Kiszka, Gleb Natapov

On Mon, Sep 9, 2013 at 9:56 PM, Paolo Bonzini <pbonzini@redhat.com> wrote:
> Il 09/09/2013 06:57, Arthur Chunqi Li ha scritto:
>> Some test cases for nested EPT features, including:
>> 1. EPT basic framework tests: read, write and remap.
>> 2. EPT misconfigurations test cases: page permission mieconfiguration
>> and memory type misconfiguration
>> 3. EPT violations test cases: page permission violation and paging
>> structure violation
>>
>> Signed-off-by: Arthur Chunqi Li <yzt356@gmail.com>
>> ---
>>  x86/vmx_tests.c |  266 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 266 insertions(+)
>>
>> diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c
>> index c1b39f4..a0b9824 100644
>> --- a/x86/vmx_tests.c
>> +++ b/x86/vmx_tests.c
>> @@ -1,4 +1,36 @@
>>  #include "vmx.h"
>> +#include "processor.h"
>> +#include "vm.h"
>> +#include "msr.h"
>> +#include "fwcfg.h"
>> +
>> +volatile u32 stage;
>> +volatile bool init_fail;
>
> Why volatile?
Because init_fail is only set but not used later in ept_init(), and if
I don't add volatile, compiler may optimize the setting to init_fail.

This occasion firstly occurred when I write set_stage/get_stage. If
one variant is set in a function but not used later, the compiler
usually optimizes this setting as redundant assignment and remove it.

Arthur
>
> The patch looks good.
>
>> +unsigned long *pml4;
>> +u64 eptp;
>> +void *data_page1, *data_page2;
>> +
>> +static inline void set_stage(u32 s)
>> +{
>> +     barrier();
>> +     stage = s;
>> +     barrier();
>> +}
>> +
>> +static inline u32 get_stage()
>> +{
>> +     u32 s;
>> +
>> +     barrier();
>> +     s = stage;
>> +     barrier();
>> +     return s;
>> +}
>> +
>> +static inline void vmcall()
>> +{
>> +     asm volatile ("vmcall");
>> +}
>>
>>  void basic_init()
>>  {
>> @@ -76,6 +108,238 @@ int vmenter_exit_handler()
>>       return VMX_TEST_VMEXIT;
>>  }
>>
>> +static int setup_ept()
>> +{
>> +     int support_2m;
>> +     unsigned long end_of_memory;
>> +
>> +     if (!(ept_vpid.val & EPT_CAP_UC) &&
>> +                     !(ept_vpid.val & EPT_CAP_WB)) {
>> +             printf("\tEPT paging-structure memory type "
>> +                             "UC&WB are not supported\n");
>> +             return 1;
>> +     }
>> +     if (ept_vpid.val & EPT_CAP_UC)
>> +             eptp = EPT_MEM_TYPE_UC;
>> +     else
>> +             eptp = EPT_MEM_TYPE_WB;
>> +     if (!(ept_vpid.val & EPT_CAP_PWL4)) {
>> +             printf("\tPWL4 is not supported\n");
>> +             return 1;
>> +     }
>> +     eptp |= (3 << EPTP_PG_WALK_LEN_SHIFT);
>> +     pml4 = alloc_page();
>> +     memset(pml4, 0, PAGE_SIZE);
>> +     eptp |= virt_to_phys(pml4);
>> +     vmcs_write(EPTP, eptp);
>> +     support_2m = !!(ept_vpid.val & EPT_CAP_2M_PAGE);
>> +     end_of_memory = fwcfg_get_u64(FW_CFG_RAM_SIZE);
>> +     if (end_of_memory < (1ul << 32))
>> +             end_of_memory = (1ul << 32);
>> +     if (setup_ept_range(pml4, 0, end_of_memory,
>> +                     0, support_2m, EPT_WA | EPT_RA | EPT_EA)) {
>> +             printf("\tSet ept tables failed.\n");
>> +             return 1;
>> +     }
>> +     return 0;
>> +}
>> +
>> +static void ept_init()
>> +{
>> +     u32 ctrl_cpu[2];
>> +
>> +     init_fail = false;
>> +     ctrl_cpu[0] = vmcs_read(CPU_EXEC_CTRL0);
>> +     ctrl_cpu[1] = vmcs_read(CPU_EXEC_CTRL1);
>> +     ctrl_cpu[0] = (ctrl_cpu[0] | CPU_SECONDARY)
>> +             & ctrl_cpu_rev[0].clr;
>> +     ctrl_cpu[1] = (ctrl_cpu[1] | CPU_EPT)
>> +             & ctrl_cpu_rev[1].clr;
>> +     vmcs_write(CPU_EXEC_CTRL0, ctrl_cpu[0]);
>> +     vmcs_write(CPU_EXEC_CTRL1, ctrl_cpu[1] | CPU_EPT);
>> +     if (setup_ept())
>> +             init_fail = true;
>> +     data_page1 = alloc_page();
>> +     data_page2 = alloc_page();
>> +     memset(data_page1, 0x0, PAGE_SIZE);
>> +     memset(data_page2, 0x0, PAGE_SIZE);
>> +     *((u32 *)data_page1) = MAGIC_VAL_1;
>> +     *((u32 *)data_page2) = MAGIC_VAL_2;
>> +     install_ept(pml4, (unsigned long)data_page1, (unsigned long)data_page2,
>> +                     EPT_RA | EPT_WA | EPT_EA);
>> +}
>> +
>> +static void ept_main()
>> +{
>> +     if (init_fail)
>> +             return;
>> +     if (!(ctrl_cpu_rev[0].clr & CPU_SECONDARY)
>> +             && !(ctrl_cpu_rev[1].clr & CPU_EPT)) {
>> +             printf("\tEPT is not supported");
>> +             return;
>> +     }
>> +     set_stage(0);
>> +     if (*((u32 *)data_page2) != MAGIC_VAL_1 &&
>> +                     *((u32 *)data_page1) != MAGIC_VAL_1)
>> +             report("EPT basic framework - read", 0);
>> +     else {
>> +             *((u32 *)data_page2) = MAGIC_VAL_3;
>> +             vmcall();
>> +             if (get_stage() == 1) {
>> +                     if (*((u32 *)data_page1) == MAGIC_VAL_3 &&
>> +                                     *((u32 *)data_page2) == MAGIC_VAL_2)
>> +                             report("EPT basic framework", 1);
>> +                     else
>> +                             report("EPT basic framework - remap", 1);
>> +             }
>> +     }
>> +     // Test EPT Misconfigurations
>> +     set_stage(1);
>> +     vmcall();
>> +     *((u32 *)data_page1) = MAGIC_VAL_1;
>> +     if (get_stage() != 2) {
>> +             report("EPT misconfigurations", 0);
>> +             goto t1;
>> +     }
>> +     set_stage(2);
>> +     vmcall();
>> +     *((u32 *)data_page1) = MAGIC_VAL_1;
>> +     if (get_stage() != 3) {
>> +             report("EPT misconfigurations", 0);
>> +             goto t1;
>> +     }
>> +     report("EPT misconfigurations", 1);
>> +t1:
>> +     // Test EPT violation
>> +     set_stage(3);
>> +     vmcall();
>> +     *((u32 *)data_page1) = MAGIC_VAL_1;
>> +     if (get_stage() == 4)
>> +             report("EPT violation - page permission", 1);
>> +     else
>> +             report("EPT violation - page permission", 0);
>> +     // Violation caused by EPT paging structure
>> +     set_stage(4);
>> +     vmcall();
>> +     *((u32 *)data_page1) = MAGIC_VAL_2;
>> +     if (get_stage() == 5)
>> +             report("EPT violation - paging structure", 1);
>> +     else
>> +             report("EPT violation - paging structure", 0);
>> +     return;
>> +}
>> +
>> +static int ept_exit_handler()
>> +{
>> +     u64 guest_rip;
>> +     ulong reason;
>> +     u32 insn_len;
>> +     u32 exit_qual;
>> +     static unsigned long data_page1_pte, data_page1_pte_pte;
>> +
>> +     guest_rip = vmcs_read(GUEST_RIP);
>> +     reason = vmcs_read(EXI_REASON) & 0xff;
>> +     insn_len = vmcs_read(EXI_INST_LEN);
>> +     exit_qual = vmcs_read(EXI_QUALIFICATION);
>> +     switch (reason) {
>> +     case VMX_VMCALL:
>> +             switch (get_stage()) {
>> +             case 0:
>> +                     if (*((u32 *)data_page1) == MAGIC_VAL_3 &&
>> +                                     *((u32 *)data_page2) == MAGIC_VAL_2) {
>> +                             set_stage(get_stage() + 1);
>> +                             install_ept(pml4, (unsigned long)data_page2,
>> +                                             (unsigned long)data_page2,
>> +                                             EPT_RA | EPT_WA | EPT_EA);
>> +                     } else
>> +                             report("EPT basic framework - write\n", 0);
>> +                     break;
>> +             case 1:
>> +                     install_ept(pml4, (unsigned long)data_page1,
>> +                             (unsigned long)data_page1, EPT_WA);
>> +                     invept(INVEPT_SINGLE, eptp);
>> +                     break;
>> +             case 2:
>> +                     install_ept(pml4, (unsigned long)data_page1,
>> +                             (unsigned long)data_page1,
>> +                             EPT_RA | EPT_WA | EPT_EA |
>> +                             (2 << EPT_MEM_TYPE_SHIFT));
>> +                     invept(INVEPT_SINGLE, eptp);
>> +                     break;
>> +             case 3:
>> +                     data_page1_pte = get_ept_pte(pml4,
>> +                             (unsigned long)data_page1, 1);
>> +                     set_ept_pte(pml4, (unsigned long)data_page1,
>> +                             1, data_page1_pte & (~EPT_PRESENT));
>> +                     invept(INVEPT_SINGLE, eptp);
>> +                     break;
>> +             case 4:
>> +                     data_page1_pte = get_ept_pte(pml4,
>> +                             (unsigned long)data_page1, 2);
>> +                     data_page1_pte &= PAGE_MASK;
>> +                     data_page1_pte_pte = get_ept_pte(pml4, data_page1_pte, 2);
>> +                     set_ept_pte(pml4, data_page1_pte, 2,
>> +                             data_page1_pte_pte & (~EPT_PRESENT));
>> +                     invept(INVEPT_SINGLE, eptp);
>> +                     break;
>> +             // Should not reach here
>> +             default:
>> +                     printf("ERROR - unknown stage, %d.\n", get_stage());
>> +                     print_vmexit_info();
>> +                     return VMX_TEST_VMEXIT;
>> +             }
>> +             vmcs_write(GUEST_RIP, guest_rip + insn_len);
>> +             return VMX_TEST_RESUME;
>> +     case VMX_EPT_MISCONFIG:
>> +             switch (get_stage()) {
>> +             case 1:
>> +             case 2:
>> +                     set_stage(get_stage() + 1);
>> +                     install_ept(pml4, (unsigned long)data_page1,
>> +                             (unsigned long)data_page1,
>> +                             EPT_RA | EPT_WA | EPT_EA);
>> +                     invept(INVEPT_SINGLE, eptp);
>> +                     break;
>> +             // Should not reach here
>> +             default:
>> +                     printf("ERROR - unknown stage, %d.\n", get_stage());
>> +                     print_vmexit_info();
>> +                     return VMX_TEST_VMEXIT;
>> +             }
>> +             vmcs_write(GUEST_RIP, guest_rip + insn_len);
>> +             return VMX_TEST_RESUME;
>> +     case VMX_EPT_VIOLATION:
>> +             switch(get_stage()) {
>> +             case 3:
>> +                     if (exit_qual == (EPT_VLT_WR | EPT_VLT_LADDR_VLD |
>> +                                     EPT_VLT_PADDR))
>> +                             set_stage(get_stage() + 1);
>> +                     set_ept_pte(pml4, (unsigned long)data_page1,
>> +                             1, data_page1_pte | (EPT_PRESENT));
>> +                     invept(INVEPT_SINGLE, eptp);
>> +                     break;
>> +             case 4:
>> +                     if (exit_qual == (EPT_VLT_RD | EPT_VLT_LADDR_VLD))
>> +                             set_stage(get_stage() + 1);
>> +                     set_ept_pte(pml4, data_page1_pte, 2,
>> +                             data_page1_pte_pte | (EPT_PRESENT));
>> +                     invept(INVEPT_SINGLE, eptp);
>> +                     break;
>> +             default:
>> +                     // Should not reach here
>> +                     printf("ERROR : unknown stage, %d\n", get_stage());
>> +                     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 +347,7 @@ struct vmx_test vmx_tests[] = {
>>               basic_syscall_handler, {0} },
>>       { "vmenter", basic_init, vmenter_main, vmenter_exit_handler,
>>               basic_syscall_handler, {0} },
>> +     { "EPT framework", ept_init, ept_main, ept_exit_handler,
>> +             basic_syscall_handler, {0} },
>>       { NULL, NULL, NULL, NULL, NULL, {0} },
>>  };
>>
>

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

* Re: [PATCH 2/2] kvm-unit-tests: VMX: Test cases for nested EPT
  2013-09-09 14:11     ` Arthur Chunqi Li
@ 2013-09-09 14:26       ` Paolo Bonzini
  0 siblings, 0 replies; 11+ messages in thread
From: Paolo Bonzini @ 2013-09-09 14:26 UTC (permalink / raw)
  To: Arthur Chunqi Li; +Cc: kvm, Jan Kiszka, Gleb Natapov

Il 09/09/2013 16:11, Arthur Chunqi Li ha scritto:
>>> >> +volatile u32 stage;
>>> >> +volatile bool init_fail;
>> >
>> > Why volatile?
> Because init_fail is only set but not used later in ept_init(), and if
> I don't add volatile, compiler may optimize the setting to init_fail.
> 
> This occasion firstly occurred when I write set_stage/get_stage. If
> one variant is set in a function but not used later, the compiler
> usually optimizes this setting as redundant assignment and remove it.

No, the two are different.  "stage" is written several times in the same
function, with no code in the middle:

	stage++;
	*p = 1;
	stage++;

To the compiler, the first store is dead.  The compiler doesn't know
that "*p = 1" traps to the hypervisor.

But this is not the case for "init_fail".

Paolo

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

* Re: [PATCH 2/2] kvm-unit-tests: VMX: Test cases for nested EPT
  2013-09-09  4:57 ` [PATCH 2/2] kvm-unit-tests: VMX: Test cases for nested EPT Arthur Chunqi Li
  2013-09-09 13:56   ` Paolo Bonzini
@ 2013-09-09 15:29   ` Arthur Chunqi Li
  2013-09-09 16:23     ` Paolo Bonzini
  1 sibling, 1 reply; 11+ messages in thread
From: Arthur Chunqi Li @ 2013-09-09 15:29 UTC (permalink / raw)
  To: kvm; +Cc: Jan Kiszka, Gleb Natapov, Paolo Bonzini, Arthur Chunqi Li

On Mon, Sep 9, 2013 at 12:57 PM, Arthur Chunqi Li <yzt356@gmail.com> wrote:
> Some test cases for nested EPT features, including:
> 1. EPT basic framework tests: read, write and remap.
> 2. EPT misconfigurations test cases: page permission mieconfiguration
> and memory type misconfiguration
> 3. EPT violations test cases: page permission violation and paging
> structure violation
>
> Signed-off-by: Arthur Chunqi Li <yzt356@gmail.com>
> ---
>  x86/vmx_tests.c |  266 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 266 insertions(+)
>
> diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c
> index c1b39f4..a0b9824 100644
> --- a/x86/vmx_tests.c
> +++ b/x86/vmx_tests.c
> @@ -1,4 +1,36 @@
>  #include "vmx.h"
> +#include "processor.h"
> +#include "vm.h"
> +#include "msr.h"
> +#include "fwcfg.h"
> +
> +volatile u32 stage;
> +volatile bool init_fail;
> +unsigned long *pml4;
> +u64 eptp;
> +void *data_page1, *data_page2;
> +
> +static inline void set_stage(u32 s)
> +{
> +       barrier();
> +       stage = s;
> +       barrier();
> +}
> +
> +static inline u32 get_stage()
> +{
> +       u32 s;
> +
> +       barrier();
> +       s = stage;
> +       barrier();
> +       return s;
> +}
> +
> +static inline void vmcall()
> +{
> +       asm volatile ("vmcall");
> +}
>
>  void basic_init()
>  {
> @@ -76,6 +108,238 @@ int vmenter_exit_handler()
>         return VMX_TEST_VMEXIT;
>  }
>
> +static int setup_ept()
> +{
> +       int support_2m;
> +       unsigned long end_of_memory;
> +
> +       if (!(ept_vpid.val & EPT_CAP_UC) &&
> +                       !(ept_vpid.val & EPT_CAP_WB)) {
> +               printf("\tEPT paging-structure memory type "
> +                               "UC&WB are not supported\n");
> +               return 1;
> +       }
> +       if (ept_vpid.val & EPT_CAP_UC)
> +               eptp = EPT_MEM_TYPE_UC;
> +       else
> +               eptp = EPT_MEM_TYPE_WB;
> +       if (!(ept_vpid.val & EPT_CAP_PWL4)) {
> +               printf("\tPWL4 is not supported\n");
> +               return 1;
> +       }
> +       eptp |= (3 << EPTP_PG_WALK_LEN_SHIFT);
> +       pml4 = alloc_page();
> +       memset(pml4, 0, PAGE_SIZE);
> +       eptp |= virt_to_phys(pml4);
> +       vmcs_write(EPTP, eptp);
> +       support_2m = !!(ept_vpid.val & EPT_CAP_2M_PAGE);
> +       end_of_memory = fwcfg_get_u64(FW_CFG_RAM_SIZE);
> +       if (end_of_memory < (1ul << 32))
> +               end_of_memory = (1ul << 32);
> +       if (setup_ept_range(pml4, 0, end_of_memory,
> +                       0, support_2m, EPT_WA | EPT_RA | EPT_EA)) {
> +               printf("\tSet ept tables failed.\n");
> +               return 1;
> +       }
> +       return 0;
> +}
> +
> +static void ept_init()
> +{
> +       u32 ctrl_cpu[2];
> +
> +       init_fail = false;
> +       ctrl_cpu[0] = vmcs_read(CPU_EXEC_CTRL0);
> +       ctrl_cpu[1] = vmcs_read(CPU_EXEC_CTRL1);
> +       ctrl_cpu[0] = (ctrl_cpu[0] | CPU_SECONDARY)
> +               & ctrl_cpu_rev[0].clr;
> +       ctrl_cpu[1] = (ctrl_cpu[1] | CPU_EPT)
> +               & ctrl_cpu_rev[1].clr;
> +       vmcs_write(CPU_EXEC_CTRL0, ctrl_cpu[0]);
> +       vmcs_write(CPU_EXEC_CTRL1, ctrl_cpu[1] | CPU_EPT);
> +       if (setup_ept())
> +               init_fail = true;
> +       data_page1 = alloc_page();
> +       data_page2 = alloc_page();
> +       memset(data_page1, 0x0, PAGE_SIZE);
> +       memset(data_page2, 0x0, PAGE_SIZE);
> +       *((u32 *)data_page1) = MAGIC_VAL_1;
> +       *((u32 *)data_page2) = MAGIC_VAL_2;
> +       install_ept(pml4, (unsigned long)data_page1, (unsigned long)data_page2,
> +                       EPT_RA | EPT_WA | EPT_EA);
> +}
> +
> +static void ept_main()
> +{
> +       if (init_fail)
> +               return;
> +       if (!(ctrl_cpu_rev[0].clr & CPU_SECONDARY)
> +               && !(ctrl_cpu_rev[1].clr & CPU_EPT)) {
> +               printf("\tEPT is not supported");
> +               return;
> +       }
> +       set_stage(0);
> +       if (*((u32 *)data_page2) != MAGIC_VAL_1 &&
> +                       *((u32 *)data_page1) != MAGIC_VAL_1)
> +               report("EPT basic framework - read", 0);
> +       else {
> +               *((u32 *)data_page2) = MAGIC_VAL_3;
> +               vmcall();
> +               if (get_stage() == 1) {
> +                       if (*((u32 *)data_page1) == MAGIC_VAL_3 &&
> +                                       *((u32 *)data_page2) == MAGIC_VAL_2)
> +                               report("EPT basic framework", 1);
> +                       else
> +                               report("EPT basic framework - remap", 1);
> +               }
> +       }
> +       // Test EPT Misconfigurations
> +       set_stage(1);
> +       vmcall();
> +       *((u32 *)data_page1) = MAGIC_VAL_1;
> +       if (get_stage() != 2) {
> +               report("EPT misconfigurations", 0);
> +               goto t1;
> +       }
> +       set_stage(2);
> +       vmcall();
> +       *((u32 *)data_page1) = MAGIC_VAL_1;
> +       if (get_stage() != 3) {
> +               report("EPT misconfigurations", 0);
> +               goto t1;
> +       }
> +       report("EPT misconfigurations", 1);
> +t1:
> +       // Test EPT violation
> +       set_stage(3);
> +       vmcall();
> +       *((u32 *)data_page1) = MAGIC_VAL_1;
> +       if (get_stage() == 4)
> +               report("EPT violation - page permission", 1);
> +       else
> +               report("EPT violation - page permission", 0);
> +       // Violation caused by EPT paging structure
> +       set_stage(4);
> +       vmcall();
> +       *((u32 *)data_page1) = MAGIC_VAL_2;
> +       if (get_stage() == 5)
> +               report("EPT violation - paging structure", 1);
> +       else
> +               report("EPT violation - paging structure", 0);
> +       return;
> +}
> +
> +static int ept_exit_handler()
> +{
> +       u64 guest_rip;
> +       ulong reason;
> +       u32 insn_len;
> +       u32 exit_qual;
> +       static unsigned long data_page1_pte, data_page1_pte_pte;
> +
> +       guest_rip = vmcs_read(GUEST_RIP);
> +       reason = vmcs_read(EXI_REASON) & 0xff;
> +       insn_len = vmcs_read(EXI_INST_LEN);
> +       exit_qual = vmcs_read(EXI_QUALIFICATION);
> +       switch (reason) {
> +       case VMX_VMCALL:
> +               switch (get_stage()) {
> +               case 0:
> +                       if (*((u32 *)data_page1) == MAGIC_VAL_3 &&
> +                                       *((u32 *)data_page2) == MAGIC_VAL_2) {
> +                               set_stage(get_stage() + 1);
> +                               install_ept(pml4, (unsigned long)data_page2,
> +                                               (unsigned long)data_page2,
> +                                               EPT_RA | EPT_WA | EPT_EA);
> +                       } else
> +                               report("EPT basic framework - write\n", 0);
> +                       break;
> +               case 1:
> +                       install_ept(pml4, (unsigned long)data_page1,
> +                               (unsigned long)data_page1, EPT_WA);
> +                       invept(INVEPT_SINGLE, eptp);
> +                       break;
> +               case 2:
> +                       install_ept(pml4, (unsigned long)data_page1,
> +                               (unsigned long)data_page1,
> +                               EPT_RA | EPT_WA | EPT_EA |
> +                               (2 << EPT_MEM_TYPE_SHIFT));
> +                       invept(INVEPT_SINGLE, eptp);
> +                       break;
> +               case 3:
> +                       data_page1_pte = get_ept_pte(pml4,
> +                               (unsigned long)data_page1, 1);
> +                       set_ept_pte(pml4, (unsigned long)data_page1,
> +                               1, data_page1_pte & (~EPT_PRESENT));
> +                       invept(INVEPT_SINGLE, eptp);
> +                       break;
> +               case 4:
> +                       data_page1_pte = get_ept_pte(pml4,
> +                               (unsigned long)data_page1, 2);
> +                       data_page1_pte &= PAGE_MASK;
> +                       data_page1_pte_pte = get_ept_pte(pml4, data_page1_pte, 2);
> +                       set_ept_pte(pml4, data_page1_pte, 2,
> +                               data_page1_pte_pte & (~EPT_PRESENT));
> +                       invept(INVEPT_SINGLE, eptp);
> +                       break;
> +               // Should not reach here
> +               default:
> +                       printf("ERROR - unknown stage, %d.\n", get_stage());
> +                       print_vmexit_info();
> +                       return VMX_TEST_VMEXIT;
> +               }
> +               vmcs_write(GUEST_RIP, guest_rip + insn_len);
> +               return VMX_TEST_RESUME;
> +       case VMX_EPT_MISCONFIG:
> +               switch (get_stage()) {
> +               case 1:
> +               case 2:
> +                       set_stage(get_stage() + 1);
> +                       install_ept(pml4, (unsigned long)data_page1,
> +                               (unsigned long)data_page1,
> +                               EPT_RA | EPT_WA | EPT_EA);
> +                       invept(INVEPT_SINGLE, eptp);
> +                       break;
> +               // Should not reach here
> +               default:
> +                       printf("ERROR - unknown stage, %d.\n", get_stage());
> +                       print_vmexit_info();
> +                       return VMX_TEST_VMEXIT;
> +               }
> +               vmcs_write(GUEST_RIP, guest_rip + insn_len);
> +               return VMX_TEST_RESUME;
> +       case VMX_EPT_VIOLATION:
> +               switch(get_stage()) {
> +               case 3:
> +                       if (exit_qual == (EPT_VLT_WR | EPT_VLT_LADDR_VLD |
> +                                       EPT_VLT_PADDR))
> +                               set_stage(get_stage() + 1);
> +                       set_ept_pte(pml4, (unsigned long)data_page1,
> +                               1, data_page1_pte | (EPT_PRESENT));
> +                       invept(INVEPT_SINGLE, eptp);
> +                       break;
> +               case 4:
> +                       if (exit_qual == (EPT_VLT_RD | EPT_VLT_LADDR_VLD))
> +                               set_stage(get_stage() + 1);
> +                       set_ept_pte(pml4, data_page1_pte, 2,
> +                               data_page1_pte_pte | (EPT_PRESENT));
> +                       invept(INVEPT_SINGLE, eptp);
> +                       break;
> +               default:
> +                       // Should not reach here
> +                       printf("ERROR : unknown stage, %d\n", get_stage());
> +                       print_vmexit_info();
> +                       return VMX_TEST_VMEXIT;
> +               }
> +               vmcs_write(GUEST_RIP, guest_rip + insn_len);
Hi Paolo,
I noticed another possible bug of this patch. Stage 4 of this patch
test the scenario that the page of a paging structure is not present,
then this will cause EPT violation vmexit with bit 8 of exit_qual
unset. My question is: will instruction length be correctly set on
this scenario? I got wrong insn_len in "case 4" of VMX_EPT_VIOLATION,
which may cause triple fault vmexit.
> +               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 +347,7 @@ struct vmx_test vmx_tests[] = {
>                 basic_syscall_handler, {0} },
>         { "vmenter", basic_init, vmenter_main, vmenter_exit_handler,
>                 basic_syscall_handler, {0} },
> +       { "EPT framework", ept_init, ept_main, ept_exit_handler,
> +               basic_syscall_handler, {0} },
>         { NULL, NULL, NULL, NULL, NULL, {0} },
>  };
> --
> 1.7.9.5
>

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

* Re: [PATCH 2/2] kvm-unit-tests: VMX: Test cases for nested EPT
  2013-09-09 15:29   ` Arthur Chunqi Li
@ 2013-09-09 16:23     ` Paolo Bonzini
  0 siblings, 0 replies; 11+ messages in thread
From: Paolo Bonzini @ 2013-09-09 16:23 UTC (permalink / raw)
  To: Arthur Chunqi Li; +Cc: kvm, Jan Kiszka, Gleb Natapov

Il 09/09/2013 17:29, Arthur Chunqi Li ha scritto:
> Hi Paolo,
> I noticed another possible bug of this patch. Stage 4 of this patch
> test the scenario that the page of a paging structure is not present,
> then this will cause EPT violation vmexit with bit 8 of exit_qual
> unset. My question is: will instruction length be correctly set on
> this scenario? I got wrong insn_len in "case 4" of VMX_EPT_VIOLATION,
> which may cause triple fault vmexit.

It's plausible that the instruction length is wrong, since the processor
might be fetching the instruction itself and doesn't know the length.

Paolo

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

end of thread, other threads:[~2013-09-09 16:23 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-09-09  4:57 [PATCH 0/2] kvm-unit-tests: VMX: Test nested EPT features Arthur Chunqi Li
2013-09-09  4:57 ` [PATCH 1/2] kvm-unit-tests: VMX: The framework of EPT for nested VMX testing Arthur Chunqi Li
2013-09-09 13:45   ` Paolo Bonzini
2013-09-09  4:57 ` [PATCH 2/2] kvm-unit-tests: VMX: Test cases for nested EPT Arthur Chunqi Li
2013-09-09 13:56   ` Paolo Bonzini
2013-09-09 14:11     ` Arthur Chunqi Li
2013-09-09 14:26       ` Paolo Bonzini
2013-09-09 15:29   ` Arthur Chunqi Li
2013-09-09 16:23     ` Paolo Bonzini
2013-09-09  7:17 ` [PATCH 0/2] kvm-unit-tests: VMX: Test nested EPT features Jan Kiszka
2013-09-09  7:44   ` Arthur Chunqi Li

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox