kvm-unit-test: nVMX: Test VM-entry MSR-load area
diff mbox series

Message ID 20191021223100.22502-1-krish.sadhukhan@oracle.com
State New
Headers show
Series
  • kvm-unit-test: nVMX: Test VM-entry MSR-load area
Related show

Commit Message

Krish Sadhukhan Oct. 21, 2019, 10:31 p.m. UTC
..to verify that the MSR values specified in VM-entry MSR-load area are
    correctly loaded in the nested guest on VM-entry.

Signed-off-by: Krish Sadhukhan <krish.sadhukhan@oracle.com>
Reviewed-by: Karl Heubaum <karl.heubaum@oracle.com>
---
 x86/vmx_tests.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 87 insertions(+)

Patch
diff mbox series

diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c
index 4aebc3f..7306150 100644
--- a/x86/vmx_tests.c
+++ b/x86/vmx_tests.c
@@ -8965,6 +8965,91 @@  static void atomic_switch_overflow_msrs_test(void)
 	atomic_switch_msrs_test(max_msr_list_size() + 1);
 }
 
+static u64 guest_efer;
+
+/*
+ * Test to verify that MSR values specified in VM-entry MSR-load area are
+ * correctly loaded into MSRs of the nested guest on VM-entry.
+ */
+static int vm_entry_msr_load_init(struct vmcs *vmcs)
+{
+	void *msr_bitmap;
+	u32 ctrl_cpu0;
+	guest_efer = vmcs_read(GUEST_EFER);
+
+	/*
+	 * Set MSR bitmap so that we don't VM-exit on RDMSR
+	 */
+	msr_bitmap = alloc_page();
+	ctrl_cpu0 = vmcs_read(CPU_EXEC_CTRL0);
+	ctrl_cpu0 |= CPU_MSR_BITMAP;
+	vmcs_write(CPU_EXEC_CTRL0, ctrl_cpu0);
+	vmcs_write(MSR_BITMAP, (u64)msr_bitmap);
+
+	entry_msr_load = alloc_page();
+	entry_msr_load[0].index = MSR_EFER;
+	entry_msr_load[0].value = guest_efer;
+	vmcs_write(ENT_MSR_LD_CNT, 1);
+	vmcs_write(ENTER_MSR_LD_ADDR, (u64) entry_msr_load);
+	vmx_set_test_stage(1);
+
+	return VMX_TEST_START;
+}
+
+static u64 guest_msr_efer;
+
+static void vm_entry_msr_load_main(void)
+{
+	while (1) {
+		if (vmx_get_test_stage() != 3) {
+			guest_msr_efer = rdmsr(MSR_EFER);
+			vmcall();
+		} else {
+			break;
+		}
+	}
+}
+
+static int vm_entry_msr_load_exit_handler(void)
+{
+	u64 guest_rip = vmcs_read(GUEST_RIP);
+	ulong reason = vmcs_read(EXI_REASON) & 0xff;
+	u32 insn_len = vmcs_read(EXI_INST_LEN);
+
+	switch (reason) {
+	case VMX_VMCALL:
+		switch(vmx_get_test_stage()) {
+		case 1:
+			report("VM-entry MSR-load, value: 0x%lx, "
+				"expected: 0x%lx", guest_msr_efer ==
+				guest_efer, guest_msr_efer, guest_efer);
+			if (guest_msr_efer == guest_efer) {
+				guest_efer ^= EFER_NX;
+				entry_msr_load[0].value = guest_efer;
+				vmx_set_test_stage(2);
+				vmcs_write(GUEST_RIP, guest_rip + insn_len);
+				return VMX_TEST_RESUME;
+			} else {
+				return VMX_TEST_VMEXIT;
+			}
+		case 2:
+			report("VM-entry MSR-load, value: 0x%lx, "
+				"expected: 0x%lx", guest_msr_efer ==
+				guest_efer, guest_msr_efer, guest_efer);
+			if (guest_msr_efer == guest_efer) {
+				vmx_set_test_stage(3);
+				vmcs_write(GUEST_RIP, guest_rip + insn_len);
+				return VMX_TEST_RESUME;
+			} else {
+				return VMX_TEST_VMEXIT;
+			}
+		}
+	default:
+		print_vmexit_info();
+	}
+	return VMX_TEST_VMEXIT;
+}
+
 #define TEST(name) { #name, .v2 = name }
 
 /* name/init/guest_main/exit_handler/syscall_handler/guest_regs */
@@ -9002,6 +9087,8 @@  struct vmx_test vmx_tests[] = {
 		exit_monitor_from_l2_handler, NULL, {0} },
 	{ "invalid_msr", invalid_msr_init, invalid_msr_main,
 		invalid_msr_exit_handler, NULL, {0}, invalid_msr_entry_failure},
+	{ "vm_entry_msr_load", vm_entry_msr_load_init, vm_entry_msr_load_main,
+		vm_entry_msr_load_exit_handler, NULL, {0}, NULL},
 	/* Basic V2 tests. */
 	TEST(v2_null_test),
 	TEST(v2_multiple_entries_test),