diff mbox series

[kvm-unit-tests,1/2] svm: introduce prepare_gif_clear callback

Message ID 1576690383-16170-2-git-send-email-pbonzini@redhat.com (mailing list archive)
State New, archived
Headers show
Series svm: make preparation more flexible | expand

Commit Message

Paolo Bonzini Dec. 18, 2019, 5:33 p.m. UTC
Generalize the set_host_if flag that was added recently, by introducing
a new callback that is called with GIF=0 && IF=1.  This is useful to
inject events that will trigger right after VMRUN.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 x86/svm.c | 124 ++++++++++++++++++++++++++++++++++++++++----------------------
 1 file changed, 81 insertions(+), 43 deletions(-)
diff mbox series

Patch

diff --git a/x86/svm.c b/x86/svm.c
index 99b1d71..63fda65 100644
--- a/x86/svm.c
+++ b/x86/svm.c
@@ -192,6 +192,7 @@  struct test {
     const char *name;
     bool (*supported)(void);
     void (*prepare)(struct test *test);
+    void (*prepare_gif_clear)(struct test *test);
     void (*guest_func)(struct test *test);
     bool (*finished)(struct test *test);
     bool (*succeeded)(struct test *test);
@@ -266,31 +267,37 @@  static void test_run(struct test *test, struct vmcb *vmcb)
     vmcb->save.rsp = (ulong)(guest_stack + ARRAY_SIZE(guest_stack));
     regs.rdi = (ulong)test;
     do {
+        struct test *the_test = test;
+        u64 the_vmcb = vmcb_phys;
         tsc_start = rdtsc();
         asm volatile (
             "clgi;\n\t" // semi-colon needed for LLVM compatibility
-            "cmpb $0, set_host_if\n\t"
-            "jz 1f\n\t"
             "sti \n\t"
-            "1: \n\t"
+            "call *%c[PREPARE_GIF_CLEAR](%[test]) \n \t"
+            "mov %[vmcb_phys], %%rax \n\t"
             "vmload \n\t"
             "vmload %0\n\t"
             "mov regs+0x80, %%r15\n\t"  // rflags
-            "mov %%r15, 0x170(%0)\n\t"
+            "mov %%r15, 0x170(%%rax)\n\t"
             "mov regs, %%r15\n\t"       // rax
-            "mov %%r15, 0x1f8(%0)\n\t"
+            "mov %%r15, 0x1f8(%%rax)\n\t"
             LOAD_GPR_C
             "vmrun %0\n\t"
             SAVE_GPR_C
-            "mov 0x170(%0), %%r15\n\t"  // rflags
+            "mov 0x170(%%rax), %%r15\n\t"  // rflags
             "mov %%r15, regs+0x80\n\t"
-            "mov 0x1f8(%0), %%r15\n\t"  // rax
+            "mov 0x1f8(%%rax), %%r15\n\t"  // rax
             "mov %%r15, regs\n\t"
             "vmsave %0\n\t"
             "cli \n\t"
             "stgi"
-            : : "a"(vmcb_phys)
-            : "rbx", "rcx", "rdx", "rsi",
+            : // inputs clobbered by the guest:
+	      "+D" (the_test),            // first argument register
+	      "+b" (the_vmcb)             // callee save register!
+            : [test] "0" (the_test),
+	      [vmcb_phys] "1"(the_vmcb),
+	      [PREPARE_GIF_CLEAR] "i" (offsetof(struct test, prepare_gif_clear))
+            : "rax", "rcx", "rdx", "rsi",
               "r8", "r9", "r10", "r11" , "r12", "r13", "r14", "r15",
               "memory");
 	tsc_end = rdtsc();
@@ -316,6 +323,12 @@  static void default_prepare(struct test *test)
     vmcb_ident(test->vmcb);
 }
 
+static void default_prepare_gif_clear(struct test *test)
+{
+    if (!set_host_if)
+        asm("cli");
+}
+
 static bool default_finished(struct test *test)
 {
     return true; /* one vmexit */
@@ -1486,58 +1499,83 @@  static bool pending_event_check_vmask(struct test *test)
 }
 
 static struct test tests[] = {
-    { "null", default_supported, default_prepare, null_test,
+    { "null", default_supported, default_prepare,
+      default_prepare_gif_clear, null_test,
       default_finished, null_check },
-    { "vmrun", default_supported, default_prepare, test_vmrun,
+    { "vmrun", default_supported, default_prepare,
+      default_prepare_gif_clear, test_vmrun,
        default_finished, check_vmrun },
-    { "ioio", default_supported, prepare_ioio, test_ioio,
+    { "ioio", default_supported, prepare_ioio,
+       default_prepare_gif_clear, test_ioio,
        ioio_finished, check_ioio },
     { "vmrun intercept check", default_supported, prepare_no_vmrun_int,
-      null_test, default_finished, check_no_vmrun_int },
-    { "cr3 read intercept", default_supported, prepare_cr3_intercept,
+      default_prepare_gif_clear, null_test, default_finished,
+      check_no_vmrun_int },
+    { "cr3 read intercept", default_supported,
+      prepare_cr3_intercept, default_prepare_gif_clear,
       test_cr3_intercept, default_finished, check_cr3_intercept },
     { "cr3 read nointercept", default_supported, default_prepare,
-      test_cr3_intercept, default_finished, check_cr3_nointercept },
+      default_prepare_gif_clear, test_cr3_intercept, default_finished,
+      check_cr3_nointercept },
     { "cr3 read intercept emulate", smp_supported,
-      prepare_cr3_intercept_bypass, test_cr3_intercept_bypass,
-      default_finished, check_cr3_intercept },
+      prepare_cr3_intercept_bypass, default_prepare_gif_clear,
+      test_cr3_intercept_bypass, default_finished, check_cr3_intercept },
     { "dr intercept check", default_supported, prepare_dr_intercept,
-      test_dr_intercept, dr_intercept_finished, check_dr_intercept },
-    { "next_rip", next_rip_supported, prepare_next_rip, test_next_rip,
+      default_prepare_gif_clear, test_dr_intercept, dr_intercept_finished,
+      check_dr_intercept },
+    { "next_rip", next_rip_supported, prepare_next_rip,
+      default_prepare_gif_clear, test_next_rip,
       default_finished, check_next_rip },
     { "msr intercept check", default_supported, prepare_msr_intercept,
-       test_msr_intercept, msr_intercept_finished, check_msr_intercept },
-    { "mode_switch", default_supported, prepare_mode_switch, test_mode_switch,
+      default_prepare_gif_clear, test_msr_intercept,
+      msr_intercept_finished, check_msr_intercept },
+    { "mode_switch", default_supported, prepare_mode_switch,
+      default_prepare_gif_clear, test_mode_switch,
        mode_switch_finished, check_mode_switch },
-    { "asid_zero", default_supported, prepare_asid_zero, test_asid_zero,
+    { "asid_zero", default_supported, prepare_asid_zero,
+      default_prepare_gif_clear, test_asid_zero,
        default_finished, check_asid_zero },
-    { "sel_cr0_bug", default_supported, sel_cr0_bug_prepare, sel_cr0_bug_test,
+    { "sel_cr0_bug", default_supported, sel_cr0_bug_prepare,
+      default_prepare_gif_clear, sel_cr0_bug_test,
        sel_cr0_bug_finished, sel_cr0_bug_check },
-    { "npt_nx", npt_supported, npt_nx_prepare, null_test,
-	    default_finished, npt_nx_check },
-    { "npt_us", npt_supported, npt_us_prepare, npt_us_test,
-	    default_finished, npt_us_check },
-    { "npt_rsvd", npt_supported, npt_rsvd_prepare, null_test,
-	    default_finished, npt_rsvd_check },
-    { "npt_rw", npt_supported, npt_rw_prepare, npt_rw_test,
-	    default_finished, npt_rw_check },
-    { "npt_rsvd_pfwalk", npt_supported, npt_rsvd_pfwalk_prepare, null_test,
-	    default_finished, npt_rsvd_pfwalk_check },
-    { "npt_rw_pfwalk", npt_supported, npt_rw_pfwalk_prepare, null_test,
-	    default_finished, npt_rw_pfwalk_check },
-    { "npt_l1mmio", npt_supported, npt_l1mmio_prepare, npt_l1mmio_test,
-	    default_finished, npt_l1mmio_check },
-    { "npt_rw_l1mmio", npt_supported, npt_rw_l1mmio_prepare, npt_rw_l1mmio_test,
-	    default_finished, npt_rw_l1mmio_check },
-    { "tsc_adjust", default_supported, tsc_adjust_prepare, tsc_adjust_test,
-       default_finished, tsc_adjust_check },
-    { "latency_run_exit", default_supported, latency_prepare, latency_test,
+    { "npt_nx", npt_supported, npt_nx_prepare,
+      default_prepare_gif_clear, null_test,
+      default_finished, npt_nx_check },
+    { "npt_us", npt_supported, npt_us_prepare,
+      default_prepare_gif_clear, npt_us_test,
+      default_finished, npt_us_check },
+    { "npt_rsvd", npt_supported, npt_rsvd_prepare,
+      default_prepare_gif_clear, null_test,
+      default_finished, npt_rsvd_check },
+    { "npt_rw", npt_supported, npt_rw_prepare,
+      default_prepare_gif_clear, npt_rw_test,
+      default_finished, npt_rw_check },
+    { "npt_rsvd_pfwalk", npt_supported, npt_rsvd_pfwalk_prepare,
+      default_prepare_gif_clear, null_test,
+      default_finished, npt_rsvd_pfwalk_check },
+    { "npt_rw_pfwalk", npt_supported, npt_rw_pfwalk_prepare,
+      default_prepare_gif_clear, null_test,
+      default_finished, npt_rw_pfwalk_check },
+    { "npt_l1mmio", npt_supported, npt_l1mmio_prepare,
+      default_prepare_gif_clear, npt_l1mmio_test,
+      default_finished, npt_l1mmio_check },
+    { "npt_rw_l1mmio", npt_supported, npt_rw_l1mmio_prepare,
+      default_prepare_gif_clear, npt_rw_l1mmio_test,
+      default_finished, npt_rw_l1mmio_check },
+    { "tsc_adjust", default_supported, tsc_adjust_prepare,
+      default_prepare_gif_clear, tsc_adjust_test,
+      default_finished, tsc_adjust_check },
+    { "latency_run_exit", default_supported, latency_prepare,
+      default_prepare_gif_clear, latency_test,
       latency_finished, latency_check },
-    { "latency_svm_insn", default_supported, lat_svm_insn_prepare, null_test,
+    { "latency_svm_insn", default_supported, lat_svm_insn_prepare,
+      default_prepare_gif_clear, null_test,
       lat_svm_insn_finished, lat_svm_insn_check },
     { "pending_event", default_supported, pending_event_prepare,
+      default_prepare_gif_clear,
       pending_event_test, pending_event_finished, pending_event_check },
     { "pending_event_vmask", default_supported, pending_event_prepare_vmask,
+      default_prepare_gif_clear,
       pending_event_test_vmask, pending_event_finished_vmask,
       pending_event_check_vmask },
 };