ia64/xen-unstable

changeset 16462:f6a587e3d5c9

x86_emulate: Allow emulated injection of exceptions and interrupts.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Sun Nov 25 18:05:10 2007 +0000 (2007-11-25)
parents d40788f07a4f
children 502f5b9469c3
files xen/arch/x86/hvm/vmx/realmode.c xen/arch/x86/x86_emulate.c xen/include/asm-x86/x86_emulate.h
line diff
     1.1 --- a/xen/arch/x86/hvm/vmx/realmode.c	Sun Nov 25 12:43:13 2007 +0000
     1.2 +++ b/xen/arch/x86/hvm/vmx/realmode.c	Sun Nov 25 18:05:10 2007 +0000
     1.3 @@ -13,6 +13,7 @@
     1.4  #include <xen/init.h>
     1.5  #include <xen/lib.h>
     1.6  #include <xen/sched.h>
     1.7 +#include <asm/event.h>
     1.8  #include <asm/hvm/hvm.h>
     1.9  #include <asm/hvm/support.h>
    1.10  #include <asm/hvm/vmx/vmx.h>
    1.11 @@ -23,35 +24,78 @@
    1.12  struct realmode_emulate_ctxt {
    1.13      struct x86_emulate_ctxt ctxt;
    1.14  
    1.15 -    /* Cache of up to 31 bytes of instruction. */
    1.16 -    uint8_t insn_buf[31];
    1.17 -    uint8_t insn_buf_bytes;
    1.18 +    /* Cache of 16 bytes of instruction. */
    1.19 +    uint8_t insn_buf[16];
    1.20      unsigned long insn_buf_eip;
    1.21  
    1.22      struct segment_register seg_reg[10];
    1.23  };
    1.24  
    1.25 -static int realmode_translate_linear_addr(
    1.26 -    enum x86_segment seg,
    1.27 -    unsigned long offset,
    1.28 -    unsigned int bytes,
    1.29 -    enum hvm_access_type access_type,
    1.30 -    struct realmode_emulate_ctxt *rm_ctxt,
    1.31 -    unsigned long *paddr)
    1.32 +static void realmode_deliver_exception(
    1.33 +    unsigned int vector,
    1.34 +    unsigned int insn_len,
    1.35 +    struct realmode_emulate_ctxt *rm_ctxt)
    1.36  {
    1.37 -    struct segment_register *reg = &rm_ctxt->seg_reg[seg];
    1.38 -    int okay;
    1.39 +    struct segment_register *idtr = &rm_ctxt->seg_reg[x86_seg_idtr];
    1.40 +    struct segment_register *csr = &rm_ctxt->seg_reg[x86_seg_cs];
    1.41 +    struct cpu_user_regs *regs = rm_ctxt->ctxt.regs;
    1.42 +    uint32_t cs_eip, pstk;
    1.43 +    uint16_t frame[3];
    1.44 +    unsigned int last_byte;
    1.45  
    1.46 -    okay = hvm_virtual_to_linear_addr(
    1.47 -        seg, reg, offset, bytes, access_type, rm_ctxt->ctxt.addr_size, paddr);
    1.48 + again:
    1.49 +    last_byte = (vector * 4) + 3;
    1.50 +    if ( idtr->limit < last_byte )
    1.51 +    {
    1.52 +        /* Software interrupt? */
    1.53 +        if ( insn_len != 0 )
    1.54 +        {
    1.55 +            insn_len = 0;
    1.56 +            vector = TRAP_gp_fault;
    1.57 +            goto again;
    1.58 +        }
    1.59  
    1.60 -    if ( !okay )
    1.61 -    {
    1.62 -        hvm_inject_exception(TRAP_gp_fault, 0, 0);
    1.63 -        return X86EMUL_EXCEPTION;
    1.64 +        /* Exception or hardware interrupt. */
    1.65 +        switch ( vector )
    1.66 +        {
    1.67 +        case TRAP_double_fault:
    1.68 +            hvm_triple_fault();
    1.69 +            return;
    1.70 +        case TRAP_gp_fault:
    1.71 +            vector = TRAP_double_fault;
    1.72 +            goto again;
    1.73 +        default:
    1.74 +            vector = TRAP_gp_fault;
    1.75 +            goto again;
    1.76 +        }
    1.77      }
    1.78  
    1.79 -    return 0;
    1.80 +    (void)hvm_copy_from_guest_phys(&cs_eip, idtr->base + vector * 4, 4);
    1.81 +
    1.82 +    frame[0] = regs->eip + insn_len;
    1.83 +    frame[1] = csr->sel;
    1.84 +    frame[2] = regs->eflags & ~X86_EFLAGS_RF;
    1.85 +
    1.86 +    if ( rm_ctxt->ctxt.addr_size == 32 )
    1.87 +    {
    1.88 +        regs->esp -= 4;
    1.89 +        pstk = regs->esp;
    1.90 +    }
    1.91 +    else
    1.92 +    {
    1.93 +        pstk = (uint16_t)(regs->esp - 4);
    1.94 +        regs->esp &= ~0xffff;
    1.95 +        regs->esp |= pstk;
    1.96 +    }
    1.97 +
    1.98 +    pstk += rm_ctxt->seg_reg[x86_seg_ss].base;
    1.99 +    (void)hvm_copy_to_guest_phys(pstk, frame, sizeof(frame));
   1.100 +
   1.101 +    csr->sel  = cs_eip >> 16;
   1.102 +    csr->base = (uint32_t)csr->sel << 4;
   1.103 +    regs->eip = (uint16_t)cs_eip;
   1.104 +    regs->eflags &= ~(X86_EFLAGS_AC | X86_EFLAGS_TF |
   1.105 +                      X86_EFLAGS_AC | X86_EFLAGS_RF);
   1.106  }
   1.107  
   1.108  static int
   1.109 @@ -63,14 +107,7 @@ realmode_read(
   1.110      enum hvm_access_type access_type,
   1.111      struct realmode_emulate_ctxt *rm_ctxt)
   1.112  {
   1.113 -    unsigned long addr;
   1.114 -    int rc;
   1.115 -
   1.116 -    rc = realmode_translate_linear_addr(
   1.117 -        seg, offset, bytes, access_type, rm_ctxt, &addr);
   1.118 -    if ( rc )
   1.119 -        return rc;
   1.120 -
   1.121 +    uint32_t addr = rm_ctxt->seg_reg[seg].base + offset;
   1.122      *val = 0;
   1.123      (void)hvm_copy_from_guest_phys(val, addr, bytes);
   1.124      return X86EMUL_OKAY;
   1.125 @@ -102,7 +139,7 @@ realmode_emulate_insn_fetch(
   1.126      unsigned int insn_off = offset - rm_ctxt->insn_buf_eip;
   1.127  
   1.128      /* Fall back if requested bytes are not in the prefetch cache. */
   1.129 -    if ( unlikely((insn_off + bytes) > rm_ctxt->insn_buf_bytes) )
   1.130 +    if ( unlikely((insn_off + bytes) > sizeof(rm_ctxt->insn_buf)) )
   1.131          return realmode_read(
   1.132              seg, offset, val, bytes,
   1.133              hvm_access_insn_fetch, rm_ctxt);
   1.134 @@ -123,14 +160,7 @@ realmode_emulate_write(
   1.135  {
   1.136      struct realmode_emulate_ctxt *rm_ctxt =
   1.137          container_of(ctxt, struct realmode_emulate_ctxt, ctxt);
   1.138 -    unsigned long addr;
   1.139 -    int rc;
   1.140 -
   1.141 -    rc = realmode_translate_linear_addr(
   1.142 -        seg, offset, bytes, hvm_access_write, rm_ctxt, &addr);
   1.143 -    if ( rc )
   1.144 -        return rc;
   1.145 -
   1.146 +    uint32_t addr = rm_ctxt->seg_reg[seg].base + offset;
   1.147      (void)hvm_copy_to_guest_phys(addr, &val, bytes);
   1.148      return X86EMUL_OKAY;
   1.149  }
   1.150 @@ -258,6 +288,31 @@ static int realmode_write_rflags(
   1.151      return X86EMUL_OKAY;
   1.152  }
   1.153  
   1.154 +static int realmode_inject_hw_exception(
   1.155 +    uint8_t vector,
   1.156 +    struct x86_emulate_ctxt *ctxt)
   1.157 +{
   1.158 +    struct realmode_emulate_ctxt *rm_ctxt =
   1.159 +        container_of(ctxt, struct realmode_emulate_ctxt, ctxt);
   1.160 +
   1.161 +    realmode_deliver_exception(vector, 0, rm_ctxt);
   1.162 +
   1.163 +    return X86EMUL_OKAY;
   1.164 +}
   1.165 +
   1.166 +static int realmode_inject_sw_interrupt(
   1.167 +    uint8_t vector,
   1.168 +    uint8_t insn_len,
   1.169 +    struct x86_emulate_ctxt *ctxt)
   1.170 +{
   1.171 +    struct realmode_emulate_ctxt *rm_ctxt =
   1.172 +        container_of(ctxt, struct realmode_emulate_ctxt, ctxt);
   1.173 +
   1.174 +    realmode_deliver_exception(vector, insn_len, rm_ctxt);
   1.175 +
   1.176 +    return X86EMUL_OKAY;
   1.177 +}
   1.178 +
   1.179  static struct x86_emulate_ops realmode_emulator_ops = {
   1.180      .read          = realmode_emulate_read,
   1.181      .insn_fetch    = realmode_emulate_insn_fetch,
   1.182 @@ -268,37 +323,44 @@ static struct x86_emulate_ops realmode_e
   1.183      .read_io       = realmode_read_io,
   1.184      .write_io      = realmode_write_io,
   1.185      .read_cr       = realmode_read_cr,
   1.186 -    .write_rflags  = realmode_write_rflags
   1.187 +    .write_rflags  = realmode_write_rflags,
   1.188 +    .inject_hw_exception = realmode_inject_hw_exception,
   1.189 +    .inject_sw_interrupt = realmode_inject_sw_interrupt
   1.190  };
   1.191  
   1.192  int vmx_realmode(struct cpu_user_regs *regs)
   1.193  {
   1.194      struct vcpu *curr = current;
   1.195      struct realmode_emulate_ctxt rm_ctxt;
   1.196 -    unsigned long addr;
   1.197 +    unsigned long intr_info;
   1.198      int i, rc = 0;
   1.199  
   1.200 +    rm_ctxt.ctxt.regs = regs;
   1.201 +
   1.202      for ( i = 0; i < 10; i++ )
   1.203          hvm_get_segment_register(curr, i, &rm_ctxt.seg_reg[i]);
   1.204  
   1.205 -    while ( !(curr->arch.hvm_vcpu.guest_cr[0] & X86_CR0_PE) &&
   1.206 -            !softirq_pending(smp_processor_id()) )
   1.207 -    {
   1.208 -        rm_ctxt.ctxt.regs = regs;
   1.209 -        rm_ctxt.ctxt.addr_size =
   1.210 -            rm_ctxt.seg_reg[x86_seg_cs].attr.fields.db ? 32 : 16;
   1.211 -        rm_ctxt.ctxt.sp_size =
   1.212 -            rm_ctxt.seg_reg[x86_seg_ss].attr.fields.db ? 32 : 16;
   1.213 +    rm_ctxt.ctxt.addr_size =
   1.214 +        rm_ctxt.seg_reg[x86_seg_cs].attr.fields.db ? 32 : 16;
   1.215 +    rm_ctxt.ctxt.sp_size =
   1.216 +        rm_ctxt.seg_reg[x86_seg_ss].attr.fields.db ? 32 : 16;
   1.217  
   1.218 +    intr_info = __vmread(VM_ENTRY_INTR_INFO);
   1.219 +    if ( intr_info & INTR_INFO_VALID_MASK )
   1.220 +    {
   1.221 +        __vmwrite(VM_ENTRY_INTR_INFO, 0);
   1.222 +        realmode_deliver_exception((uint8_t)intr_info, 0, &rm_ctxt);
   1.223 +    }
   1.224 +
   1.225 +    while ( !(curr->arch.hvm_vcpu.guest_cr[0] & X86_CR0_PE) &&
   1.226 +            !softirq_pending(smp_processor_id()) &&
   1.227 +            !hvm_local_events_need_delivery(curr) )
   1.228 +    {
   1.229          rm_ctxt.insn_buf_eip = regs->eip;
   1.230 -        rm_ctxt.insn_buf_bytes =
   1.231 -            (hvm_virtual_to_linear_addr(
   1.232 -                x86_seg_cs, &rm_ctxt.seg_reg[x86_seg_cs],
   1.233 -                regs->eip, sizeof(rm_ctxt.insn_buf),
   1.234 -                hvm_access_insn_fetch, rm_ctxt.ctxt.addr_size, &addr) &&
   1.235 -             !hvm_copy_from_guest_virt(
   1.236 -                 rm_ctxt.insn_buf, addr, sizeof(rm_ctxt.insn_buf)))
   1.237 -            ? sizeof(rm_ctxt.insn_buf) : 0;
   1.238 +        (void)hvm_copy_from_guest_phys(
   1.239 +            rm_ctxt.insn_buf,
   1.240 +            (uint32_t)(rm_ctxt.seg_reg[x86_seg_cs].base + regs->eip),
   1.241 +            sizeof(rm_ctxt.insn_buf));
   1.242  
   1.243          rc = x86_emulate(&rm_ctxt.ctxt, &realmode_emulator_ops);
   1.244  
   1.245 @@ -308,7 +370,7 @@ int vmx_realmode(struct cpu_user_regs *r
   1.246              break;
   1.247          }
   1.248  
   1.249 -        if ( rc )
   1.250 +        if ( rc == X86EMUL_UNHANDLEABLE )
   1.251          {
   1.252              gdprintk(XENLOG_DEBUG,
   1.253                       "RM %04x:%08lx: %02x %02x %02x %02x %02x %02x\n",
     2.1 --- a/xen/arch/x86/x86_emulate.c	Sun Nov 25 12:43:13 2007 +0000
     2.2 +++ b/xen/arch/x86/x86_emulate.c	Sun Nov 25 18:05:10 2007 +0000
     2.3 @@ -149,7 +149,7 @@ static uint8_t opcode_table[256] = {
     2.4      ImplicitOps, ImplicitOps,
     2.5      0, 0, ByteOp|DstMem|SrcImm|ModRM|Mov, DstMem|SrcImm|ModRM|Mov,
     2.6      /* 0xC8 - 0xCF */
     2.7 -    0, 0, 0, 0, 0, 0, 0, 0,
     2.8 +    0, 0, 0, 0, ImplicitOps, ImplicitOps, ImplicitOps, 0,
     2.9      /* 0xD0 - 0xD7 */
    2.10      ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM, 
    2.11      ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM, 
    2.12 @@ -163,7 +163,7 @@ static uint8_t opcode_table[256] = {
    2.13      ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
    2.14      ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
    2.15      /* 0xF0 - 0xF7 */
    2.16 -    0, 0, 0, 0,
    2.17 +    0, ImplicitOps, 0, 0,
    2.18      0, ImplicitOps, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|ModRM,
    2.19      /* 0xF8 - 0xFF */
    2.20      ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
    2.21 @@ -270,6 +270,7 @@ struct operand {
    2.22  #define EFLG_OF (1<<11)
    2.23  #define EFLG_DF (1<<10)
    2.24  #define EFLG_IF (1<<9)
    2.25 +#define EFLG_TF (1<<8)
    2.26  #define EFLG_SF (1<<7)
    2.27  #define EFLG_ZF (1<<6)
    2.28  #define EFLG_AF (1<<4)
    2.29 @@ -278,6 +279,9 @@ struct operand {
    2.30  
    2.31  /* Exception definitions. */
    2.32  #define EXC_DE  0
    2.33 +#define EXC_DB  1
    2.34 +#define EXC_BP  3
    2.35 +#define EXC_OF  4
    2.36  #define EXC_BR  5
    2.37  #define EXC_UD  6
    2.38  #define EXC_GP 13
    2.39 @@ -477,8 +481,13 @@ do {                                    
    2.40      if ( rc ) goto done;                                \
    2.41  } while (0)
    2.42  
    2.43 -/* In future we will be able to generate arbitrary exceptions. */
    2.44 -#define generate_exception_if(p, e) fail_if(p)
    2.45 +#define generate_exception_if(p, e)                                     \
    2.46 +({  if ( (p) ) {                                                        \
    2.47 +        fail_if(ops->inject_hw_exception == NULL);                      \
    2.48 +        rc = ops->inject_hw_exception(e, ctxt) ? : X86EMUL_EXCEPTION;   \
    2.49 +        goto done;                                                      \
    2.50 +    }                                                                   \
    2.51 +})
    2.52  
    2.53  /* Given byte has even parity (even number of 1s)? */
    2.54  static int even_parity(uint8_t v)
    2.55 @@ -1771,7 +1780,11 @@ x86_emulate(
    2.56      /* Commit shadow register state. */
    2.57      _regs.eflags &= ~EFLG_RF;
    2.58      *ctxt->regs = _regs;
    2.59 -    /* FIXME generate_exception_if(_regs.eflags & EFLG_TF, EXC_DB); */
    2.60 +
    2.61 +    if ( (_regs.eflags & EFLG_TF) &&
    2.62 +         (rc == X86EMUL_OKAY) &&
    2.63 +         (ops->inject_hw_exception != NULL) )
    2.64 +        rc = ops->inject_hw_exception(EXC_DB, ctxt) ? : X86EMUL_EXCEPTION;
    2.65  
    2.66   done:
    2.67      return rc;
    2.68 @@ -2152,6 +2165,25 @@ x86_emulate(
    2.69          break;
    2.70      }
    2.71  
    2.72 +    case 0xcc: /* int3 */
    2.73 +        src.val = EXC_BP;
    2.74 +        goto swint;
    2.75 +
    2.76 +    case 0xcd: /* int imm8 */
    2.77 +        src.val = insn_fetch_type(uint8_t);
    2.78 +    swint:
    2.79 +        fail_if(ops->inject_sw_interrupt == NULL);
    2.80 +        rc = ops->inject_sw_interrupt(src.val, _regs.eip - ctxt->regs->eip,
    2.81 +                                      ctxt) ? : X86EMUL_EXCEPTION;
    2.82 +        goto done;
    2.83 +
    2.84 +    case 0xce: /* into */
    2.85 +        generate_exception_if(mode_64bit(), EXC_UD);
    2.86 +        if ( !(_regs.eflags & EFLG_OF) )
    2.87 +            break;
    2.88 +        src.val = EXC_OF;
    2.89 +        goto swint;
    2.90 +
    2.91      case 0xd4: /* aam */ {
    2.92          unsigned int base = insn_fetch_type(uint8_t);
    2.93          uint8_t al = _regs.eax;
    2.94 @@ -2292,6 +2324,10 @@ x86_emulate(
    2.95          jmp_rel(insn_fetch_type(int8_t));
    2.96          break;
    2.97  
    2.98 +    case 0xf1: /* int1 (icebp) */
    2.99 +        src.val = EXC_DB;
   2.100 +        goto swint;
   2.101 +
   2.102      case 0xf5: /* cmc */
   2.103          _regs.eflags ^= EFLG_CF;
   2.104          break;
     3.1 --- a/xen/include/asm-x86/x86_emulate.h	Sun Nov 25 12:43:13 2007 +0000
     3.2 +++ b/xen/include/asm-x86/x86_emulate.h	Sun Nov 25 18:05:10 2007 +0000
     3.3 @@ -274,6 +274,17 @@ struct x86_emulate_ops
     3.4      /* wbinvd: Write-back and invalidate cache contents. */
     3.5      int (*wbinvd)(
     3.6          struct x86_emulate_ctxt *ctxt);
     3.7 +
     3.8 +    /* inject_hw_exception */
     3.9 +    int (*inject_hw_exception)(
    3.10 +        uint8_t vector,
    3.11 +        struct x86_emulate_ctxt *ctxt);
    3.12 +
    3.13 +    /* inject_sw_interrupt */
    3.14 +    int (*inject_sw_interrupt)(
    3.15 +        uint8_t vector,
    3.16 +        uint8_t insn_len,
    3.17 +        struct x86_emulate_ctxt *ctxt);
    3.18  };
    3.19  
    3.20  struct cpu_user_regs;