diff mbox

[13/14] hvf: refactor event injection code for hvf

Message ID 20170828015654.2530-14-Sergio.G.DelReal@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

This commit refactors the event-injection code for hvf through using the
appropriate fields already provided by CPUX86State. At vmexit, it fills
these fields so that hvf_inject_interrupts can just retrieve them without
calling into hvf.

Signed-off-by: Sergio Andres Gomez Del Real <Sergio.G.DelReal@gmail.com>
---
 target/i386/cpu.c              |  3 ++
 target/i386/hvf-all.c          | 57 ++++++++++++++++++++++++++++++++++----
 target/i386/hvf-utils/vmcs.h   |  3 ++
 target/i386/hvf-utils/vmx.h    |  8 ++++++
 target/i386/hvf-utils/x86hvf.c | 63 ++++++++++++++++++++----------------------
 target/i386/kvm.c              |  2 --
 6 files changed, 96 insertions(+), 40 deletions(-)
diff mbox

Patch

diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 8c531a0ffa..7d2080d023 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -3275,6 +3275,9 @@  static void x86_cpu_reset(CPUState *s)
     memset(env->mtrr_var, 0, sizeof(env->mtrr_var));
     memset(env->mtrr_fixed, 0, sizeof(env->mtrr_fixed));
 
+    env->interrupt_injected = -1;
+    env->exception_injected = -1;
+    env->nmi_injected = false;
 #if !defined(CONFIG_USER_ONLY)
     /* We hard-wire the BSP to the first CPU. */
     apic_designate_bsp(cpu->apic_state, s->cpu_index == 0);
diff --git a/target/i386/hvf-all.c b/target/i386/hvf-all.c
index 8a75723dcf..25e4fd4eb2 100644
--- a/target/i386/hvf-all.c
+++ b/target/i386/hvf-all.c
@@ -750,6 +750,55 @@  void hvf_disable(int shouldDisable)
     hvf_disabled = shouldDisable;
 }
 
+static void hvf_store_events(CPUState *cpu, uint32_t ins_len, uint64_t idtvec_info)
+{
+    X86CPU *x86_cpu = X86_CPU(cpu);
+    CPUX86State *env = &x86_cpu->env;
+
+    env->exception_injected = -1;
+    env->interrupt_injected = -1;
+    env->nmi_injected = false;
+    if (idtvec_info & VMCS_IDT_VEC_VALID) {
+        switch (idtvec_info & VMCS_IDT_VEC_TYPE) {
+        case VMCS_IDT_VEC_HWINTR:
+        case VMCS_IDT_VEC_SWINTR:
+            env->interrupt_injected = idtvec_info & VMCS_IDT_VEC_VECNUM;
+            break;
+        case VMCS_IDT_VEC_NMI:
+            env->nmi_injected = true;
+            break;
+        case VMCS_IDT_VEC_HWEXCEPTION:
+        case VMCS_IDT_VEC_SWEXCEPTION:
+            env->exception_injected = idtvec_info & VMCS_IDT_VEC_VECNUM;
+            break;
+        case VMCS_IDT_VEC_PRIV_SWEXCEPTION:
+        default:
+            abort();
+        }
+        if ((idtvec_info & VMCS_IDT_VEC_TYPE) == VMCS_IDT_VEC_SWEXCEPTION ||
+            (idtvec_info & VMCS_IDT_VEC_TYPE) == VMCS_IDT_VEC_SWINTR) {
+            env->ins_len = ins_len;
+        }
+        if (idtvec_info & VMCS_INTR_DEL_ERRCODE) {
+            env->has_error_code = true;
+            env->error_code = rvmcs(cpu->hvf_fd, VMCS_IDT_VECTORING_ERROR);
+        }
+    }
+    if ((rvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY) &
+        VMCS_INTERRUPTIBILITY_NMI_BLOCKING)) {
+        env->hflags2 |= HF2_NMI_MASK;
+    } else {
+        env->hflags2 &= ~HF2_NMI_MASK;
+    }
+    if (rvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY) &
+         (VMCS_INTERRUPTIBILITY_STI_BLOCKING |
+         VMCS_INTERRUPTIBILITY_MOVSS_BLOCKING)) {
+        env->hflags |= HF_INHIBIT_IRQ_MASK;
+    } else {
+        env->hflags &= ~HF_INHIBIT_IRQ_MASK;
+    }
+}
+
 int hvf_vcpu_exec(CPUState *cpu)
 {
     X86CPU *x86_cpu = X86_CPU(cpu);
@@ -769,11 +818,6 @@  int hvf_vcpu_exec(CPUState *cpu)
             cpu->vcpu_dirty = false;
         }
 
-        env->hvf_emul->interruptable =
-            !(rvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY) &
-             (VMCS_INTERRUPTIBILITY_STI_BLOCKING |
-             VMCS_INTERRUPTIBILITY_MOVSS_BLOCKING));
-
         hvf_inject_interrupts(cpu);
         vmx_update_tpr(cpu);
 
@@ -792,7 +836,10 @@  int hvf_vcpu_exec(CPUState *cpu)
         uint64_t exit_qual = rvmcs(cpu->hvf_fd, VMCS_EXIT_QUALIFICATION);
         uint32_t ins_len = (uint32_t)rvmcs(cpu->hvf_fd,
                                            VMCS_EXIT_INSTRUCTION_LENGTH);
+
         uint64_t idtvec_info = rvmcs(cpu->hvf_fd, VMCS_IDT_VECTORING_INFO);
+
+        hvf_store_events(cpu, ins_len, idtvec_info);
         rip = rreg(cpu->hvf_fd, HV_X86_RIP);
         RFLAGS(env) = rreg(cpu->hvf_fd, HV_X86_RFLAGS);
         env->eflags = RFLAGS(env);
diff --git a/target/i386/hvf-utils/vmcs.h b/target/i386/hvf-utils/vmcs.h
index c410dcfaaa..0fae73dce5 100644
--- a/target/i386/hvf-utils/vmcs.h
+++ b/target/i386/hvf-utils/vmcs.h
@@ -299,6 +299,7 @@ 
 /*
  * VMCS IDT-Vectoring information fields
  */
+#define VMCS_IDT_VEC_VECNUM 0xFF
 #define VMCS_IDT_VEC_VALID (1U << 31)
 #define VMCS_IDT_VEC_TYPE 0x700
 #define VMCS_IDT_VEC_ERRCODE_VALID (1U << 11)
@@ -306,6 +307,8 @@ 
 #define VMCS_IDT_VEC_NMI (2 << 8)
 #define VMCS_IDT_VEC_HWEXCEPTION (3 << 8)
 #define VMCS_IDT_VEC_SWINTR (4 << 8)
+#define VMCS_IDT_VEC_PRIV_SWEXCEPTION (5 << 8)
+#define VMCS_IDT_VEC_SWEXCEPTION (6 << 8)
 
 /*
  * VMCS Guest interruptibility field
diff --git a/target/i386/hvf-utils/vmx.h b/target/i386/hvf-utils/vmx.h
index d086c8d253..6d557045a5 100644
--- a/target/i386/hvf-utils/vmx.h
+++ b/target/i386/hvf-utils/vmx.h
@@ -181,6 +181,10 @@  static inline void macvm_set_rip(CPUState *cpu, uint64_t rip)
 
 static inline void vmx_clear_nmi_blocking(CPUState *cpu)
 {
+    X86CPU *x86_cpu = X86_CPU(cpu);
+    CPUX86State *env = &x86_cpu->env;
+
+    env->hflags2 &= ~HF2_NMI_MASK;
     uint32_t gi = (uint32_t) rvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY);
     gi &= ~VMCS_INTERRUPTIBILITY_NMI_BLOCKING;
     wvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY, gi);
@@ -188,6 +192,10 @@  static inline void vmx_clear_nmi_blocking(CPUState *cpu)
 
 static inline void vmx_set_nmi_blocking(CPUState *cpu)
 {
+    X86CPU *x86_cpu = X86_CPU(cpu);
+    CPUX86State *env = &x86_cpu->env;
+
+    env->hflags2 |= HF2_NMI_MASK;
     uint32_t gi = (uint32_t)rvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY);
     gi |= VMCS_INTERRUPTIBILITY_NMI_BLOCKING;
     wvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY, gi);
diff --git a/target/i386/hvf-utils/x86hvf.c b/target/i386/hvf-utils/x86hvf.c
index 8986b4e5e5..3a50548817 100644
--- a/target/i386/hvf-utils/x86hvf.c
+++ b/target/i386/hvf-utils/x86hvf.c
@@ -356,50 +356,47 @@  void vmx_clear_int_window_exiting(CPUState *cpu)
 
 void hvf_inject_interrupts(CPUState *cpu_state)
 {
-    int allow_nmi = !(rvmcs(cpu_state->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY) &
-                VMCS_INTERRUPTIBILITY_NMI_BLOCKING);
     X86CPU *x86cpu = X86_CPU(cpu_state);
     CPUX86State *env = &x86cpu->env;
 
-    uint64_t idt_info = rvmcs(cpu_state->hvf_fd, VMCS_IDT_VECTORING_INFO);
-    uint64_t info = 0;
-
-    if (idt_info & VMCS_IDT_VEC_VALID) {
-        uint8_t vector = idt_info & 0xff;
-        uint64_t intr_type = idt_info & VMCS_INTR_T_MASK;
-        info = idt_info;
+    uint8_t vector;
+    uint64_t intr_type;
+    bool have_event = true;
+    if (env->interrupt_injected != -1) {
+        vector = env->interrupt_injected;
+        intr_type = VMCS_INTR_T_SWINTR;
+    } else if (env->exception_injected != -1) {
+        vector = env->exception_injected;
+        if (vector == EXCP03_INT3 || vector == EXCP04_INTO) {
+            intr_type = VMCS_INTR_T_SWEXCEPTION;
+        } else {
+            intr_type = VMCS_INTR_T_HWEXCEPTION;
+        }
+    } else if (env->nmi_injected) {
+        vector = NMI_VEC;
+        intr_type = VMCS_INTR_T_NMI;
+    } else {
+        have_event = false;
+    }
 
+    uint64_t info = 0;
+    if (have_event) {
+        info = vector | intr_type | VMCS_INTR_VALID;
         uint64_t reason = rvmcs(cpu_state->hvf_fd, VMCS_EXIT_REASON);
-        if (intr_type == VMCS_INTR_T_NMI && reason != EXIT_REASON_TASK_SWITCH) {
-            allow_nmi = 1;
+        if (env->nmi_injected && reason != EXIT_REASON_TASK_SWITCH) {
             vmx_clear_nmi_blocking(cpu_state);
         }
 
-        if ((allow_nmi || intr_type != VMCS_INTR_T_NMI)) {
+        if (!(env->hflags2 & HF2_NMI_MASK) || intr_type != VMCS_INTR_T_NMI) {
             info &= ~(1 << 12); /* clear undefined bit */
             if (intr_type == VMCS_INTR_T_SWINTR ||
-                intr_type == VMCS_INTR_T_PRIV_SWEXCEPTION ||
                 intr_type == VMCS_INTR_T_SWEXCEPTION) {
-                uint64_t ins_len = rvmcs(cpu_state->hvf_fd,
-                                         VMCS_EXIT_INSTRUCTION_LENGTH);
-                wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_INST_LENGTH, ins_len);
-            }
-            if (vector == EXCEPTION_BP || vector == EXCEPTION_OF) {
-                /*
-                 * VT-x requires #BP and #OF to be injected as software
-                 * exceptions.
-                 */
-                info &= ~VMCS_INTR_T_MASK;
-                info |= VMCS_INTR_T_SWEXCEPTION;
-                uint64_t ins_len = rvmcs(cpu_state->hvf_fd,
-                                         VMCS_EXIT_INSTRUCTION_LENGTH);
-                wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_INST_LENGTH, ins_len);
+                wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_INST_LENGTH, env->ins_len);
             }
 
-            uint64_t err = 0;
-            if (idt_info & VMCS_INTR_DEL_ERRCODE) {
-                err = rvmcs(cpu_state->hvf_fd, VMCS_IDT_VECTORING_ERROR);
-                wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_EXCEPTION_ERROR, err);
+            if (env->has_error_code) {
+                wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_EXCEPTION_ERROR,
+                      env->error_code);
             }
             /*printf("reinject  %lx err %d\n", info, err);*/
             wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_INTR_INFO, info);
@@ -407,7 +404,7 @@  void hvf_inject_interrupts(CPUState *cpu_state)
     }
 
     if (cpu_state->interrupt_request & CPU_INTERRUPT_NMI) {
-        if (allow_nmi && !(info & VMCS_INTR_VALID)) {
+        if (!(env->hflags2 & HF2_NMI_MASK) && !(info & VMCS_INTR_VALID)) {
             cpu_state->interrupt_request &= ~CPU_INTERRUPT_NMI;
             info = VMCS_INTR_VALID | VMCS_INTR_T_NMI | NMI_VEC;
             wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_INTR_INFO, info);
@@ -416,7 +413,7 @@  void hvf_inject_interrupts(CPUState *cpu_state)
         }
     }
 
-    if (env->hvf_emul->interruptable &&
+    if (!(env->hflags & HF_INHIBIT_IRQ_MASK) &&
         (cpu_state->interrupt_request & CPU_INTERRUPT_HARD) &&
         (EFLAGS(env) & IF_MASK) && !(info & VMCS_INTR_VALID)) {
         int line = cpu_get_pic_interrupt(&x86cpu->env);
diff --git a/target/i386/kvm.c b/target/i386/kvm.c
index 6db7783edc..a695b8cd4e 100644
--- a/target/i386/kvm.c
+++ b/target/i386/kvm.c
@@ -1030,8 +1030,6 @@  void kvm_arch_reset_vcpu(X86CPU *cpu)
 {
     CPUX86State *env = &cpu->env;
 
-    env->exception_injected = -1;
-    env->interrupt_injected = -1;
     env->xcr0 = 1;
     if (kvm_irqchip_in_kernel()) {
         env->mp_state = cpu_is_bsp(cpu) ? KVM_MP_STATE_RUNNABLE :