ia64/xen-unstable

changeset 9804:29e9a0313c09

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@intel.com>
Signed-off-by: Eddie Dong <eddie.dong@intel.com>
author kaf24@firebug.cl.cam.ac.uk
date Fri Apr 21 10:11:00 2006 +0100 (2006-04-21)
parents 9c313ff7a0ed
children 42358db788fd
files xen/arch/x86/hvm/vmx/io.c xen/arch/x86/hvm/vmx/vmx.c
line diff
     1.1 --- a/xen/arch/x86/hvm/vmx/io.c	Fri Apr 21 09:56:50 2006 +0100
     1.2 +++ b/xen/arch/x86/hvm/vmx/io.c	Fri Apr 21 10:11:00 2006 +0100
     1.3 @@ -153,6 +153,9 @@ asmlinkage void vmx_intr_assist(void)
     1.4      struct hvm_domain *plat=&v->domain->arch.hvm_domain;
     1.5      struct hvm_time_info *time_info = &plat->vpit.time_info;
     1.6      struct hvm_virpic *pic= &plat->vpic;
     1.7 +    unsigned int idtv_info_field;
     1.8 +    unsigned long inst_len;
     1.9 +    int    has_ext_irq;
    1.10  
    1.11      if ( v->vcpu_id == 0 )
    1.12          hvm_pic_assist(v);
    1.13 @@ -162,8 +165,29 @@ asmlinkage void vmx_intr_assist(void)
    1.14          pic_set_irq(pic, 0, 1);
    1.15      }
    1.16  
    1.17 -    if ( !cpu_has_pending_irq(v) ) return;
    1.18 +    has_ext_irq = cpu_has_pending_irq(v);
    1.19 +    __vmread(IDT_VECTORING_INFO_FIELD, &idtv_info_field);
    1.20 +    if (idtv_info_field & INTR_INFO_VALID_MASK) {
    1.21 +        __vmwrite(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field);
    1.22  
    1.23 +        __vmread(VM_EXIT_INSTRUCTION_LEN, &inst_len);
    1.24 +        if (inst_len >= 1 && inst_len <= 15)
    1.25 +            __vmwrite(VM_ENTRY_INSTRUCTION_LEN, inst_len);
    1.26 +
    1.27 +        if (idtv_info_field & 0x800) { /* valid error code */
    1.28 +            unsigned long error_code;
    1.29 +            __vmread(IDT_VECTORING_ERROR_CODE, &error_code);
    1.30 +            __vmwrite(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code);
    1.31 +        }
    1.32 +        if ( has_ext_irq )
    1.33 +            enable_irq_window(v);
    1.34 +
    1.35 +        HVM_DBG_LOG(DBG_LEVEL_1, "idtv_info_field=%x", idtv_info_field);
    1.36 +
    1.37 +        return;
    1.38 +    }
    1.39 +
    1.40 +    if ( !has_ext_irq ) return;
    1.41      if ( is_interruptibility_state() ) {    /* pre-cleared for emulated instruction */
    1.42          enable_irq_window(v);
    1.43          HVM_DBG_LOG(DBG_LEVEL_1, "interruptibility");
     2.1 --- a/xen/arch/x86/hvm/vmx/vmx.c	Fri Apr 21 09:56:50 2006 +0100
     2.2 +++ b/xen/arch/x86/hvm/vmx/vmx.c	Fri Apr 21 10:11:00 2006 +0100
     2.3 @@ -2046,7 +2046,7 @@ void restore_cpu_user_regs(struct cpu_us
     2.4  
     2.5  asmlinkage void vmx_vmexit_handler(struct cpu_user_regs regs)
     2.6  {
     2.7 -    unsigned int exit_reason, idtv_info_field;
     2.8 +    unsigned int exit_reason;
     2.9      unsigned long exit_qualification, eip, inst_len = 0;
    2.10      struct vcpu *v = current;
    2.11      int error;
    2.12 @@ -2056,23 +2056,6 @@ asmlinkage void vmx_vmexit_handler(struc
    2.13  
    2.14      perfc_incra(vmexits, exit_reason);
    2.15  
    2.16 -    __vmread(IDT_VECTORING_INFO_FIELD, &idtv_info_field);
    2.17 -    if (idtv_info_field & INTR_INFO_VALID_MASK) {
    2.18 -        __vmwrite(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field);
    2.19 -
    2.20 -        __vmread(VM_EXIT_INSTRUCTION_LEN, &inst_len);
    2.21 -        if (inst_len >= 1 && inst_len <= 15)
    2.22 -            __vmwrite(VM_ENTRY_INSTRUCTION_LEN, inst_len);
    2.23 -
    2.24 -        if (idtv_info_field & 0x800) { /* valid error code */
    2.25 -            unsigned long error_code;
    2.26 -            __vmread(IDT_VECTORING_ERROR_CODE, &error_code);
    2.27 -            __vmwrite(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code);
    2.28 -        }
    2.29 -
    2.30 -        HVM_DBG_LOG(DBG_LEVEL_1, "idtv_info_field=%x", idtv_info_field);
    2.31 -    }
    2.32 -
    2.33      /* don't bother H/W interrutps */
    2.34      if (exit_reason != EXIT_REASON_EXTERNAL_INTERRUPT &&
    2.35          exit_reason != EXIT_REASON_VMCALL &&