..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@xxxxxxxxxx> Reviewed-by: Karl Heubaum <karl.heubaum@xxxxxxxxxx> --- x86/vmx_tests.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) 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), -- 2.20.1