ia64/xen-unstable

changeset 16869:db620f1c9d30

vmx realmode: Restructure code for clarity and better treatment of
VM_ENTRY_INTR_INFO. Also add more sanity checking.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Jan 24 14:29:13 2008 +0000 (2008-01-24)
parents 05e36e506c09
children edc268331a9e
files xen/arch/x86/hvm/vmx/realmode.c
line diff
     1.1 --- a/xen/arch/x86/hvm/vmx/realmode.c	Wed Jan 23 18:12:37 2008 +0000
     1.2 +++ b/xen/arch/x86/hvm/vmx/realmode.c	Thu Jan 24 14:29:13 2008 +0000
     1.3 @@ -41,6 +41,8 @@ struct realmode_emulate_ctxt {
     1.4  
     1.5      uint8_t exn_vector;
     1.6      uint8_t exn_insn_len;
     1.7 +
     1.8 +    uint32_t intr_shadow;
     1.9  };
    1.10  
    1.11  static void realmode_deliver_exception(
    1.12 @@ -502,13 +504,108 @@ static struct x86_emulate_ops realmode_e
    1.13      .load_fpu_ctxt = realmode_load_fpu_ctxt
    1.14  };
    1.15  
    1.16 +static void realmode_emulate_one(struct realmode_emulate_ctxt *rm_ctxt)
    1.17 +{
    1.18 +    struct cpu_user_regs *regs = rm_ctxt->ctxt.regs;
    1.19 +    struct vcpu *curr = current;
    1.20 +    u32 new_intr_shadow;
    1.21 +    int rc, io_completed;
    1.22 +
    1.23 +    rm_ctxt->insn_buf_eip = regs->eip;
    1.24 +    (void)hvm_copy_from_guest_phys(
    1.25 +        rm_ctxt->insn_buf,
    1.26 +        (uint32_t)(rm_ctxt->seg_reg[x86_seg_cs].base + regs->eip),
    1.27 +        sizeof(rm_ctxt->insn_buf));
    1.28 +
    1.29 +    rm_ctxt->flag_word = 0;
    1.30 +
    1.31 +    io_completed = curr->arch.hvm_vmx.real_mode_io_completed;
    1.32 +    if ( curr->arch.hvm_vmx.real_mode_io_in_progress )
    1.33 +    {
    1.34 +        gdprintk(XENLOG_ERR, "I/O in progress before insn is emulated.\n");
    1.35 +        goto fail;
    1.36 +    }
    1.37 +
    1.38 +    rc = x86_emulate(&rm_ctxt->ctxt, &realmode_emulator_ops);
    1.39 +
    1.40 +    if ( curr->arch.hvm_vmx.real_mode_io_completed )
    1.41 +    {
    1.42 +        gdprintk(XENLOG_ERR, "I/O completion after insn is emulated.\n");
    1.43 +        goto fail;
    1.44 +    }
    1.45 +
    1.46 +    if ( io_completed && curr->arch.hvm_vmx.real_mode_io_in_progress )
    1.47 +    {
    1.48 +        gdprintk(XENLOG_ERR, "Multiple I/O transactions in a single insn.\n");
    1.49 +        goto fail;
    1.50 +    }
    1.51 +
    1.52 +    if ( rc == X86EMUL_UNHANDLEABLE )
    1.53 +    {
    1.54 +        gdprintk(XENLOG_ERR, "Failed to emulate insn.\n");
    1.55 +        goto fail;
    1.56 +    }
    1.57 +
    1.58 +    if ( rc == X86EMUL_RETRY )
    1.59 +        return;
    1.60 +
    1.61 +    if ( curr->arch.hvm_vmx.real_mode_io_in_progress &&
    1.62 +         (get_ioreq(curr)->vp_ioreq.dir == IOREQ_READ) )
    1.63 +    {
    1.64 +        gdprintk(XENLOG_ERR, "I/O read in progress but insn is retired.\n");
    1.65 +        goto fail;
    1.66 +    }
    1.67 +
    1.68 +    new_intr_shadow = rm_ctxt->intr_shadow;
    1.69 +
    1.70 +    /* MOV-SS instruction toggles MOV-SS shadow, else we just clear it. */
    1.71 +    if ( rm_ctxt->flags.mov_ss )
    1.72 +        new_intr_shadow ^= VMX_INTR_SHADOW_MOV_SS;
    1.73 +    else
    1.74 +        new_intr_shadow &= ~VMX_INTR_SHADOW_MOV_SS;
    1.75 +
    1.76 +    /* STI instruction toggles STI shadow, else we just clear it. */
    1.77 +    if ( rm_ctxt->flags.sti )
    1.78 +        new_intr_shadow ^= VMX_INTR_SHADOW_STI;
    1.79 +    else
    1.80 +        new_intr_shadow &= ~VMX_INTR_SHADOW_STI;
    1.81 +
    1.82 +    /* Update interrupt shadow information in VMCS only if it changes. */
    1.83 +    if ( rm_ctxt->intr_shadow != new_intr_shadow )
    1.84 +    {
    1.85 +        rm_ctxt->intr_shadow = new_intr_shadow;
    1.86 +        __vmwrite(GUEST_INTERRUPTIBILITY_INFO, rm_ctxt->intr_shadow);
    1.87 +    }
    1.88 +
    1.89 +    if ( rc == X86EMUL_EXCEPTION )
    1.90 +    {
    1.91 +        realmode_deliver_exception(
    1.92 +            rm_ctxt->exn_vector, rm_ctxt->exn_insn_len, rm_ctxt);
    1.93 +    }
    1.94 +    else if ( rm_ctxt->flags.hlt && !hvm_local_events_need_delivery(curr) )
    1.95 +    {
    1.96 +        hvm_hlt(regs->eflags);
    1.97 +    }
    1.98 +
    1.99 +    return;
   1.100 +
   1.101 + fail:
   1.102 +    gdprintk(XENLOG_ERR,
   1.103 +             "Real-mode emulation failed @ %04x:%08lx: "
   1.104 +             "%02x %02x %02x %02x %02x %02x\n",
   1.105 +             rm_ctxt->seg_reg[x86_seg_cs].sel, rm_ctxt->insn_buf_eip,
   1.106 +             rm_ctxt->insn_buf[0], rm_ctxt->insn_buf[1],
   1.107 +             rm_ctxt->insn_buf[2], rm_ctxt->insn_buf[3],
   1.108 +             rm_ctxt->insn_buf[4], rm_ctxt->insn_buf[5]);
   1.109 +    domain_crash_synchronous();
   1.110 +}
   1.111 +
   1.112  void vmx_realmode(struct cpu_user_regs *regs)
   1.113  {
   1.114      struct vcpu *curr = current;
   1.115      struct realmode_emulate_ctxt rm_ctxt;
   1.116      unsigned long intr_info;
   1.117 -    int i, rc;
   1.118 -    u32 intr_shadow, new_intr_shadow;
   1.119 +    int i;
   1.120  
   1.121      rm_ctxt.ctxt.regs = regs;
   1.122  
   1.123 @@ -520,77 +617,24 @@ void vmx_realmode(struct cpu_user_regs *
   1.124      rm_ctxt.ctxt.sp_size =
   1.125          rm_ctxt.seg_reg[x86_seg_ss].attr.fields.db ? 32 : 16;
   1.126  
   1.127 +    rm_ctxt.intr_shadow = __vmread(GUEST_INTERRUPTIBILITY_INFO);
   1.128 +
   1.129 +    if ( curr->arch.hvm_vmx.real_mode_io_in_progress ||
   1.130 +         curr->arch.hvm_vmx.real_mode_io_completed )
   1.131 +        realmode_emulate_one(&rm_ctxt);
   1.132 +
   1.133      intr_info = __vmread(VM_ENTRY_INTR_INFO);
   1.134 -    intr_shadow = __vmread(GUEST_INTERRUPTIBILITY_INFO);
   1.135 -    new_intr_shadow = intr_shadow;
   1.136 +    if ( intr_info & INTR_INFO_VALID_MASK )
   1.137 +    {
   1.138 +        realmode_deliver_exception((uint8_t)intr_info, 0, &rm_ctxt);
   1.139 +        __vmwrite(VM_ENTRY_INTR_INFO, 0);
   1.140 +    }
   1.141  
   1.142      while ( !(curr->arch.hvm_vcpu.guest_cr[0] & X86_CR0_PE) &&
   1.143              !softirq_pending(smp_processor_id()) &&
   1.144              !hvm_local_events_need_delivery(curr) &&
   1.145              !curr->arch.hvm_vmx.real_mode_io_in_progress )
   1.146 -    {
   1.147 -        if ( (intr_info & INTR_INFO_VALID_MASK) &&
   1.148 -             !curr->arch.hvm_vmx.real_mode_io_completed )
   1.149 -        {
   1.150 -            realmode_deliver_exception((uint8_t)intr_info, 0, &rm_ctxt);
   1.151 -            __vmwrite(VM_ENTRY_INTR_INFO, 0);
   1.152 -            intr_info = 0;
   1.153 -        }
   1.154 -
   1.155 -        rm_ctxt.insn_buf_eip = regs->eip;
   1.156 -        (void)hvm_copy_from_guest_phys(
   1.157 -            rm_ctxt.insn_buf,
   1.158 -            (uint32_t)(rm_ctxt.seg_reg[x86_seg_cs].base + regs->eip),
   1.159 -            sizeof(rm_ctxt.insn_buf));
   1.160 -
   1.161 -        rm_ctxt.flag_word = 0;
   1.162 -
   1.163 -        rc = x86_emulate(&rm_ctxt.ctxt, &realmode_emulator_ops);
   1.164 -
   1.165 -        if ( rc == X86EMUL_RETRY )
   1.166 -            continue;
   1.167 -
   1.168 -        if ( rc == X86EMUL_UNHANDLEABLE )
   1.169 -        {
   1.170 -            gdprintk(XENLOG_ERR,
   1.171 -                     "Real-mode emulation failed @ %04x:%08lx: "
   1.172 -                     "%02x %02x %02x %02x %02x %02x\n",
   1.173 -                     rm_ctxt.seg_reg[x86_seg_cs].sel, rm_ctxt.insn_buf_eip,
   1.174 -                     rm_ctxt.insn_buf[0], rm_ctxt.insn_buf[1],
   1.175 -                     rm_ctxt.insn_buf[2], rm_ctxt.insn_buf[3],
   1.176 -                     rm_ctxt.insn_buf[4], rm_ctxt.insn_buf[5]);
   1.177 -            domain_crash_synchronous();
   1.178 -        }
   1.179 -
   1.180 -        /* MOV-SS instruction toggles MOV-SS shadow, else we just clear it. */
   1.181 -        if ( rm_ctxt.flags.mov_ss )
   1.182 -            new_intr_shadow ^= VMX_INTR_SHADOW_MOV_SS;
   1.183 -        else
   1.184 -            new_intr_shadow &= ~VMX_INTR_SHADOW_MOV_SS;
   1.185 -
   1.186 -        /* STI instruction toggles STI shadow, else we just clear it. */
   1.187 -        if ( rm_ctxt.flags.sti )
   1.188 -            new_intr_shadow ^= VMX_INTR_SHADOW_STI;
   1.189 -        else
   1.190 -            new_intr_shadow &= ~VMX_INTR_SHADOW_STI;
   1.191 -
   1.192 -        /* Update interrupt shadow information in VMCS only if it changes. */
   1.193 -        if ( intr_shadow != new_intr_shadow )
   1.194 -        {
   1.195 -            intr_shadow = new_intr_shadow;
   1.196 -            __vmwrite(GUEST_INTERRUPTIBILITY_INFO, intr_shadow);
   1.197 -        }
   1.198 -
   1.199 -        if ( rc == X86EMUL_EXCEPTION )
   1.200 -        {
   1.201 -            realmode_deliver_exception(
   1.202 -                rm_ctxt.exn_vector, rm_ctxt.exn_insn_len, &rm_ctxt);
   1.203 -        }
   1.204 -        else if ( rm_ctxt.flags.hlt && !hvm_local_events_need_delivery(curr) )
   1.205 -        {
   1.206 -            hvm_hlt(regs->eflags);
   1.207 -        }
   1.208 -    }
   1.209 +        realmode_emulate_one(&rm_ctxt);
   1.210  
   1.211      /*
   1.212       * Cannot enter protected mode with bogus selector RPLs and DPLs. Hence we