# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxx
# Node ID 29e9a0313c090e64cce0c97bd13f142f603e8817
# Parent 9c313ff7a0ed53b25ce3ae75686bdb26dd20227c
Fix the "hda lost interrupt" issue when creating a VMX guest on a PAE
host.
Occasionally when injecting an IDE DMA interrupt into the guest, a
page fault occurs (e.g., because the IDT mapping is not present in
shadow pagetables). This causes an immediate vmexit and, because it
occurred during event delivery, the original VM_ENTRY_INTR_INFO_FIELD
is kept in IDT_VECTORING_INFO_FIELD.
The current code copies IDT_VECTORING_INFO_FIELD back to
VM_ENTRY_INTR_INFO_FIELD, intending that the interrupt will be
injected again on next vmresume.
However, there is a corner case: if, before the next vmresume, a timer
interrupt happened then vmx_intr_assist may overwrite the information
on VM_ENTRY_INTR_INFO_FIELD, and the IDE DMA interrupt is effectively
lost.
This patch checks the IDT_VECTORING_INFO_FIELD in vmx_intr_assist and,
if it is set, copies it to VM_ENTRY_INTR_INFO_FIELD and returns.
Signed-off-by: Yunhong Jiang <Yunhong.jiang@xxxxxxxxx>
Signed-off-by: Eddie Dong <eddie.dong@xxxxxxxxx>
diff -r 9c313ff7a0ed -r 29e9a0313c09 xen/arch/x86/hvm/vmx/io.c
--- a/xen/arch/x86/hvm/vmx/io.c Fri Apr 21 09:56:50 2006 +0100
+++ b/xen/arch/x86/hvm/vmx/io.c Fri Apr 21 10:11:00 2006 +0100
@@ -153,6 +153,9 @@ asmlinkage void vmx_intr_assist(void)
struct hvm_domain *plat=&v->domain->arch.hvm_domain;
struct hvm_time_info *time_info = &plat->vpit.time_info;
struct hvm_virpic *pic= &plat->vpic;
+ unsigned int idtv_info_field;
+ unsigned long inst_len;
+ int has_ext_irq;
if ( v->vcpu_id == 0 )
hvm_pic_assist(v);
@@ -162,8 +165,29 @@ asmlinkage void vmx_intr_assist(void)
pic_set_irq(pic, 0, 1);
}
- if ( !cpu_has_pending_irq(v) ) return;
-
+ has_ext_irq = cpu_has_pending_irq(v);
+ __vmread(IDT_VECTORING_INFO_FIELD, &idtv_info_field);
+ if (idtv_info_field & INTR_INFO_VALID_MASK) {
+ __vmwrite(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field);
+
+ __vmread(VM_EXIT_INSTRUCTION_LEN, &inst_len);
+ if (inst_len >= 1 && inst_len <= 15)
+ __vmwrite(VM_ENTRY_INSTRUCTION_LEN, inst_len);
+
+ if (idtv_info_field & 0x800) { /* valid error code */
+ unsigned long error_code;
+ __vmread(IDT_VECTORING_ERROR_CODE, &error_code);
+ __vmwrite(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code);
+ }
+ if ( has_ext_irq )
+ enable_irq_window(v);
+
+ HVM_DBG_LOG(DBG_LEVEL_1, "idtv_info_field=%x", idtv_info_field);
+
+ return;
+ }
+
+ if ( !has_ext_irq ) return;
if ( is_interruptibility_state() ) { /* pre-cleared for emulated
instruction */
enable_irq_window(v);
HVM_DBG_LOG(DBG_LEVEL_1, "interruptibility");
diff -r 9c313ff7a0ed -r 29e9a0313c09 xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c Fri Apr 21 09:56:50 2006 +0100
+++ b/xen/arch/x86/hvm/vmx/vmx.c Fri Apr 21 10:11:00 2006 +0100
@@ -2046,7 +2046,7 @@ void restore_cpu_user_regs(struct cpu_us
asmlinkage void vmx_vmexit_handler(struct cpu_user_regs regs)
{
- unsigned int exit_reason, idtv_info_field;
+ unsigned int exit_reason;
unsigned long exit_qualification, eip, inst_len = 0;
struct vcpu *v = current;
int error;
@@ -2055,23 +2055,6 @@ asmlinkage void vmx_vmexit_handler(struc
__hvm_bug(®s);
perfc_incra(vmexits, exit_reason);
-
- __vmread(IDT_VECTORING_INFO_FIELD, &idtv_info_field);
- if (idtv_info_field & INTR_INFO_VALID_MASK) {
- __vmwrite(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field);
-
- __vmread(VM_EXIT_INSTRUCTION_LEN, &inst_len);
- if (inst_len >= 1 && inst_len <= 15)
- __vmwrite(VM_ENTRY_INSTRUCTION_LEN, inst_len);
-
- if (idtv_info_field & 0x800) { /* valid error code */
- unsigned long error_code;
- __vmread(IDT_VECTORING_ERROR_CODE, &error_code);
- __vmwrite(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code);
- }
-
- HVM_DBG_LOG(DBG_LEVEL_1, "idtv_info_field=%x", idtv_info_field);
- }
/* don't bother H/W interrutps */
if (exit_reason != EXIT_REASON_EXTERNAL_INTERRUPT &&
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|