ia64/xen-unstable

changeset 16561:a74efcdc87b3

vmx realmode: Fix exception delivery w.r.t. in-flight I/O.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Dec 07 16:39:15 2007 +0000 (2007-12-07)
parents 822d4ec5cfb1
children 35890b260971
files xen/arch/x86/hvm/vmx/realmode.c
line diff
     1.1 --- a/xen/arch/x86/hvm/vmx/realmode.c	Fri Dec 07 14:44:13 2007 +0000
     1.2 +++ b/xen/arch/x86/hvm/vmx/realmode.c	Fri Dec 07 16:39:15 2007 +0000
     1.3 @@ -35,10 +35,12 @@ struct realmode_emulate_ctxt {
     1.4              unsigned int hlt:1;
     1.5              unsigned int mov_ss:1;
     1.6              unsigned int sti:1;
     1.7 -            unsigned int exn_raised:1;
     1.8          } flags;
     1.9          unsigned int flag_word;
    1.10      };
    1.11 +
    1.12 +    uint8_t exn_vector;
    1.13 +    uint8_t exn_insn_len;
    1.14  };
    1.15  
    1.16  static void realmode_deliver_exception(
    1.17 @@ -104,8 +106,7 @@ static void realmode_deliver_exception(
    1.18      csr->sel  = cs_eip >> 16;
    1.19      csr->base = (uint32_t)csr->sel << 4;
    1.20      regs->eip = (uint16_t)cs_eip;
    1.21 -    regs->eflags &= ~(X86_EFLAGS_AC | X86_EFLAGS_TF |
    1.22 -                      X86_EFLAGS_AC | X86_EFLAGS_RF);
    1.23 +    regs->eflags &= ~(X86_EFLAGS_TF | X86_EFLAGS_IF | X86_EFLAGS_RF);
    1.24  }
    1.25  
    1.26  static int
    1.27 @@ -145,7 +146,7 @@ realmode_read(
    1.28          }
    1.29  
    1.30          if ( !curr->arch.hvm_vmx.real_mode_io_completed )
    1.31 -            return X86EMUL_UNHANDLEABLE;
    1.32 +            return X86EMUL_RETRY;
    1.33  
    1.34          *val = curr->arch.hvm_vmx.real_mode_io_data;
    1.35          curr->arch.hvm_vmx.real_mode_io_completed = 0;
    1.36 @@ -286,7 +287,7 @@ realmode_read_io(
    1.37      }
    1.38  
    1.39      if ( !curr->arch.hvm_vmx.real_mode_io_completed )
    1.40 -        return X86EMUL_UNHANDLEABLE;
    1.41 +        return X86EMUL_RETRY;
    1.42      
    1.43      *val = curr->arch.hvm_vmx.real_mode_io_data;
    1.44      curr->arch.hvm_vmx.real_mode_io_completed = 0;
    1.45 @@ -413,8 +414,8 @@ static int realmode_inject_hw_exception(
    1.46      struct realmode_emulate_ctxt *rm_ctxt =
    1.47          container_of(ctxt, struct realmode_emulate_ctxt, ctxt);
    1.48  
    1.49 -    rm_ctxt->flags.exn_raised = 1;
    1.50 -    realmode_deliver_exception(vector, 0, rm_ctxt);
    1.51 +    rm_ctxt->exn_vector = vector;
    1.52 +    rm_ctxt->exn_insn_len = 0;
    1.53  
    1.54      return X86EMUL_OKAY;
    1.55  }
    1.56 @@ -427,7 +428,8 @@ static int realmode_inject_sw_interrupt(
    1.57      struct realmode_emulate_ctxt *rm_ctxt =
    1.58          container_of(ctxt, struct realmode_emulate_ctxt, ctxt);
    1.59  
    1.60 -    realmode_deliver_exception(vector, insn_len, rm_ctxt);
    1.61 +    rm_ctxt->exn_vector = vector;
    1.62 +    rm_ctxt->exn_insn_len = insn_len;
    1.63  
    1.64      return X86EMUL_OKAY;
    1.65  }
    1.66 @@ -470,19 +472,22 @@ void vmx_realmode(struct cpu_user_regs *
    1.67          rm_ctxt.seg_reg[x86_seg_ss].attr.fields.db ? 32 : 16;
    1.68  
    1.69      intr_info = __vmread(VM_ENTRY_INTR_INFO);
    1.70 -    if ( intr_info & INTR_INFO_VALID_MASK )
    1.71 -    {
    1.72 -        __vmwrite(VM_ENTRY_INTR_INFO, 0);
    1.73 -        realmode_deliver_exception((uint8_t)intr_info, 0, &rm_ctxt);
    1.74 -    }
    1.75 -
    1.76      intr_shadow = __vmread(GUEST_INTERRUPTIBILITY_INFO);
    1.77      new_intr_shadow = intr_shadow;
    1.78  
    1.79      while ( !(curr->arch.hvm_vcpu.guest_cr[0] & X86_CR0_PE) &&
    1.80              !softirq_pending(smp_processor_id()) &&
    1.81 -            !hvm_local_events_need_delivery(curr) )
    1.82 +            !hvm_local_events_need_delivery(curr) &&
    1.83 +            !curr->arch.hvm_vmx.real_mode_io_in_progress )
    1.84      {
    1.85 +        if ( (intr_info & INTR_INFO_VALID_MASK) &&
    1.86 +             !curr->arch.hvm_vmx.real_mode_io_completed )
    1.87 +        {
    1.88 +            realmode_deliver_exception((uint8_t)intr_info, 0, &rm_ctxt);
    1.89 +            __vmwrite(VM_ENTRY_INTR_INFO, 0);
    1.90 +            intr_info = 0;
    1.91 +        }
    1.92 +
    1.93          rm_ctxt.insn_buf_eip = regs->eip;
    1.94          (void)hvm_copy_from_guest_phys(
    1.95              rm_ctxt.insn_buf,
    1.96 @@ -493,6 +498,21 @@ void vmx_realmode(struct cpu_user_regs *
    1.97  
    1.98          rc = x86_emulate(&rm_ctxt.ctxt, &realmode_emulator_ops);
    1.99  
   1.100 +        if ( rc == X86EMUL_RETRY )
   1.101 +            continue;
   1.102 +
   1.103 +        if ( rc == X86EMUL_UNHANDLEABLE )
   1.104 +        {
   1.105 +            gdprintk(XENLOG_ERR,
   1.106 +                     "Real-mode emulation failed @ %04x:%08lx: "
   1.107 +                     "%02x %02x %02x %02x %02x %02x\n",
   1.108 +                     rm_ctxt.seg_reg[x86_seg_cs].sel, rm_ctxt.insn_buf_eip,
   1.109 +                     rm_ctxt.insn_buf[0], rm_ctxt.insn_buf[1],
   1.110 +                     rm_ctxt.insn_buf[2], rm_ctxt.insn_buf[3],
   1.111 +                     rm_ctxt.insn_buf[4], rm_ctxt.insn_buf[5]);
   1.112 +            domain_crash_synchronous();
   1.113 +        }
   1.114 +
   1.115          /* MOV-SS instruction toggles MOV-SS shadow, else we just clear it. */
   1.116          if ( rm_ctxt.flags.mov_ss )
   1.117              new_intr_shadow ^= VMX_INTR_SHADOW_MOV_SS;
   1.118 @@ -512,25 +532,14 @@ void vmx_realmode(struct cpu_user_regs *
   1.119              __vmwrite(GUEST_INTERRUPTIBILITY_INFO, intr_shadow);
   1.120          }
   1.121  
   1.122 -        /* HLT happens after instruction retire, if no interrupt/exception. */
   1.123 -        if ( unlikely(rm_ctxt.flags.hlt) &&
   1.124 -             !rm_ctxt.flags.exn_raised &&
   1.125 -             !hvm_local_events_need_delivery(curr) )
   1.126 +        if ( rc == X86EMUL_EXCEPTION )
   1.127 +        {
   1.128 +            realmode_deliver_exception(
   1.129 +                rm_ctxt.exn_vector, rm_ctxt.exn_insn_len, &rm_ctxt);
   1.130 +        }
   1.131 +        else if ( rm_ctxt.flags.hlt && !hvm_local_events_need_delivery(curr) )
   1.132 +        {
   1.133              hvm_hlt(regs->eflags);
   1.134 -
   1.135 -        if ( curr->arch.hvm_vmx.real_mode_io_in_progress )
   1.136 -            break;
   1.137 -
   1.138 -        if ( rc == X86EMUL_UNHANDLEABLE )
   1.139 -        {
   1.140 -            gdprintk(XENLOG_ERR,
   1.141 -                     "Real-mode emulation failed @ %04x:%08lx: "
   1.142 -                     "%02x %02x %02x %02x %02x %02x\n",
   1.143 -                     rm_ctxt.seg_reg[x86_seg_cs].sel, rm_ctxt.insn_buf_eip,
   1.144 -                     rm_ctxt.insn_buf[0], rm_ctxt.insn_buf[1],
   1.145 -                     rm_ctxt.insn_buf[2], rm_ctxt.insn_buf[3],
   1.146 -                     rm_ctxt.insn_buf[4], rm_ctxt.insn_buf[5]);
   1.147 -            domain_crash_synchronous();
   1.148          }
   1.149      }
   1.150