ia64/xen-unstable

changeset 12769:12ee3d6e61ef

[XEN] Add 'insn_fetch' memory operation to the x86_emulator.

This can be used to perform correct access checks, provide appropriate
error codes when injecting faults, and to implement an
instruction-stream prefetch cache (which is included here for HVM PTE
update emulations).

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@localhost.localdomain
date Sun Dec 03 17:15:48 2006 +0000 (2006-12-03)
parents de8abd5ce652
children 3bd721db6db5
files tools/tests/test_x86_emulator.c xen/arch/x86/mm.c xen/arch/x86/mm/shadow/common.c xen/arch/x86/mm/shadow/multi.c xen/arch/x86/mm/shadow/private.h xen/arch/x86/x86_emulate.c xen/include/asm-x86/x86_emulate.h
line diff
     1.1 --- a/tools/tests/test_x86_emulator.c	Sun Dec 03 13:30:23 2006 +0000
     1.2 +++ b/tools/tests/test_x86_emulator.c	Sun Dec 03 17:15:48 2006 +0000
     1.3 @@ -88,7 +88,11 @@ static int cmpxchg8b(
     1.4  }
     1.5  
     1.6  static struct x86_emulate_ops emulops = {
     1.7 -    read, write, cmpxchg, cmpxchg8b
     1.8 +    .read       = read,
     1.9 +    .insn_fetch = read,
    1.10 +    .write      = write,
    1.11 +    .cmpxchg    = cmpxchg,
    1.12 +    .cmpxchg8b  = cmpxchg8b
    1.13  };
    1.14  
    1.15  int main(int argc, char **argv)
     2.1 --- a/xen/arch/x86/mm.c	Sun Dec 03 13:30:23 2006 +0000
     2.2 +++ b/xen/arch/x86/mm.c	Sun Dec 03 17:15:48 2006 +0000
     2.3 @@ -3224,10 +3224,11 @@ static int ptwr_emulated_cmpxchg8b(
     2.4  }
     2.5  
     2.6  static struct x86_emulate_ops ptwr_emulate_ops = {
     2.7 -    .read      = ptwr_emulated_read,
     2.8 -    .write     = ptwr_emulated_write,
     2.9 -    .cmpxchg   = ptwr_emulated_cmpxchg,
    2.10 -    .cmpxchg8b = ptwr_emulated_cmpxchg8b
    2.11 +    .read       = ptwr_emulated_read,
    2.12 +    .insn_fetch = ptwr_emulated_read,
    2.13 +    .write      = ptwr_emulated_write,
    2.14 +    .cmpxchg    = ptwr_emulated_cmpxchg,
    2.15 +    .cmpxchg8b  = ptwr_emulated_cmpxchg8b
    2.16  };
    2.17  
    2.18  /* Write page fault handler: check if guest is trying to modify a PTE. */
     3.1 --- a/xen/arch/x86/mm/shadow/common.c	Sun Dec 03 13:30:23 2006 +0000
     3.2 +++ b/xen/arch/x86/mm/shadow/common.c	Sun Dec 03 17:15:48 2006 +0000
     3.3 @@ -78,43 +78,54 @@ struct segment_register *hvm_get_seg_reg
     3.4      return seg_reg;
     3.5  }
     3.6  
     3.7 +enum hvm_access_type {
     3.8 +    hvm_access_insn_fetch, hvm_access_read, hvm_access_write
     3.9 +};
    3.10 +
    3.11  static int hvm_translate_linear_addr(
    3.12      enum x86_segment seg,
    3.13      unsigned long offset,
    3.14      unsigned int bytes,
    3.15 -    unsigned int is_write,
    3.16 +    enum hvm_access_type access_type,
    3.17      struct sh_emulate_ctxt *sh_ctxt,
    3.18      unsigned long *paddr)
    3.19  {
    3.20 -    struct segment_register *creg, *dreg;
    3.21 +    struct segment_register *reg = hvm_get_seg_reg(seg, sh_ctxt);
    3.22      unsigned long limit, addr = offset;
    3.23      uint32_t last_byte;
    3.24  
    3.25 -    creg = hvm_get_seg_reg(x86_seg_cs, sh_ctxt);
    3.26 -    dreg = hvm_get_seg_reg(seg,        sh_ctxt);
    3.27 -
    3.28 -    if ( !creg->attr.fields.l || !hvm_long_mode_enabled(current) )
    3.29 +    if ( sh_ctxt->ctxt.mode != X86EMUL_MODE_PROT64 )
    3.30      {
    3.31          /*
    3.32           * COMPATIBILITY MODE: Apply segment checks and add base.
    3.33           */
    3.34  
    3.35 -        /* If this is a store, is the segment a writable data segment? */
    3.36 -        if ( is_write && ((dreg->attr.fields.type & 0xa) != 0x2) )
    3.37 -            goto gpf;
    3.38 +        switch ( access_type )
    3.39 +        {
    3.40 +        case hvm_access_read:
    3.41 +            if ( (reg->attr.fields.type & 0xa) == 0x8 )
    3.42 +                goto gpf; /* execute-only code segment */
    3.43 +            break;
    3.44 +        case hvm_access_write:
    3.45 +            if ( (reg->attr.fields.type & 0xa) != 0x2 )
    3.46 +                goto gpf; /* not a writable data segment */
    3.47 +            break;
    3.48 +        default:
    3.49 +            break;
    3.50 +        }
    3.51  
    3.52          /* Calculate the segment limit, including granularity flag. */
    3.53 -        limit = dreg->limit;
    3.54 -        if ( dreg->attr.fields.g )
    3.55 +        limit = reg->limit;
    3.56 +        if ( reg->attr.fields.g )
    3.57              limit = (limit << 12) | 0xfff;
    3.58  
    3.59          last_byte = offset + bytes - 1;
    3.60  
    3.61          /* Is this a grows-down data segment? Special limit check if so. */
    3.62 -        if ( (dreg->attr.fields.type & 0xc) == 0x4 )
    3.63 +        if ( (reg->attr.fields.type & 0xc) == 0x4 )
    3.64          {
    3.65              /* Is upper limit 0xFFFF or 0xFFFFFFFF? */
    3.66 -            if ( !dreg->attr.fields.db )
    3.67 +            if ( !reg->attr.fields.db )
    3.68                  last_byte = (uint16_t)last_byte;
    3.69  
    3.70              /* Check first byte and last byte against respective bounds. */
    3.71 @@ -128,7 +139,7 @@ static int hvm_translate_linear_addr(
    3.72           * Hardware truncates to 32 bits in compatibility mode.
    3.73           * It does not truncate to 16 bits in 16-bit address-size mode.
    3.74           */
    3.75 -        addr = (uint32_t)(addr + dreg->base);
    3.76 +        addr = (uint32_t)(addr + reg->base);
    3.77      }
    3.78      else
    3.79      {
    3.80 @@ -137,7 +148,7 @@ static int hvm_translate_linear_addr(
    3.81           */
    3.82  
    3.83          if ( (seg == x86_seg_fs) || (seg == x86_seg_gs) )
    3.84 -            addr += dreg->base;
    3.85 +            addr += reg->base;
    3.86  
    3.87          if ( !is_canonical_address(addr) )
    3.88              goto gpf;
    3.89 @@ -153,18 +164,18 @@ static int hvm_translate_linear_addr(
    3.90  }
    3.91  
    3.92  static int
    3.93 -sh_x86_emulate_read(enum x86_segment seg,
    3.94 -                    unsigned long offset,
    3.95 -                    unsigned long *val,
    3.96 -                    unsigned int bytes,
    3.97 -                    struct x86_emulate_ctxt *ctxt)
    3.98 +hvm_read(enum x86_segment seg,
    3.99 +         unsigned long offset,
   3.100 +         unsigned long *val,
   3.101 +         unsigned int bytes,
   3.102 +         enum hvm_access_type access_type,
   3.103 +         struct sh_emulate_ctxt *sh_ctxt)
   3.104  {
   3.105 -    struct sh_emulate_ctxt *sh_ctxt =
   3.106 -        container_of(ctxt, struct sh_emulate_ctxt, ctxt);
   3.107      unsigned long addr;
   3.108      int rc, errcode;
   3.109  
   3.110 -    rc = hvm_translate_linear_addr(seg, offset, bytes, 0, sh_ctxt, &addr);
   3.111 +    rc = hvm_translate_linear_addr(
   3.112 +        seg, offset, bytes, access_type, sh_ctxt, &addr);
   3.113      if ( rc )
   3.114          return rc;
   3.115  
   3.116 @@ -189,10 +200,78 @@ sh_x86_emulate_read(enum x86_segment seg
   3.117       * of a write fault at the end of the instruction we're emulating. */ 
   3.118      SHADOW_PRINTK("read failed to va %#lx\n", addr);
   3.119      errcode = ring_3(sh_ctxt->ctxt.regs) ? PFEC_user_mode : 0;
   3.120 +    if ( access_type == hvm_access_insn_fetch )
   3.121 +        errcode |= PFEC_insn_fetch;
   3.122      hvm_inject_exception(TRAP_page_fault, errcode, addr + bytes - rc);
   3.123      return X86EMUL_PROPAGATE_FAULT;
   3.124  }
   3.125  
   3.126 +void shadow_init_emulation(struct sh_emulate_ctxt *sh_ctxt, 
   3.127 +                           struct cpu_user_regs *regs)
   3.128 +{
   3.129 +    struct segment_register *creg;
   3.130 +    struct vcpu *v = current;
   3.131 +    unsigned long addr;
   3.132 +
   3.133 +    sh_ctxt->ctxt.regs = regs;
   3.134 +
   3.135 +    /* Segment cache initialisation. Primed with CS. */
   3.136 +    sh_ctxt->valid_seg_regs = 0;
   3.137 +    creg = hvm_get_seg_reg(x86_seg_cs, sh_ctxt);
   3.138 +
   3.139 +    /* Work out the emulation mode. */
   3.140 +    if ( hvm_long_mode_enabled(v) )
   3.141 +        sh_ctxt->ctxt.mode = creg->attr.fields.l ?
   3.142 +            X86EMUL_MODE_PROT64 : X86EMUL_MODE_PROT32;
   3.143 +    else if ( regs->eflags & X86_EFLAGS_VM )
   3.144 +        sh_ctxt->ctxt.mode = X86EMUL_MODE_REAL;
   3.145 +    else
   3.146 +        sh_ctxt->ctxt.mode = creg->attr.fields.db ?
   3.147 +            X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
   3.148 +
   3.149 +    /* Attempt to prefetch whole instruction. */
   3.150 +    sh_ctxt->insn_buf_bytes =
   3.151 +        (!hvm_translate_linear_addr(
   3.152 +            x86_seg_cs, regs->eip, sizeof(sh_ctxt->insn_buf),
   3.153 +            hvm_access_insn_fetch, sh_ctxt, &addr) &&
   3.154 +         !hvm_copy_from_guest_virt(
   3.155 +             sh_ctxt->insn_buf, addr, sizeof(sh_ctxt->insn_buf)))
   3.156 +        ? sizeof(sh_ctxt->insn_buf) : 0;
   3.157 +}
   3.158 +
   3.159 +static int
   3.160 +sh_x86_emulate_read(enum x86_segment seg,
   3.161 +                    unsigned long offset,
   3.162 +                    unsigned long *val,
   3.163 +                    unsigned int bytes,
   3.164 +                    struct x86_emulate_ctxt *ctxt)
   3.165 +{
   3.166 +    return hvm_read(seg, offset, val, bytes, hvm_access_read,
   3.167 +                    container_of(ctxt, struct sh_emulate_ctxt, ctxt));
   3.168 +}
   3.169 +
   3.170 +static int
   3.171 +sh_x86_emulate_insn_fetch(enum x86_segment seg,
   3.172 +                          unsigned long offset,
   3.173 +                          unsigned long *val,
   3.174 +                          unsigned int bytes,
   3.175 +                          struct x86_emulate_ctxt *ctxt)
   3.176 +{
   3.177 +    struct sh_emulate_ctxt *sh_ctxt =
   3.178 +        container_of(ctxt, struct sh_emulate_ctxt, ctxt);
   3.179 +    unsigned int insn_off = offset - ctxt->regs->eip;
   3.180 +
   3.181 +    /* Fall back if requested bytes are not in the prefetch cache. */
   3.182 +    if ( unlikely((insn_off + bytes) > sh_ctxt->insn_buf_bytes) )
   3.183 +        return hvm_read(seg, offset, val, bytes,
   3.184 +                        hvm_access_insn_fetch, sh_ctxt);
   3.185 +
   3.186 +    /* Hit the cache. Simple memcpy. */
   3.187 +    *val = 0;
   3.188 +    memcpy(val, &sh_ctxt->insn_buf[insn_off], bytes);
   3.189 +    return X86EMUL_CONTINUE;
   3.190 +}
   3.191 +
   3.192  static int
   3.193  sh_x86_emulate_write(enum x86_segment seg,
   3.194                       unsigned long offset,
   3.195 @@ -206,7 +285,8 @@ sh_x86_emulate_write(enum x86_segment se
   3.196      unsigned long addr;
   3.197      int rc;
   3.198  
   3.199 -    rc = hvm_translate_linear_addr(seg, offset, bytes, 1, sh_ctxt, &addr);
   3.200 +    rc = hvm_translate_linear_addr(
   3.201 +        seg, offset, bytes, hvm_access_write, sh_ctxt, &addr);
   3.202      if ( rc )
   3.203          return rc;
   3.204  
   3.205 @@ -232,7 +312,8 @@ sh_x86_emulate_cmpxchg(enum x86_segment 
   3.206      unsigned long addr;
   3.207      int rc;
   3.208  
   3.209 -    rc = hvm_translate_linear_addr(seg, offset, bytes, 1, sh_ctxt, &addr);
   3.210 +    rc = hvm_translate_linear_addr(
   3.211 +        seg, offset, bytes, hvm_access_write, sh_ctxt, &addr);
   3.212      if ( rc )
   3.213          return rc;
   3.214  
   3.215 @@ -259,7 +340,8 @@ sh_x86_emulate_cmpxchg8b(enum x86_segmen
   3.216      unsigned long addr;
   3.217      int rc;
   3.218  
   3.219 -    rc = hvm_translate_linear_addr(seg, offset, 8, 1, sh_ctxt, &addr);
   3.220 +    rc = hvm_translate_linear_addr(
   3.221 +        seg, offset, 8, hvm_access_write, sh_ctxt, &addr);
   3.222      if ( rc )
   3.223          return rc;
   3.224  
   3.225 @@ -274,10 +356,11 @@ sh_x86_emulate_cmpxchg8b(enum x86_segmen
   3.226  
   3.227  
   3.228  struct x86_emulate_ops shadow_emulator_ops = {
   3.229 -    .read      = sh_x86_emulate_read,
   3.230 -    .write     = sh_x86_emulate_write,
   3.231 -    .cmpxchg   = sh_x86_emulate_cmpxchg,
   3.232 -    .cmpxchg8b = sh_x86_emulate_cmpxchg8b,
   3.233 +    .read       = sh_x86_emulate_read,
   3.234 +    .insn_fetch = sh_x86_emulate_insn_fetch,
   3.235 +    .write      = sh_x86_emulate_write,
   3.236 +    .cmpxchg    = sh_x86_emulate_cmpxchg,
   3.237 +    .cmpxchg8b  = sh_x86_emulate_cmpxchg8b,
   3.238  };
   3.239  
   3.240  /**************************************************************************/
     4.1 --- a/xen/arch/x86/mm/shadow/multi.c	Sun Dec 03 13:30:23 2006 +0000
     4.2 +++ b/xen/arch/x86/mm/shadow/multi.c	Sun Dec 03 17:15:48 2006 +0000
     4.3 @@ -2808,24 +2808,20 @@ static int sh_page_fault(struct vcpu *v,
     4.4      return EXCRET_fault_fixed;
     4.5  
     4.6   emulate:
     4.7 -    if ( !is_hvm_domain(d) )
     4.8 +    if ( !is_hvm_domain(d) || !guest_mode(regs) )
     4.9          goto not_a_shadow_fault;
    4.10  
    4.11      hvm_store_cpu_guest_regs(v, regs, NULL);
    4.12 -    emul_ctxt.ctxt.regs = regs;
    4.13 -    emul_ctxt.ctxt.mode = (is_hvm_domain(d) ?
    4.14 -                           hvm_guest_x86_mode(v) : X86EMUL_MODE_HOST);
    4.15 -    emul_ctxt.valid_seg_regs = 0;
    4.16 -
    4.17      SHADOW_PRINTK("emulate: eip=%#lx\n", regs->eip);
    4.18  
    4.19 +    shadow_init_emulation(&emul_ctxt, regs);
    4.20 +
    4.21      /*
    4.22       * We do not emulate user writes. Instead we use them as a hint that the
    4.23       * page is no longer a page table. This behaviour differs from native, but
    4.24       * it seems very unlikely that any OS grants user access to page tables.
    4.25 -     * We also disallow guest PTE updates from within Xen.
    4.26       */
    4.27 -    if ( (regs->error_code & PFEC_user_mode) || !guest_mode(regs) ||
    4.28 +    if ( (regs->error_code & PFEC_user_mode) ||
    4.29           x86_emulate_memop(&emul_ctxt.ctxt, &shadow_emulator_ops) )
    4.30      {
    4.31          SHADOW_PRINTK("emulator failure, unshadowing mfn %#lx\n", 
     5.1 --- a/xen/arch/x86/mm/shadow/private.h	Sun Dec 03 13:30:23 2006 +0000
     5.2 +++ b/xen/arch/x86/mm/shadow/private.h	Sun Dec 03 17:15:48 2006 +0000
     5.3 @@ -513,11 +513,17 @@ static inline void sh_unpin(struct vcpu 
     5.4  struct sh_emulate_ctxt {
     5.5      struct x86_emulate_ctxt ctxt;
     5.6  
     5.7 +    /* Cache of up to 15 bytes of instruction. */
     5.8 +    uint8_t insn_buf[15];
     5.9 +    uint8_t insn_buf_bytes;
    5.10 +
    5.11      /* Cache of segment registers already gathered for this emulation. */
    5.12      unsigned int valid_seg_regs;
    5.13      struct segment_register seg_reg[6];
    5.14  };
    5.15  
    5.16 +void shadow_init_emulation(struct sh_emulate_ctxt *sh_ctxt,
    5.17 +                           struct cpu_user_regs *regs);
    5.18  
    5.19  #endif /* _XEN_SHADOW_PRIVATE_H */
    5.20  
     6.1 --- a/xen/arch/x86/x86_emulate.c	Sun Dec 03 13:30:23 2006 +0000
     6.2 +++ b/xen/arch/x86/x86_emulate.c	Sun Dec 03 17:15:48 2006 +0000
     6.3 @@ -19,11 +19,6 @@
     6.4  #endif
     6.5  #include <asm-x86/x86_emulate.h>
     6.6  
     6.7 -#ifndef PFEC_write_access
     6.8 -#define PFEC_write_access (1U<<1)
     6.9 -#define PFEC_insn_fetch   (1U<<4)
    6.10 -#endif
    6.11 -
    6.12  /*
    6.13   * Opcode effective-address decode tables.
    6.14   * Note that we only emulate instructions that have at least one memory
    6.15 @@ -374,15 +369,15 @@ do{ __asm__ __volatile__ (              
    6.16  #endif /* __i386__ */
    6.17  
    6.18  /* Fetch next part of the instruction being emulated. */
    6.19 -#define _insn_fetch(_size)                                      \
    6.20 -({ unsigned long _x;                                            \
    6.21 -   rc = ops->read(x86_seg_cs, _regs.eip, &_x, (_size), ctxt);   \
    6.22 -   if ( rc != 0 )                                               \
    6.23 -       goto done;                                               \
    6.24 -   _regs.eip += (_size);                                        \
    6.25 -   _x;                                                          \
    6.26 +#define insn_fetch_bytes(_size)                                         \
    6.27 +({ unsigned long _x;                                                    \
    6.28 +   rc = ops->insn_fetch(x86_seg_cs, _regs.eip, &_x, (_size), ctxt);     \
    6.29 +   if ( rc != 0 )                                                       \
    6.30 +       goto done;                                                       \
    6.31 +   _regs.eip += (_size);                                                \
    6.32 +   _x;                                                                  \
    6.33  })
    6.34 -#define insn_fetch(_type) ((_type)_insn_fetch(sizeof(_type)))
    6.35 +#define insn_fetch_type(_type) ((_type)insn_fetch_bytes(sizeof(_type)))
    6.36  
    6.37  #define truncate_ea(ea)                                 \
    6.38  ({  unsigned long __ea = (ea);                          \
    6.39 @@ -481,7 +476,7 @@ x86_emulate_memop(
    6.40      /* Legacy prefixes. */
    6.41      for ( i = 0; i < 8; i++ )
    6.42      {
    6.43 -        switch ( b = insn_fetch(uint8_t) )
    6.44 +        switch ( b = insn_fetch_type(uint8_t) )
    6.45          {
    6.46          case 0x66: /* operand-size override */
    6.47              op_bytes ^= 6;      /* switch between 2/4 bytes */
    6.48 @@ -530,7 +525,7 @@ x86_emulate_memop(
    6.49          rex_prefix = b;
    6.50          if ( b & 8 ) /* REX.W */
    6.51              op_bytes = 8;
    6.52 -        b = insn_fetch(uint8_t);
    6.53 +        b = insn_fetch_type(uint8_t);
    6.54      }
    6.55  
    6.56      /* Opcode byte(s). */
    6.57 @@ -541,7 +536,7 @@ x86_emulate_memop(
    6.58          if ( b == 0x0f )
    6.59          {
    6.60              twobyte = 1;
    6.61 -            b = insn_fetch(uint8_t);
    6.62 +            b = insn_fetch_type(uint8_t);
    6.63              d = twobyte_table[b];
    6.64          }
    6.65  
    6.66 @@ -553,7 +548,7 @@ x86_emulate_memop(
    6.67      /* ModRM and SIB bytes. */
    6.68      if ( d & ModRM )
    6.69      {
    6.70 -        modrm = insn_fetch(uint8_t);
    6.71 +        modrm = insn_fetch_type(uint8_t);
    6.72          modrm_mod = (modrm & 0xc0) >> 6;
    6.73          modrm_reg = ((rex_prefix & 4) << 1) | ((modrm & 0x38) >> 3);
    6.74          modrm_rm  = modrm & 0x07;
    6.75 @@ -577,9 +572,16 @@ x86_emulate_memop(
    6.76              }
    6.77              switch ( modrm_mod )
    6.78              {
    6.79 -            case 0: if ( modrm_rm == 6 ) ea_off = insn_fetch(int16_t); break;
    6.80 -            case 1: ea_off += insn_fetch(int8_t);  break;
    6.81 -            case 2: ea_off += insn_fetch(int16_t); break;
    6.82 +            case 0:
    6.83 +                if ( modrm_rm == 6 )
    6.84 +                    ea_off = insn_fetch_type(int16_t);
    6.85 +                break;
    6.86 +            case 1:
    6.87 +                ea_off += insn_fetch_type(int8_t);
    6.88 +                break;
    6.89 +            case 2:
    6.90 +                ea_off += insn_fetch_type(int16_t);
    6.91 +                break;
    6.92              }
    6.93          }
    6.94          else
    6.95 @@ -587,14 +589,14 @@ x86_emulate_memop(
    6.96              /* 32/64-bit ModR/M decode. */
    6.97              if ( modrm_rm == 4 )
    6.98              {
    6.99 -                sib = insn_fetch(uint8_t);
   6.100 +                sib = insn_fetch_type(uint8_t);
   6.101                  sib_index = ((sib >> 3) & 7) | ((rex_prefix << 2) & 8);
   6.102                  sib_base  = (sib & 7) | ((rex_prefix << 3) & 8);
   6.103                  if ( sib_index != 4 )
   6.104                      ea_off = *(long *)decode_register(sib_index, &_regs, 0);
   6.105                  ea_off <<= (sib >> 6) & 3;
   6.106                  if ( (modrm_mod == 0) && ((sib_base & 7) == 5) )
   6.107 -                    ea_off += insn_fetch(int32_t);
   6.108 +                    ea_off += insn_fetch_type(int32_t);
   6.109                  else
   6.110                      ea_off += *(long *)decode_register(sib_base, &_regs, 0);
   6.111              }
   6.112 @@ -608,7 +610,7 @@ x86_emulate_memop(
   6.113              case 0:
   6.114                  if ( (modrm_rm & 7) != 5 )
   6.115                      break;
   6.116 -                ea_off = insn_fetch(int32_t);
   6.117 +                ea_off = insn_fetch_type(int32_t);
   6.118                  if ( mode != X86EMUL_MODE_PROT64 )
   6.119                      break;
   6.120                  /* Relative to RIP of next instruction. Argh! */
   6.121 @@ -624,8 +626,12 @@ x86_emulate_memop(
   6.122                      ea_off += (d & ByteOp) ? 1
   6.123                          : ((op_bytes == 8) ? 4 : op_bytes);
   6.124                  break;
   6.125 -            case 1: ea_off += insn_fetch(int8_t);  break;
   6.126 -            case 2: ea_off += insn_fetch(int32_t); break;
   6.127 +            case 1:
   6.128 +                ea_off += insn_fetch_type(int8_t);
   6.129 +                break;
   6.130 +            case 2:
   6.131 +                ea_off += insn_fetch_type(int32_t);
   6.132 +                break;
   6.133              }
   6.134          }
   6.135  
   6.136 @@ -684,15 +690,15 @@ x86_emulate_memop(
   6.137          /* NB. Immediates are sign-extended as necessary. */
   6.138          switch ( src.bytes )
   6.139          {
   6.140 -        case 1: src.val = insn_fetch(int8_t);  break;
   6.141 -        case 2: src.val = insn_fetch(int16_t); break;
   6.142 -        case 4: src.val = insn_fetch(int32_t); break;
   6.143 +        case 1: src.val = insn_fetch_type(int8_t);  break;
   6.144 +        case 2: src.val = insn_fetch_type(int16_t); break;
   6.145 +        case 4: src.val = insn_fetch_type(int32_t); break;
   6.146          }
   6.147          break;
   6.148      case SrcImmByte:
   6.149          src.type  = OP_IMM;
   6.150          src.bytes = 1;
   6.151 -        src.val   = insn_fetch(int8_t);
   6.152 +        src.val   = insn_fetch_type(int8_t);
   6.153          break;
   6.154      }
   6.155  
   6.156 @@ -885,9 +891,9 @@ x86_emulate_memop(
   6.157              if ( src.bytes == 8 ) src.bytes = 4;
   6.158              switch ( src.bytes )
   6.159              {
   6.160 -            case 1: src.val = insn_fetch(int8_t);  break;
   6.161 -            case 2: src.val = insn_fetch(int16_t); break;
   6.162 -            case 4: src.val = insn_fetch(int32_t); break;
   6.163 +            case 1: src.val = insn_fetch_type(int8_t);  break;
   6.164 +            case 2: src.val = insn_fetch_type(int16_t); break;
   6.165 +            case 4: src.val = insn_fetch_type(int32_t); break;
   6.166              }
   6.167              goto test;
   6.168          case 2: /* not */
   6.169 @@ -986,7 +992,7 @@ x86_emulate_memop(
   6.170          dst.type  = OP_REG;
   6.171          dst.reg   = (unsigned long *)&_regs.eax;
   6.172          dst.bytes = (d & ByteOp) ? 1 : op_bytes;
   6.173 -        if ( (rc = ops->read(ea_seg, _insn_fetch(ad_bytes),
   6.174 +        if ( (rc = ops->read(ea_seg, insn_fetch_bytes(ad_bytes),
   6.175                               &dst.val, dst.bytes, ctxt)) != 0 )
   6.176              goto done;
   6.177          break;
   6.178 @@ -994,7 +1000,7 @@ x86_emulate_memop(
   6.179          /* Destination EA is not encoded via ModRM. */
   6.180          dst.type    = OP_MEM;
   6.181          dst.mem_seg = ea_seg;
   6.182 -        dst.mem_off = _insn_fetch(ad_bytes);
   6.183 +        dst.mem_off = insn_fetch_bytes(ad_bytes);
   6.184          dst.bytes   = (d & ByteOp) ? 1 : op_bytes;
   6.185          dst.val     = (unsigned long)_regs.eax;
   6.186          break;
   6.187 @@ -1198,7 +1204,7 @@ x86_emulate_memop(
   6.188      for ( ea_off = ctxt->regs->eip; ea_off < _regs.eip; ea_off++ )
   6.189      {
   6.190          unsigned long x;
   6.191 -        ops->read(x86_seg_cs, ea_off, &x, 1, ctxt);
   6.192 +        ops->insn_fetch(x86_seg_cs, ea_off, &x, 1, ctxt);
   6.193          printk(" %02x", (uint8_t)x);
   6.194      }
   6.195      printk("\n");
     7.1 --- a/xen/include/asm-x86/x86_emulate.h	Sun Dec 03 13:30:23 2006 +0000
     7.2 +++ b/xen/include/asm-x86/x86_emulate.h	Sun Dec 03 17:15:48 2006 +0000
     7.3 @@ -56,7 +56,8 @@ struct x86_emulate_ops
     7.4      /*
     7.5       * All functions:
     7.6       *  @seg:   [IN ] Segment being dereferenced (specified as x86_seg_??).
     7.7 -     *  @offset [IN ] Offset within segment.
     7.8 +     *  @offset:[IN ] Offset within segment.
     7.9 +     *  @ctxt:  [IN ] Emulation context info as passed to the emulator.
    7.10       */
    7.11  
    7.12      /*
    7.13 @@ -72,6 +73,17 @@ struct x86_emulate_ops
    7.14          struct x86_emulate_ctxt *ctxt);
    7.15  
    7.16      /*
    7.17 +     * insn_fetch: Emulate fetch from instruction byte stream.
    7.18 +     *  Parameters are same as for 'read'. @seg is always x86_seg_cs.
    7.19 +     */
    7.20 +    int (*insn_fetch)(
    7.21 +        enum x86_segment seg,
    7.22 +        unsigned long offset,
    7.23 +        unsigned long *val,
    7.24 +        unsigned int bytes,
    7.25 +        struct x86_emulate_ctxt *ctxt);
    7.26 +
    7.27 +    /*
    7.28       * write: Emulate a memory write.
    7.29       *  @val:   [IN ] Value to write to memory (low-order bytes used as req'd).
    7.30       *  @bytes: [IN ] Number of bytes to write to memory.