This patch implements the GIF flag and the clgi and stgi instructions that
set this flag. Only if the flag is set (default), interrupts can be received by
the CPU.

To keep the information about that somewhere, this patch adds a new hidden
flags vector. that is used to store information that does not go into the
vmcb, but is SVM specific.

Signed-off-by: Alexander Graf <[EMAIL PROTECTED]>
---
 arch/x86/kvm/kvm_svm.h |    2 +
 arch/x86/kvm/svm.c     |   50 +++++++++++++++++++++++++++++++++++++++++++++--
 arch/x86/kvm/svm.h     |    2 +
 3 files changed, 51 insertions(+), 3 deletions(-)

diff --git a/arch/x86/kvm/kvm_svm.h b/arch/x86/kvm/kvm_svm.h
index 65ef0fc..a3105a6 100644
--- a/arch/x86/kvm/kvm_svm.h
+++ b/arch/x86/kvm/kvm_svm.h
@@ -41,6 +41,8 @@ struct vcpu_svm {
        unsigned long host_dr7;
 
        u32 *msrpm;
+
+       u32 hflags;
 };
 
 #endif
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 0f423ce..7c75484 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -602,6 +602,8 @@ static void init_vmcb(struct vcpu_svm *svm)
                save->cr4 = 0;
        }
        force_new_asid(&svm->vcpu);
+
+       svm->hflags = HF_GIF_MASK;
 }
 
 static int svm_vcpu_reset(struct kvm_vcpu *vcpu)
@@ -1138,6 +1140,44 @@ static int vmmcall_interception(struct vcpu_svm *svm, 
struct kvm_run *kvm_run)
        return 1;
 }
 
+static int stgi_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+{
+       svm->next_rip = kvm_rip_read(&svm->vcpu) + 3;
+       skip_emulated_instruction(&svm->vcpu);
+
+       if (svm->vmcb->save.cpl) {
+               printk(KERN_ERR "%s: invalid cpl 0x%x at ip 0x%lx\n",
+                      __func__, svm->vmcb->save.cpl, kvm_rip_read(&svm->vcpu));
+               kvm_queue_exception(&svm->vcpu, GP_VECTOR);
+               return 1;
+       }
+
+       svm->hflags |= HF_GIF_MASK;
+
+       return 1;
+}
+
+static int clgi_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+{
+       svm->next_rip = kvm_rip_read(&svm->vcpu) + 3;
+       skip_emulated_instruction(&svm->vcpu);
+
+       if (svm->vmcb->save.cpl) {
+               printk(KERN_ERR "%s: invalid cpl 0x%x at ip 0x%lx\n",
+                      __func__, svm->vmcb->save.cpl, kvm_rip_read(&svm->vcpu));
+               kvm_queue_exception(&svm->vcpu, GP_VECTOR);
+               return 1;
+       }
+
+       svm->hflags &= ~HF_GIF_MASK;
+
+       /* After a CLGI no interrupts should come */
+       svm_set_vintr(svm, false);
+       svm->vmcb->control.int_ctl &= ~V_IRQ_MASK;
+
+       return 1;
+}
+
 static int invalid_op_interception(struct vcpu_svm *svm,
                                   struct kvm_run *kvm_run)
 {
@@ -1432,8 +1472,8 @@ static int (*svm_exit_handlers[])(struct vcpu_svm *svm,
        [SVM_EXIT_VMMCALL]                      = vmmcall_interception,
        [SVM_EXIT_VMLOAD]                       = invalid_op_interception,
        [SVM_EXIT_VMSAVE]                       = invalid_op_interception,
-       [SVM_EXIT_STGI]                         = invalid_op_interception,
-       [SVM_EXIT_CLGI]                         = invalid_op_interception,
+       [SVM_EXIT_STGI]                         = stgi_interception,
+       [SVM_EXIT_CLGI]                         = clgi_interception,
        [SVM_EXIT_SKINIT]                       = invalid_op_interception,
        [SVM_EXIT_WBINVD]                       = emulate_on_interception,
        [SVM_EXIT_MONITOR]                      = invalid_op_interception,
@@ -1580,6 +1620,9 @@ static void svm_intr_assist(struct kvm_vcpu *vcpu)
        if (!kvm_cpu_has_interrupt(vcpu))
                goto out;
 
+       if (!(svm->hflags & HF_GIF_MASK))
+               goto out;
+
        if (!(vmcb->save.rflags & X86_EFLAGS_IF) ||
            (vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) ||
            (vmcb->control.event_inj & SVM_EVTINJ_VALID)) {
@@ -1631,7 +1674,8 @@ static void do_interrupt_requests(struct kvm_vcpu *vcpu,
 
        svm->vcpu.arch.interrupt_window_open =
                (!(control->int_state & SVM_INTERRUPT_SHADOW_MASK) &&
-                (svm->vmcb->save.rflags & X86_EFLAGS_IF));
+                (svm->vmcb->save.rflags & X86_EFLAGS_IF) &&
+                (svm->hflags & HF_GIF_MASK));
 
        if (svm->vcpu.arch.interrupt_window_open && svm->vcpu.arch.irq_summary)
                /*
diff --git a/arch/x86/kvm/svm.h b/arch/x86/kvm/svm.h
index 1b8afa7..61c0904 100644
--- a/arch/x86/kvm/svm.h
+++ b/arch/x86/kvm/svm.h
@@ -324,5 +324,7 @@ struct __attribute__ ((__packed__)) vmcb {
 #define SVM_STGI   ".byte 0x0f, 0x01, 0xdc"
 #define SVM_INVLPGA ".byte 0x0f, 0x01, 0xdf"
 
+#define HF_GIF_MASK            (1 << 0)
+
 #endif
 
-- 
1.5.6

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

Reply via email to