@@ -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),