direct-io.hg

changeset 12528:62307643804e

[XEN] Extend emulator to fully decode ModRM and SIB bytes.
Use this to detect data accesses that straddle a page boundary
and fault on the second page. We cannot handle these properly.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Thu Nov 23 17:32:18 2006 +0000 (2006-11-23)
parents 2d8784764b52
children 3127a43786d8
files xen/arch/x86/x86_emulate.c
line diff
     1.1 --- a/xen/arch/x86/x86_emulate.c	Thu Nov 23 17:21:26 2006 +0000
     1.2 +++ b/xen/arch/x86/x86_emulate.c	Thu Nov 23 17:32:18 2006 +0000
     1.3 @@ -113,12 +113,10 @@ static uint8_t opcode_table[256] = {
     1.4      /* 0xA0 - 0xA7 */
     1.5      ByteOp|DstReg|SrcMem|Mov, DstReg|SrcMem|Mov,
     1.6      ByteOp|DstMem|SrcReg|Mov, DstMem|SrcReg|Mov,
     1.7 -    ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,
     1.8 -    ByteOp|ImplicitOps, ImplicitOps,
     1.9 +    ByteOp|ImplicitOps|Mov, ImplicitOps|Mov, 0, 0,
    1.10      /* 0xA8 - 0xAF */
    1.11      0, 0, ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,
    1.12 -    ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,
    1.13 -    ByteOp|ImplicitOps, ImplicitOps,
    1.14 +    ByteOp|ImplicitOps|Mov, ImplicitOps|Mov, 0, 0,
    1.15      /* 0xB0 - 0xBF */
    1.16      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    1.17      /* 0xC0 - 0xC7 */
    1.18 @@ -368,15 +366,16 @@ do{ __asm__ __volatile__ (              
    1.19  #endif /* __i386__ */
    1.20  
    1.21  /* Fetch next part of the instruction being emulated. */
    1.22 -#define insn_fetch(_type, _size)                                        \
    1.23 +#define _insn_fetch(_size)                                              \
    1.24  ({ unsigned long _x, _ptr = _regs.eip;                                  \
    1.25     if ( mode == X86EMUL_MODE_REAL ) _ptr += _regs.cs << 4;              \
    1.26     rc = ops->read_std(_ptr, &_x, (_size), ctxt);                        \
    1.27     if ( rc != 0 )                                                       \
    1.28         goto done;                                                       \
    1.29     _regs.eip += (_size);                                                \
    1.30 -   (_type)_x;                                                           \
    1.31 +   _x;                                                                  \
    1.32  })
    1.33 +#define insn_fetch(_type) ((_type)_insn_fetch(sizeof(_type)))
    1.34  
    1.35  /* Access/update address held in a register, based on addressing mode. */
    1.36  #define register_address(sel, reg)                                      \
    1.37 @@ -393,6 +392,17 @@ do {                                    
    1.38                  (((reg) + _inc) & ((1UL << (ad_bytes << 3)) - 1));      \
    1.39  } while (0)
    1.40  
    1.41 +/*
    1.42 + * We cannot handle a page fault on a data access that straddles two pages
    1.43 + * and faults on the second page. This is because CR2 is not equal to the
    1.44 + * memory operand's effective address in this case. Rather than fix up the
    1.45 + * effective address it is okay for us to fail the emulation.
    1.46 + */
    1.47 +#define page_boundary_test() do {                               \
    1.48 +    if ( ((cr2 & (PAGE_SIZE-1)) == 0) && ((ea & 3) != 0) )      \
    1.49 +        goto bad_ea;                                            \
    1.50 +} while ( 0 )
    1.51 +
    1.52  void *
    1.53  decode_register(
    1.54      uint8_t modrm_reg, struct cpu_user_regs *regs, int highbyte_regs)
    1.55 @@ -438,13 +448,13 @@ x86_emulate_memop(
    1.56      struct x86_emulate_ctxt *ctxt,
    1.57      struct x86_emulate_ops  *ops)
    1.58  {
    1.59 -    uint8_t b, d, sib, twobyte = 0, rex_prefix = 0;
    1.60 +    uint8_t b, d, sib, sib_index, sib_base, twobyte = 0, rex_prefix = 0;
    1.61      uint8_t modrm, modrm_mod = 0, modrm_reg = 0, modrm_rm = 0;
    1.62      uint16_t *seg = NULL; /* override segment */
    1.63      unsigned int op_bytes, ad_bytes, lock_prefix = 0, rep_prefix = 0, i;
    1.64      int rc = 0;
    1.65      struct operand src, dst;
    1.66 -    unsigned long cr2 = ctxt->cr2;
    1.67 +    unsigned long ea = 0, cr2 = ctxt->cr2;
    1.68      int mode = ctxt->mode;
    1.69  
    1.70      /* Shadow copy of register state. Committed on successful emulation. */
    1.71 @@ -479,7 +489,7 @@ x86_emulate_memop(
    1.72      /* Legacy prefixes. */
    1.73      for ( i = 0; i < 8; i++ )
    1.74      {
    1.75 -        switch ( b = insn_fetch(uint8_t, 1) )
    1.76 +        switch ( b = insn_fetch(uint8_t) )
    1.77          {
    1.78          case 0x66: /* operand-size override */
    1.79              op_bytes ^= 6;      /* switch between 2/4 bytes */
    1.80 @@ -526,11 +536,9 @@ x86_emulate_memop(
    1.81      if ( (mode == X86EMUL_MODE_PROT64) && ((b & 0xf0) == 0x40) )
    1.82      {
    1.83          rex_prefix = b;
    1.84 -        if ( b & 8 )
    1.85 -            op_bytes = 8;          /* REX.W */
    1.86 -        modrm_reg = (b & 4) << 1;  /* REX.R */
    1.87 -        /* REX.B and REX.X do not need to be decoded. */
    1.88 -        b = insn_fetch(uint8_t, 1);
    1.89 +        if ( b & 8 ) /* REX.W */
    1.90 +            op_bytes = 8;
    1.91 +        b = insn_fetch(uint8_t);
    1.92      }
    1.93  
    1.94      /* Opcode byte(s). */
    1.95 @@ -541,7 +549,7 @@ x86_emulate_memop(
    1.96          if ( b == 0x0f )
    1.97          {
    1.98              twobyte = 1;
    1.99 -            b = insn_fetch(uint8_t, 1);
   1.100 +            b = insn_fetch(uint8_t);
   1.101              d = twobyte_table[b];
   1.102          }
   1.103  
   1.104 @@ -553,10 +561,10 @@ x86_emulate_memop(
   1.105      /* ModRM and SIB bytes. */
   1.106      if ( d & ModRM )
   1.107      {
   1.108 -        modrm = insn_fetch(uint8_t, 1);
   1.109 -        modrm_mod |= (modrm & 0xc0) >> 6;
   1.110 -        modrm_reg |= (modrm & 0x38) >> 3;
   1.111 -        modrm_rm  |= (modrm & 0x07);
   1.112 +        modrm = insn_fetch(uint8_t);
   1.113 +        modrm_mod = (modrm & 0xc0) >> 6;
   1.114 +        modrm_reg = ((rex_prefix & 4) << 1) | ((modrm & 0x38) >> 3);
   1.115 +        modrm_rm  = modrm & 0x07;
   1.116  
   1.117          if ( modrm_mod == 3 )
   1.118          {
   1.119 @@ -567,44 +575,74 @@ x86_emulate_memop(
   1.120          if ( ad_bytes == 2 )
   1.121          {
   1.122              /* 16-bit ModR/M decode. */
   1.123 +            switch ( modrm_rm )
   1.124 +            {
   1.125 +            case 0: ea = _regs.ebx + _regs.esi; break;
   1.126 +            case 1: ea = _regs.ebx + _regs.edi; break;
   1.127 +            case 2: ea = _regs.ebp + _regs.esi; break;
   1.128 +            case 3: ea = _regs.ebp + _regs.edi; break;
   1.129 +            case 4: ea = _regs.esi; break;
   1.130 +            case 5: ea = _regs.edi; break;
   1.131 +            case 6: ea = _regs.ebp; break;
   1.132 +            case 7: ea = _regs.ebx; break;
   1.133 +            }
   1.134              switch ( modrm_mod )
   1.135              {
   1.136 -            case 0:
   1.137 -                if ( modrm_rm == 6 )
   1.138 -                    _regs.eip += 2; /* skip disp16 */
   1.139 -                break;
   1.140 -            case 1:
   1.141 -                _regs.eip += 1; /* skip disp8 */
   1.142 -                break;
   1.143 -            case 2:
   1.144 -                _regs.eip += 2; /* skip disp16 */
   1.145 -                break;
   1.146 +            case 0: if ( modrm_rm == 6 ) ea = insn_fetch(uint16_t); break;
   1.147 +            case 1: ea += insn_fetch(uint8_t);  break;
   1.148 +            case 2: ea += insn_fetch(uint16_t); break;
   1.149              }
   1.150 +            ea = (uint16_t)ea;
   1.151          }
   1.152          else
   1.153          {
   1.154              /* 32/64-bit ModR/M decode. */
   1.155 +            if ( modrm_rm == 4 )
   1.156 +            {
   1.157 +                sib = insn_fetch(uint8_t);
   1.158 +                sib_index = ((sib >> 3) & 7) | ((modrm << 2) & 8);
   1.159 +                sib_base  = (sib & 7) | ((modrm << 3) & 8);
   1.160 +                if ( sib_index != 4 )
   1.161 +                    ea = *(long *)decode_register(sib_index, &_regs, 0);
   1.162 +                ea <<= (sib >> 6) & 3;
   1.163 +                if ( (modrm_mod == 0) && ((sib_base & 7) == 5) )
   1.164 +                    ea += insn_fetch(uint32_t);
   1.165 +                else
   1.166 +                    ea += *(long *)decode_register(sib_base, &_regs, 0);
   1.167 +            }
   1.168 +            else
   1.169 +            {
   1.170 +                modrm_rm |= (rex_prefix & 1) << 3;
   1.171 +                ea = *(long *)decode_register(modrm_rm, &_regs, 0);
   1.172 +            }
   1.173              switch ( modrm_mod )
   1.174              {
   1.175              case 0:
   1.176 -                if ( (modrm_rm == 4) && 
   1.177 -                     (((sib = insn_fetch(uint8_t, 1)) & 7) == 5) )
   1.178 -                    _regs.eip += 4; /* skip disp32 specified by SIB.base */
   1.179 -                else if ( modrm_rm == 5 )
   1.180 -                    _regs.eip += 4; /* skip disp32 */
   1.181 +                if ( (modrm_rm & 7) != 5 )
   1.182 +                    break;
   1.183 +                ea = insn_fetch(uint32_t);
   1.184 +                if ( mode != X86EMUL_MODE_PROT64 )
   1.185 +                    break;
   1.186 +                /* Relative to RIP of next instruction. Argh! */
   1.187 +                ea += _regs.eip;
   1.188 +                if ( (d & SrcMask) == SrcImm )
   1.189 +                    ea += (d & ByteOp) ? 1 : op_bytes;
   1.190 +                else if ( (d & SrcMask) == SrcImmByte )
   1.191 +                    ea += 1;
   1.192 +                else if ( ((b == 0xf6) || (b == 0xf7)) &&
   1.193 +                          ((modrm_reg & 7) <= 1) )
   1.194 +                    /* Special case in Grp3: test has immediate operand. */
   1.195 +                    ea += (d & ByteOp) ? 1
   1.196 +                        : ((op_bytes == 8) ? 4 : op_bytes);
   1.197                  break;
   1.198 -            case 1:
   1.199 -                if ( modrm_rm == 4 )
   1.200 -                    sib = insn_fetch(uint8_t, 1);
   1.201 -                _regs.eip += 1; /* skip disp8 */
   1.202 -                break;
   1.203 -            case 2:
   1.204 -                if ( modrm_rm == 4 )
   1.205 -                    sib = insn_fetch(uint8_t, 1);
   1.206 -                _regs.eip += 4; /* skip disp32 */
   1.207 -                break;
   1.208 +            case 1: ea += insn_fetch(uint8_t);  break;
   1.209 +            case 2: ea += insn_fetch(uint32_t); break;
   1.210              }
   1.211 +            if ( ad_bytes == 4 )
   1.212 +                ea = (uint32_t)ea;
   1.213          }
   1.214 +
   1.215 +        page_boundary_test();
   1.216      }
   1.217  
   1.218      /* Decode and fetch the destination operand: register or memory. */
   1.219 @@ -692,16 +730,16 @@ x86_emulate_memop(
   1.220          /* NB. Immediates are sign-extended as necessary. */
   1.221          switch ( src.bytes )
   1.222          {
   1.223 -        case 1: src.val = insn_fetch(int8_t,  1); break;
   1.224 -        case 2: src.val = insn_fetch(int16_t, 2); break;
   1.225 -        case 4: src.val = insn_fetch(int32_t, 4); break;
   1.226 +        case 1: src.val = insn_fetch(int8_t);  break;
   1.227 +        case 2: src.val = insn_fetch(int16_t); break;
   1.228 +        case 4: src.val = insn_fetch(int32_t); break;
   1.229          }
   1.230          break;
   1.231      case SrcImmByte:
   1.232          src.type  = OP_IMM;
   1.233          src.ptr   = (unsigned long *)_regs.eip;
   1.234          src.bytes = 1;
   1.235 -        src.val   = insn_fetch(int8_t,  1);
   1.236 +        src.val   = insn_fetch(int8_t);
   1.237          break;
   1.238      }
   1.239  
   1.240 @@ -740,7 +778,7 @@ x86_emulate_memop(
   1.241          dst.val = (int32_t)src.val;
   1.242          break;
   1.243      case 0x80 ... 0x83: /* Grp1 */
   1.244 -        switch ( modrm_reg )
   1.245 +        switch ( modrm_reg & 7 )
   1.246          {
   1.247          case 0: goto add;
   1.248          case 1: goto or;
   1.249 @@ -771,11 +809,13 @@ x86_emulate_memop(
   1.250      case 0xa0 ... 0xa1: /* mov */
   1.251          dst.ptr = (unsigned long *)&_regs.eax;
   1.252          dst.val = src.val;
   1.253 -        _regs.eip += ad_bytes; /* skip src displacement */
   1.254 +        ea = _insn_fetch(ad_bytes); /* src effective address */
   1.255 +        page_boundary_test();
   1.256          break;
   1.257      case 0xa2 ... 0xa3: /* mov */
   1.258          dst.val = (unsigned long)_regs.eax;
   1.259 -        _regs.eip += ad_bytes; /* skip dst displacement */
   1.260 +        ea = _insn_fetch(ad_bytes); /* dst effective address */
   1.261 +        page_boundary_test();
   1.262          break;
   1.263      case 0x88 ... 0x8b: /* mov */
   1.264      case 0xc6 ... 0xc7: /* mov (sole member of Grp11) */
   1.265 @@ -798,7 +838,7 @@ x86_emulate_memop(
   1.266          register_address_increment(_regs.esp, dst.bytes);
   1.267          break;
   1.268      case 0xc0 ... 0xc1: grp2: /* Grp2 */
   1.269 -        switch ( modrm_reg )
   1.270 +        switch ( modrm_reg & 7 )
   1.271          {
   1.272          case 0: /* rol */
   1.273              emulate_2op_SrcB("rol", src, dst, _regs.eflags);
   1.274 @@ -831,7 +871,7 @@ x86_emulate_memop(
   1.275          src.val = _regs.ecx;
   1.276          goto grp2;
   1.277      case 0xf6 ... 0xf7: /* Grp3 */
   1.278 -        switch ( modrm_reg )
   1.279 +        switch ( modrm_reg & 7 )
   1.280          {
   1.281          case 0 ... 1: /* test */
   1.282              /* Special case in Grp3: test has an immediate source operand. */
   1.283 @@ -841,9 +881,9 @@ x86_emulate_memop(
   1.284              if ( src.bytes == 8 ) src.bytes = 4;
   1.285              switch ( src.bytes )
   1.286              {
   1.287 -            case 1: src.val = insn_fetch(int8_t,  1); break;
   1.288 -            case 2: src.val = insn_fetch(int16_t, 2); break;
   1.289 -            case 4: src.val = insn_fetch(int32_t, 4); break;
   1.290 +            case 1: src.val = insn_fetch(int8_t);  break;
   1.291 +            case 2: src.val = insn_fetch(int16_t); break;
   1.292 +            case 4: src.val = insn_fetch(int32_t); break;
   1.293              }
   1.294              goto test;
   1.295          case 2: /* not */
   1.296 @@ -857,7 +897,7 @@ x86_emulate_memop(
   1.297          }
   1.298          break;
   1.299      case 0xfe ... 0xff: /* Grp4/Grp5 */
   1.300 -        switch ( modrm_reg )
   1.301 +        switch ( modrm_reg & 7 )
   1.302          {
   1.303          case 0: /* inc */
   1.304              emulate_1op("inc", dst, _regs.eflags);
   1.305 @@ -955,6 +995,7 @@ x86_emulate_memop(
   1.306                                                        _regs.esi),
   1.307                                       &dst.val, dst.bytes, ctxt)) != 0 )
   1.308                  goto done;
   1.309 +            ea = _regs.edi & ((1UL << (ad_bytes*8)) - 1UL);
   1.310          }
   1.311          else
   1.312          {
   1.313 @@ -963,15 +1004,14 @@ x86_emulate_memop(
   1.314              if ( (rc = ops->read_emulated(cr2, &dst.val,
   1.315                                            dst.bytes, ctxt)) != 0 )
   1.316                  goto done;
   1.317 +            ea = _regs.esi & ((1UL << (ad_bytes*8)) - 1UL);
   1.318          }
   1.319          register_address_increment(
   1.320              _regs.esi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
   1.321          register_address_increment(
   1.322              _regs.edi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
   1.323 +        page_boundary_test();
   1.324          break;
   1.325 -    case 0xa6 ... 0xa7: /* cmps */
   1.326 -        dprintf("Urk! I don't handle CMPS.\n");
   1.327 -        goto cannot_emulate;
   1.328      case 0xaa ... 0xab: /* stos */
   1.329          dst.type  = OP_MEM;
   1.330          dst.bytes = (d & ByteOp) ? 1 : op_bytes;
   1.331 @@ -979,6 +1019,8 @@ x86_emulate_memop(
   1.332          dst.val   = _regs.eax;
   1.333          register_address_increment(
   1.334              _regs.edi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
   1.335 +        ea = _regs.edi & ((1UL << (ad_bytes*8)) - 1UL);
   1.336 +        page_boundary_test();
   1.337          break;
   1.338      case 0xac ... 0xad: /* lods */
   1.339          dst.type  = OP_REG;
   1.340 @@ -988,10 +1030,9 @@ x86_emulate_memop(
   1.341              goto done;
   1.342          register_address_increment(
   1.343              _regs.esi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
   1.344 +        ea = _regs.esi & ((1UL << (ad_bytes*8)) - 1UL);
   1.345 +        page_boundary_test();
   1.346          break;
   1.347 -    case 0xae ... 0xaf: /* scas */
   1.348 -        dprintf("Urk! I don't handle SCAS.\n");
   1.349 -        goto cannot_emulate;
   1.350      }
   1.351      goto writeback;
   1.352  
   1.353 @@ -1151,6 +1192,10 @@ x86_emulate_memop(
   1.354   cannot_emulate:
   1.355      dprintf("Cannot emulate %02x\n", b);
   1.356      return -1;
   1.357 +
   1.358 + bad_ea:
   1.359 +    dprintf("Access faulted on page boundary (cr2=%lx,ea=%lx).\n", cr2, ea);
   1.360 +    return -1;
   1.361  }
   1.362  
   1.363  #ifdef __XEN__