direct-io.hg

changeset 13335:f455a26a4170

[XEN] Fix/implement JMP/CALL/RET emulation.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Thu Jan 11 17:47:13 2007 +0000 (2007-01-11)
parents 66eba8d1b83a
children 77041741529c
files xen/arch/x86/x86_emulate.c
line diff
     1.1 --- a/xen/arch/x86/x86_emulate.c	Thu Jan 11 17:03:11 2007 +0000
     1.2 +++ b/xen/arch/x86/x86_emulate.c	Thu Jan 11 17:47:13 2007 +0000
     1.3 @@ -85,9 +85,11 @@ static uint8_t opcode_table[256] = {
     1.4      ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov,
     1.5      ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov,
     1.6      ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov,
     1.7 -    /* 0x60 - 0x6F */
     1.8 +    /* 0x60 - 0x67 */
     1.9      0, 0, 0, DstReg|SrcMem32|ModRM|Mov /* movsxd (x86/64) */,
    1.10 -    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    1.11 +    0, 0, 0, 0,
    1.12 +    /* 0x68 - 0x6F */
    1.13 +    ImplicitOps|Mov, 0, ImplicitOps|Mov, 0, 0, 0, 0, 0,
    1.14      /* 0x70 - 0x77 */
    1.15      ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
    1.16      ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
    1.17 @@ -125,7 +127,8 @@ static uint8_t opcode_table[256] = {
    1.18      DstReg|SrcImm|Mov, DstReg|SrcImm|Mov, DstReg|SrcImm|Mov, DstReg|SrcImm|Mov,
    1.19      DstReg|SrcImm|Mov, DstReg|SrcImm|Mov, DstReg|SrcImm|Mov, DstReg|SrcImm|Mov,
    1.20      /* 0xC0 - 0xC7 */
    1.21 -    ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImmByte|ModRM, 0, 0,
    1.22 +    ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImmByte|ModRM,
    1.23 +    ImplicitOps, ImplicitOps,
    1.24      0, 0, ByteOp|DstMem|SrcImm|ModRM|Mov, DstMem|SrcImm|ModRM|Mov,
    1.25      /* 0xC8 - 0xCF */
    1.26      0, 0, 0, 0, 0, 0, 0, 0,
    1.27 @@ -138,7 +141,7 @@ static uint8_t opcode_table[256] = {
    1.28      /* 0xE0 - 0xE7 */
    1.29      0, 0, 0, ImplicitOps, 0, 0, 0, 0,
    1.30      /* 0xE8 - 0xEF */
    1.31 -    0, ImplicitOps, 0, ImplicitOps, 0, 0, 0, 0,
    1.32 +    ImplicitOps, ImplicitOps, 0, ImplicitOps, 0, 0, 0, 0,
    1.33      /* 0xF0 - 0xF7 */
    1.34      0, 0, 0, 0,
    1.35      0, ImplicitOps, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|ModRM,
    1.36 @@ -1110,6 +1113,20 @@ x86_emulate(
    1.37          case 1: /* dec */
    1.38              emulate_1op("dec", dst, _regs.eflags);
    1.39              break;
    1.40 +        case 2: /* call (near) */
    1.41 +        case 3: /* jmp (near) */
    1.42 +            if ( ((op_bytes = dst.bytes) != 8) && mode_64bit() )
    1.43 +            {
    1.44 +                dst.bytes = op_bytes = 8;
    1.45 +                if ( (rc = ops->read(dst.mem.seg, dst.mem.off,
    1.46 +                                     &dst.val, 8, ctxt)) != 0 )
    1.47 +                    goto done;
    1.48 +            }
    1.49 +            src.val = _regs.eip;
    1.50 +            _regs.eip = dst.val;
    1.51 +            if ( (modrm_reg & 7) == 2 )
    1.52 +                goto push; /* call */
    1.53 +            break;
    1.54          case 6: /* push */
    1.55              /* 64-bit mode: PUSH defaults to a 64-bit operand. */
    1.56              if ( mode_64bit() && (dst.bytes == 4) )
    1.57 @@ -1264,16 +1281,9 @@ x86_emulate(
    1.58          break;
    1.59  
    1.60      case 0x50 ... 0x57: /* push reg */
    1.61 -        dst.type  = OP_MEM;
    1.62 -        dst.bytes = op_bytes;
    1.63 -        if ( mode_64bit() && (dst.bytes == 4) )
    1.64 -            dst.bytes = 8;
    1.65 -        dst.val = *(unsigned long *)decode_register(
    1.66 +        src.val = *(unsigned long *)decode_register(
    1.67              (b & 7) | ((rex_prefix & 1) << 3), &_regs, 0);
    1.68 -        register_address_increment(_regs.esp, -dst.bytes);
    1.69 -        dst.mem.seg = x86_seg_ss;
    1.70 -        dst.mem.off = truncate_ea(_regs.esp);
    1.71 -        break;
    1.72 +        goto push;
    1.73  
    1.74      case 0x58 ... 0x5f: /* pop reg */
    1.75          dst.type  = OP_REG;
    1.76 @@ -1288,6 +1298,26 @@ x86_emulate(
    1.77          register_address_increment(_regs.esp, dst.bytes);
    1.78          break;
    1.79  
    1.80 +    case 0x68: /* push imm{16,32,64} */
    1.81 +        src.val = ((op_bytes == 2)
    1.82 +                   ? (int32_t)insn_fetch_type(int16_t)
    1.83 +                   : insn_fetch_type(int32_t));
    1.84 +        goto push;
    1.85 +
    1.86 +    case 0x6a: /* push imm8 */
    1.87 +        src.val = insn_fetch_type(int8_t);
    1.88 +    push:
    1.89 +        d |= Mov; /* force writeback */
    1.90 +        dst.type  = OP_MEM;
    1.91 +        dst.bytes = op_bytes;
    1.92 +        if ( mode_64bit() && (dst.bytes == 4) )
    1.93 +            dst.bytes = 8;
    1.94 +        dst.val = src.val;
    1.95 +        register_address_increment(_regs.esp, -dst.bytes);
    1.96 +        dst.mem.seg = x86_seg_ss;
    1.97 +        dst.mem.off = truncate_ea(_regs.esp);
    1.98 +        break;
    1.99 +
   1.100      case 0x70 ... 0x7f: /* jcc (short) */ {
   1.101          int rel = insn_fetch_type(int8_t);
   1.102          if ( test_cc(b, _regs.eflags) )
   1.103 @@ -1371,6 +1401,18 @@ x86_emulate(
   1.104              _regs.esi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
   1.105          break;
   1.106  
   1.107 +    case 0xc2: /* ret imm16 (near) */
   1.108 +    case 0xc3: /* ret (near) */ {
   1.109 +        int offset = (b == 0xc2) ? insn_fetch_type(uint16_t) : 0;
   1.110 +        op_bytes = mode_64bit() ? 8 : op_bytes;
   1.111 +        if ( (rc = ops->read(x86_seg_ss, truncate_ea(_regs.esp),
   1.112 +                             &dst.val, op_bytes, ctxt)) != 0 )
   1.113 +            goto done;
   1.114 +        _regs.eip = dst.val;
   1.115 +        register_address_increment(_regs.esp, op_bytes + offset);
   1.116 +        break;
   1.117 +    }
   1.118 +
   1.119      case 0xd4: /* aam */ {
   1.120          unsigned int base = insn_fetch_type(uint8_t);
   1.121          uint8_t al = _regs.eax;
   1.122 @@ -1418,12 +1460,26 @@ x86_emulate(
   1.123          break;
   1.124      }
   1.125  
   1.126 -    case 0xe9: /* jmp (short) */
   1.127 -        jmp_rel(insn_fetch_type(int8_t));
   1.128 +    case 0xe8: /* call (near) */ {
   1.129 +        int rel = (((op_bytes == 2) && !mode_64bit())
   1.130 +                   ? (int32_t)insn_fetch_type(int16_t)
   1.131 +                   : insn_fetch_type(int32_t));
   1.132 +        op_bytes = mode_64bit() ? 8 : op_bytes;
   1.133 +        src.val = _regs.eip;
   1.134 +        jmp_rel(rel);
   1.135 +        goto push;
   1.136 +    }
   1.137 +
   1.138 +    case 0xe9: /* jmp (near) */ {
   1.139 +        int rel = (((op_bytes == 2) && !mode_64bit())
   1.140 +                   ? (int32_t)insn_fetch_type(int16_t)
   1.141 +                   : insn_fetch_type(int32_t));
   1.142 +        jmp_rel(rel);
   1.143          break;
   1.144 +    }
   1.145  
   1.146 -    case 0xeb: /* jmp (near) */
   1.147 -        jmp_rel(insn_fetch_bytes(mode_64bit() ? 4 : op_bytes));
   1.148 +    case 0xeb: /* jmp (short) */
   1.149 +        jmp_rel(insn_fetch_type(int8_t));
   1.150          break;
   1.151  
   1.152      case 0xf5: /* cmc */
   1.153 @@ -1550,7 +1606,9 @@ x86_emulate(
   1.154          break;
   1.155  
   1.156      case 0x80 ... 0x8f: /* jcc (near) */ {
   1.157 -        int rel = insn_fetch_bytes(mode_64bit() ? 4 : op_bytes);
   1.158 +        int rel = (((op_bytes == 2) && !mode_64bit())
   1.159 +                   ? (int32_t)insn_fetch_type(int16_t)
   1.160 +                   : insn_fetch_type(int32_t));
   1.161          if ( test_cc(b, _regs.eflags) )
   1.162              jmp_rel(rel);
   1.163          break;