Instead of acking an interrupt when we *think* the guest is ready for it,
and then juggling it around in subarch-specific registers if it isn't (e.g.
page fault while trying to inject the interrupt), separate the injection and
ack.
Subarh specific code now provides two hooks: ->queue_interrupt() will attempt
to inject the interrupt, and ->interrupt_injected() will check whether this
actually succeeded (upon which common code will ack the interrupt). This
allows much simpler management of pending interrupts.
Signed-off-by: Avi Kivity <[EMAIL PROTECTED]>
---
drivers/kvm/svm.c | 113 ++++++++------------------------------------
drivers/kvm/vmx.c | 137 +++++++++--------------------------------------------
drivers/kvm/x86.c | 79 ++++++++++++++++++++++---------
drivers/kvm/x86.h | 11 ++--
4 files changed, 103 insertions(+), 237 deletions(-)
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c
index 10146a8..9fb9ee1 100644
--- a/drivers/kvm/svm.c
+++ b/drivers/kvm/svm.c
@@ -46,8 +46,6 @@ MODULE_LICENSE("GPL");
#define SVM_FEATURE_LBRV (1 << 1)
#define SVM_DEATURE_SVML (1 << 2)
-static void kvm_reput_irq(struct vcpu_svm *svm);
-
static inline struct vcpu_svm *to_svm(struct kvm_vcpu *vcpu)
{
return container_of(vcpu, struct vcpu_svm, vcpu);
@@ -838,16 +836,6 @@ static int svm_guest_debug(struct kvm_vcpu *vcpu, struct
kvm_debug_guest *dbg)
return -EOPNOTSUPP;
}
-static int svm_get_irq(struct kvm_vcpu *vcpu)
-{
- struct vcpu_svm *svm = to_svm(vcpu);
- u32 exit_int_info = svm->vmcb->control.exit_int_info;
-
- if (is_external_interrupt(exit_int_info))
- return exit_int_info & SVM_EVTINJ_VEC_MASK;
- return -1;
-}
-
static void load_host_msrs(struct kvm_vcpu *vcpu)
{
#ifdef CONFIG_X86_64
@@ -1245,8 +1233,6 @@ static int handle_exit(struct kvm_run *kvm_run, struct
kvm_vcpu *vcpu)
struct vcpu_svm *svm = to_svm(vcpu);
u32 exit_code = svm->vmcb->control.exit_code;
- kvm_reput_irq(svm);
-
if (svm->vmcb->control.exit_code == SVM_EXIT_ERR) {
kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
kvm_run->fail_entry.hardware_entry_failure_reason
@@ -1304,102 +1290,43 @@ static inline void svm_inject_irq(struct vcpu_svm
*svm, int irq)
((/*control->int_vector >> 4*/ 0xf) << V_INTR_PRIO_SHIFT);
}
-static void svm_set_irq(struct kvm_vcpu *vcpu, int irq)
+static void svm_set_tpr_threshold(struct kvm_vcpu *vcpu)
{
- struct vcpu_svm *svm = to_svm(vcpu);
-
- svm_inject_irq(svm, irq);
}
-static void svm_intr_assist(struct kvm_vcpu *vcpu)
+static bool svm_queue_interrupt(struct kvm_vcpu *vcpu, unsigned vector)
{
struct vcpu_svm *svm = to_svm(vcpu);
struct vmcb *vmcb = svm->vmcb;
- int intr_vector = -1;
- struct kvm_pending_irq irq;
- unsigned tpr_threshold;
-
- 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_get_interrupt(vcpu, &irq, &tpr_threshold))
- return;
+ return false;
if (!(vmcb->save.rflags & X86_EFLAGS_IF) ||
(vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) ||
- (vmcb->control.event_inj & SVM_EVTINJ_VALID)) {
+ vcpu->exception.pending) {
/* 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. */
- irq.ack(vcpu, irq.info);
- intr_vector = irq.vector;
- svm_inject_irq(svm, intr_vector);
- kvm_timer_intr_post(vcpu, intr_vector);
-}
-
-static void kvm_reput_irq(struct vcpu_svm *svm)
-{
- struct vmcb_control_area *control = &svm->vmcb->control;
-
- if ((control->int_ctl & V_IRQ_MASK)
- && !irqchip_in_kernel(svm->vcpu.kvm)) {
- control->int_ctl &= ~V_IRQ_MASK;
- push_irq(&svm->vcpu, control->int_vector);
+ return false;
}
-
- svm->vcpu.interrupt_window_open =
- !(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);
+ svm_inject_irq(svm, vector);
+ return true;
}
-static void do_interrupt_requests(struct kvm_vcpu *vcpu,
- struct kvm_run *kvm_run)
+static bool svm_interrupt_injected(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
struct vmcb_control_area *control = &svm->vmcb->control;
+ bool injected;
- svm->vcpu.interrupt_window_open =
- (!(control->int_state & SVM_INTERRUPT_SHADOW_MASK) &&
- (svm->vmcb->save.rflags & X86_EFLAGS_IF));
-
- if (svm->vcpu.interrupt_window_open && svm->vcpu.irq_summary)
- /*
- * If interrupts enabled, and not blocked by sti or mov ss.
Good.
- */
- svm_do_inject_vector(svm);
+ injected = !(control->int_ctl & V_IRQ_MASK)
+ && !(control->intercept & (1ULL << INTERCEPT_VINTR))
+ && !(control->exit_int_info & SVM_EXITINTINFO_VALID);
- /*
- * Interrupts blocked. Wait for unblock.
- */
- if (!svm->vcpu.interrupt_window_open &&
- (svm->vcpu.irq_summary || kvm_run->request_interrupt_window))
- control->intercept |= 1ULL << INTERCEPT_VINTR;
- else
- control->intercept &= ~(1ULL << INTERCEPT_VINTR);
+ if (!injected)
+ control->int_ctl &= ~V_IRQ_MASK;
+ return injected;
}
static int svm_set_tss_addr(struct kvm *kvm, unsigned int addr)
@@ -1586,6 +1513,8 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct
kvm_run *kvm_run)
stgi();
svm->next_rip = 0;
+ svm->vcpu.interrupt_window_open =
+ !(svm->vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK);
}
static void svm_set_cr3(struct kvm_vcpu *vcpu, unsigned long root)
@@ -1676,13 +1605,11 @@ static struct kvm_x86_ops svm_x86_ops = {
.handle_exit = handle_exit,
.skip_emulated_instruction = skip_emulated_instruction,
.patch_hypercall = svm_patch_hypercall,
- .get_irq = svm_get_irq,
- .set_irq = svm_set_irq,
.queue_exception = svm_queue_exception,
.exception_injected = svm_exception_injected,
- .inject_pending_irq = svm_intr_assist,
- .inject_pending_vectors = do_interrupt_requests,
-
+ .queue_interrupt = svm_queue_interrupt,
+ .interrupt_injected = svm_interrupt_injected,
+ .set_tpr_threshold = svm_set_tpr_threshold,
.set_tss_addr = svm_set_tss_addr,
};
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
index b788c6b..c180c04 100644
--- a/drivers/kvm/vmx.c
+++ b/drivers/kvm/vmx.c
@@ -861,21 +861,6 @@ static int set_guest_debug(struct kvm_vcpu *vcpu, struct
kvm_debug_guest *dbg)
return 0;
}
-static int vmx_get_irq(struct kvm_vcpu *vcpu)
-{
- struct vcpu_vmx *vmx = to_vmx(vcpu);
- u32 idtv_info_field;
-
- idtv_info_field = vmx->idt_vectoring_info;
- if (idtv_info_field & INTR_INFO_VALID_MASK) {
- if (is_external_interrupt(idtv_info_field))
- return idtv_info_field & VECTORING_INFO_VECTOR_MASK;
- else
- printk(KERN_DEBUG "pending exception: not handled
yet\n");
- }
- return -1;
-}
-
static __init int cpu_has_kvm_support(void)
{
unsigned long ecx = cpuid_ecx(1);
@@ -1732,48 +1717,6 @@ static void vmx_inject_irq(struct kvm_vcpu *vcpu, int
irq)
irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
}
-static void kvm_do_inject_irq(struct kvm_vcpu *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);
- vmx_inject_irq(vcpu, irq);
-}
-
-
-static void do_interrupt_requests(struct kvm_vcpu *vcpu,
- struct kvm_run *kvm_run)
-{
- u32 cpu_based_vm_exec_control;
-
- vcpu->interrupt_window_open =
- ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) &&
- (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0);
-
- if (vcpu->interrupt_window_open &&
- vcpu->irq_summary &&
- !(vmcs_read32(VM_ENTRY_INTR_INFO_FIELD) & INTR_INFO_VALID_MASK))
- /*
- * If interrupts enabled, and not blocked by sti or mov ss.
Good.
- */
- kvm_do_inject_irq(vcpu);
-
- cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
- if (!vcpu->interrupt_window_open &&
- (vcpu->irq_summary || kvm_run->request_interrupt_window))
- /*
- * Interrupts blocked. Wait for unblock.
- */
- cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING;
- else
- cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING;
- vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
-}
-
static int vmx_set_tss_addr(struct kvm *kvm, unsigned int addr)
{
int ret;
@@ -2218,12 +2161,12 @@ static void vmx_flush_tlb(struct kvm_vcpu *vcpu)
{
}
-static void update_tpr_threshold(struct kvm_vcpu *vcpu, unsigned tpr_threshold)
+static void update_tpr_threshold(struct kvm_vcpu *vcpu)
{
if (!vm_need_tpr_shadow(vcpu->kvm))
return;
- vmcs_write32(TPR_THRESHOLD, tpr_threshold >> 4);
+ vmcs_write32(TPR_THRESHOLD, vcpu->tpr_threshold >> 4);
}
static void enable_irq_window(struct kvm_vcpu *vcpu)
@@ -2235,65 +2178,30 @@ static void enable_irq_window(struct kvm_vcpu *vcpu)
vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
}
-static void vmx_intr_assist(struct kvm_vcpu *vcpu)
+static bool vmx_queue_interrupt(struct kvm_vcpu *vcpu, unsigned vector)
{
- struct vcpu_vmx *vmx = to_vmx(vcpu);
- u32 idtv_info_field, intr_info_field;
- int has_ext_irq, interrupt_window_open;
- struct kvm_pending_irq irq;
- int vector;
- unsigned tpr_threshold;
-
- has_ext_irq = kvm_cpu_get_interrupt(vcpu, &irq, &tpr_threshold);
-
- update_tpr_threshold(vcpu, tpr_threshold);
-
- intr_info_field = vmcs_read32(VM_ENTRY_INTR_INFO_FIELD);
- idtv_info_field = vmx->idt_vectoring_info;
- if (intr_info_field & INTR_INFO_VALID_MASK) {
- if (idtv_info_field & INTR_INFO_VALID_MASK) {
- /* TODO: fault when IDT_Vectoring */
- printk(KERN_ERR "Fault when IDT_Vectoring\n");
- }
- if (has_ext_irq)
- enable_irq_window(vcpu);
- return;
- }
- if (unlikely(idtv_info_field & INTR_INFO_VALID_MASK)) {
- if ((idtv_info_field & VECTORING_INFO_TYPE_MASK)
- == INTR_TYPE_EXT_INTR
- && vcpu->rmode.active) {
- u8 vect = idtv_info_field & VECTORING_INFO_VECTOR_MASK;
-
- vmx_inject_irq(vcpu, vect);
- if (unlikely(has_ext_irq))
- enable_irq_window(vcpu);
- return;
- }
-
- vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field);
- vmcs_write32(VM_ENTRY_INSTRUCTION_LEN,
- vmcs_read32(VM_EXIT_INSTRUCTION_LEN));
+ int interrupt_window_open;
- if (unlikely(idtv_info_field & INTR_INFO_DELIEVER_CODE_MASK))
- vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE,
- vmcs_read32(IDT_VECTORING_ERROR_CODE));
- if (unlikely(has_ext_irq))
- enable_irq_window(vcpu);
- return;
- }
- if (!has_ext_irq)
- return;
interrupt_window_open =
((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) &&
(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0);
- if (interrupt_window_open) {
- irq.ack(vcpu, irq.info);
- vector = irq.vector;
+
+ if (!vcpu->exception.pending && interrupt_window_open) {
vmx_inject_irq(vcpu, vector);
- kvm_timer_intr_post(vcpu, vector);
- } else
+ return true;
+ } else {
enable_irq_window(vcpu);
+ return false;
+ }
+}
+
+static bool vmx_interrupt_injected(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
+ bool valid = vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK;
+ unsigned type = vmx->idt_vectoring_info & VECTORING_INFO_TYPE_MASK;
+
+ return !(valid && (type == INTR_TYPE_EXT_INTR));
}
/*
@@ -2597,12 +2505,11 @@ static struct kvm_x86_ops vmx_x86_ops = {
.handle_exit = kvm_handle_exit,
.skip_emulated_instruction = skip_emulated_instruction,
.patch_hypercall = vmx_patch_hypercall,
- .get_irq = vmx_get_irq,
- .set_irq = vmx_inject_irq,
.queue_exception = vmx_queue_exception,
.exception_injected = vmx_exception_injected,
- .inject_pending_irq = vmx_intr_assist,
- .inject_pending_vectors = do_interrupt_requests,
+ .queue_interrupt = vmx_queue_interrupt,
+ .interrupt_injected = vmx_interrupt_injected,
+ .set_tpr_threshold = update_tpr_threshold,
.set_tss_addr = vmx_set_tss_addr,
};
diff --git a/drivers/kvm/x86.c b/drivers/kvm/x86.c
index 6deb052..a196d5d 100644
--- a/drivers/kvm/x86.c
+++ b/drivers/kvm/x86.c
@@ -2365,9 +2365,51 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu,
vcpu->irq_summary == 0);
}
+static void ack_vector(struct kvm_vcpu *vcpu, unsigned vector)
+{
+ unsigned word_index = vector / BITS_PER_LONG;
+ unsigned bit_index = vector % BITS_PER_LONG;
+
+ clear_bit(bit_index, &vcpu->irq_pending[word_index]);
+ if (!vcpu->irq_pending[word_index])
+ clear_bit(word_index, &vcpu->irq_summary);
+}
+
+static bool get_pending_irq(struct kvm_vcpu *vcpu, struct kvm_pending_irq *irq,
+ unsigned *tpr_threshold)
+{
+ unsigned word_index, bit_index;
+
+ if (irqchip_in_kernel(vcpu->kvm))
+ return kvm_cpu_get_interrupt(vcpu, irq, tpr_threshold);
+
+ *tpr_threshold = 0;
+
+ if (!vcpu->irq_summary)
+ return false;
+
+ word_index = __ffs(vcpu->irq_summary);
+ bit_index = __ffs(vcpu->irq_pending[word_index]);
+ irq->vector = word_index * BITS_PER_LONG + bit_index;
+ irq->ack = ack_vector;
+ irq->info = irq->vector;
+ return true;
+}
+
+static void update_tpr_threshold(struct kvm_vcpu *vcpu, unsigned tpr_threshold)
+{
+ if (tpr_threshold != vcpu->tpr_threshold) {
+ vcpu->tpr_threshold = tpr_threshold;
+ kvm_x86_ops->set_tpr_threshold(vcpu);
+ }
+}
+
static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
int r;
+ bool irq_pending;
+ struct kvm_pending_irq irq;
+ unsigned tpr_threshold;
if (unlikely(vcpu->mp_state == VCPU_MP_STATE_SIPI_RECEIVED)) {
pr_debug("vcpu %d received sipi with vector # %x\n",
@@ -2408,10 +2450,12 @@ again:
if (vcpu->exception.pending)
__queue_exception(vcpu);
- else if (irqchip_in_kernel(vcpu->kvm))
- kvm_x86_ops->inject_pending_irq(vcpu);
- else
- kvm_x86_ops->inject_pending_vectors(vcpu, kvm_run);
+
+ irq_pending = get_pending_irq(vcpu, &irq, &tpr_threshold);
+ if (irq_pending)
+ irq_pending = kvm_x86_ops->queue_interrupt(vcpu, irq.vector);
+
+ update_tpr_threshold(vcpu, tpr_threshold);
vcpu->guest_mode = 1;
kvm_guest_enter();
@@ -2450,6 +2494,11 @@ again:
if (vcpu->exception.pending && kvm_x86_ops->exception_injected(vcpu))
vcpu->exception.pending = false;
+ if (irq_pending && kvm_x86_ops->interrupt_injected(vcpu)) {
+ irq.ack(vcpu, irq.info);
+ kvm_timer_intr_post(vcpu, irq.vector);
+ }
+
r = kvm_x86_ops->handle_exit(kvm_run, vcpu);
if (r > 0) {
@@ -2623,7 +2672,6 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
struct kvm_sregs *sregs)
{
struct descriptor_table dt;
- int pending_vec;
vcpu_load(vcpu);
@@ -2653,14 +2701,10 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
sregs->efer = vcpu->shadow_efer;
sregs->apic_base = kvm_get_apic_base(vcpu);
- if (irqchip_in_kernel(vcpu->kvm)) {
+ if (irqchip_in_kernel(vcpu->kvm))
memset(sregs->interrupt_bitmap, 0,
sizeof sregs->interrupt_bitmap);
- pending_vec = kvm_x86_ops->get_irq(vcpu);
- if (pending_vec >= 0)
- set_bit(pending_vec,
- (unsigned long *)sregs->interrupt_bitmap);
- } else
+ else
memcpy(sregs->interrupt_bitmap, vcpu->irq_pending,
sizeof sregs->interrupt_bitmap);
@@ -2679,7 +2723,7 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
struct kvm_sregs *sregs)
{
int mmu_reset_needed = 0;
- int i, pending_vec, max_bits;
+ int i;
struct descriptor_table dt;
vcpu_load(vcpu);
@@ -2724,17 +2768,6 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
for (i = 0; i < ARRAY_SIZE(vcpu->irq_pending); ++i)
if (vcpu->irq_pending[i])
__set_bit(i, &vcpu->irq_summary);
- } else {
- max_bits = (sizeof sregs->interrupt_bitmap) << 3;
- pending_vec = find_first_bit(
- (const unsigned long *)sregs->interrupt_bitmap,
- max_bits);
- /* Only pending external irq is handled here */
- if (pending_vec < max_bits) {
- kvm_x86_ops->set_irq(vcpu, pending_vec);
- pr_debug("Set back pending irq %d\n",
- pending_vec);
- }
}
set_segment(vcpu, &sregs->cs, VCPU_SREG_CS);
diff --git a/drivers/kvm/x86.h b/drivers/kvm/x86.h
index fb48b2f..52f3199 100644
--- a/drivers/kvm/x86.h
+++ b/drivers/kvm/x86.h
@@ -136,6 +136,8 @@ struct kvm_vcpu {
struct kvm_pio_request pio;
void *pio_data;
+ unsigned tpr_threshold;
+
struct kvm_queued_exception {
bool pending;
bool has_error_code;
@@ -217,15 +219,12 @@ struct kvm_x86_ops {
void (*skip_emulated_instruction)(struct kvm_vcpu *vcpu);
void (*patch_hypercall)(struct kvm_vcpu *vcpu,
unsigned char *hypercall_addr);
- int (*get_irq)(struct kvm_vcpu *vcpu);
- void (*set_irq)(struct kvm_vcpu *vcpu, int vec);
void (*queue_exception)(struct kvm_vcpu *vcpu, unsigned nr,
bool has_error_code, u32 error_code);
bool (*exception_injected)(struct kvm_vcpu *vcpu);
- void (*inject_pending_irq)(struct kvm_vcpu *vcpu);
- void (*inject_pending_vectors)(struct kvm_vcpu *vcpu,
- struct kvm_run *run);
-
+ bool (*queue_interrupt)(struct kvm_vcpu *vcpu, unsigned vector);
+ bool (*interrupt_injected)(struct kvm_vcpu *vcpu);
+ void (*set_tpr_threshold)(struct kvm_vcpu *vcpu);
int (*set_tss_addr)(struct kvm *kvm, unsigned int addr);
};
--
1.5.3
-------------------------------------------------------------------------
SF.Net email is sponsored by: The Future of Linux Business White Paper
from Novell. From the desktop to the data center, Linux is going
mainstream. Let it simplify your IT future.
http://altfarm.mediaplex.com/ad/ck/8857-50307-18918-4
_______________________________________________
kvm-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/kvm-devel