This checks some usage cases of VMX MSR load/store feature:
1) VM-entry MSR-load area is correctly filled
2) VM-exit MSR-store area is correctly filled
3) VM-exit MSR-load area is correctly filled
4) Attempt to load MSR_FS_BASE on VM entry (must generate
VM-entry failure due to MSR loading)

Signed-off-by: Eugene Korenevsky <[email protected]>
---
 x86/vmx_tests.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 76 insertions(+)

diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c
index 184fafc..913904a 100644
--- a/x86/vmx_tests.c
+++ b/x86/vmx_tests.c
@@ -1525,6 +1525,80 @@ static int dbgctls_exit_handler(void)
        return VMX_TEST_VMEXIT;
 }
 
+struct vmx_msr_entry {
+       u32 index;
+       u32 reserved;
+       u64 value;
+} __attribute__((packed));
+
+#define MSR_MAGIC 0x31415926
+struct vmx_msr_entry *exit_msr_store, *entry_msr_load, *exit_msr_load;
+
+static int msr_switch_init(struct vmcs *vmcs)
+{
+       msr_bmp_init();
+       exit_msr_store = alloc_page();
+       exit_msr_load = alloc_page();
+       entry_msr_load = alloc_page();
+       memset(exit_msr_store, 0, PAGE_SIZE);
+       memset(exit_msr_load, 0, PAGE_SIZE);
+       memset(entry_msr_load, 0, PAGE_SIZE);
+       entry_msr_load[0].index = MSR_KERNEL_GS_BASE;
+       entry_msr_load[0].value = MSR_MAGIC;
+
+       vmx_set_test_stage(1);
+       vmcs_write(ENT_MSR_LD_CNT, 1);
+       vmcs_write(ENTER_MSR_LD_ADDR, (u64)entry_msr_load);
+       vmcs_write(EXI_MSR_ST_CNT, 1);
+       vmcs_write(EXIT_MSR_ST_ADDR, (u64)exit_msr_store);
+       vmcs_write(EXI_MSR_LD_CNT, 1);
+       vmcs_write(EXIT_MSR_LD_ADDR, (u64)exit_msr_load);
+       return VMX_TEST_START;
+}
+
+static void msr_switch_main()
+{
+       if (vmx_get_test_stage() == 1) {
+               report("VM entry MSR load",
+                       rdmsr(MSR_KERNEL_GS_BASE) == MSR_MAGIC);
+               vmx_set_test_stage(2);
+               wrmsr(MSR_KERNEL_GS_BASE, MSR_MAGIC + 1);
+               exit_msr_store[0].index = MSR_KERNEL_GS_BASE;
+               exit_msr_load[0].index = MSR_KERNEL_GS_BASE;
+               exit_msr_load[0].value = MSR_MAGIC + 2;
+       }
+       vmcall();
+}
+
+static int msr_switch_exit_handler()
+{
+       ulong reason;
+
+       reason = vmcs_read(EXI_REASON);
+       switch (reason) {
+       case 0x80000000 | VMX_FAIL_MSR:
+               if (vmx_get_test_stage() == 3) {
+                       report("VM entry MSR load: try to load FS_BASE",
+                               vmcs_read(EXI_QUALIFICATION) == 1);
+                       return VMX_TEST_VMEXIT;
+               }
+               break;
+       case VMX_VMCALL:
+               if (vmx_get_test_stage() == 2) {
+                       report("VM exit MSR store",
+                               exit_msr_store[0].value == MSR_MAGIC + 1);
+                       report("VM exit MSR load",
+                               rdmsr(MSR_KERNEL_GS_BASE) == MSR_MAGIC + 2);
+                       vmx_set_test_stage(3);
+                       entry_msr_load[0].index = MSR_FS_BASE;
+                       return VMX_TEST_RESUME;
+               }
+       }
+       printf("ERROR %s: unexpected stage=%u or reason=%lu\n",
+               __func__, vmx_get_test_stage(), reason);
+       return VMX_TEST_EXIT;
+}
+
 /* name/init/guest_main/exit_handler/syscall_handler/guest_regs */
 struct vmx_test vmx_tests[] = {
        { "null", NULL, basic_guest_main, basic_exit_handler, NULL, {0} },
@@ -1546,5 +1620,7 @@ struct vmx_test vmx_tests[] = {
                interrupt_exit_handler, NULL, {0} },
        { "debug controls", dbgctls_init, dbgctls_main, dbgctls_exit_handler,
                NULL, {0} },
+       { "MSR switch", msr_switch_init, msr_switch_main,
+               msr_switch_exit_handler, NULL, {0} },
        { NULL, NULL, NULL, NULL, NULL, {0} },
 };
-- 
2.0.4

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to