diff mbox

[kvm-unit-tests] vmx_tests: Add Page Modification Logging tests

Message ID jpgr3036r1o.fsf@linux.bootlegged.copy (mailing list archive)
State New, archived
Headers show

Commit Message

Bandan Das May 5, 2017, 7:29 p.m. UTC
Verify that a gpa is logged in the pml buffer when
it's written to. Also verify that when the PML buffer
overflows, a PML FULL event occurs.

Signed-off-by: Bandan Das <bsd@redhat.com>
---
 x86/vmx.h       |  8 ++++-
 x86/vmx_tests.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 100 insertions(+), 1 deletion(-)
diff mbox

Patch

diff --git a/x86/vmx.h b/x86/vmx.h
index 290e6bd..087eb0c 100644
--- a/x86/vmx.h
+++ b/x86/vmx.h
@@ -108,6 +108,7 @@  enum Encoding {
 	GUEST_SEL_LDTR		= 0x080cul,
 	GUEST_SEL_TR		= 0x080eul,
 	GUEST_INT_STATUS	= 0x0810ul,
+	GUEST_PML_INDEX         = 0x0812ul,
 
 	/* 16-Bit Host State Fields */
 	HOST_SEL_ES		= 0x0c00ul,
@@ -132,6 +133,9 @@  enum Encoding {
 	APIC_ACCS_ADDR		= 0x2014ul,
 	EPTP			= 0x201aul,
 	EPTP_HI			= 0x201bul,
+	PMLADDR                 = 0x200eul,
+	PMLADDR_HI              = 0x200ful,
+
 
 	/* 64-Bit Readonly Data Field */
 	INFO_PHYS_ADDR		= 0x2400ul,
@@ -317,7 +321,8 @@  enum Reason {
 	VMX_PREEMPT		= 52,
 	VMX_INVVPID		= 53,
 	VMX_WBINVD		= 54,
-	VMX_XSETBV		= 55
+	VMX_XSETBV		= 55,
+	VMX_PMLFULL             = 62,
 };
 
 enum Ctrl_exi {
@@ -375,6 +380,7 @@  enum Ctrl1 {
 	CPU_URG			= 1ul << 7,
 	CPU_WBINVD		= 1ul << 6,
 	CPU_RDRAND		= 1ul << 11,
+	CPU_PML                 = 1ul << 17,
 };
 
 enum Intr_type {
diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c
index eca7fbd..8f4ad05 100644
--- a/x86/vmx_tests.c
+++ b/x86/vmx_tests.c
@@ -22,6 +22,9 @@  unsigned long *pml4;
 u64 eptp;
 void *data_page1, *data_page2;
 
+void *pml_log;
+#define PML_INDEX 512
+
 static inline void vmcall()
 {
 	asm volatile("vmcall");
@@ -1090,6 +1093,52 @@  bool invept_test(int type, u64 eptp)
 	return true;
 }
 
+static int pml_exit_handler(void)
+{
+	u16 index, count;
+	ulong reason = vmcs_read(EXI_REASON) & 0xff;
+	u64 *pmlbuf = pml_log;
+	u64 guest_rip = vmcs_read(GUEST_RIP);;
+	u64 guest_cr3 = vmcs_read(GUEST_CR3);
+	u32 insn_len = vmcs_read(EXI_INST_LEN);
+
+	switch (reason) {
+	case VMX_VMCALL:
+		switch (vmx_get_test_stage()) {
+		case 0:
+			index = vmcs_read(GUEST_PML_INDEX);
+			for (count = index + 1; count < PML_INDEX; count++) {
+				if (pmlbuf[count] == (u64)data_page2) {
+					vmx_inc_test_stage();
+					clear_ept_ad(pml4, guest_cr3, (unsigned long)data_page2);
+					break;
+				}
+			}
+			break;
+		case 1:
+			index = vmcs_read(GUEST_PML_INDEX);
+			/* Keep clearing the dirty bit till a overflow */
+			clear_ept_ad(pml4, guest_cr3, (unsigned long)data_page2);
+			break;
+		default:
+			printf("ERROR - unexpected stage, %d.\n",
+			       vmx_get_test_stage());
+			print_vmexit_info();
+			return VMX_TEST_VMEXIT;
+		}
+		vmcs_write(GUEST_RIP, guest_rip + insn_len);
+		return VMX_TEST_RESUME;
+	case VMX_PMLFULL:
+		vmx_inc_test_stage();
+		vmcs_write(GUEST_PML_INDEX, PML_INDEX - 1);
+		return VMX_TEST_RESUME;
+	default:
+		printf("Unknown exit reason, %ld\n", reason);
+		print_vmexit_info();
+	}
+	return VMX_TEST_VMEXIT;
+}
+
 static int ept_exit_handler_common(bool have_ad)
 {
 	u64 guest_rip;
@@ -1249,6 +1298,49 @@  static int eptad_init()
 	return r;
 }
 
+static int pml_init()
+{
+	u32 ctrl_cpu;
+	int r = eptad_init();
+
+	if (r == VMX_TEST_EXIT)
+		return r;
+
+	if (!(ctrl_cpu_rev[0].clr & CPU_SECONDARY) ||
+		!(ctrl_cpu_rev[1].clr & CPU_PML)) {
+		printf("\tPML is not supported");
+		return VMX_TEST_EXIT;
+	}
+
+	pml_log = alloc_page();
+	memset(pml_log, 0x0, PAGE_SIZE);
+	vmcs_write(PMLADDR, (u64)pml_log);
+	vmcs_write(GUEST_PML_INDEX, PML_INDEX - 1);
+
+	ctrl_cpu = vmcs_read(CPU_EXEC_CTRL1) | CPU_PML;
+	vmcs_write(CPU_EXEC_CTRL1, ctrl_cpu);
+
+	return VMX_TEST_START;
+}
+
+static void pml_main()
+{
+	int count = 0;
+
+	vmx_set_test_stage(0);
+	*((u32 *)data_page2) = 0x1;
+	vmcall();
+	report("PML - Dirty GPA Logging", vmx_get_test_stage() == 1);
+
+	while (vmx_get_test_stage() == 1) {
+		*((u32 *)data_page2) = 0x1;
+		if (count++ > PML_INDEX)
+			break;
+		vmcall();
+	}
+	report("PML Full Event", vmx_get_test_stage() == 2);
+}
+
 static void eptad_main()
 {
 	ept_common();
@@ -1902,6 +1994,7 @@  struct vmx_test vmx_tests[] = {
 		insn_intercept_exit_handler, NULL, {0} },
 	{ "EPT, A/D disabled", ept_init, ept_main, ept_exit_handler, NULL, {0} },
 	{ "EPT, A/D enabled", eptad_init, eptad_main, eptad_exit_handler, NULL, {0} },
+	{ "PML", pml_init, pml_main, pml_exit_handler, NULL, {0} },
 	{ "VPID", vpid_init, vpid_main, vpid_exit_handler, NULL, {0} },
 	{ "interrupt", interrupt_init, interrupt_main,
 		interrupt_exit_handler, NULL, {0} },