summaryrefslogtreecommitdiffstats
path: root/drivers/kvm/svm.c
diff options
context:
space:
mode:
authorEddie Dong2007-07-06 11:20:49 +0200
committerAvi Kivity2007-10-13 10:18:24 +0200
commit85f455f7ddbed403b34b4d54b1eaf0e14126a126 (patch)
tree1dba7aa8fee3c8f756e12049c496dee5baae752c /drivers/kvm/svm.c
parentKVM: VMX: Split segments reload in vmx_load_host_state() (diff)
downloadkernel-qcow2-linux-85f455f7ddbed403b34b4d54b1eaf0e14126a126.tar.gz
kernel-qcow2-linux-85f455f7ddbed403b34b4d54b1eaf0e14126a126.tar.xz
kernel-qcow2-linux-85f455f7ddbed403b34b4d54b1eaf0e14126a126.zip
KVM: Add support for in-kernel PIC emulation
Signed-off-by: Yaozu (Eddie) Dong <eddie.dong@intel.com> Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers/kvm/svm.c')
-rw-r--r--drivers/kvm/svm.c69
1 files changed, 61 insertions, 8 deletions
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c
index cc674bfd31d9..2237a594a8ef 100644
--- a/drivers/kvm/svm.c
+++ b/drivers/kvm/svm.c
@@ -16,6 +16,7 @@
#include "kvm_svm.h"
#include "x86_emulate.h"
+#include "irq.h"
#include <linux/module.h>
#include <linux/kernel.h>
@@ -921,7 +922,8 @@ static int pf_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
enum emulation_result er;
int r;
- if (is_external_interrupt(exit_int_info))
+ if (!irqchip_in_kernel(kvm) &&
+ is_external_interrupt(exit_int_info))
push_irq(&svm->vcpu, exit_int_info & SVM_EVTINJ_VEC_MASK);
mutex_lock(&kvm->lock);
@@ -1185,6 +1187,8 @@ static int msr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
static int interrupt_window_interception(struct vcpu_svm *svm,
struct kvm_run *kvm_run)
{
+ svm->vmcb->control.intercept &= ~(1ULL << INTERCEPT_VINTR);
+ svm->vmcb->control.int_ctl &= ~V_IRQ_MASK;
/*
* If the user space waits to inject interrupts, exit as soon as
* possible
@@ -1289,22 +1293,56 @@ static void pre_svm_run(struct vcpu_svm *svm)
}
-static inline void inject_irq(struct vcpu_svm *svm)
+static inline void svm_inject_irq(struct vcpu_svm *svm, int irq)
{
struct vmcb_control_area *control;
control = &svm->vmcb->control;
- control->int_vector = pop_irq(&svm->vcpu);
+ control->int_vector = irq;
control->int_ctl &= ~V_INTR_PRIO_MASK;
control->int_ctl |= V_IRQ_MASK |
((/*control->int_vector >> 4*/ 0xf) << V_INTR_PRIO_SHIFT);
}
-static void reput_irq(struct vcpu_svm *svm)
+static void svm_intr_assist(struct vcpu_svm *svm)
{
+ struct vmcb *vmcb = svm->vmcb;
+ int intr_vector = -1;
+
+ if ((vmcb->control.exit_int_info & SVM_EVTINJ_VALID) &&
+ ((vmcb->control.exit_int_info & SVM_EVTINJ_TYPE_MASK) == 0)) {
+ intr_vector = vmcb->control.exit_int_info &
+ SVM_EVTINJ_VEC_MASK;
+ vmcb->control.exit_int_info = 0;
+ svm_inject_irq(svm, intr_vector);
+ return;
+ }
+
+ if (vmcb->control.int_ctl & V_IRQ_MASK)
+ return;
+
+ if (!kvm_cpu_has_interrupt(&svm->vcpu))
+ return;
+
+ if (!(vmcb->save.rflags & X86_EFLAGS_IF) ||
+ (vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) ||
+ (vmcb->control.event_inj & SVM_EVTINJ_VALID)) {
+ /* unable to deliver irq, set pending irq */
+ vmcb->control.intercept |= (1ULL << INTERCEPT_VINTR);
+ svm_inject_irq(svm, 0x0);
+ return;
+ }
+ /* Okay, we can deliver the interrupt: grab it and update PIC state. */
+ intr_vector = kvm_cpu_get_interrupt(&svm->vcpu);
+ svm_inject_irq(svm, intr_vector);
+}
+
+static void kvm_reput_irq(struct vcpu_svm *svm)
+{
+ struct kvm_vcpu *vcpu = &svm->vcpu;
struct vmcb_control_area *control = &svm->vmcb->control;
- if (control->int_ctl & V_IRQ_MASK) {
+ if ((control->int_ctl & V_IRQ_MASK) && !irqchip_in_kernel(vcpu->kvm)) {
control->int_ctl &= ~V_IRQ_MASK;
push_irq(&svm->vcpu, control->int_vector);
}
@@ -1313,6 +1351,19 @@ static void reput_irq(struct vcpu_svm *svm)
!(control->int_state & SVM_INTERRUPT_SHADOW_MASK);
}
+static void svm_do_inject_vector(struct vcpu_svm *svm)
+{
+ struct kvm_vcpu *vcpu = &svm->vcpu;
+ int word_index = __ffs(vcpu->irq_summary);
+ int bit_index = __ffs(vcpu->irq_pending[word_index]);
+ int irq = word_index * BITS_PER_LONG + bit_index;
+
+ clear_bit(bit_index, &vcpu->irq_pending[word_index]);
+ if (!vcpu->irq_pending[word_index])
+ clear_bit(word_index, &vcpu->irq_summary);
+ svm_inject_irq(svm, irq);
+}
+
static void do_interrupt_requests(struct vcpu_svm *svm,
struct kvm_run *kvm_run)
{
@@ -1326,7 +1377,7 @@ static void do_interrupt_requests(struct vcpu_svm *svm,
/*
* If interrupts enabled, and not blocked by sti or mov ss. Good.
*/
- inject_irq(svm);
+ svm_do_inject_vector(svm);
/*
* Interrupts blocked. Wait for unblock.
@@ -1408,7 +1459,9 @@ again:
return -EINTR;
}
- if (!vcpu->mmio_read_completed)
+ if (irqchip_in_kernel(vcpu->kvm))
+ svm_intr_assist(svm);
+ else if (!vcpu->mmio_read_completed)
do_interrupt_requests(svm, kvm_run);
vcpu->guest_mode = 1;
@@ -1576,7 +1629,7 @@ again:
stgi();
- reput_irq(svm);
+ kvm_reput_irq(svm);
svm->next_rip = 0;