]> git.hungrycats.org Git - linux/commitdiff
KVM: Introduce {set/get}_interrupt_shadow()
authorGlauber Costa <glommer@redhat.com>
Mon, 3 Aug 2009 17:57:52 +0000 (14:57 -0300)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 9 Sep 2009 03:33:30 +0000 (20:33 -0700)
This patch introduces set/get_interrupt_shadow(), that does exactly
what the name suggests. It also replaces open code that explicitly does
it with the now existent functions. It differs slightly from upstream,
because upstream merged it after gleb's interrupt rework, that we don't
ship.

Just for reference, upstream changelog is
(2809f5d2c4cfad171167b131bb2a21ab65eba40f):

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>
Signed-off-by: Avi Kivity <avi@redhat.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
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

index a93d1cc413e1c95024184e319bed8e97ca3abfe4..a9471db9b6926aba5f7313e45927f473484f1c0a 100644 (file)
@@ -513,6 +513,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);
        int (*get_irq)(struct kvm_vcpu *vcpu);
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 1f8510c51d6e8abc2f315d9724e34708f49e2a6b..0f10a69a18a21abf65a43b750ef689790b4ca067 100644 (file)
@@ -227,6 +227,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);
@@ -240,7 +261,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);
 
        vcpu->arch.interrupt_window_open = (svm->vcpu.arch.hflags & HF_GIF_MASK);
 }
@@ -2667,6 +2688,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,
        .get_irq = svm_get_irq,
        .set_irq = svm_set_irq,
index fa0adcd8a36f12b4e526f7ac1989f4b9e8847f69..1a0d5cdd1a10bb8b6e605242bd2621ce13f9a76f 100644 (file)
@@ -732,23 +732,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);
        vcpu->arch.interrupt_window_open = 1;
 }
 
@@ -3738,6 +3760,8 @@ static struct kvm_x86_ops vmx_x86_ops = {
        .run = vmx_vcpu_run,
        .handle_exit = kvm_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,
        .get_irq = vmx_get_irq,
        .set_irq = vmx_inject_irq,