KVM: Replace ->drop_interrupt_shadow() by ->set_interrupt_shadow()
authorGlauber Costa <glommer@redhat.com>
Tue, 12 May 2009 20:21:05 +0000 (16:21 -0400)
committerAvi Kivity <avi@redhat.com>
Wed, 10 Jun 2009 08:48:54 +0000 (11:48 +0300)
This patch replaces drop_interrupt_shadow with the more
general set_interrupt_shadow, that can either drop or raise
it, depending on its parameter.  It also adds ->get_interrupt_shadow()
for future use.

Signed-off-by: Glauber Costa <glommer@redhat.com>
CC: H. Peter Anvin <hpa@zytor.com>
CC: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/kvm_x86_emulate.h
arch/x86/kvm/svm.c
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c

index ab7de4a1195544f0a55f9c4162a6d63e3e399b28..16d1481aa231c55d69639a87502b0261b3f58ca6 100644 (file)
@@ -508,6 +508,8 @@ struct kvm_x86_ops {
        void (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run);
        int (*handle_exit)(struct kvm_run *run, struct kvm_vcpu *vcpu);
        void (*skip_emulated_instruction)(struct kvm_vcpu *vcpu);
+       void (*set_interrupt_shadow)(struct kvm_vcpu *vcpu, int mask);
+       u32 (*get_interrupt_shadow)(struct kvm_vcpu *vcpu, int mask);
        void (*patch_hypercall)(struct kvm_vcpu *vcpu,
                                unsigned char *hypercall_addr);
        void (*set_irq)(struct kvm_vcpu *vcpu, int vec);
@@ -519,7 +521,6 @@ struct kvm_x86_ops {
        void (*enable_nmi_window)(struct kvm_vcpu *vcpu);
        void (*enable_irq_window)(struct kvm_vcpu *vcpu);
        void (*update_cr8_intercept)(struct kvm_vcpu *vcpu, int tpr, int irr);
-       void (*drop_interrupt_shadow)(struct kvm_vcpu *vcpu);
        int (*set_tss_addr)(struct kvm *kvm, unsigned int addr);
        int (*get_tdp_level)(void);
        u64 (*get_mt_mask)(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio);
index 6a159732881a6b4067fd552fd4576cce797a5926..be40d6e2b6bb2f6a050e3d4c93583f34159583d0 100644 (file)
@@ -143,6 +143,9 @@ struct decode_cache {
        struct fetch_cache fetch;
 };
 
+#define X86_SHADOW_INT_MOV_SS  1
+#define X86_SHADOW_INT_STI     2
+
 struct x86_emulate_ctxt {
        /* Register state before/after emulation. */
        struct kvm_vcpu *vcpu;
index f994c6df78be5b70f2f2f4a0e882f3f0b89e3eba..8b5ffbd55c11e78c31914b91cc72b97106af163c 100644 (file)
@@ -202,6 +202,27 @@ static int is_external_interrupt(u32 info)
        return info == (SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR);
 }
 
+static u32 svm_get_interrupt_shadow(struct kvm_vcpu *vcpu, int mask)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
+       u32 ret = 0;
+
+       if (svm->vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK)
+               ret |= X86_SHADOW_INT_STI | X86_SHADOW_INT_MOV_SS;
+       return ret & mask;
+}
+
+static void svm_set_interrupt_shadow(struct kvm_vcpu *vcpu, int mask)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
+
+       if (mask == 0)
+               svm->vmcb->control.int_state &= ~SVM_INTERRUPT_SHADOW_MASK;
+       else
+               svm->vmcb->control.int_state |= SVM_INTERRUPT_SHADOW_MASK;
+
+}
+
 static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
@@ -215,7 +236,7 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
                       __func__, kvm_rip_read(vcpu), svm->next_rip);
 
        kvm_rip_write(vcpu, svm->next_rip);
-       svm->vmcb->control.int_state &= ~SVM_INTERRUPT_SHADOW_MASK;
+       svm_set_interrupt_shadow(vcpu, 0);
 }
 
 static int has_svm(void)
@@ -2259,12 +2280,6 @@ static void pre_svm_run(struct vcpu_svm *svm)
                new_asid(svm, svm_data);
 }
 
-static void svm_drop_interrupt_shadow(struct kvm_vcpu *vcpu)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-       svm->vmcb->control.int_state &= ~SVM_INTERRUPT_SHADOW_MASK;
-}
-
 static void svm_inject_nmi(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
@@ -2667,6 +2682,8 @@ static struct kvm_x86_ops svm_x86_ops = {
        .run = svm_vcpu_run,
        .handle_exit = handle_exit,
        .skip_emulated_instruction = skip_emulated_instruction,
+       .set_interrupt_shadow = svm_set_interrupt_shadow,
+       .get_interrupt_shadow = svm_get_interrupt_shadow,
        .patch_hypercall = svm_patch_hypercall,
        .set_irq = svm_set_irq,
        .set_nmi = svm_inject_nmi,
@@ -2676,7 +2693,6 @@ static struct kvm_x86_ops svm_x86_ops = {
        .enable_nmi_window = enable_nmi_window,
        .enable_irq_window = enable_irq_window,
        .update_cr8_intercept = update_cr8_intercept,
-       .drop_interrupt_shadow = svm_drop_interrupt_shadow,
 
        .set_tss_addr = svm_set_tss_addr,
        .get_tdp_level = get_npt_level,
index e8a5649f9c159484fb7495dc2478f28c56622025..f3ab27b5a6b2c6d42b5ef9229cd8d195f9e8cb89 100644 (file)
@@ -736,23 +736,45 @@ static void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
        vmcs_writel(GUEST_RFLAGS, rflags);
 }
 
+static u32 vmx_get_interrupt_shadow(struct kvm_vcpu *vcpu, int mask)
+{
+       u32 interruptibility = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO);
+       int ret = 0;
+
+       if (interruptibility & GUEST_INTR_STATE_STI)
+               ret |= X86_SHADOW_INT_STI;
+       if (interruptibility & GUEST_INTR_STATE_MOV_SS)
+               ret |= X86_SHADOW_INT_MOV_SS;
+
+       return ret & mask;
+}
+
+static void vmx_set_interrupt_shadow(struct kvm_vcpu *vcpu, int mask)
+{
+       u32 interruptibility_old = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO);
+       u32 interruptibility = interruptibility_old;
+
+       interruptibility &= ~(GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS);
+
+       if (mask & X86_SHADOW_INT_MOV_SS)
+               interruptibility |= GUEST_INTR_STATE_MOV_SS;
+       if (mask & X86_SHADOW_INT_STI)
+               interruptibility |= GUEST_INTR_STATE_STI;
+
+       if ((interruptibility != interruptibility_old))
+               vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, interruptibility);
+}
+
 static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
 {
        unsigned long rip;
-       u32 interruptibility;
 
        rip = kvm_rip_read(vcpu);
        rip += vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
        kvm_rip_write(vcpu, rip);
 
-       /*
-        * We emulated an instruction, so temporary interrupt blocking
-        * should be removed, if set.
-        */
-       interruptibility = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO);
-       if (interruptibility & 3)
-               vmcs_write32(GUEST_INTERRUPTIBILITY_INFO,
-                            interruptibility & ~3);
+       /* skipping an emulated instruction also counts */
+       vmx_set_interrupt_shadow(vcpu, 0);
 }
 
 static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr,
@@ -2400,12 +2422,6 @@ out:
        return ret;
 }
 
-void vmx_drop_interrupt_shadow(struct kvm_vcpu *vcpu)
-{
-       vmcs_clear_bits(GUEST_INTERRUPTIBILITY_INFO,
-                       GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS);
-}
-
 static void enable_irq_window(struct kvm_vcpu *vcpu)
 {
        u32 cpu_based_vm_exec_control;
@@ -3649,6 +3665,8 @@ static struct kvm_x86_ops vmx_x86_ops = {
        .run = vmx_vcpu_run,
        .handle_exit = vmx_handle_exit,
        .skip_emulated_instruction = skip_emulated_instruction,
+       .set_interrupt_shadow = vmx_set_interrupt_shadow,
+       .get_interrupt_shadow = vmx_get_interrupt_shadow,
        .patch_hypercall = vmx_patch_hypercall,
        .set_irq = vmx_inject_irq,
        .set_nmi = vmx_inject_nmi,
@@ -3658,7 +3676,6 @@ static struct kvm_x86_ops vmx_x86_ops = {
        .enable_nmi_window = enable_nmi_window,
        .enable_irq_window = enable_irq_window,
        .update_cr8_intercept = update_cr8_intercept,
-       .drop_interrupt_shadow = vmx_drop_interrupt_shadow,
 
        .set_tss_addr = vmx_set_tss_addr,
        .get_tdp_level = get_ept_level,
index 3c4c327490af36527fd253426fe869d2d784e10e..7475b029b2ad848ccdfaf89a80f96e879b17cb9b 100644 (file)
@@ -3178,7 +3178,7 @@ static void inject_pending_irq(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                kvm_run->request_interrupt_window;
 
        if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
-               kvm_x86_ops->drop_interrupt_shadow(vcpu);
+               kvm_x86_ops->set_interrupt_shadow(vcpu, 0);
 
        inject_irq(vcpu);