# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1199966099 0
# Node ID f4a17a5dc9b03a05a525ffc2b75e80e764cf8924
# Parent 48c800d5a3718a4a8115c02fc0b76d16f85d35f8
x86 hvm: Tolerate failure to complete INTACK cycle on an
interrupt. Failure can occur because we do not hold locks between
detecting a pending interrupt and acknowledging it. Satte can change
between these two points.
Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx>
---
xen/arch/x86/hvm/svm/intr.c | 62 +++++++++++++-------------
xen/arch/x86/hvm/vmx/intr.c | 103 ++++++++++++++++++++++----------------------
2 files changed, 85 insertions(+), 80 deletions(-)
diff -r 48c800d5a371 -r f4a17a5dc9b0 xen/arch/x86/hvm/svm/intr.c
--- a/xen/arch/x86/hvm/svm/intr.c Thu Jan 10 11:49:19 2008 +0000
+++ b/xen/arch/x86/hvm/svm/intr.c Thu Jan 10 11:54:59 2008 +0000
@@ -126,38 +126,40 @@ asmlinkage void svm_intr_assist(void)
/* Crank the handle on interrupt state and check for new interrrupts. */
pt_update_irq(v);
hvm_maybe_deassert_evtchn_irq();
- if ( !cpu_has_pending_irq(v) )
- goto out;
- /*
- * If the guest can't take an interrupt right now, create a 'fake'
- * virtual interrupt on to intercept as soon as the guest _can_ take
- * interrupts. Do not obtain the next interrupt from the vlapic/pic
- * if unable to inject.
- *
- * Also do this if there is an exception pending. This is because
- * the delivery of the exception can arbitrarily delay the injection
- * of the vintr (for example, if the exception is handled via an
- * interrupt gate, hence zeroing RFLAGS.IF). In the meantime:
- * - the vTPR could be modified upwards, so we need to wait until the
- * exception is delivered before we can safely decide that an
- * interrupt is deliverable; and
- * - the guest might look at the APIC/PIC state, so we ought not to have
- * cleared the interrupt out of the IRR.
- */
- if ( irq_masked(vmcb->rflags) || vmcb->interrupt_shadow
- || vmcb->eventinj.fields.v )
- {
- vmcb->general1_intercepts |= GENERAL1_INTERCEPT_VINTR;
- HVMTRACE_2D(INJ_VIRQ, v, 0x0, /*fake=*/ 1);
- svm_inject_extint(v, 0x0); /* actual vector doesn't matter */
- intr_window_enabled = 1;
- goto out;
- }
+ do {
+ if ( !cpu_has_pending_irq(v) )
+ goto out;
- /* Okay, we can deliver the interrupt: grab it and update PIC state. */
- intr_vector = cpu_get_interrupt(v, &intr_type);
- BUG_ON(intr_vector < 0);
+ /*
+ * If the guest can't take an interrupt right now, create a 'fake'
+ * virtual interrupt on to intercept as soon as the guest _can_ take
+ * interrupts. Do not obtain the next interrupt from the vlapic/pic
+ * if unable to inject.
+ *
+ * Also do this if there is an exception pending. This is because
+ * the delivery of the exception can arbitrarily delay the injection
+ * of the vintr (for example, if the exception is handled via an
+ * interrupt gate, hence zeroing RFLAGS.IF). In the meantime:
+ * - the vTPR could be modified upwards, so we need to wait until the
+ * exception is delivered before we can safely decide that an
+ * interrupt is deliverable; and
+ * - the guest might look at the APIC/PIC state, so we ought not to
+ * have cleared the interrupt out of the IRR.
+ */
+ if ( irq_masked(vmcb->rflags) || vmcb->interrupt_shadow
+ || vmcb->eventinj.fields.v )
+ {
+ vmcb->general1_intercepts |= GENERAL1_INTERCEPT_VINTR;
+ HVMTRACE_2D(INJ_VIRQ, v, 0x0, /*fake=*/ 1);
+ svm_inject_extint(v, 0x0); /* actual vector doesn't matter */
+ intr_window_enabled = 1;
+ goto out;
+ }
+
+ /* Okay, we can deliver the interrupt: grab it and update PIC state. */
+ intr_vector = cpu_get_interrupt(v, &intr_type);
+ } while ( intr_vector < 0 );
HVMTRACE_2D(INJ_VIRQ, v, intr_vector, /*fake=*/ 0);
svm_inject_extint(v, intr_vector);
diff -r 48c800d5a371 -r f4a17a5dc9b0 xen/arch/x86/hvm/vmx/intr.c
--- a/xen/arch/x86/hvm/vmx/intr.c Thu Jan 10 11:49:19 2008 +0000
+++ b/xen/arch/x86/hvm/vmx/intr.c Thu Jan 10 11:54:59 2008 +0000
@@ -114,60 +114,63 @@ asmlinkage void vmx_intr_assist(void)
update_tpr_threshold(vcpu_vlapic(v));
- has_ext_irq = cpu_has_pending_irq(v);
+ do {
+ has_ext_irq = cpu_has_pending_irq(v);
- if ( unlikely(v->arch.hvm_vmx.vector_injected) )
- {
- v->arch.hvm_vmx.vector_injected = 0;
- if ( unlikely(has_ext_irq) )
+ if ( unlikely(v->arch.hvm_vmx.vector_injected) )
+ {
+ v->arch.hvm_vmx.vector_injected = 0;
+ if ( unlikely(has_ext_irq) )
+ enable_irq_window(v);
+ return;
+ }
+
+ /* This could be moved earlier in the VMX resume sequence. */
+ idtv_info_field = __vmread(IDT_VECTORING_INFO_FIELD);
+ if ( unlikely(idtv_info_field & INTR_INFO_VALID_MASK) )
+ {
+ __vmwrite(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field);
+
+ /*
+ * Safe: the length will only be interpreted for software
+ * exceptions and interrupts. If we get here then delivery of some
+ * event caused a fault, and this always results in defined
+ * VM_EXIT_INSTRUCTION_LEN.
+ */
+ inst_len = __vmread(VM_EXIT_INSTRUCTION_LEN); /* Safe */
+ __vmwrite(VM_ENTRY_INSTRUCTION_LEN, inst_len);
+
+ if ( unlikely(idtv_info_field & 0x800) ) /* valid error code */
+ __vmwrite(VM_ENTRY_EXCEPTION_ERROR_CODE,
+ __vmread(IDT_VECTORING_ERROR_CODE));
+ if ( unlikely(has_ext_irq) )
+ enable_irq_window(v);
+
+ HVM_DBG_LOG(DBG_LEVEL_1, "idtv_info_field=%x", idtv_info_field);
+ return;
+ }
+
+ if ( likely(!has_ext_irq) )
+ return;
+
+ intr_shadow = __vmread(GUEST_INTERRUPTIBILITY_INFO);
+ if ( unlikely(intr_shadow & (VMX_INTR_SHADOW_STI|
+ VMX_INTR_SHADOW_MOV_SS)) )
+ {
enable_irq_window(v);
- return;
- }
+ HVM_DBG_LOG(DBG_LEVEL_1, "interruptibility");
+ return;
+ }
- /* This could be moved earlier in the VMX resume sequence. */
- idtv_info_field = __vmread(IDT_VECTORING_INFO_FIELD);
- if ( unlikely(idtv_info_field & INTR_INFO_VALID_MASK) )
- {
- __vmwrite(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field);
+ eflags = __vmread(GUEST_RFLAGS);
+ if ( irq_masked(eflags) )
+ {
+ enable_irq_window(v);
+ return;
+ }
- /*
- * Safe: the length will only be interpreted for software exceptions
- * and interrupts. If we get here then delivery of some event caused a
- * fault, and this always results in defined VM_EXIT_INSTRUCTION_LEN.
- */
- inst_len = __vmread(VM_EXIT_INSTRUCTION_LEN); /* Safe */
- __vmwrite(VM_ENTRY_INSTRUCTION_LEN, inst_len);
-
- if ( unlikely(idtv_info_field & 0x800) ) /* valid error code */
- __vmwrite(VM_ENTRY_EXCEPTION_ERROR_CODE,
- __vmread(IDT_VECTORING_ERROR_CODE));
- if ( unlikely(has_ext_irq) )
- enable_irq_window(v);
-
- HVM_DBG_LOG(DBG_LEVEL_1, "idtv_info_field=%x", idtv_info_field);
- return;
- }
-
- if ( likely(!has_ext_irq) )
- return;
-
- intr_shadow = __vmread(GUEST_INTERRUPTIBILITY_INFO);
- if ( unlikely(intr_shadow & (VMX_INTR_SHADOW_STI|VMX_INTR_SHADOW_MOV_SS)) )
- {
- enable_irq_window(v);
- HVM_DBG_LOG(DBG_LEVEL_1, "interruptibility");
- return;
- }
-
- eflags = __vmread(GUEST_RFLAGS);
- if ( irq_masked(eflags) )
- {
- enable_irq_window(v);
- return;
- }
-
- intr_vector = cpu_get_interrupt(v, &intr_type);
- BUG_ON(intr_vector < 0);
+ intr_vector = cpu_get_interrupt(v, &intr_type);
+ } while ( intr_vector < 0 );
HVMTRACE_2D(INJ_VIRQ, v, intr_vector, /*fake=*/ 0);
vmx_inject_extint(v, intr_vector, VMX_DELIVER_NO_ERROR_CODE);
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|