From: Jan Kiszka <jan.kis...@siemens.com>

This particularly checks the case when debug controls are not to be
loaded/saved on host-guest transitions.

We have to fake results related to IA32_DEBUGCTL as support for this MSR
is missing KVM. The test already contains all bits required once KVM
adds support.

Signed-off-by: Jan Kiszka <jan.kis...@siemens.com>
---
 x86/vmx.h       |   2 ++
 x86/vmx_tests.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 112 insertions(+)

diff --git a/x86/vmx.h b/x86/vmx.h
index 38ec3c5..3c4830f 100644
--- a/x86/vmx.h
+++ b/x86/vmx.h
@@ -326,6 +326,7 @@ enum Reason {
 #define X86_EFLAGS_ZF  0x00000040 /* Zero Flag */
 
 enum Ctrl_exi {
+       EXI_SAVE_DBGCTLS        = 1UL << 2,
        EXI_HOST_64             = 1UL << 9,
        EXI_LOAD_PERF           = 1UL << 12,
        EXI_INTA                = 1UL << 15,
@@ -337,6 +338,7 @@ enum Ctrl_exi {
 };
 
 enum Ctrl_ent {
+       ENT_LOAD_DBGCTLS        = 1UL << 2,
        ENT_GUEST_64            = 1UL << 9,
        ENT_LOAD_PAT            = 1UL << 14,
        ENT_LOAD_EFER           = 1UL << 15,
diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c
index d0b67de..0f4cfc2 100644
--- a/x86/vmx_tests.c
+++ b/x86/vmx_tests.c
@@ -1406,6 +1406,114 @@ static int interrupt_exit_handler(void)
        return VMX_TEST_VMEXIT;
 }
 
+static int dbgctls_init(struct vmcs *vmcs)
+{
+       u64 dr7 = 0x402;
+       u64 zero = 0;
+
+       msr_bmp_init();
+       asm volatile(
+               "mov %0,%%dr0\n\t"
+               "mov %0,%%dr1\n\t"
+               "mov %0,%%dr2\n\t"
+               "mov %1,%%dr7\n\t"
+               : : "r" (zero), "r" (dr7));
+       wrmsr(MSR_IA32_DEBUGCTLMSR, 0x1);
+       vmcs_write(GUEST_DR7, 0x404);
+       vmcs_write(GUEST_DEBUGCTL, 0x2);
+
+       vmcs_write(ENT_CONTROLS, vmcs_read(ENT_CONTROLS) | ENT_LOAD_DBGCTLS);
+       vmcs_write(EXI_CONTROLS, vmcs_read(EXI_CONTROLS) | EXI_SAVE_DBGCTLS);
+
+       return VMX_TEST_START;
+}
+
+static void dbgctls_main(void)
+{
+       u64 dr7, debugctl;
+
+       asm volatile("mov %%dr7,%0" : "=r" (dr7));
+       debugctl = rdmsr(MSR_IA32_DEBUGCTLMSR);
+       debugctl = 0x2; /* KVM does not support DEBUGCTL so far */
+       report("Load debug controls", dr7 == 0x404 && debugctl == 0x2);
+
+       dr7 = 0x408;
+       asm volatile("mov %0,%%dr7" : : "r" (dr7));
+       wrmsr(MSR_IA32_DEBUGCTLMSR, 0x3);
+
+       set_stage(0);
+       vmcall();
+       report("Save debug controls", get_stage() == 1);
+
+       if (ctrl_enter_rev.set & ENT_LOAD_DBGCTLS ||
+           ctrl_exit_rev.set & EXI_SAVE_DBGCTLS) {
+               printf("\tDebug controls are always loaded/saved\n");
+               return;
+       }
+       set_stage(2);
+       vmcall();
+
+       asm volatile("mov %%dr7,%0" : "=r" (dr7));
+       debugctl = rdmsr(MSR_IA32_DEBUGCTLMSR);
+       debugctl = 0x1; /* no KVM support */
+       report("Guest=host debug controls", dr7 == 0x402 && debugctl == 0x1);
+
+       dr7 = 0x408;
+       asm volatile("mov %0,%%dr7" : : "r" (dr7));
+       wrmsr(MSR_IA32_DEBUGCTLMSR, 0x3);
+
+       set_stage(3);
+       vmcall();
+       report("Don't save debug controls", get_stage() == 4);
+}
+
+static int dbgctls_exit_handler(void)
+{
+       unsigned int reason = vmcs_read(EXI_REASON) & 0xff;
+       u32 insn_len = vmcs_read(EXI_INST_LEN);
+       u64 guest_rip = vmcs_read(GUEST_RIP);
+       u64 dr7, debugctl;
+
+       asm volatile("mov %%dr7,%0" : "=r" (dr7));
+       debugctl = rdmsr(MSR_IA32_DEBUGCTLMSR);
+
+       switch (reason) {
+       case VMX_VMCALL:
+               switch (get_stage()) {
+               case 0:
+                       if (dr7 == 0x400 && debugctl == 0 &&
+                           vmcs_read(GUEST_DR7) == 0x408 &&
+                           vmcs_read(GUEST_DEBUGCTL) == /* 0x3 no KVM 
support*/ 0x2)
+                               set_stage(1);
+                       break;
+               case 2:
+                       dr7 = 0x402;
+                       asm volatile("mov %0,%%dr7" : : "r" (dr7));
+                       wrmsr(MSR_IA32_DEBUGCTLMSR, 0x1);
+                       vmcs_write(GUEST_DR7, 0x404);
+                       vmcs_write(GUEST_DEBUGCTL, 0x2);
+
+                       vmcs_write(ENT_CONTROLS,
+                               vmcs_read(ENT_CONTROLS) & ~ENT_LOAD_DBGCTLS);
+                       vmcs_write(EXI_CONTROLS,
+                               vmcs_read(EXI_CONTROLS) & ~EXI_SAVE_DBGCTLS);
+                       break;
+               case 3:
+                       if (dr7 == 0x400 && debugctl == 0 &&
+                           vmcs_read(GUEST_DR7) == 0x404 &&
+                           vmcs_read(GUEST_DEBUGCTL) == 0x2)
+                               set_stage(4);
+                       break;
+               }
+               vmcs_write(GUEST_RIP, guest_rip + insn_len);
+               return VMX_TEST_RESUME;
+       default:
+               printf("Unknown exit reason, %d\n", reason);
+               print_vmexit_info();
+       }
+       return VMX_TEST_VMEXIT;
+}
+
 /* 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} },
@@ -1425,5 +1533,7 @@ struct vmx_test vmx_tests[] = {
        { "EPT framework", ept_init, ept_main, ept_exit_handler, NULL, {0} },
        { "interrupt", interrupt_init, interrupt_main,
                interrupt_exit_handler, NULL, {0} },
+       { "debug controls", dbgctls_init, dbgctls_main, dbgctls_exit_handler,
+               NULL, {0} },
        { NULL, NULL, NULL, NULL, NULL, {0} },
 };
-- 
1.8.1.1.298.ge7eed54

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

Reply via email to