ia64/xen-unstable

annotate xen/arch/x86/x86_emulate.c @ 16478:c5332fa8b68d

x86_emulate: Emulate RETF and RETF imm16.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Nov 26 16:46:22 2007 +0000 (2007-11-26)
parents 9f61a0add5b6
children f676c0dacbb9
rev   line source
kaf24@4047 1 /******************************************************************************
kaf24@4047 2 * x86_emulate.c
kaf24@4047 3 *
kaf24@4047 4 * Generic x86 (32-bit and 64-bit) instruction decoder and emulator.
kaf24@4047 5 *
kaf24@13426 6 * Copyright (c) 2005-2007 Keir Fraser
kfraser@13620 7 * Copyright (c) 2005-2007 XenSource Inc.
kaf24@13426 8 *
kaf24@13426 9 * This program is free software; you can redistribute it and/or modify
kaf24@13426 10 * it under the terms of the GNU General Public License as published by
kaf24@13426 11 * the Free Software Foundation; either version 2 of the License, or
kaf24@13426 12 * (at your option) any later version.
kaf24@13426 13 *
kaf24@13426 14 * This program is distributed in the hope that it will be useful,
kaf24@13426 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
kaf24@13426 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
kaf24@13426 17 * GNU General Public License for more details.
kaf24@13426 18 *
kaf24@13426 19 * You should have received a copy of the GNU General Public License
kaf24@13426 20 * along with this program; if not, write to the Free Software
kaf24@13426 21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
kaf24@4047 22 */
kaf24@4047 23
kaf24@10096 24 #ifndef __XEN__
kfraser@12726 25 #include <stddef.h>
kaf24@4047 26 #include <stdint.h>
kaf24@4047 27 #include <public/xen.h>
kaf24@4047 28 #else
kaf24@4047 29 #include <xen/config.h>
kaf24@4047 30 #include <xen/types.h>
kaf24@4047 31 #include <xen/lib.h>
kaf24@4047 32 #include <asm/regs.h>
kfraser@12675 33 #undef cmpxchg
kaf24@4047 34 #endif
kaf24@4047 35 #include <asm-x86/x86_emulate.h>
kaf24@4047 36
kaf24@4047 37 /* Operand sizes: 8-bit operands or specified/overridden size. */
kaf24@4047 38 #define ByteOp (1<<0) /* 8-bit operands. */
kaf24@4047 39 /* Destination operand type. */
kfraser@12675 40 #define DstBitBase (0<<1) /* Memory operand, bit string. */
kaf24@4047 41 #define ImplicitOps (1<<1) /* Implicit in opcode. No generic decode. */
kaf24@4047 42 #define DstReg (2<<1) /* Register operand. */
kaf24@4047 43 #define DstMem (3<<1) /* Memory operand. */
kaf24@4047 44 #define DstMask (3<<1)
kaf24@4047 45 /* Source operand type. */
kaf24@4047 46 #define SrcNone (0<<3) /* No source operand. */
kaf24@4047 47 #define SrcImplicit (0<<3) /* Source operand is implicit in the opcode. */
kaf24@4047 48 #define SrcReg (1<<3) /* Register operand. */
kaf24@4047 49 #define SrcMem (2<<3) /* Memory operand. */
kaf24@8423 50 #define SrcMem16 (3<<3) /* Memory operand (16-bit). */
kaf24@13428 51 #define SrcImm (4<<3) /* Immediate operand. */
kaf24@13428 52 #define SrcImmByte (5<<3) /* 8-bit sign-extended immediate operand. */
kaf24@4047 53 #define SrcMask (7<<3)
kaf24@4047 54 /* Generic ModRM decode. */
kaf24@4047 55 #define ModRM (1<<6)
kaf24@4047 56 /* Destination is only written; never read. */
kaf24@4047 57 #define Mov (1<<7)
kaf24@4047 58
kaf24@8423 59 static uint8_t opcode_table[256] = {
kaf24@4047 60 /* 0x00 - 0x07 */
kaf24@4047 61 ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
kaf24@4047 62 ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
keir@16454 63 ByteOp|DstReg|SrcImm, DstReg|SrcImm, ImplicitOps, ImplicitOps,
kaf24@4047 64 /* 0x08 - 0x0F */
kaf24@4047 65 ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
kaf24@4047 66 ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
keir@16454 67 ByteOp|DstReg|SrcImm, DstReg|SrcImm, ImplicitOps, 0,
kaf24@4047 68 /* 0x10 - 0x17 */
kaf24@4047 69 ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
kaf24@4047 70 ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
keir@16454 71 ByteOp|DstReg|SrcImm, DstReg|SrcImm, ImplicitOps, ImplicitOps,
kaf24@4047 72 /* 0x18 - 0x1F */
kaf24@4047 73 ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
kaf24@4047 74 ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
keir@16454 75 ByteOp|DstReg|SrcImm, DstReg|SrcImm, ImplicitOps, ImplicitOps,
kaf24@4047 76 /* 0x20 - 0x27 */
kaf24@4047 77 ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
kaf24@4047 78 ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
kfraser@13334 79 ByteOp|DstReg|SrcImm, DstReg|SrcImm, 0, ImplicitOps,
kaf24@4047 80 /* 0x28 - 0x2F */
kaf24@4047 81 ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
kaf24@4047 82 ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
kfraser@13334 83 ByteOp|DstReg|SrcImm, DstReg|SrcImm, 0, ImplicitOps,
kaf24@4047 84 /* 0x30 - 0x37 */
kaf24@4047 85 ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
kaf24@4047 86 ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
kfraser@13334 87 ByteOp|DstReg|SrcImm, DstReg|SrcImm, 0, ImplicitOps,
kaf24@4047 88 /* 0x38 - 0x3F */
kaf24@4047 89 ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
kaf24@4047 90 ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
kfraser@13334 91 ByteOp|DstReg|SrcImm, DstReg|SrcImm, 0, ImplicitOps,
kaf24@4047 92 /* 0x40 - 0x4F */
kfraser@13265 93 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
kfraser@13265 94 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
kfraser@13265 95 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
kfraser@13265 96 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
kaf24@4047 97 /* 0x50 - 0x5F */
kfraser@13265 98 ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov,
kfraser@13265 99 ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov,
kfraser@13265 100 ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov,
kfraser@13265 101 ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov,
kfraser@13388 102 /* 0x60 - 0x67 */
kaf24@13428 103 ImplicitOps, ImplicitOps, DstReg|SrcMem|ModRM, DstReg|SrcMem16|ModRM|Mov,
kfraser@13388 104 0, 0, 0, 0,
kfraser@13388 105 /* 0x68 - 0x6F */
kaf24@13426 106 ImplicitOps|Mov, DstMem|SrcImm|ModRM|Mov,
kaf24@13426 107 ImplicitOps|Mov, DstMem|SrcImmByte|ModRM|Mov,
kfraser@13624 108 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
kfraser@13328 109 /* 0x70 - 0x77 */
kfraser@13328 110 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
kfraser@13328 111 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
kfraser@13328 112 /* 0x78 - 0x7F */
kfraser@13328 113 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
kfraser@13328 114 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
kaf24@4047 115 /* 0x80 - 0x87 */
kaf24@4047 116 ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImm|ModRM,
kaf24@4047 117 ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImmByte|ModRM,
kaf24@4047 118 ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
kaf24@4047 119 ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
kaf24@4047 120 /* 0x88 - 0x8F */
kfraser@10312 121 ByteOp|DstMem|SrcReg|ModRM|Mov, DstMem|SrcReg|ModRM|Mov,
kfraser@10312 122 ByteOp|DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
keir@16454 123 DstMem|SrcReg|ModRM|Mov, DstReg|SrcNone|ModRM,
keir@16454 124 DstReg|SrcMem|ModRM|Mov, DstMem|SrcNone|ModRM|Mov,
kfraser@13282 125 /* 0x90 - 0x97 */
kfraser@13282 126 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
kfraser@13282 127 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
kfraser@13282 128 /* 0x98 - 0x9F */
keir@16461 129 ImplicitOps, ImplicitOps, ImplicitOps, 0,
keir@16463 130 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
kaf24@4047 131 /* 0xA0 - 0xA7 */
kfraser@12675 132 ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,
kfraser@12675 133 ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,
keir@16465 134 ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,
keir@16465 135 ByteOp|ImplicitOps, ImplicitOps,
kaf24@4047 136 /* 0xA8 - 0xAF */
kfraser@13334 137 ByteOp|DstReg|SrcImm, DstReg|SrcImm,
kfraser@13334 138 ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,
keir@16465 139 ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,
keir@16465 140 ByteOp|ImplicitOps, ImplicitOps,
kaf24@13321 141 /* 0xB0 - 0xB7 */
kaf24@13321 142 ByteOp|DstReg|SrcImm|Mov, ByteOp|DstReg|SrcImm|Mov,
kaf24@13321 143 ByteOp|DstReg|SrcImm|Mov, ByteOp|DstReg|SrcImm|Mov,
kaf24@13321 144 ByteOp|DstReg|SrcImm|Mov, ByteOp|DstReg|SrcImm|Mov,
kaf24@13321 145 ByteOp|DstReg|SrcImm|Mov, ByteOp|DstReg|SrcImm|Mov,
kaf24@13321 146 /* 0xB8 - 0xBF */
kaf24@13321 147 DstReg|SrcImm|Mov, DstReg|SrcImm|Mov, DstReg|SrcImm|Mov, DstReg|SrcImm|Mov,
kaf24@13321 148 DstReg|SrcImm|Mov, DstReg|SrcImm|Mov, DstReg|SrcImm|Mov, DstReg|SrcImm|Mov,
kaf24@4047 149 /* 0xC0 - 0xC7 */
kfraser@13388 150 ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImmByte|ModRM,
kfraser@13388 151 ImplicitOps, ImplicitOps,
keir@16467 152 DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
keir@16467 153 ByteOp|DstMem|SrcImm|ModRM|Mov, DstMem|SrcImm|ModRM|Mov,
kaf24@4047 154 /* 0xC8 - 0xCF */
keir@16478 155 0, 0, ImplicitOps, ImplicitOps,
keir@16478 156 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
kaf24@4047 157 /* 0xD0 - 0xD7 */
kaf24@4047 158 ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM,
kaf24@4047 159 ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM,
kfraser@13334 160 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
kaf24@4047 161 /* 0xD8 - 0xDF */
kaf24@4047 162 0, 0, 0, 0, 0, 0, 0, 0,
kfraser@13328 163 /* 0xE0 - 0xE7 */
kfraser@13624 164 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
kfraser@13624 165 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
kfraser@13328 166 /* 0xE8 - 0xEF */
keir@16454 167 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
kfraser@13624 168 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
kaf24@4047 169 /* 0xF0 - 0xF7 */
keir@16462 170 0, ImplicitOps, 0, 0,
keir@16468 171 ImplicitOps, ImplicitOps,
keir@16468 172 ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|ModRM,
kaf24@4047 173 /* 0xF8 - 0xFF */
kfraser@13623 174 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
kfraser@13282 175 ImplicitOps, ImplicitOps, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|ModRM
kaf24@4047 176 };
kaf24@4047 177
kaf24@8423 178 static uint8_t twobyte_table[256] = {
kfraser@13623 179 /* 0x00 - 0x07 */
keir@16454 180 0, ImplicitOps|ModRM, 0, 0, 0, ImplicitOps, 0, 0,
kfraser@13623 181 /* 0x08 - 0x0F */
kfraser@13623 182 ImplicitOps, ImplicitOps, 0, 0, 0, ImplicitOps|ModRM, 0, 0,
kaf24@13429 183 /* 0x10 - 0x17 */
kaf24@13429 184 0, 0, 0, 0, 0, 0, 0, 0,
kaf24@13429 185 /* 0x18 - 0x1F */
kaf24@13429 186 ImplicitOps|ModRM, ImplicitOps|ModRM, ImplicitOps|ModRM, ImplicitOps|ModRM,
kaf24@13429 187 ImplicitOps|ModRM, ImplicitOps|ModRM, ImplicitOps|ModRM, ImplicitOps|ModRM,
kfraser@13623 188 /* 0x20 - 0x27 */
kfraser@13623 189 ImplicitOps|ModRM, ImplicitOps|ModRM, ImplicitOps|ModRM, ImplicitOps|ModRM,
kfraser@13623 190 0, 0, 0, 0,
kfraser@13623 191 /* 0x28 - 0x2F */
kfraser@13623 192 0, 0, 0, 0, 0, 0, 0, 0,
kfraser@13623 193 /* 0x30 - 0x37 */
kfraser@13623 194 ImplicitOps, 0, ImplicitOps, 0, 0, 0, 0, 0,
kfraser@13623 195 /* 0x38 - 0x3F */
kfraser@13623 196 0, 0, 0, 0, 0, 0, 0, 0,
kaf24@4047 197 /* 0x40 - 0x47 */
kaf24@4047 198 DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
kaf24@4047 199 DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
kaf24@4047 200 DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
kaf24@4047 201 DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
kaf24@4047 202 /* 0x48 - 0x4F */
kaf24@4047 203 DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
kaf24@4047 204 DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
kaf24@4047 205 DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
kaf24@4047 206 DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
kaf24@4047 207 /* 0x50 - 0x5F */
kaf24@4047 208 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
kaf24@4047 209 /* 0x60 - 0x6F */
kaf24@4047 210 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
kaf24@4047 211 /* 0x70 - 0x7F */
kaf24@4047 212 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
kfraser@13328 213 /* 0x80 - 0x87 */
kfraser@13328 214 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
kfraser@13328 215 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
kfraser@13328 216 /* 0x88 - 0x8F */
kfraser@13328 217 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
kfraser@13328 218 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
kfraser@13383 219 /* 0x90 - 0x97 */
kfraser@13383 220 ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
kfraser@13383 221 ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
kfraser@13383 222 ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
kfraser@13383 223 ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
kfraser@13383 224 /* 0x98 - 0x9F */
kfraser@13383 225 ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
kfraser@13383 226 ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
kfraser@13383 227 ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
kfraser@13383 228 ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
kaf24@4047 229 /* 0xA0 - 0xA7 */
keir@16468 230 ImplicitOps, ImplicitOps, ImplicitOps, DstBitBase|SrcReg|ModRM,
keir@16468 231 0, 0, 0, 0,
kaf24@4047 232 /* 0xA8 - 0xAF */
keir@16454 233 ImplicitOps, ImplicitOps, 0, DstBitBase|SrcReg|ModRM,
keir@16454 234 0, 0, 0, DstReg|SrcMem|ModRM,
kaf24@4047 235 /* 0xB0 - 0xB7 */
kfraser@12675 236 ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
keir@16467 237 DstReg|SrcMem|ModRM|Mov, DstBitBase|SrcReg|ModRM,
keir@16467 238 DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
keir@16467 239 ByteOp|DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem16|ModRM|Mov,
kaf24@4047 240 /* 0xB8 - 0xBF */
kfraser@12675 241 0, 0, DstBitBase|SrcImmByte|ModRM, DstBitBase|SrcReg|ModRM,
kaf24@13430 242 DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
kaf24@13430 243 ByteOp|DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem16|ModRM|Mov,
kfraser@12746 244 /* 0xC0 - 0xC7 */
kfraser@12746 245 ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, 0, 0,
kfraser@12746 246 0, 0, 0, ImplicitOps|ModRM,
kfraser@12746 247 /* 0xC8 - 0xCF */
kfraser@13383 248 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
kfraser@13383 249 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
kaf24@4047 250 /* 0xD0 - 0xDF */
kaf24@4047 251 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
kaf24@4047 252 /* 0xE0 - 0xEF */
kaf24@4047 253 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
kaf24@4047 254 /* 0xF0 - 0xFF */
kaf24@4047 255 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
kaf24@4047 256 };
kaf24@4047 257
kaf24@4047 258 /* Type, address-of, and value of an instruction's operand. */
kaf24@4047 259 struct operand {
kfraser@13383 260 enum { OP_REG, OP_MEM, OP_IMM, OP_NONE } type;
kaf24@4047 261 unsigned int bytes;
kfraser@12675 262 unsigned long val, orig_val;
kfraser@13145 263 union {
kfraser@13145 264 /* OP_REG: Pointer to register field. */
kfraser@13145 265 unsigned long *reg;
kfraser@13145 266 /* OP_MEM: Segment and offset. */
kfraser@13145 267 struct {
kfraser@13145 268 enum x86_segment seg;
kfraser@13145 269 unsigned long off;
kfraser@13145 270 } mem;
kfraser@13145 271 };
kaf24@4047 272 };
kaf24@4047 273
kaf24@4047 274 /* EFLAGS bit definitions. */
keir@16463 275 #define EFLG_VIP (1<<20)
keir@16463 276 #define EFLG_VIF (1<<19)
keir@16463 277 #define EFLG_AC (1<<18)
keir@16463 278 #define EFLG_VM (1<<17)
keir@16463 279 #define EFLG_RF (1<<16)
keir@16463 280 #define EFLG_NT (1<<14)
keir@16463 281 #define EFLG_IOPL (3<<12)
keir@16463 282 #define EFLG_OF (1<<11)
keir@16463 283 #define EFLG_DF (1<<10)
keir@16463 284 #define EFLG_IF (1<<9)
keir@16463 285 #define EFLG_TF (1<<8)
keir@16463 286 #define EFLG_SF (1<<7)
keir@16463 287 #define EFLG_ZF (1<<6)
keir@16463 288 #define EFLG_AF (1<<4)
keir@16463 289 #define EFLG_PF (1<<2)
keir@16463 290 #define EFLG_CF (1<<0)
kaf24@4047 291
kfraser@13334 292 /* Exception definitions. */
kfraser@13380 293 #define EXC_DE 0
keir@16462 294 #define EXC_DB 1
keir@16462 295 #define EXC_BP 3
keir@16462 296 #define EXC_OF 4
kaf24@13428 297 #define EXC_BR 5
kaf24@13428 298 #define EXC_UD 6
kfraser@13380 299 #define EXC_GP 13
kfraser@13334 300
kaf24@4047 301 /*
kaf24@4047 302 * Instruction emulation:
kaf24@4047 303 * Most instructions are emulated directly via a fragment of inline assembly
kaf24@4047 304 * code. This allows us to save/restore EFLAGS and thus very easily pick up
kaf24@4047 305 * any modified flags.
kaf24@4047 306 */
kaf24@4047 307
kaf24@4047 308 #if defined(__x86_64__)
kaf24@4047 309 #define _LO32 "k" /* force 32-bit operand */
kaf24@4047 310 #define _STK "%%rsp" /* stack pointer */
keir@16309 311 #define _BYTES_PER_LONG "8"
kaf24@4047 312 #elif defined(__i386__)
kaf24@4047 313 #define _LO32 "" /* force 32-bit operand */
kaf24@4047 314 #define _STK "%%esp" /* stack pointer */
keir@16309 315 #define _BYTES_PER_LONG "4"
kaf24@4047 316 #endif
kaf24@4047 317
kaf24@4047 318 /*
kaf24@4047 319 * These EFLAGS bits are restored from saved value during emulation, and
kaf24@4047 320 * any changes are written back to the saved value after emulation.
kaf24@4047 321 */
kaf24@4047 322 #define EFLAGS_MASK (EFLG_OF|EFLG_SF|EFLG_ZF|EFLG_AF|EFLG_PF|EFLG_CF)
kaf24@4047 323
kaf24@4047 324 /* Before executing instruction: restore necessary bits in EFLAGS. */
keir@16164 325 #define _PRE_EFLAGS(_sav, _msk, _tmp) \
keir@16164 326 /* EFLAGS = (_sav & _msk) | (EFLAGS & ~_msk); _sav &= ~_msk; */ \
keir@16164 327 "movl %"_sav",%"_LO32 _tmp"; " \
keir@16164 328 "push %"_tmp"; " \
keir@16164 329 "push %"_tmp"; " \
keir@16164 330 "movl %"_msk",%"_LO32 _tmp"; " \
keir@16164 331 "andl %"_LO32 _tmp",("_STK"); " \
keir@16164 332 "pushf; " \
keir@16164 333 "notl %"_LO32 _tmp"; " \
keir@16164 334 "andl %"_LO32 _tmp",("_STK"); " \
keir@16309 335 "andl %"_LO32 _tmp",2*"_BYTES_PER_LONG"("_STK"); " \
keir@16164 336 "pop %"_tmp"; " \
keir@16164 337 "orl %"_LO32 _tmp",("_STK"); " \
keir@16164 338 "popf; " \
keir@16164 339 "pop %"_sav"; "
kaf24@4047 340
kaf24@4047 341 /* After executing instruction: write-back necessary bits in EFLAGS. */
kaf24@4047 342 #define _POST_EFLAGS(_sav, _msk, _tmp) \
kaf24@4211 343 /* _sav |= EFLAGS & _msk; */ \
kaf24@4047 344 "pushf; " \
kaf24@4047 345 "pop %"_tmp"; " \
kaf24@4047 346 "andl %"_msk",%"_LO32 _tmp"; " \
kaf24@4047 347 "orl %"_LO32 _tmp",%"_sav"; "
kaf24@4047 348
kaf24@4047 349 /* Raw emulation: instruction has two explicit operands. */
kaf24@4047 350 #define __emulate_2op_nobyte(_op,_src,_dst,_eflags,_wx,_wy,_lx,_ly,_qx,_qy)\
kaf24@4047 351 do{ unsigned long _tmp; \
kaf24@4047 352 switch ( (_dst).bytes ) \
kaf24@4047 353 { \
kaf24@4047 354 case 2: \
kfraser@15872 355 asm volatile ( \
kaf24@4047 356 _PRE_EFLAGS("0","4","2") \
kaf24@4047 357 _op"w %"_wx"3,%1; " \
kaf24@4047 358 _POST_EFLAGS("0","4","2") \
kaf24@4047 359 : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \
kaf24@13430 360 : _wy ((_src).val), "i" (EFLAGS_MASK), \
kaf24@13430 361 "m" (_eflags), "m" ((_dst).val) ); \
kaf24@4047 362 break; \
kaf24@4047 363 case 4: \
kfraser@15872 364 asm volatile ( \
kaf24@4047 365 _PRE_EFLAGS("0","4","2") \
kaf24@4047 366 _op"l %"_lx"3,%1; " \
kaf24@4047 367 _POST_EFLAGS("0","4","2") \
kaf24@4047 368 : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \
kaf24@13430 369 : _ly ((_src).val), "i" (EFLAGS_MASK), \
kaf24@13430 370 "m" (_eflags), "m" ((_dst).val) ); \
kaf24@4047 371 break; \
kaf24@4047 372 case 8: \
kaf24@4047 373 __emulate_2op_8byte(_op, _src, _dst, _eflags, _qx, _qy); \
kaf24@4047 374 break; \
kaf24@4047 375 } \
kaf24@4047 376 } while (0)
kaf24@4047 377 #define __emulate_2op(_op,_src,_dst,_eflags,_bx,_by,_wx,_wy,_lx,_ly,_qx,_qy)\
kaf24@4047 378 do{ unsigned long _tmp; \
kaf24@4047 379 switch ( (_dst).bytes ) \
kaf24@4047 380 { \
kaf24@4047 381 case 1: \
kfraser@15872 382 asm volatile ( \
kaf24@4047 383 _PRE_EFLAGS("0","4","2") \
kaf24@4047 384 _op"b %"_bx"3,%1; " \
kaf24@4047 385 _POST_EFLAGS("0","4","2") \
kaf24@4047 386 : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \
kaf24@13430 387 : _by ((_src).val), "i" (EFLAGS_MASK), \
kaf24@13430 388 "m" (_eflags), "m" ((_dst).val) ); \
kaf24@4047 389 break; \
kaf24@4047 390 default: \
kaf24@4047 391 __emulate_2op_nobyte(_op,_src,_dst,_eflags,_wx,_wy,_lx,_ly,_qx,_qy);\
kaf24@4047 392 break; \
kaf24@4047 393 } \
kaf24@4047 394 } while (0)
kaf24@4047 395 /* Source operand is byte-sized and may be restricted to just %cl. */
kaf24@4047 396 #define emulate_2op_SrcB(_op, _src, _dst, _eflags) \
kaf24@4047 397 __emulate_2op(_op, _src, _dst, _eflags, \
kaf24@4047 398 "b", "c", "b", "c", "b", "c", "b", "c")
kaf24@4047 399 /* Source operand is byte, word, long or quad sized. */
kaf24@4047 400 #define emulate_2op_SrcV(_op, _src, _dst, _eflags) \
kaf24@4047 401 __emulate_2op(_op, _src, _dst, _eflags, \
kaf24@4047 402 "b", "q", "w", "r", _LO32, "r", "", "r")
kaf24@4047 403 /* Source operand is word, long or quad sized. */
kaf24@4047 404 #define emulate_2op_SrcV_nobyte(_op, _src, _dst, _eflags) \
kaf24@4047 405 __emulate_2op_nobyte(_op, _src, _dst, _eflags, \
kaf24@4047 406 "w", "r", _LO32, "r", "", "r")
kaf24@4047 407
kaf24@4047 408 /* Instruction has only one explicit operand (no source operand). */
kaf24@4047 409 #define emulate_1op(_op,_dst,_eflags) \
kaf24@4047 410 do{ unsigned long _tmp; \
kaf24@4047 411 switch ( (_dst).bytes ) \
kaf24@4047 412 { \
kaf24@4047 413 case 1: \
kfraser@15872 414 asm volatile ( \
kaf24@4047 415 _PRE_EFLAGS("0","3","2") \
kaf24@4047 416 _op"b %1; " \
kaf24@4047 417 _POST_EFLAGS("0","3","2") \
kaf24@4047 418 : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \
kaf24@13430 419 : "i" (EFLAGS_MASK), "m" (_eflags), "m" ((_dst).val) ); \
kaf24@4047 420 break; \
kaf24@4047 421 case 2: \
kfraser@15872 422 asm volatile ( \
kaf24@4047 423 _PRE_EFLAGS("0","3","2") \
kaf24@4047 424 _op"w %1; " \
kaf24@4047 425 _POST_EFLAGS("0","3","2") \
kaf24@4047 426 : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \
kaf24@13430 427 : "i" (EFLAGS_MASK), "m" (_eflags), "m" ((_dst).val) ); \
kaf24@4047 428 break; \
kaf24@4047 429 case 4: \
kfraser@15872 430 asm volatile ( \
kaf24@4047 431 _PRE_EFLAGS("0","3","2") \
kaf24@4047 432 _op"l %1; " \
kaf24@4047 433 _POST_EFLAGS("0","3","2") \
kaf24@4047 434 : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \
kaf24@13430 435 : "i" (EFLAGS_MASK), "m" (_eflags), "m" ((_dst).val) ); \
kaf24@4047 436 break; \
kaf24@4047 437 case 8: \
kaf24@4047 438 __emulate_1op_8byte(_op, _dst, _eflags); \
kaf24@4047 439 break; \
kaf24@4047 440 } \
kaf24@4047 441 } while (0)
kaf24@4047 442
kaf24@4047 443 /* Emulate an instruction with quadword operands (x86/64 only). */
kaf24@4047 444 #if defined(__x86_64__)
kaf24@4047 445 #define __emulate_2op_8byte(_op, _src, _dst, _eflags, _qx, _qy) \
kfraser@15872 446 do{ asm volatile ( \
kaf24@4047 447 _PRE_EFLAGS("0","4","2") \
kaf24@4047 448 _op"q %"_qx"3,%1; " \
kaf24@4047 449 _POST_EFLAGS("0","4","2") \
kaf24@4047 450 : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \
kaf24@13430 451 : _qy ((_src).val), "i" (EFLAGS_MASK), \
kaf24@13430 452 "m" (_eflags), "m" ((_dst).val) ); \
kaf24@4047 453 } while (0)
kaf24@4047 454 #define __emulate_1op_8byte(_op, _dst, _eflags) \
kfraser@15872 455 do{ asm volatile ( \
kaf24@4047 456 _PRE_EFLAGS("0","3","2") \
kaf24@4047 457 _op"q %1; " \
kaf24@4047 458 _POST_EFLAGS("0","3","2") \
kaf24@4047 459 : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \
kaf24@13430 460 : "i" (EFLAGS_MASK), "m" (_eflags), "m" ((_dst).val) ); \
kaf24@4047 461 } while (0)
kaf24@4047 462 #elif defined(__i386__)
kaf24@4047 463 #define __emulate_2op_8byte(_op, _src, _dst, _eflags, _qx, _qy)
kaf24@4047 464 #define __emulate_1op_8byte(_op, _dst, _eflags)
kaf24@4047 465 #endif /* __i386__ */
kaf24@4047 466
kaf24@4047 467 /* Fetch next part of the instruction being emulated. */
kaf24@12769 468 #define insn_fetch_bytes(_size) \
kfraser@13380 469 ({ unsigned long _x, _eip = _regs.eip; \
kfraser@13331 470 if ( !mode_64bit() ) _eip = (uint32_t)_eip; /* ignore upper dword */ \
kfraser@13380 471 _regs.eip += (_size); /* real hardware doesn't truncate */ \
kfraser@13380 472 generate_exception_if((uint8_t)(_regs.eip - ctxt->regs->eip) > 15, \
kfraser@13380 473 EXC_GP); \
kfraser@13328 474 rc = ops->insn_fetch(x86_seg_cs, _eip, &_x, (_size), ctxt); \
kfraser@13331 475 if ( rc ) goto done; \
kaf24@12769 476 _x; \
kaf24@4047 477 })
kaf24@12769 478 #define insn_fetch_type(_type) ((_type)insn_fetch_bytes(sizeof(_type)))
kaf24@4047 479
kfraser@13443 480 #define _truncate_ea(ea, byte_width) \
kfraser@13443 481 ({ unsigned long __ea = (ea); \
kfraser@13443 482 unsigned int _width = (byte_width); \
kfraser@13443 483 ((_width == sizeof(unsigned long)) ? __ea : \
kfraser@13443 484 (__ea & ((1UL << (_width << 3)) - 1))); \
kaf24@12572 485 })
kfraser@13328 486 #define truncate_ea(ea) _truncate_ea((ea), ad_bytes)
kfraser@12675 487
kfraser@13331 488 #define mode_64bit() (def_ad_bytes == 8)
kfraser@13331 489
kfraser@14063 490 #define fail_if(p) \
kfraser@14063 491 do { \
kfraser@14063 492 rc = (p) ? X86EMUL_UNHANDLEABLE : X86EMUL_OKAY; \
kfraser@14063 493 if ( rc ) goto done; \
kfraser@13334 494 } while (0)
kfraser@13334 495
keir@16462 496 #define generate_exception_if(p, e) \
keir@16462 497 ({ if ( (p) ) { \
keir@16462 498 fail_if(ops->inject_hw_exception == NULL); \
keir@16462 499 rc = ops->inject_hw_exception(e, ctxt) ? : X86EMUL_EXCEPTION; \
keir@16462 500 goto done; \
keir@16462 501 } \
keir@16462 502 })
kfraser@13334 503
kfraser@13334 504 /* Given byte has even parity (even number of 1s)? */
kfraser@13334 505 static int even_parity(uint8_t v)
kfraser@13334 506 {
kfraser@15872 507 asm ( "test %%al,%%al; setp %%al"
kfraser@13334 508 : "=a" (v) : "0" (v) );
kfraser@13334 509 return v;
kfraser@13334 510 }
kfraser@13334 511
kfraser@12675 512 /* Update address held in a register, based on addressing mode. */
kfraser@13328 513 #define _register_address_increment(reg, inc, byte_width) \
kaf24@8447 514 do { \
kfraser@10279 515 int _inc = (inc); /* signed type ensures sign extension to long */ \
kfraser@13443 516 unsigned int _width = (byte_width); \
kfraser@13443 517 if ( _width == sizeof(unsigned long) ) \
kfraser@10279 518 (reg) += _inc; \
kfraser@13331 519 else if ( mode_64bit() ) \
kfraser@13443 520 (reg) = ((reg) + _inc) & ((1UL << (_width << 3)) - 1); \
kaf24@8447 521 else \
kfraser@13443 522 (reg) = ((reg) & ~((1UL << (_width << 3)) - 1)) | \
kfraser@13443 523 (((reg) + _inc) & ((1UL << (_width << 3)) - 1)); \
kaf24@8447 524 } while (0)
kfraser@13328 525 #define register_address_increment(reg, inc) \
kfraser@13328 526 _register_address_increment((reg), (inc), ad_bytes)
kfraser@13328 527
kfraser@13443 528 #define sp_pre_dec(dec) ({ \
kfraser@13443 529 _register_address_increment(_regs.esp, -(dec), ctxt->sp_size/8); \
kfraser@13443 530 _truncate_ea(_regs.esp, ctxt->sp_size/8); \
kfraser@13443 531 })
kfraser@13443 532 #define sp_post_inc(inc) ({ \
kfraser@13443 533 unsigned long __esp = _truncate_ea(_regs.esp, ctxt->sp_size/8); \
kfraser@13443 534 _register_address_increment(_regs.esp, (inc), ctxt->sp_size/8); \
kfraser@13443 535 __esp; \
kfraser@13443 536 })
kfraser@13443 537
kfraser@13328 538 #define jmp_rel(rel) \
kfraser@13328 539 do { \
kfraser@13328 540 _regs.eip += (int)(rel); \
kfraser@13331 541 if ( !mode_64bit() ) \
kfraser@13328 542 _regs.eip = ((op_bytes == 2) \
kfraser@13328 543 ? (uint16_t)_regs.eip : (uint32_t)_regs.eip); \
kfraser@13328 544 } while (0)
kfraser@13328 545
kfraser@14034 546 static int __handle_rep_prefix(
kfraser@14034 547 struct cpu_user_regs *int_regs,
kfraser@14034 548 struct cpu_user_regs *ext_regs,
kfraser@14034 549 int ad_bytes)
kfraser@14034 550 {
kfraser@14034 551 unsigned long ecx = ((ad_bytes == 2) ? (uint16_t)int_regs->ecx :
kfraser@14034 552 (ad_bytes == 4) ? (uint32_t)int_regs->ecx :
kfraser@14034 553 int_regs->ecx);
kfraser@14034 554
kfraser@14034 555 if ( ecx-- == 0 )
kfraser@14034 556 {
kfraser@14034 557 ext_regs->eip = int_regs->eip;
kfraser@14034 558 return 1;
kfraser@14034 559 }
kfraser@14034 560
kfraser@14034 561 if ( ad_bytes == 2 )
kfraser@14034 562 *(uint16_t *)&int_regs->ecx = ecx;
kfraser@14034 563 else if ( ad_bytes == 4 )
kfraser@14034 564 int_regs->ecx = (uint32_t)ecx;
kfraser@14034 565 else
kfraser@14034 566 int_regs->ecx = ecx;
kfraser@14034 567 int_regs->eip = ext_regs->eip;
kfraser@14034 568 return 0;
kfraser@14034 569 }
kfraser@14034 570
kfraser@14034 571 #define handle_rep_prefix() \
kfraser@14034 572 do { \
kfraser@14034 573 if ( rep_prefix && __handle_rep_prefix(&_regs, ctxt->regs, ad_bytes) ) \
kfraser@14034 574 goto done; \
kfraser@14034 575 } while (0)
kfraser@14034 576
kaf24@13426 577 /*
kaf24@13426 578 * Unsigned multiplication with double-word result.
kaf24@13426 579 * IN: Multiplicand=m[0], Multiplier=m[1]
kaf24@13426 580 * OUT: Return CF/OF (overflow status); Result=m[1]:m[0]
kaf24@13426 581 */
kaf24@13426 582 static int mul_dbl(unsigned long m[2])
kaf24@13426 583 {
kaf24@13426 584 int rc;
kaf24@13426 585 asm ( "mul %4; seto %b2"
kaf24@13426 586 : "=a" (m[0]), "=d" (m[1]), "=q" (rc)
kaf24@13426 587 : "0" (m[0]), "1" (m[1]), "2" (0) );
kaf24@13426 588 return rc;
kaf24@13426 589 }
kaf24@13426 590
kaf24@13426 591 /*
kaf24@13426 592 * Signed multiplication with double-word result.
kaf24@13426 593 * IN: Multiplicand=m[0], Multiplier=m[1]
kaf24@13426 594 * OUT: Return CF/OF (overflow status); Result=m[1]:m[0]
kaf24@13426 595 */
kaf24@13426 596 static int imul_dbl(unsigned long m[2])
kaf24@13426 597 {
kaf24@13426 598 int rc;
kaf24@13426 599 asm ( "imul %4; seto %b2"
kaf24@13426 600 : "=a" (m[0]), "=d" (m[1]), "=q" (rc)
kaf24@13426 601 : "0" (m[0]), "1" (m[1]), "2" (0) );
kaf24@13426 602 return rc;
kaf24@13426 603 }
kaf24@13426 604
kaf24@13426 605 /*
kaf24@13426 606 * Unsigned division of double-word dividend.
kaf24@13426 607 * IN: Dividend=u[1]:u[0], Divisor=v
kaf24@13426 608 * OUT: Return 1: #DE
kaf24@13426 609 * Return 0: Quotient=u[0], Remainder=u[1]
kaf24@13426 610 */
kaf24@13426 611 static int div_dbl(unsigned long u[2], unsigned long v)
kaf24@13426 612 {
keir@16097 613 if ( (v == 0) || (u[1] >= v) )
kaf24@13426 614 return 1;
kaf24@13426 615 asm ( "div %4"
kaf24@13426 616 : "=a" (u[0]), "=d" (u[1])
kaf24@13426 617 : "0" (u[0]), "1" (u[1]), "r" (v) );
kaf24@13426 618 return 0;
kaf24@13426 619 }
kaf24@13426 620
kaf24@13426 621 /*
kaf24@13426 622 * Signed division of double-word dividend.
kaf24@13426 623 * IN: Dividend=u[1]:u[0], Divisor=v
kaf24@13426 624 * OUT: Return 1: #DE
kaf24@13426 625 * Return 0: Quotient=u[0], Remainder=u[1]
kaf24@13426 626 * NB. We don't use idiv directly as it's moderately hard to work out
kaf24@13426 627 * ahead of time whether it will #DE, which we cannot allow to happen.
kaf24@13426 628 */
kaf24@13426 629 static int idiv_dbl(unsigned long u[2], unsigned long v)
kaf24@13426 630 {
kaf24@13426 631 int negu = (long)u[1] < 0, negv = (long)v < 0;
kaf24@13426 632
kaf24@13426 633 /* u = abs(u) */
kaf24@13426 634 if ( negu )
kaf24@13426 635 {
kaf24@13426 636 u[1] = ~u[1];
kaf24@13426 637 if ( (u[0] = -u[0]) == 0 )
kaf24@13426 638 u[1]++;
kaf24@13426 639 }
kaf24@13426 640
kaf24@13426 641 /* abs(u) / abs(v) */
kaf24@13426 642 if ( div_dbl(u, negv ? -v : v) )
kaf24@13426 643 return 1;
kaf24@13426 644
kaf24@13426 645 /* Remainder has same sign as dividend. It cannot overflow. */
kaf24@13426 646 if ( negu )
kaf24@13426 647 u[1] = -u[1];
kaf24@13426 648
kaf24@13426 649 /* Quotient is overflowed if sign bit is set. */
kaf24@13426 650 if ( negu ^ negv )
kaf24@13426 651 {
kaf24@13426 652 if ( (long)u[0] >= 0 )
kaf24@13426 653 u[0] = -u[0];
kaf24@13426 654 else if ( (u[0] << 1) != 0 ) /* == 0x80...0 is okay */
kaf24@13426 655 return 1;
kaf24@13426 656 }
kaf24@13426 657 else if ( (long)u[0] < 0 )
kaf24@13426 658 return 1;
kaf24@13426 659
kaf24@13426 660 return 0;
kaf24@13426 661 }
kaf24@13426 662
kfraser@13328 663 static int
kfraser@13328 664 test_cc(
kfraser@13328 665 unsigned int condition, unsigned int flags)
kfraser@13328 666 {
kfraser@13328 667 int rc = 0;
kfraser@13328 668
kfraser@13328 669 switch ( (condition & 15) >> 1 )
kfraser@13328 670 {
kfraser@13328 671 case 0: /* o */
kfraser@13328 672 rc |= (flags & EFLG_OF);
kfraser@13328 673 break;
kfraser@13328 674 case 1: /* b/c/nae */
kfraser@13328 675 rc |= (flags & EFLG_CF);
kfraser@13328 676 break;
kfraser@13328 677 case 2: /* z/e */
kfraser@13328 678 rc |= (flags & EFLG_ZF);
kfraser@13328 679 break;
kfraser@13328 680 case 3: /* be/na */
kfraser@13328 681 rc |= (flags & (EFLG_CF|EFLG_ZF));
kfraser@13328 682 break;
kfraser@13328 683 case 4: /* s */
kfraser@13328 684 rc |= (flags & EFLG_SF);
kfraser@13328 685 break;
kfraser@13328 686 case 5: /* p/pe */
kfraser@13328 687 rc |= (flags & EFLG_PF);
kfraser@13328 688 break;
kfraser@13328 689 case 7: /* le/ng */
kfraser@13328 690 rc |= (flags & EFLG_ZF);
kfraser@13328 691 /* fall through */
kfraser@13328 692 case 6: /* l/nge */
kfraser@13328 693 rc |= (!(flags & EFLG_SF) != !(flags & EFLG_OF));
kfraser@13328 694 break;
kfraser@13328 695 }
kfraser@13328 696
kfraser@13328 697 /* Odd condition identifiers (lsb == 1) have inverted sense. */
kfraser@13328 698 return (!!rc ^ (condition & 1));
kfraser@13328 699 }
kaf24@8447 700
keir@16454 701 static int
keir@16459 702 get_cpl(
keir@16459 703 struct x86_emulate_ctxt *ctxt,
keir@16459 704 struct x86_emulate_ops *ops)
keir@16459 705 {
keir@16459 706 struct segment_register reg;
keir@16459 707
keir@16459 708 if ( ctxt->regs->eflags & EFLG_VM )
keir@16459 709 return 3;
keir@16459 710
keir@16459 711 if ( (ops->read_segment == NULL) ||
keir@16459 712 ops->read_segment(x86_seg_ss, &reg, ctxt) )
keir@16459 713 return -1;
keir@16459 714
keir@16459 715 return reg.attr.fields.dpl;
keir@16459 716 }
keir@16459 717
keir@16459 718 static int
keir@16459 719 _mode_iopl(
keir@16459 720 struct x86_emulate_ctxt *ctxt,
keir@16459 721 struct x86_emulate_ops *ops)
keir@16459 722 {
keir@16459 723 int cpl = get_cpl(ctxt, ops);
keir@16459 724 return ((cpl >= 0) && (cpl <= ((ctxt->regs->eflags >> 12) & 3)));
keir@16459 725 }
keir@16459 726
keir@16459 727 #define mode_ring0() (get_cpl(ctxt, ops) == 0)
keir@16459 728 #define mode_iopl() _mode_iopl(ctxt, ops)
keir@16459 729
keir@16459 730 static int
keir@16454 731 in_realmode(
keir@16454 732 struct x86_emulate_ctxt *ctxt,
keir@16454 733 struct x86_emulate_ops *ops)
keir@16454 734 {
keir@16454 735 unsigned long cr0;
keir@16454 736 int rc;
keir@16454 737
keir@16454 738 if ( ops->read_cr == NULL )
keir@16454 739 return 0;
keir@16454 740
keir@16454 741 rc = ops->read_cr(0, &cr0, ctxt);
keir@16454 742 return (!rc && !(cr0 & 1));
keir@16454 743 }
keir@16454 744
keir@16454 745 static int
keir@16454 746 load_seg(
keir@16454 747 enum x86_segment seg,
keir@16454 748 uint16_t sel,
keir@16454 749 struct x86_emulate_ctxt *ctxt,
keir@16454 750 struct x86_emulate_ops *ops)
keir@16454 751 {
keir@16454 752 struct segment_register reg;
keir@16454 753 int rc;
keir@16454 754
keir@16454 755 if ( !in_realmode(ctxt, ops) ||
keir@16454 756 (ops->read_segment == NULL) ||
keir@16454 757 (ops->write_segment == NULL) )
keir@16454 758 return X86EMUL_UNHANDLEABLE;
keir@16454 759
keir@16454 760 if ( (rc = ops->read_segment(seg, &reg, ctxt)) != 0 )
keir@16454 761 return rc;
keir@16454 762
keir@16454 763 reg.sel = sel;
keir@16454 764 reg.base = (uint32_t)sel << 4;
keir@16454 765
keir@16454 766 return ops->write_segment(seg, &reg, ctxt);
keir@16454 767 }
keir@16454 768
kaf24@4047 769 void *
kaf24@4047 770 decode_register(
kaf24@8423 771 uint8_t modrm_reg, struct cpu_user_regs *regs, int highbyte_regs)
kaf24@4047 772 {
kaf24@4047 773 void *p;
kaf24@4047 774
kaf24@4047 775 switch ( modrm_reg )
kaf24@4047 776 {
kaf24@4047 777 case 0: p = &regs->eax; break;
kaf24@4047 778 case 1: p = &regs->ecx; break;
kaf24@4047 779 case 2: p = &regs->edx; break;
kaf24@4047 780 case 3: p = &regs->ebx; break;
kaf24@4047 781 case 4: p = (highbyte_regs ?
kaf24@4047 782 ((unsigned char *)&regs->eax + 1) :
kaf24@4047 783 (unsigned char *)&regs->esp); break;
kaf24@4047 784 case 5: p = (highbyte_regs ?
kaf24@4047 785 ((unsigned char *)&regs->ecx + 1) :
kaf24@4047 786 (unsigned char *)&regs->ebp); break;
kaf24@4047 787 case 6: p = (highbyte_regs ?
kaf24@4047 788 ((unsigned char *)&regs->edx + 1) :
kaf24@4047 789 (unsigned char *)&regs->esi); break;
kaf24@4047 790 case 7: p = (highbyte_regs ?
kaf24@4047 791 ((unsigned char *)&regs->ebx + 1) :
kaf24@4047 792 (unsigned char *)&regs->edi); break;
kaf24@4047 793 #if defined(__x86_64__)
kaf24@4047 794 case 8: p = &regs->r8; break;
kaf24@4047 795 case 9: p = &regs->r9; break;
kaf24@4047 796 case 10: p = &regs->r10; break;
kaf24@4047 797 case 11: p = &regs->r11; break;
kaf24@4047 798 case 12: p = &regs->r12; break;
kaf24@4047 799 case 13: p = &regs->r13; break;
kaf24@4047 800 case 14: p = &regs->r14; break;
kaf24@4047 801 case 15: p = &regs->r15; break;
kaf24@4047 802 #endif
kaf24@4047 803 default: p = NULL; break;
kaf24@4047 804 }
kaf24@4047 805
kaf24@4047 806 return p;
kaf24@4047 807 }
kaf24@4047 808
keir@16454 809 #define decode_segment_failed x86_seg_tr
keir@16454 810 enum x86_segment
keir@16454 811 decode_segment(
keir@16454 812 uint8_t modrm_reg)
keir@16454 813 {
keir@16454 814 switch ( modrm_reg )
keir@16454 815 {
keir@16454 816 case 0: return x86_seg_es;
keir@16454 817 case 1: return x86_seg_cs;
keir@16454 818 case 2: return x86_seg_ss;
keir@16454 819 case 3: return x86_seg_ds;
keir@16454 820 case 4: return x86_seg_fs;
keir@16454 821 case 5: return x86_seg_gs;
keir@16454 822 default: break;
keir@16454 823 }
keir@16454 824 return decode_segment_failed;
keir@16454 825 }
keir@16454 826
kaf24@10179 827 int
kfraser@13268 828 x86_emulate(
kaf24@10179 829 struct x86_emulate_ctxt *ctxt,
kaf24@10179 830 struct x86_emulate_ops *ops)
kaf24@4047 831 {
kaf24@12572 832 /* Shadow copy of register state. Committed on successful emulation. */
kaf24@12572 833 struct cpu_user_regs _regs = *ctxt->regs;
kaf24@12572 834
kfraser@12559 835 uint8_t b, d, sib, sib_index, sib_base, twobyte = 0, rex_prefix = 0;
kaf24@8423 836 uint8_t modrm, modrm_mod = 0, modrm_reg = 0, modrm_rm = 0;
kfraser@13380 837 unsigned int op_bytes, def_op_bytes, ad_bytes, def_ad_bytes;
keir@16465 838 #define REPE_PREFIX 1
keir@16465 839 #define REPNE_PREFIX 2
kfraser@13380 840 unsigned int lock_prefix = 0, rep_prefix = 0;
kfraser@14370 841 int override_seg = -1, rc = X86EMUL_OKAY;
kaf24@4047 842 struct operand src, dst;
kaf24@4047 843
kfraser@13145 844 /* Data operand effective address (usually computed from ModRM). */
kfraser@13145 845 struct operand ea;
kfraser@13145 846
kfraser@13145 847 /* Default is a memory operand relative to segment DS. */
kfraser@13145 848 ea.type = OP_MEM;
kfraser@13145 849 ea.mem.seg = x86_seg_ds;
kfraser@13145 850 ea.mem.off = 0;
kfraser@11282 851
kfraser@13443 852 op_bytes = def_op_bytes = ad_bytes = def_ad_bytes = ctxt->addr_size/8;
kfraser@13331 853 if ( op_bytes == 8 )
kaf24@8447 854 {
kfraser@13380 855 op_bytes = def_op_bytes = 4;
kfraser@13331 856 #ifndef __x86_64__
kfraser@14063 857 return X86EMUL_UNHANDLEABLE;
kaf24@8447 858 #endif
kaf24@8447 859 }
kaf24@8447 860
kfraser@13282 861 /* Prefix bytes. */
kfraser@13380 862 for ( ; ; )
kaf24@4047 863 {
kaf24@12769 864 switch ( b = insn_fetch_type(uint8_t) )
kaf24@4103 865 {
kaf24@4103 866 case 0x66: /* operand-size override */
kfraser@13380 867 op_bytes = def_op_bytes ^ 6;
kaf24@4103 868 break;
kaf24@4103 869 case 0x67: /* address-size override */
kfraser@13380 870 ad_bytes = def_ad_bytes ^ (mode_64bit() ? 12 : 6);
kaf24@4103 871 break;
kaf24@4103 872 case 0x2e: /* CS override */
kfraser@14370 873 override_seg = x86_seg_cs;
kaf24@8447 874 break;
kaf24@4103 875 case 0x3e: /* DS override */
kfraser@14370 876 override_seg = x86_seg_ds;
kaf24@8447 877 break;
kaf24@4103 878 case 0x26: /* ES override */
kfraser@14370 879 override_seg = x86_seg_es;
kaf24@8447 880 break;
kaf24@4103 881 case 0x64: /* FS override */
kfraser@14370 882 override_seg = x86_seg_fs;
kaf24@8447 883 break;
kaf24@4103 884 case 0x65: /* GS override */
kfraser@14370 885 override_seg = x86_seg_gs;
kaf24@8447 886 break;
kaf24@4103 887 case 0x36: /* SS override */
kfraser@14370 888 override_seg = x86_seg_ss;
kaf24@4103 889 break;
kaf24@4103 890 case 0xf0: /* LOCK */
kaf24@4103 891 lock_prefix = 1;
kaf24@4103 892 break;
kfraser@13282 893 case 0xf2: /* REPNE/REPNZ */
keir@16465 894 rep_prefix = REPNE_PREFIX;
keir@16465 895 break;
kaf24@4103 896 case 0xf3: /* REP/REPE/REPZ */
keir@16465 897 rep_prefix = REPE_PREFIX;
kaf24@4103 898 break;
kfraser@13282 899 case 0x40 ... 0x4f: /* REX */
kfraser@13331 900 if ( !mode_64bit() )
kfraser@13282 901 goto done_prefixes;
kfraser@13282 902 rex_prefix = b;
kfraser@13282 903 continue;
kaf24@4103 904 default:
kaf24@4103 905 goto done_prefixes;
kaf24@4103 906 }
kfraser@13282 907
kfraser@13282 908 /* Any legacy prefix after a REX prefix nullifies its effect. */
kfraser@13282 909 rex_prefix = 0;
kaf24@4047 910 }
kaf24@4103 911 done_prefixes:
kaf24@4047 912
kfraser@13282 913 if ( rex_prefix & 8 ) /* REX.W */
kfraser@13282 914 op_bytes = 8;
kaf24@4047 915
kaf24@4047 916 /* Opcode byte(s). */
kaf24@4047 917 d = opcode_table[b];
kaf24@4047 918 if ( d == 0 )
kaf24@4047 919 {
kaf24@4047 920 /* Two-byte opcode? */
kaf24@4047 921 if ( b == 0x0f )
kaf24@4047 922 {
kaf24@4047 923 twobyte = 1;
kaf24@12769 924 b = insn_fetch_type(uint8_t);
kaf24@4047 925 d = twobyte_table[b];
kaf24@4047 926 }
kaf24@4047 927
kaf24@4047 928 /* Unrecognised? */
kaf24@4047 929 if ( d == 0 )
kaf24@4047 930 goto cannot_emulate;
kaf24@4047 931 }
kaf24@4047 932
kfraser@13383 933 /* Lock prefix is allowed only on RMW instructions. */
kfraser@13383 934 generate_exception_if((d & Mov) && lock_prefix, EXC_GP);
kfraser@13383 935
kaf24@4047 936 /* ModRM and SIB bytes. */
kaf24@4047 937 if ( d & ModRM )
kaf24@4047 938 {
kaf24@12769 939 modrm = insn_fetch_type(uint8_t);
kfraser@12559 940 modrm_mod = (modrm & 0xc0) >> 6;
kfraser@12559 941 modrm_reg = ((rex_prefix & 4) << 1) | ((modrm & 0x38) >> 3);
kfraser@12559 942 modrm_rm = modrm & 0x07;
kaf24@8423 943
kaf24@8423 944 if ( modrm_mod == 3 )
kfraser@13145 945 {
kfraser@13282 946 modrm_rm |= (rex_prefix & 1) << 3;
kfraser@13145 947 ea.type = OP_REG;
kfraser@13145 948 ea.reg = decode_register(
kfraser@13145 949 modrm_rm, &_regs, (d & ByteOp) && (rex_prefix == 0));
kfraser@13145 950 }
kfraser@13145 951 else if ( ad_bytes == 2 )
kaf24@8423 952 {
kaf24@8423 953 /* 16-bit ModR/M decode. */
kfraser@12559 954 switch ( modrm_rm )
kfraser@12559 955 {
kfraser@14370 956 case 0:
kfraser@14370 957 ea.mem.off = _regs.ebx + _regs.esi;
kfraser@14370 958 break;
kfraser@14370 959 case 1:
kfraser@14370 960 ea.mem.off = _regs.ebx + _regs.edi;
kfraser@14370 961 break;
kfraser@14370 962 case 2:
kfraser@14370 963 ea.mem.seg = x86_seg_ss;
kfraser@14370 964 ea.mem.off = _regs.ebp + _regs.esi;
kfraser@14370 965 break;
kfraser@14370 966 case 3:
kfraser@14370 967 ea.mem.seg = x86_seg_ss;
kfraser@14370 968 ea.mem.off = _regs.ebp + _regs.edi;
kfraser@14370 969 break;
kfraser@14370 970 case 4:
kfraser@14370 971 ea.mem.off = _regs.esi;
kfraser@14370 972 break;
kfraser@14370 973 case 5:
kfraser@14370 974 ea.mem.off = _regs.edi;
kfraser@14370 975 break;
kfraser@14370 976 case 6:
kfraser@14370 977 if ( modrm_mod == 0 )
kfraser@14370 978 break;
kfraser@14370 979 ea.mem.seg = x86_seg_ss;
kfraser@14370 980 ea.mem.off = _regs.ebp;
kfraser@14370 981 break;
kfraser@14370 982 case 7:
kfraser@14370 983 ea.mem.off = _regs.ebx;
kfraser@14370 984 break;
kfraser@12559 985 }
kaf24@8423 986 switch ( modrm_mod )
kaf24@8423 987 {
kaf24@12769 988 case 0:
kaf24@12769 989 if ( modrm_rm == 6 )
kfraser@13145 990 ea.mem.off = insn_fetch_type(int16_t);
kaf24@12769 991 break;
kaf24@12769 992 case 1:
kfraser@13145 993 ea.mem.off += insn_fetch_type(int8_t);
kaf24@12769 994 break;
kaf24@12769 995 case 2:
kfraser@13145 996 ea.mem.off += insn_fetch_type(int16_t);
kaf24@12769 997 break;
kaf24@8423 998 }
kfraser@13145 999 ea.mem.off = truncate_ea(ea.mem.off);
kaf24@8423 1000 }
kaf24@8423 1001 else
kaf24@8423 1002 {
kaf24@8423 1003 /* 32/64-bit ModR/M decode. */
kfraser@12559 1004 if ( modrm_rm == 4 )
kfraser@12559 1005 {
kaf24@12769 1006 sib = insn_fetch_type(uint8_t);
kfraser@12684 1007 sib_index = ((sib >> 3) & 7) | ((rex_prefix << 2) & 8);
kfraser@12684 1008 sib_base = (sib & 7) | ((rex_prefix << 3) & 8);
kfraser@12559 1009 if ( sib_index != 4 )
kfraser@13145 1010 ea.mem.off = *(long*)decode_register(sib_index, &_regs, 0);
kfraser@13145 1011 ea.mem.off <<= (sib >> 6) & 3;
kfraser@12559 1012 if ( (modrm_mod == 0) && ((sib_base & 7) == 5) )
kfraser@13145 1013 ea.mem.off += insn_fetch_type(int32_t);
kfraser@14370 1014 else if ( sib_base == 4 )
kfraser@14370 1015 {
kfraser@14370 1016 ea.mem.seg = x86_seg_ss;
kfraser@14370 1017 ea.mem.off += _regs.esp;
kfraser@14370 1018 if ( !twobyte && (b == 0x8f) )
kfraser@14370 1019 /* POP <rm> computes its EA post increment. */
kfraser@14370 1020 ea.mem.off += ((mode_64bit() && (op_bytes == 4))
kfraser@14370 1021 ? 8 : op_bytes);
kfraser@14370 1022 }
kfraser@14370 1023 else if ( sib_base == 5 )
kfraser@14370 1024 {
kfraser@14370 1025 ea.mem.seg = x86_seg_ss;
kfraser@14370 1026 ea.mem.off += _regs.ebp;
kfraser@14370 1027 }
kfraser@12559 1028 else
kfraser@13145 1029 ea.mem.off += *(long*)decode_register(sib_base, &_regs, 0);
kfraser@12559 1030 }
kfraser@12559 1031 else
kfraser@12559 1032 {
kfraser@12559 1033 modrm_rm |= (rex_prefix & 1) << 3;
kfraser@13145 1034 ea.mem.off = *(long *)decode_register(modrm_rm, &_regs, 0);
kfraser@14370 1035 if ( (modrm_rm == 5) && (modrm_mod != 0) )
kfraser@14370 1036 ea.mem.seg = x86_seg_ss;
kfraser@12559 1037 }
kaf24@8423 1038 switch ( modrm_mod )
kaf24@8423 1039 {
kaf24@8423 1040 case 0:
kfraser@12559 1041 if ( (modrm_rm & 7) != 5 )
kfraser@12559 1042 break;
kfraser@13145 1043 ea.mem.off = insn_fetch_type(int32_t);
kfraser@13331 1044 if ( !mode_64bit() )
kfraser@12559 1045 break;
kfraser@12559 1046 /* Relative to RIP of next instruction. Argh! */
kfraser@13145 1047 ea.mem.off += _regs.eip;
kfraser@12559 1048 if ( (d & SrcMask) == SrcImm )
kfraser@13145 1049 ea.mem.off += (d & ByteOp) ? 1 :
kfraser@12675 1050 ((op_bytes == 8) ? 4 : op_bytes);
kfraser@12559 1051 else if ( (d & SrcMask) == SrcImmByte )
kfraser@13145 1052 ea.mem.off += 1;
kfraser@12559 1053 else if ( ((b == 0xf6) || (b == 0xf7)) &&
kfraser@12559 1054 ((modrm_reg & 7) <= 1) )
kfraser@12559 1055 /* Special case in Grp3: test has immediate operand. */
kfraser@13145 1056 ea.mem.off += (d & ByteOp) ? 1
kfraser@12559 1057 : ((op_bytes == 8) ? 4 : op_bytes);
kaf24@8423 1058 break;
kaf24@12769 1059 case 1:
kfraser@13145 1060 ea.mem.off += insn_fetch_type(int8_t);
kaf24@12769 1061 break;
kaf24@12769 1062 case 2:
kfraser@13145 1063 ea.mem.off += insn_fetch_type(int32_t);
kaf24@12769 1064 break;
kaf24@8423 1065 }
kfraser@13145 1066 ea.mem.off = truncate_ea(ea.mem.off);
kaf24@8423 1067 }
kaf24@4047 1068 }
kaf24@4047 1069
kfraser@14370 1070 if ( override_seg != -1 )
kfraser@14370 1071 ea.mem.seg = override_seg;
kfraser@14370 1072
kfraser@12675 1073 /* Special instructions do their own operand decoding. */
kfraser@12675 1074 if ( (d & DstMask) == ImplicitOps )
kaf24@4047 1075 goto special_insn;
kaf24@4047 1076
kaf24@4047 1077 /* Decode and fetch the source operand: register, memory or immediate. */
kaf24@4047 1078 switch ( d & SrcMask )
kaf24@4047 1079 {
kaf24@4047 1080 case SrcNone:
kaf24@4047 1081 break;
kaf24@4047 1082 case SrcReg:
kaf24@4047 1083 src.type = OP_REG;
kaf24@4047 1084 if ( d & ByteOp )
kaf24@4047 1085 {
kfraser@12675 1086 src.reg = decode_register(modrm_reg, &_regs, (rex_prefix == 0));
kfraser@13145 1087 src.val = *(uint8_t *)src.reg;
kaf24@4047 1088 src.bytes = 1;
kaf24@4047 1089 }
kaf24@4047 1090 else
kaf24@4047 1091 {
kfraser@12675 1092 src.reg = decode_register(modrm_reg, &_regs, 0);
kaf24@4047 1093 switch ( (src.bytes = op_bytes) )
kaf24@4047 1094 {
kfraser@13145 1095 case 2: src.val = *(uint16_t *)src.reg; break;
kfraser@13145 1096 case 4: src.val = *(uint32_t *)src.reg; break;
kfraser@13145 1097 case 8: src.val = *(uint64_t *)src.reg; break;
kaf24@4047 1098 }
kaf24@4047 1099 }
kaf24@4047 1100 break;
kaf24@8423 1101 case SrcMem16:
kfraser@13145 1102 ea.bytes = 2;
kaf24@8423 1103 goto srcmem_common;
kaf24@4047 1104 case SrcMem:
kfraser@13145 1105 ea.bytes = (d & ByteOp) ? 1 : op_bytes;
kaf24@8423 1106 srcmem_common:
kfraser@13145 1107 src = ea;
kfraser@13145 1108 if ( src.type == OP_REG )
kfraser@13145 1109 {
kfraser@13145 1110 switch ( src.bytes )
kfraser@13145 1111 {
kfraser@13145 1112 case 1: src.val = *(uint8_t *)src.reg; break;
kfraser@13145 1113 case 2: src.val = *(uint16_t *)src.reg; break;
kfraser@13145 1114 case 4: src.val = *(uint32_t *)src.reg; break;
kfraser@13145 1115 case 8: src.val = *(uint64_t *)src.reg; break;
kfraser@13145 1116 }
kfraser@13145 1117 }
kfraser@13145 1118 else if ( (rc = ops->read(src.mem.seg, src.mem.off,
kfraser@13145 1119 &src.val, src.bytes, ctxt)) )
kaf24@4047 1120 goto done;
kaf24@4047 1121 break;
kaf24@4047 1122 case SrcImm:
kaf24@4047 1123 src.type = OP_IMM;
kaf24@4047 1124 src.bytes = (d & ByteOp) ? 1 : op_bytes;
kaf24@4047 1125 if ( src.bytes == 8 ) src.bytes = 4;
kaf24@4047 1126 /* NB. Immediates are sign-extended as necessary. */
kaf24@4047 1127 switch ( src.bytes )
kaf24@4047 1128 {
kaf24@12769 1129 case 1: src.val = insn_fetch_type(int8_t); break;
kaf24@12769 1130 case 2: src.val = insn_fetch_type(int16_t); break;
kaf24@12769 1131 case 4: src.val = insn_fetch_type(int32_t); break;
kaf24@4047 1132 }
kaf24@4047 1133 break;
kaf24@4047 1134 case SrcImmByte:
kaf24@4047 1135 src.type = OP_IMM;
kaf24@4047 1136 src.bytes = 1;
kaf24@12769 1137 src.val = insn_fetch_type(int8_t);
kaf24@4047 1138 break;
kaf24@4047 1139 }
kaf24@4047 1140
kfraser@12675 1141 /* Decode and fetch the destination operand: register or memory. */
kfraser@12675 1142 switch ( d & DstMask )
kfraser@12675 1143 {
kfraser@12675 1144 case DstReg:
kfraser@12675 1145 dst.type = OP_REG;
kfraser@12675 1146 if ( d & ByteOp )
kfraser@12675 1147 {
kfraser@12675 1148 dst.reg = decode_register(modrm_reg, &_regs, (rex_prefix == 0));
kfraser@12675 1149 dst.val = *(uint8_t *)dst.reg;
kfraser@12675 1150 dst.bytes = 1;
kfraser@12675 1151 }
kfraser@12675 1152 else
kfraser@12675 1153 {
kfraser@12675 1154 dst.reg = decode_register(modrm_reg, &_regs, 0);
kfraser@12675 1155 switch ( (dst.bytes = op_bytes) )
kfraser@12675 1156 {
kfraser@12675 1157 case 2: dst.val = *(uint16_t *)dst.reg; break;
kfraser@12675 1158 case 4: dst.val = *(uint32_t *)dst.reg; break;
kfraser@12675 1159 case 8: dst.val = *(uint64_t *)dst.reg; break;
kfraser@12675 1160 }
kfraser@12675 1161 }
kfraser@12675 1162 break;
kfraser@12675 1163 case DstBitBase:
kfraser@13145 1164 if ( ((d & SrcMask) == SrcImmByte) || (ea.type == OP_REG) )
kfraser@12675 1165 {
kfraser@12675 1166 src.val &= (op_bytes << 3) - 1;
kfraser@12675 1167 }
kfraser@12675 1168 else
kfraser@12675 1169 {
kfraser@12675 1170 /*
kfraser@12675 1171 * EA += BitOffset DIV op_bytes*8
kaf24@13425 1172 * BitOffset = BitOffset MOD op_bytes*8
kfraser@12675 1173 * DIV truncates towards negative infinity.
kfraser@12675 1174 * MOD always produces a positive result.
kfraser@12675 1175 */
kfraser@12675 1176 if ( op_bytes == 2 )
kfraser@12675 1177 src.val = (int16_t)src.val;
kfraser@12675 1178 else if ( op_bytes == 4 )
kfraser@12675 1179 src.val = (int32_t)src.val;
kfraser@12675 1180 if ( (long)src.val < 0 )
kfraser@12675 1181 {
kfraser@12675 1182 unsigned long byte_offset;
kfraser@12675 1183 byte_offset = op_bytes + (((-src.val-1) >> 3) & ~(op_bytes-1));
kfraser@13145 1184 ea.mem.off -= byte_offset;
kfraser@12675 1185 src.val = (byte_offset << 3) + src.val;
kfraser@12675 1186 }
kfraser@12675 1187 else
kfraser@12675 1188 {
kfraser@13145 1189 ea.mem.off += (src.val >> 3) & ~(op_bytes - 1);
kfraser@12675 1190 src.val &= (op_bytes << 3) - 1;
kfraser@12675 1191 }
kfraser@12675 1192 }
kfraser@12675 1193 /* Becomes a normal DstMem operation from here on. */
kfraser@12675 1194 d = (d & ~DstMask) | DstMem;
kfraser@12675 1195 case DstMem:
kfraser@13145 1196 ea.bytes = (d & ByteOp) ? 1 : op_bytes;
kfraser@13145 1197 dst = ea;
kfraser@13145 1198 if ( dst.type == OP_REG )
kfraser@13145 1199 {
kfraser@13145 1200 switch ( dst.bytes )
kfraser@13145 1201 {
kfraser@13145 1202 case 1: dst.val = *(uint8_t *)dst.reg; break;
kfraser@13145 1203 case 2: dst.val = *(uint16_t *)dst.reg; break;
kfraser@13145 1204 case 4: dst.val = *(uint32_t *)dst.reg; break;
kfraser@13145 1205 case 8: dst.val = *(uint64_t *)dst.reg; break;
kfraser@13145 1206 }
kfraser@13145 1207 }
kfraser@13383 1208 else if ( !(d & Mov) ) /* optimisation - avoid slow emulated read */
kfraser@13383 1209 {
kfraser@13383 1210 if ( (rc = ops->read(dst.mem.seg, dst.mem.off,
kfraser@13383 1211 &dst.val, dst.bytes, ctxt)) )
kfraser@13383 1212 goto done;
kfraser@13383 1213 dst.orig_val = dst.val;
kfraser@13383 1214 }
kfraser@12675 1215 break;
kfraser@12675 1216 }
kfraser@13383 1217
kfraser@13383 1218 /* LOCK prefix allowed only on instructions with memory destination. */
kfraser@13383 1219 generate_exception_if(lock_prefix && (dst.type != OP_MEM), EXC_GP);
kfraser@12675 1220
kaf24@4047 1221 if ( twobyte )
kaf24@4047 1222 goto twobyte_insn;
kaf24@4047 1223
kaf24@4047 1224 switch ( b )
kaf24@4047 1225 {
kfraser@13282 1226 case 0x04 ... 0x05: /* add imm,%%eax */
kfraser@13282 1227 dst.reg = (unsigned long *)&_regs.eax;
kfraser@13383 1228 dst.val = _regs.eax;
kfraser@13282 1229 case 0x00 ... 0x03: add: /* add */
kaf24@4047 1230 emulate_2op_SrcV("add", src, dst, _regs.eflags);
kaf24@4047 1231 break;
kfraser@13328 1232
kfraser@13282 1233 case 0x0c ... 0x0d: /* or imm,%%eax */
kfraser@13282 1234 dst.reg = (unsigned long *)&_regs.eax;
kfraser@13383 1235 dst.val = _regs.eax;
kfraser@13282 1236 case 0x08 ... 0x0b: or: /* or */
kaf24@4047 1237 emulate_2op_SrcV("or", src, dst, _regs.eflags);
kaf24@4047 1238 break;
kfraser@13328 1239
kfraser@13282 1240 case 0x14 ... 0x15: /* adc imm,%%eax */
kfraser@13282 1241 dst.reg = (unsigned long *)&_regs.eax;
kfraser@13383 1242 dst.val = _regs.eax;
kfraser@13282 1243 case 0x10 ... 0x13: adc: /* adc */
kaf24@4047 1244 emulate_2op_SrcV("adc", src, dst, _regs.eflags);
kaf24@4047 1245 break;
kfraser@13328 1246
kfraser@13282 1247 case 0x1c ... 0x1d: /* sbb imm,%%eax */
kfraser@13282 1248 dst.reg = (unsigned long *)&_regs.eax;
kfraser@13383 1249 dst.val = _regs.eax;
kfraser@13282 1250 case 0x18 ... 0x1b: sbb: /* sbb */
kaf24@4047 1251 emulate_2op_SrcV("sbb", src, dst, _regs.eflags);
kaf24@4047 1252 break;
kfraser@13328 1253
kfraser@13282 1254 case 0x24 ... 0x25: /* and imm,%%eax */
kfraser@13282 1255 dst.reg = (unsigned long *)&_regs.eax;
kfraser@13383 1256 dst.val = _regs.eax;
kfraser@13282 1257 case 0x20 ... 0x23: and: /* and */
kaf24@4047 1258 emulate_2op_SrcV("and", src, dst, _regs.eflags);
kaf24@4047 1259 break;
kfraser@13328 1260
kfraser@13282 1261 case 0x2c ... 0x2d: /* sub imm,%%eax */
kfraser@13282 1262 dst.reg = (unsigned long *)&_regs.eax;
kfraser@13383 1263 dst.val = _regs.eax;
kfraser@13282 1264 case 0x28 ... 0x2b: sub: /* sub */
kaf24@4047 1265 emulate_2op_SrcV("sub", src, dst, _regs.eflags);
kaf24@4047 1266 break;
kfraser@13328 1267
kfraser@13282 1268 case 0x34 ... 0x35: /* xor imm,%%eax */
kfraser@13282 1269 dst.reg = (unsigned long *)&_regs.eax;
kfraser@13383 1270 dst.val = _regs.eax;
kfraser@13282 1271 case 0x30 ... 0x33: xor: /* xor */
kaf24@4047 1272 emulate_2op_SrcV("xor", src, dst, _regs.eflags);
kaf24@4047 1273 break;
kfraser@13328 1274
kfraser@13282 1275 case 0x3c ... 0x3d: /* cmp imm,%%eax */
kfraser@13282 1276 dst.reg = (unsigned long *)&_regs.eax;
kfraser@13383 1277 dst.val = _regs.eax;
kfraser@13282 1278 case 0x38 ... 0x3b: cmp: /* cmp */
kaf24@4047 1279 emulate_2op_SrcV("cmp", src, dst, _regs.eflags);
kaf24@4047 1280 break;
kfraser@13328 1281
kaf24@13428 1282 case 0x62: /* bound */ {
kaf24@13428 1283 unsigned long src_val2;
kaf24@13428 1284 int lb, ub, idx;
kaf24@13428 1285 generate_exception_if(mode_64bit() || (src.type != OP_MEM), EXC_UD);
kaf24@13428 1286 if ( (rc = ops->read(src.mem.seg, src.mem.off + op_bytes,
kaf24@13428 1287 &src_val2, op_bytes, ctxt)) )
kaf24@13428 1288 goto done;
kaf24@13428 1289 ub = (op_bytes == 2) ? (int16_t)src_val2 : (int32_t)src_val2;
kaf24@13428 1290 lb = (op_bytes == 2) ? (int16_t)src.val : (int32_t)src.val;
kaf24@13428 1291 idx = (op_bytes == 2) ? (int16_t)dst.val : (int32_t)dst.val;
kaf24@13428 1292 generate_exception_if((idx < lb) || (idx > ub), EXC_BR);
kaf24@13428 1293 dst.type = OP_NONE;
kaf24@13428 1294 break;
kaf24@13428 1295 }
kaf24@13428 1296
kaf24@13428 1297 case 0x63: /* movsxd (x86/64) / arpl (x86/32) */
kaf24@13428 1298 if ( mode_64bit() )
kaf24@13428 1299 {
kaf24@13428 1300 /* movsxd */
kaf24@13428 1301 if ( src.type == OP_REG )
kaf24@13428 1302 src.val = *(int32_t *)src.reg;
kaf24@13428 1303 else if ( (rc = ops->read(src.mem.seg, src.mem.off,
kaf24@13428 1304 &src.val, 4, ctxt)) )
kaf24@13428 1305 goto done;
kaf24@13428 1306 dst.val = (int32_t)src.val;
kaf24@13428 1307 }
kaf24@13428 1308 else
kaf24@13428 1309 {
kaf24@13428 1310 /* arpl */
kaf24@13428 1311 uint16_t src_val = dst.val;
kaf24@13428 1312 dst = src;
kaf24@13430 1313 _regs.eflags &= ~EFLG_ZF;
kaf24@13430 1314 _regs.eflags |= ((src_val & 3) > (dst.val & 3)) ? EFLG_ZF : 0;
kaf24@13430 1315 if ( _regs.eflags & EFLG_ZF )
kaf24@13428 1316 dst.val = (dst.val & ~3) | (src_val & 3);
kaf24@13428 1317 else
kaf24@13428 1318 dst.type = OP_NONE;
keir@16454 1319 generate_exception_if(in_realmode(ctxt, ops), EXC_UD);
kaf24@13428 1320 }
kaf24@8423 1321 break;
kfraser@13328 1322
kaf24@13426 1323 case 0x69: /* imul imm16/32 */
kaf24@13426 1324 case 0x6b: /* imul imm8 */ {
kaf24@13426 1325 unsigned long reg = *(long *)decode_register(modrm_reg, &_regs, 0);
kaf24@13426 1326 _regs.eflags &= ~(EFLG_OF|EFLG_CF);
kaf24@13426 1327 switch ( dst.bytes )
kaf24@13426 1328 {
kaf24@13426 1329 case 2:
kaf24@13426 1330 dst.val = ((uint32_t)(int16_t)src.val *
kaf24@13426 1331 (uint32_t)(int16_t)reg);
kaf24@13426 1332 if ( (int16_t)dst.val != (uint32_t)dst.val )
kaf24@13426 1333 _regs.eflags |= EFLG_OF|EFLG_CF;
kaf24@13426 1334 break;
kaf24@13426 1335 #ifdef __x86_64__
kaf24@13426 1336 case 4:
kaf24@13426 1337 dst.val = ((uint64_t)(int32_t)src.val *
kaf24@13426 1338 (uint64_t)(int32_t)reg);
kaf24@13426 1339 if ( (int32_t)dst.val != dst.val )
kaf24@13426 1340 _regs.eflags |= EFLG_OF|EFLG_CF;
kaf24@13426 1341 break;
kaf24@13426 1342 #endif
kaf24@13426 1343 default: {
kaf24@13426 1344 unsigned long m[2] = { src.val, reg };
kaf24@13426 1345 if ( imul_dbl(m) )
kaf24@13426 1346 _regs.eflags |= EFLG_OF|EFLG_CF;
kaf24@13426 1347 dst.val = m[0];
kaf24@13426 1348 break;
kaf24@13426 1349 }
kaf24@13426 1350 }
kaf24@13426 1351 dst.type = OP_REG;
kaf24@13426 1352 dst.reg = decode_register(modrm_reg, &_regs, 0);
kaf24@13426 1353 break;
kaf24@13426 1354 }
kaf24@13426 1355
kfraser@13462 1356 case 0x82: /* Grp1 (x86/32 only) */
kfraser@13462 1357 generate_exception_if(mode_64bit(), EXC_UD);
kfraser@13462 1358 case 0x80: case 0x81: case 0x83: /* Grp1 */
kfraser@12559 1359 switch ( modrm_reg & 7 )
kaf24@4047 1360 {
kaf24@4047 1361 case 0: goto add;
kaf24@4047 1362 case 1: goto or;
kaf24@4047 1363 case 2: goto adc;
kaf24@4047 1364 case 3: goto sbb;
kaf24@4047 1365 case 4: goto and;
kaf24@4047 1366 case 5: goto sub;
kaf24@4047 1367 case 6: goto xor;
kaf24@4047 1368 case 7: goto cmp;
kaf24@4047 1369 }
kaf24@4047 1370 break;
kfraser@13328 1371
kfraser@13334 1372 case 0xa8 ... 0xa9: /* test imm,%%eax */
kfraser@13334 1373 dst.reg = (unsigned long *)&_regs.eax;
kfraser@13383 1374 dst.val = _regs.eax;
kaf24@4047 1375 case 0x84 ... 0x85: test: /* test */
kaf24@4047 1376 emulate_2op_SrcV("test", src, dst, _regs.eflags);
kaf24@4047 1377 break;
kfraser@13328 1378
kfraser@13282 1379 case 0x86 ... 0x87: xchg: /* xchg */
kaf24@4270 1380 /* Write back the register source. */
kaf24@4269 1381 switch ( dst.bytes )
kaf24@4269 1382 {
kfraser@12675 1383 case 1: *(uint8_t *)src.reg = (uint8_t)dst.val; break;
kfraser@12675 1384 case 2: *(uint16_t *)src.reg = (uint16_t)dst.val; break;
kfraser@12675 1385 case 4: *src.reg = (uint32_t)dst.val; break; /* 64b reg: zero-extend */
kfraser@12675 1386 case 8: *src.reg = dst.val; break;
kaf24@4269 1387 }
kaf24@4270 1388 /* Write back the memory destination with implicit LOCK prefix. */
kaf24@4270 1389 dst.val = src.val;
kaf24@4270 1390 lock_prefix = 1;
kaf24@4047 1391 break;
kfraser@13328 1392
kfraser@13334 1393 case 0xc6 ... 0xc7: /* mov (sole member of Grp11) */
kaf24@13428 1394 generate_exception_if((modrm_reg & 7) != 0, EXC_UD);
kaf24@4047 1395 case 0x88 ... 0x8b: /* mov */
kaf24@4047 1396 dst.val = src.val;
kaf24@4047 1397 break;
kfraser@13328 1398
keir@16454 1399 case 0x8c: /* mov Sreg,r/m */ {
keir@16454 1400 struct segment_register reg;
keir@16454 1401 enum x86_segment seg = decode_segment(modrm_reg);
keir@16454 1402 generate_exception_if(seg == decode_segment_failed, EXC_UD);
keir@16454 1403 fail_if(ops->read_segment == NULL);
keir@16454 1404 if ( (rc = ops->read_segment(seg, &reg, ctxt)) != 0 )
keir@16454 1405 goto done;
keir@16454 1406 dst.val = reg.sel;
keir@16454 1407 if ( dst.type == OP_MEM )
keir@16454 1408 dst.bytes = 2;
keir@16454 1409 break;
keir@16454 1410 }
keir@16454 1411
keir@16454 1412 case 0x8e: /* mov r/m,Sreg */ {
keir@16454 1413 enum x86_segment seg = decode_segment(modrm_reg);
keir@16454 1414 generate_exception_if(seg == decode_segment_failed, EXC_UD);
keir@16454 1415 if ( (rc = load_seg(seg, (uint16_t)src.val, ctxt, ops)) != 0 )
keir@16454 1416 goto done;
keir@16454 1417 dst.type = OP_NONE;
keir@16454 1418 break;
keir@16454 1419 }
keir@16454 1420
kfraser@13268 1421 case 0x8d: /* lea */
kfraser@13268 1422 dst.val = ea.mem.off;
kfraser@13268 1423 break;
kfraser@13328 1424
kaf24@4047 1425 case 0x8f: /* pop (sole member of Grp1a) */
kaf24@13428 1426 generate_exception_if((modrm_reg & 7) != 0, EXC_UD);
kfraser@13265 1427 /* 64-bit mode: POP defaults to a 64-bit operand. */
kfraser@13331 1428 if ( mode_64bit() && (dst.bytes == 4) )
kaf24@4047 1429 dst.bytes = 8;
kfraser@13443 1430 if ( (rc = ops->read(x86_seg_ss, sp_post_inc(dst.bytes),
kfraser@12675 1431 &dst.val, dst.bytes, ctxt)) != 0 )
kaf24@4047 1432 goto done;
kaf24@4047 1433 break;
kfraser@13328 1434
kaf24@13321 1435 case 0xb0 ... 0xb7: /* mov imm8,r8 */
kaf24@13321 1436 dst.reg = decode_register(
kaf24@13321 1437 (b & 7) | ((rex_prefix & 1) << 3), &_regs, (rex_prefix == 0));
kaf24@13321 1438 dst.val = src.val;
kaf24@13321 1439 break;
kfraser@13328 1440
kaf24@13321 1441 case 0xb8 ... 0xbf: /* mov imm{16,32,64},r{16,32,64} */
kaf24@13321 1442 if ( dst.bytes == 8 ) /* Fetch more bytes to obtain imm64 */
kaf24@13321 1443 src.val = ((uint32_t)src.val |
kaf24@13321 1444 ((uint64_t)insn_fetch_type(uint32_t) << 32));
kaf24@13321 1445 dst.reg = decode_register(
kaf24@13321 1446 (b & 7) | ((rex_prefix & 1) << 3), &_regs, 0);
kaf24@13321 1447 dst.val = src.val;
kaf24@13321 1448 break;
kfraser@13328 1449
kaf24@4047 1450 case 0xc0 ... 0xc1: grp2: /* Grp2 */
kfraser@12559 1451 switch ( modrm_reg & 7 )
kaf24@4047 1452 {
kaf24@4047 1453 case 0: /* rol */
kaf24@4047 1454 emulate_2op_SrcB("rol", src, dst, _regs.eflags);
kaf24@4047 1455 break;
kaf24@4047 1456 case 1: /* ror */
kaf24@4047 1457 emulate_2op_SrcB("ror", src, dst, _regs.eflags);
kaf24@4047 1458 break;
kaf24@4047 1459 case 2: /* rcl */
kaf24@4047 1460 emulate_2op_SrcB("rcl", src, dst, _regs.eflags);
kaf24@4047 1461 break;
kaf24@4047 1462 case 3: /* rcr */
kaf24@4047 1463 emulate_2op_SrcB("rcr", src, dst, _regs.eflags);
kaf24@4047 1464 break;
kaf24@4047 1465 case 4: /* sal/shl */
kaf24@4047 1466 case 6: /* sal/shl */
kaf24@4047 1467 emulate_2op_SrcB("sal", src, dst, _regs.eflags);
kaf24@4047 1468 break;
kaf24@4047 1469 case 5: /* shr */
kaf24@4047 1470 emulate_2op_SrcB("shr", src, dst, _regs.eflags);
kaf24@4047 1471 break;
kaf24@4047 1472 case 7: /* sar */
kaf24@4047 1473 emulate_2op_SrcB("sar", src, dst, _regs.eflags);
kaf24@4047 1474 break;
kaf24@4047 1475 }
kaf24@4047 1476 break;
kfraser@13328 1477
keir@16467 1478 case 0xc4: /* les */ {
keir@16467 1479 unsigned long sel;
keir@16467 1480 dst.val = x86_seg_es;
keir@16467 1481 les:
keir@16467 1482 generate_exception_if(src.type != OP_MEM, EXC_UD);
keir@16467 1483 if ( (rc = ops->read(src.mem.seg, src.mem.off + src.bytes,
keir@16467 1484 &sel, 2, ctxt)) != 0 )
keir@16467 1485 goto done;
keir@16467 1486 if ( (rc = load_seg(dst.val, (uint16_t)sel, ctxt, ops)) != 0 )
keir@16467 1487 goto done;
keir@16467 1488 dst.val = src.val;
keir@16467 1489 break;
keir@16467 1490 }
keir@16467 1491
keir@16467 1492 case 0xc5: /* lds */
keir@16467 1493 dst.val = x86_seg_ds;
keir@16467 1494 goto les;
keir@16467 1495
kaf24@4047 1496 case 0xd0 ... 0xd1: /* Grp2 */
kaf24@4047 1497 src.val = 1;
kaf24@4047 1498 goto grp2;
kfraser@13328 1499
kaf24@4047 1500 case 0xd2 ... 0xd3: /* Grp2 */
kaf24@4047 1501 src.val = _regs.ecx;
kaf24@4047 1502 goto grp2;
kfraser@13328 1503
kaf24@4047 1504 case 0xf6 ... 0xf7: /* Grp3 */
kfraser@12559 1505 switch ( modrm_reg & 7 )
kaf24@4047 1506 {
kaf24@4047 1507 case 0 ... 1: /* test */
kaf24@4047 1508 /* Special case in Grp3: test has an immediate source operand. */
kaf24@4047 1509 src.type = OP_IMM;
kaf24@4047 1510 src.bytes = (d & ByteOp) ? 1 : op_bytes;
kaf24@4047 1511 if ( src.bytes == 8 ) src.bytes = 4;
kaf24@4047 1512 switch ( src.bytes )
kaf24@4047 1513 {
kaf24@12769 1514 case 1: src.val = insn_fetch_type(int8_t); break;
kaf24@12769 1515 case 2: src.val = insn_fetch_type(int16_t); break;
kaf24@12769 1516 case 4: src.val = insn_fetch_type(int32_t); break;
kaf24@4047 1517 }
kaf24@4047 1518 goto test;
kaf24@4047 1519 case 2: /* not */
kaf24@4047 1520 dst.val = ~dst.val;
kaf24@4047 1521 break;
kaf24@4047 1522 case 3: /* neg */
kaf24@4047 1523 emulate_1op("neg", dst, _regs.eflags);
kaf24@4047 1524 break;
kaf24@13426 1525 case 4: /* mul */
kaf24@13426 1526 src = dst;
kaf24@13426 1527 dst.type = OP_REG;
kaf24@13426 1528 dst.reg = (unsigned long *)&_regs.eax;
kaf24@13426 1529 dst.val = *dst.reg;
kaf24@13426 1530 _regs.eflags &= ~(EFLG_OF|EFLG_CF);
kaf24@13426 1531 switch ( src.bytes )
kaf24@13426 1532 {
kaf24@13426 1533 case 1:
kaf24@13426 1534 dst.val *= src.val;
kaf24@13426 1535 if ( (uint8_t)dst.val != (uint16_t)dst.val )
kaf24@13426 1536 _regs.eflags |= EFLG_OF|EFLG_CF;
kaf24@13426 1537 break;
kaf24@13426 1538 case 2:
kaf24@13426 1539 dst.val *= src.val;
kaf24@13426 1540 if ( (uint16_t)dst.val != (uint32_t)dst.val )
kaf24@13426 1541 _regs.eflags |= EFLG_OF|EFLG_CF;
kaf24@13426 1542 *(uint16_t *)&_regs.edx = dst.val >> 16;
kaf24@13426 1543 break;
kaf24@13426 1544 #ifdef __x86_64__
kaf24@13426 1545 case 4:
kaf24@13426 1546 dst.val *= src.val;
kaf24@13426 1547 if ( (uint32_t)dst.val != dst.val )
kaf24@13426 1548 _regs.eflags |= EFLG_OF|EFLG_CF;
kaf24@13426 1549 _regs.edx = (uint32_t)(dst.val >> 32);
kaf24@13426 1550 break;
kaf24@13426 1551 #endif
kaf24@13426 1552 default: {
kaf24@13426 1553 unsigned long m[2] = { src.val, dst.val };
kaf24@13426 1554 if ( mul_dbl(m) )
kaf24@13426 1555 _regs.eflags |= EFLG_OF|EFLG_CF;
kaf24@13426 1556 _regs.edx = m[1];
kaf24@13426 1557 dst.val = m[0];
kaf24@13426 1558 break;
kaf24@13426 1559 }
kaf24@13426 1560 }
kaf24@13426 1561 break;
kaf24@13426 1562 case 5: /* imul */
kaf24@13426 1563 src = dst;
kaf24@13426 1564 dst.type = OP_REG;
kaf24@13426 1565 dst.reg = (unsigned long *)&_regs.eax;
kaf24@13426 1566 dst.val = *dst.reg;
kaf24@13426 1567 _regs.eflags &= ~(EFLG_OF|EFLG_CF);
kaf24@13426 1568 switch ( src.bytes )
kaf24@13426 1569 {
kaf24@13426 1570 case 1:
kaf24@13426 1571 dst.val = ((uint16_t)(int8_t)src.val *
kaf24@13426 1572 (uint16_t)(int8_t)dst.val);
kaf24@13426 1573 if ( (int8_t)dst.val != (uint16_t)dst.val )
kaf24@13426 1574 _regs.eflags |= EFLG_OF|EFLG_CF;
kaf24@13426 1575 break;
kaf24@13426 1576 case 2:
kaf24@13426 1577 dst.val = ((uint32_t)(int16_t)src.val *
kaf24@13426 1578 (uint32_t)(int16_t)dst.val);
kaf24@13426 1579 if ( (int16_t)dst.val != (uint32_t)dst.val )
kaf24@13426 1580 _regs.eflags |= EFLG_OF|EFLG_CF;
kaf24@13426 1581 *(uint16_t *)&_regs.edx = dst.val >> 16;
kaf24@13426 1582 break;
kaf24@13426 1583 #ifdef __x86_64__
kaf24@13426 1584 case 4:
kaf24@13426 1585 dst.val = ((uint64_t)(int32_t)src.val *
kaf24@13426 1586 (uint64_t)(int32_t)dst.val);
kaf24@13426 1587 if ( (int32_t)dst.val != dst.val )
kaf24@13426 1588 _regs.eflags |= EFLG_OF|EFLG_CF;
kaf24@13426 1589 _regs.edx = (uint32_t)(dst.val >> 32);
kaf24@13426 1590 break;
kaf24@13426 1591 #endif
kaf24@13426 1592 default: {
kaf24@13426 1593 unsigned long m[2] = { src.val, dst.val };
kaf24@13426 1594 if ( imul_dbl(m) )
kaf24@13426 1595 _regs.eflags |= EFLG_OF|EFLG_CF;
kaf24@13426 1596 _regs.edx = m[1];
kaf24@13426 1597 dst.val = m[0];
kaf24@13426 1598 break;
kaf24@13426 1599 }
kaf24@13426 1600 }
kaf24@13426 1601 break;
kaf24@13426 1602 case 6: /* div */ {
kaf24@13426 1603 unsigned long u[2], v;
kaf24@13426 1604 src = dst;
kaf24@13426 1605 dst.type = OP_REG;
kaf24@13426 1606 dst.reg = (unsigned long *)&_regs.eax;
kaf24@13426 1607 switch ( src.bytes )
kaf24@13426 1608 {
kaf24@13426 1609 case 1:
kaf24@13426 1610 u[0] = (uint16_t)_regs.eax;
kaf24@13426 1611 u[1] = 0;
kaf24@13426 1612 v = (uint8_t)src.val;
kaf24@13426 1613 generate_exception_if(
kaf24@13426 1614 div_dbl(u, v) || ((uint8_t)u[0] != (uint16_t)u[0]),
kaf24@13426 1615 EXC_DE);
kaf24@13426 1616 dst.val = (uint8_t)u[0];
kaf24@13426 1617 ((uint8_t *)&_regs.eax)[1] = u[1];
kaf24@13426 1618 break;
kaf24@13426 1619 case 2:
kaf24@13426 1620 u[0] = ((uint32_t)_regs.edx << 16) | (uint16_t)_regs.eax;
kaf24@13426 1621 u[1] = 0;
kaf24@13426 1622 v = (uint16_t)src.val;
kaf24@13426 1623 generate_exception_if(
kaf24@13426 1624 div_dbl(u, v) || ((uint16_t)u[0] != (uint32_t)u[0]),
kaf24@13426 1625 EXC_DE);
kaf24@13426 1626 dst.val = (uint16_t)u[0];
kaf24@13426 1627 *(uint16_t *)&_regs.edx = u[1];
kaf24@13426 1628 break;
kaf24@13426 1629 #ifdef __x86_64__
kaf24@13426 1630 case 4:
kaf24@13426 1631 u[0] = (_regs.edx << 32) | (uint32_t)_regs.eax;
kaf24@13426 1632 u[1] = 0;
kaf24@13426 1633 v = (uint32_t)src.val;
kaf24@13426 1634 generate_exception_if(
kaf24@13426 1635 div_dbl(u, v) || ((uint32_t)u[0] != u[0]),
kaf24@13426 1636 EXC_DE);
kaf24@13426 1637 dst.val = (uint32_t)u[0];
kaf24@13426 1638 _regs.edx = (uint32_t)u[1];
kaf24@13426 1639 break;
kaf24@13426 1640 #endif
kaf24@13426 1641 default:
kaf24@13426 1642 u[0] = _regs.eax;
kaf24@13426 1643 u[1] = _regs.edx;
kaf24@13426 1644 v = src.val;
kaf24@13426 1645 generate_exception_if(div_dbl(u, v), EXC_DE);
kaf24@13426 1646 dst.val = u[0];
kaf24@13426 1647 _regs.edx = u[1];
kaf24@13426 1648 break;
kaf24@13426 1649 }
kaf24@13426 1650 break;
kaf24@13426 1651 }
kaf24@13426 1652 case 7: /* idiv */ {
kaf24@13426 1653 unsigned long u[2], v;
kaf24@13426 1654 src = dst;
kaf24@13426 1655 dst.type = OP_REG;
kaf24@13426 1656 dst.reg = (unsigned long *)&_regs.eax;
kaf24@13426 1657 switch ( src.bytes )
kaf24@13426 1658 {
kaf24@13426 1659 case 1:
kaf24@13426 1660 u[0] = (int16_t)_regs.eax;
kaf24@13426 1661 u[1] = ((long)u[0] < 0) ? ~0UL : 0UL;
kaf24@13426 1662 v = (int8_t)src.val;
kaf24@13426 1663 generate_exception_if(
kaf24@13426 1664 idiv_dbl(u, v) || ((int8_t)u[0] != (int16_t)u[0]),
kaf24@13426 1665 EXC_DE);
kaf24@13426 1666 dst.val = (int8_t)u[0];
kaf24@13426 1667 ((int8_t *)&_regs.eax)[1] = u[1];
kaf24@13426 1668 break;
kaf24@13426 1669 case 2:
kaf24@13426 1670 u[0] = (int32_t)((_regs.edx << 16) | (uint16_t)_regs.eax);
kaf24@13426 1671 u[1] = ((long)u[0] < 0) ? ~0UL : 0UL;
kaf24@13426 1672 v = (int16_t)src.val;
kaf24@13426 1673 generate_exception_if(
kaf24@13426 1674 idiv_dbl(u, v) || ((int16_t)u[0] != (int32_t)u[0]),
kaf24@13426 1675 EXC_DE);
kaf24@13426 1676 dst.val = (int16_t)u[0];
kaf24@13426 1677 *(int16_t *)&_regs.edx = u[1];
kaf24@13426 1678 break;
kaf24@13426 1679 #ifdef __x86_64__
kaf24@13426 1680 case 4:
kaf24@13426 1681 u[0] = (_regs.edx << 32) | (uint32_t)_regs.eax;
kaf24@13426 1682 u[1] = ((long)u[0] < 0) ? ~0UL : 0UL;
kaf24@13426 1683 v = (int32_t)src.val;
kaf24@13426 1684 generate_exception_if(
kaf24@13426 1685 idiv_dbl(u, v) || ((int32_t)u[0] != u[0]),
kaf24@13426 1686 EXC_DE);
kaf24@13426 1687 dst.val = (int32_t)u[0];
kaf24@13426 1688 _regs.edx = (uint32_t)u[1];
kaf24@13426 1689 break;
kaf24@13426 1690 #endif
kaf24@13426 1691 default:
kaf24@13426 1692 u[0] = _regs.eax;
kaf24@13426 1693 u[1] = _regs.edx;
kaf24@13426 1694 v = src.val;
kaf24@13426 1695 generate_exception_if(idiv_dbl(u, v), EXC_DE);
kaf24@13426 1696 dst.val = u[0];
kaf24@13426 1697 _regs.edx = u[1];
kaf24@13426 1698 break;
kaf24@13426 1699 }
kaf24@13426 1700 break;
kaf24@13426 1701 }
kaf24@4047 1702 default:
kaf24@4047 1703 goto cannot_emulate;
kaf24@4047 1704 }
kaf24@4047 1705 break;
kfraser@13328 1706
kfraser@13334 1707 case 0xfe: /* Grp4 */
kaf24@13428 1708 generate_exception_if((modrm_reg & 7) >= 2, EXC_UD);
kfraser@13334 1709 case 0xff: /* Grp5 */
kfraser@12559 1710 switch ( modrm_reg & 7 )
kaf24@4047 1711 {
kaf24@4047 1712 case 0: /* inc */
kaf24@4047 1713 emulate_1op("inc", dst, _regs.eflags);
kaf24@4047 1714 break;
kaf24@4047 1715 case 1: /* dec */
kaf24@4047 1716 emulate_1op("dec", dst, _regs.eflags);
kaf24@4047 1717 break;
kfraser@13388 1718 case 2: /* call (near) */
kfraser@13462 1719 case 4: /* jmp (near) */
kfraser@13388 1720 if ( ((op_bytes = dst.bytes) != 8) && mode_64bit() )
kfraser@13388 1721 {
kfraser@13388 1722 dst.bytes = op_bytes = 8;
kfraser@14579 1723 if ( dst.type == OP_REG )
kfraser@14579 1724 dst.val = *dst.reg;
kfraser@14579 1725 else if ( (rc = ops->read(dst.mem.seg, dst.mem.off,
kfraser@14579 1726 &dst.val, 8, ctxt)) != 0 )
kfraser@13388 1727 goto done;
kfraser@13388 1728 }
kfraser@13388 1729 src.val = _regs.eip;
kfraser@13388 1730 _regs.eip = dst.val;
kfraser@13388 1731 if ( (modrm_reg & 7) == 2 )
kfraser@13388 1732 goto push; /* call */
kfraser@13388 1733 break;
keir@16461 1734 case 3: /* call (far, absolute indirect) */
keir@16461 1735 case 5: /* jmp (far, absolute indirect) */ {
keir@16461 1736 unsigned long sel, eip = dst.val;
keir@16461 1737
keir@16461 1738 if ( (rc = ops->read(dst.mem.seg, dst.mem.off+dst.bytes,
keir@16461 1739 &sel, 2, ctxt)) )
keir@16461 1740 goto done;
keir@16461 1741
keir@16461 1742 if ( (modrm_reg & 7) == 3 ) /* call */
keir@16461 1743 {
keir@16461 1744 struct segment_register reg;
keir@16461 1745 fail_if(ops->read_segment == NULL);
keir@16461 1746 if ( (rc = ops->read_segment(x86_seg_cs, &reg, ctxt)) ||
keir@16461 1747 (rc = ops->write(x86_seg_ss, sp_pre_dec(op_bytes),
keir@16461 1748 reg.sel, op_bytes, ctxt)) ||
keir@16461 1749 (rc = ops->write(x86_seg_ss, sp_pre_dec(op_bytes),
keir@16461 1750 _regs.eip, op_bytes, ctxt)) )
keir@16461 1751 goto done;
keir@16461 1752 }
keir@16461 1753
keir@16461 1754 if ( (rc = load_seg(x86_seg_cs, sel, ctxt, ops)) != 0 )
keir@16461 1755 goto done;
keir@16461 1756 _regs.eip = eip;
keir@16461 1757
keir@16461 1758 dst.type = OP_NONE;
keir@16461 1759 break;
keir@16461 1760 }
kaf24@4047 1761 case 6: /* push */
kfraser@13265 1762 /* 64-bit mode: PUSH defaults to a 64-bit operand. */
kfraser@13331 1763 if ( mode_64bit() && (dst.bytes == 4) )
kaf24@4047 1764 {
kaf24@4047 1765 dst.bytes = 8;
kfraser@14579 1766 if ( dst.type == OP_REG )
kfraser@14579 1767 dst.val = *dst.reg;
kfraser@14579 1768 else if ( (rc = ops->read(dst.mem.seg, dst.mem.off,
kfraser@14579 1769 &dst.val, 8, ctxt)) != 0 )
kaf24@4047 1770 goto done;
kaf24@4047 1771 }
kfraser@13443 1772 if ( (rc = ops->write(x86_seg_ss, sp_pre_dec(dst.bytes),
kfraser@12675 1773 dst.val, dst.bytes, ctxt)) != 0 )
kaf24@4047 1774 goto done;
kfraser@13383 1775 dst.type = OP_NONE;
kaf24@4047 1776 break;
kfraser@13334 1777 case 7:
kaf24@13428 1778 generate_exception_if(1, EXC_UD);
kaf24@4047 1779 default:
kaf24@4047 1780 goto cannot_emulate;
kaf24@4047 1781 }
kaf24@4047 1782 break;
kaf24@4047 1783 }
kaf24@4047 1784
kaf24@4047 1785 writeback:
kfraser@13383 1786 switch ( dst.type )
kaf24@4047 1787 {
kfraser@13383 1788 case OP_REG:
kfraser@13383 1789 /* The 4-byte case *is* correct: in 64-bit mode we zero-extend. */
kfraser@13383 1790 switch ( dst.bytes )
kaf24@4047 1791 {
kfraser@13383 1792 case 1: *(uint8_t *)dst.reg = (uint8_t)dst.val; break;
kfraser@13383 1793 case 2: *(uint16_t *)dst.reg = (uint16_t)dst.val; break;
kfraser@13383 1794 case 4: *dst.reg = (uint32_t)dst.val; break; /* 64b: zero-ext */
kfraser@13383 1795 case 8: *dst.reg = dst.val; break;
kaf24@4047 1796 }
kfraser@13383 1797 break;
kfraser@13383 1798 case OP_MEM:
kfraser@13383 1799 if ( !(d & Mov) && (dst.orig_val == dst.val) )
kfraser@13383 1800 /* nothing to do */;
kfraser@13383 1801 else if ( lock_prefix )
kfraser@13383 1802 rc = ops->cmpxchg(
kfraser@13383 1803 dst.mem.seg, dst.mem.off, dst.orig_val,
kfraser@13383 1804 dst.val, dst.bytes, ctxt);
kfraser@13383 1805 else
kfraser@13383 1806 rc = ops->write(
kfraser@13383 1807 dst.mem.seg, dst.mem.off, dst.val, dst.bytes, ctxt);
kfraser@13383 1808 if ( rc != 0 )
kfraser@13383 1809 goto done;
kfraser@13383 1810 default:
kfraser@13383 1811 break;
kaf24@4047 1812 }
kaf24@4047 1813
kaf24@4047 1814 /* Commit shadow register state. */
keir@16309 1815 _regs.eflags &= ~EFLG_RF;
kaf24@10179 1816 *ctxt->regs = _regs;
keir@16462 1817
keir@16462 1818 if ( (_regs.eflags & EFLG_TF) &&
keir@16462 1819 (rc == X86EMUL_OKAY) &&
keir@16462 1820 (ops->inject_hw_exception != NULL) )
keir@16462 1821 rc = ops->inject_hw_exception(EXC_DB, ctxt) ? : X86EMUL_EXCEPTION;
kaf24@4047 1822
kaf24@4047 1823 done:
kfraser@14063 1824 return rc;
kaf24@4047 1825
kaf24@4047 1826 special_insn:
kfraser@13383 1827 dst.type = OP_NONE;
kfraser@13383 1828
kfraser@13383 1829 /*
kfraser@13623 1830 * The only implicit-operands instructions allowed a LOCK prefix are
kfraser@13623 1831 * CMPXCHG{8,16}B, MOV CRn, MOV DRn.
kfraser@13383 1832 */
kfraser@13623 1833 generate_exception_if(lock_prefix &&
kfraser@13623 1834 ((b < 0x20) || (b > 0x23)) && /* MOV CRn/DRn */
kfraser@13623 1835 (b != 0xc7), /* CMPXCHG{8,16}B */
kfraser@13623 1836 EXC_GP);
kfraser@13328 1837
kaf24@4047 1838 if ( twobyte )
kaf24@4047 1839 goto twobyte_special_insn;
kfraser@13328 1840
kaf24@4047 1841 switch ( b )
kaf24@4047 1842 {
keir@16454 1843 case 0x06: /* push %%es */ {
keir@16454 1844 struct segment_register reg;
keir@16454 1845 src.val = x86_seg_es;
keir@16454 1846 push_seg:
keir@16454 1847 fail_if(ops->read_segment == NULL);
keir@16454 1848 if ( (rc = ops->read_segment(src.val, &reg, ctxt)) != 0 )
keir@16454 1849 return rc;
keir@16454 1850 /* 64-bit mode: PUSH defaults to a 64-bit operand. */
keir@16454 1851 if ( mode_64bit() && (op_bytes == 4) )
keir@16454 1852 op_bytes = 8;
keir@16454 1853 if ( (rc = ops->write(x86_seg_ss, sp_pre_dec(op_bytes),
keir@16454 1854 reg.sel, op_bytes, ctxt)) != 0 )
keir@16454 1855 goto done;
keir@16454 1856 break;
keir@16454 1857 }
keir@16454 1858
keir@16454 1859 case 0x07: /* pop %%es */
keir@16454 1860 src.val = x86_seg_es;
keir@16454 1861 pop_seg:
keir@16454 1862 fail_if(ops->write_segment == NULL);
keir@16454 1863 /* 64-bit mode: PUSH defaults to a 64-bit operand. */
keir@16454 1864 if ( mode_64bit() && (op_bytes == 4) )
keir@16454 1865 op_bytes = 8;
keir@16454 1866 if ( (rc = ops->read(x86_seg_ss, sp_post_inc(op_bytes),
keir@16454 1867 &dst.val, op_bytes, ctxt)) != 0 )
keir@16454 1868 goto done;
keir@16454 1869 if ( (rc = load_seg(src.val, (uint16_t)dst.val, ctxt, ops)) != 0 )
keir@16454 1870 return rc;
keir@16454 1871 break;
keir@16454 1872
keir@16454 1873 case 0x0e: /* push %%cs */
keir@16454 1874 src.val = x86_seg_cs;
keir@16454 1875 goto push_seg;
keir@16454 1876
keir@16454 1877 case 0x16: /* push %%ss */
keir@16454 1878 src.val = x86_seg_ss;
keir@16454 1879 goto push_seg;
keir@16454 1880
keir@16454 1881 case 0x17: /* pop %%ss */
keir@16454 1882 src.val = x86_seg_ss;
keir@16454 1883 goto pop_seg;
keir@16454 1884
keir@16454 1885 case 0x1e: /* push %%ds */
keir@16454 1886 src.val = x86_seg_ds;
keir@16454 1887 goto push_seg;
keir@16454 1888
keir@16454 1889 case 0x1f: /* pop %%ds */
keir@16454 1890 src.val = x86_seg_ds;
keir@16454 1891 goto pop_seg;
keir@16454 1892
kfraser@13334 1893 case 0x27: /* daa */ {
kfraser@13334 1894 uint8_t al = _regs.eax;
kfraser@13343 1895 unsigned long eflags = _regs.eflags;
kaf24@13428 1896 generate_exception_if(mode_64bit(), EXC_UD);
kfraser@13343 1897 _regs.eflags &= ~(EFLG_CF|EFLG_AF);
kfraser@13343 1898 if ( ((al & 0x0f) > 9) || (eflags & EFLG_AF) )
kfraser@13343 1899 {
kfraser@13343 1900 *(uint8_t *)&_regs.eax += 6;
kfraser@13343 1901 _regs.eflags |= EFLG_AF;
kfraser@13343 1902 }
kfraser@13343 1903 if ( (al > 0x99) || (eflags & EFLG_CF) )
kfraser@13343 1904 {
kfraser@13343 1905 *(uint8_t *)&_regs.eax += 0x60;
kfraser@13343 1906 _regs.eflags |= EFLG_CF;
kfraser@13343 1907 }
kfraser@13343 1908 _regs.eflags &= ~(EFLG_SF|EFLG_ZF|EFLG_PF);
kfraser@13343 1909 _regs.eflags |= ((uint8_t)_regs.eax == 0) ? EFLG_ZF : 0;
kfraser@13343 1910 _regs.eflags |= (( int8_t)_regs.eax < 0) ? EFLG_SF : 0;
kfraser@13343 1911 _regs.eflags |= even_parity(_regs.eax) ? EFLG_PF : 0;
kfraser@13334 1912 break;
kfraser@13334 1913 }
kfraser@13334 1914
kfraser@13334 1915 case 0x2f: /* das */ {
kfraser@13334 1916 uint8_t al = _regs.eax;
kfraser@13343 1917 unsigned long eflags = _regs.eflags;
kaf24@13428 1918 generate_exception_if(mode_64bit(), EXC_UD);
kfraser@13343 1919 _regs.eflags &= ~(EFLG_CF|EFLG_AF);
kfraser@13343 1920 if ( ((al & 0x0f) > 9) || (eflags & EFLG_AF) )
kfraser@13343 1921 {
kfraser@13343 1922 _regs.eflags |= EFLG_AF;
kfraser@13343 1923 if ( (al < 6) || (eflags & EFLG_CF) )
kfraser@13343 1924 _regs.eflags |= EFLG_CF;
kfraser@13343 1925 *(uint8_t *)&_regs.eax -= 6;
kfraser@13343 1926 }
kfraser@13343 1927 if ( (al > 0x99) || (eflags & EFLG_CF) )
kfraser@13343 1928 {
kfraser@13343 1929 *(uint8_t *)&_regs.eax -= 0x60;
kfraser@13343 1930 _regs.eflags |= EFLG_CF;
kfraser@13343 1931 }
kfraser@13343 1932 _regs.eflags &= ~(EFLG_SF|EFLG_ZF|EFLG_PF);
kfraser@13343 1933 _regs.eflags |= ((uint8_t)_regs.eax == 0) ? EFLG_ZF : 0;
kfraser@13343 1934 _regs.eflags |= (( int8_t)_regs.eax < 0) ? EFLG_SF : 0;
kfraser@13343 1935 _regs.eflags |= even_parity(_regs.eax) ? EFLG_PF : 0;
kfraser@13334 1936 break;
kfraser@13334 1937 }
kfraser@13334 1938
kfraser@13334 1939 case 0x37: /* aaa */
kfraser@13334 1940 case 0x3f: /* aas */
kaf24@13428 1941 generate_exception_if(mode_64bit(), EXC_UD);
kfraser@13334 1942 _regs.eflags &= ~EFLG_CF;
kfraser@13334 1943 if ( ((uint8_t)_regs.eax > 9) || (_regs.eflags & EFLG_AF) )
kfraser@13334 1944 {
kfraser@13334 1945 ((uint8_t *)&_regs.eax)[0] += (b == 0x37) ? 6 : -6;
kfraser@13334 1946 ((uint8_t *)&_regs.eax)[1] += (b == 0x37) ? 1 : -1;
kfraser@13334 1947 _regs.eflags |= EFLG_CF | EFLG_AF;
kfraser@13334 1948 }
kfraser@13334 1949 ((uint8_t *)&_regs.eax)[0] &= 0x0f;
kfraser@13334 1950 break;
kfraser@13334 1951
kfraser@13265 1952 case 0x40 ... 0x4f: /* inc/dec reg */
kfraser@13265 1953 dst.type = OP_REG;
kfraser@13282 1954 dst.reg = decode_register(b & 7, &_regs, 0);
kfraser@13265 1955 dst.bytes = op_bytes;
kfraser@13383 1956 dst.val = *dst.reg;
kfraser@13265 1957 if ( b & 8 )
kfraser@13265 1958 emulate_1op("dec", dst, _regs.eflags);
kfraser@13265 1959 else
kfraser@13265 1960 emulate_1op("inc", dst, _regs.eflags);
kfraser@13265 1961 break;
kfraser@13328 1962
kfraser@13265 1963 case 0x50 ... 0x57: /* push reg */
kfraser@13388 1964 src.val = *(unsigned long *)decode_register(
kfraser@13282 1965 (b & 7) | ((rex_prefix & 1) << 3), &_regs, 0);
kfraser@13388 1966 goto push;
kfraser@13328 1967
kfraser@13265 1968 case 0x58 ... 0x5f: /* pop reg */
kfraser@13265 1969 dst.type = OP_REG;
kfraser@13282 1970 dst.reg = decode_register(
kfraser@13282 1971 (b & 7) | ((rex_prefix & 1) << 3), &_regs, 0);
kfraser@13265 1972 dst.bytes = op_bytes;
kfraser@13331 1973 if ( mode_64bit() && (dst.bytes == 4) )
kfraser@13265 1974 dst.bytes = 8;
kfraser@13443 1975 if ( (rc = ops->read(x86_seg_ss, sp_post_inc(dst.bytes),
kfraser@13265 1976 &dst.val, dst.bytes, ctxt)) != 0 )
kfraser@13265 1977 goto done;
kfraser@13265 1978 break;
kfraser@13328 1979
kaf24@13428 1980 case 0x60: /* pusha */ {
kaf24@13428 1981 int i;
kaf24@13428 1982 unsigned long regs[] = {
kaf24@13428 1983 _regs.eax, _regs.ecx, _regs.edx, _regs.ebx,
kaf24@13428 1984 _regs.esp, _regs.ebp, _regs.esi, _regs.edi };
kaf24@13428 1985 generate_exception_if(mode_64bit(), EXC_UD);
kaf24@13428 1986 for ( i = 0; i < 8; i++ )
kfraser@13443 1987 if ( (rc = ops->write(x86_seg_ss, sp_pre_dec(op_bytes),
kaf24@13428 1988 regs[i], op_bytes, ctxt)) != 0 )
kaf24@13428 1989 goto done;
kaf24@13428 1990 break;
kaf24@13428 1991 }
kaf24@13428 1992
kaf24@13428 1993 case 0x61: /* popa */ {
kaf24@13428 1994 int i;
kaf24@13428 1995 unsigned long dummy_esp, *regs[] = {
kaf24@13430 1996 (unsigned long *)&_regs.edi, (unsigned long *)&_regs.esi,
kaf24@13430 1997 (unsigned long *)&_regs.ebp, (unsigned long *)&dummy_esp,
kaf24@13430 1998 (unsigned long *)&_regs.ebx, (unsigned long *)&_regs.edx,
kaf24@13430 1999 (unsigned long *)&_regs.ecx, (unsigned long *)&_regs.eax };
kaf24@13428 2000 generate_exception_if(mode_64bit(), EXC_UD);
kaf24@13428 2001 for ( i = 0; i < 8; i++ )
kfraser@13443 2002 if ( (rc = ops->read(x86_seg_ss, sp_post_inc(op_bytes),
kaf24@13428 2003 regs[i], op_bytes, ctxt)) != 0 )
kaf24@13428 2004 goto done;
kaf24@13428 2005 break;
kaf24@13428 2006 }
kaf24@13428 2007
kfraser@13388 2008 case 0x68: /* push imm{16,32,64} */
kfraser@13388 2009 src.val = ((op_bytes == 2)
kfraser@13388 2010 ? (int32_t)insn_fetch_type(int16_t)
kfraser@13388 2011 : insn_fetch_type(int32_t));
kfraser@13388 2012 goto push;
kfraser@13388 2013
kfraser@13388 2014 case 0x6a: /* push imm8 */
kfraser@13388 2015 src.val = insn_fetch_type(int8_t);
kfraser@13388 2016 push:
kfraser@13388 2017 d |= Mov; /* force writeback */
kfraser@13388 2018 dst.type = OP_MEM;
kfraser@13388 2019 dst.bytes = op_bytes;
kfraser@13388 2020 if ( mode_64bit() && (dst.bytes == 4) )
kfraser@13388 2021 dst.bytes = 8;
kfraser@13388 2022 dst.val = src.val;
kfraser@13388 2023 dst.mem.seg = x86_seg_ss;
kfraser@13443 2024 dst.mem.off = sp_pre_dec(dst.bytes);
kfraser@13388 2025 break;
kfraser@13388 2026
kfraser@13624 2027 case 0x6c ... 0x6d: /* ins %dx,%es:%edi */
kfraser@14034 2028 handle_rep_prefix();
kfraser@13624 2029 generate_exception_if(!mode_iopl(), EXC_GP);
kfraser@13624 2030 dst.type = OP_MEM;
kfraser@13624 2031 dst.bytes = !(b & 1) ? 1 : (op_bytes == 8) ? 4 : op_bytes;
kfraser@13624 2032 dst.mem.seg = x86_seg_es;
kfraser@13624 2033 dst.mem.off = truncate_ea(_regs.edi);
kfraser@13624 2034 fail_if(ops->read_io == NULL);
kfraser@13624 2035 if ( (rc = ops->read_io((uint16_t)_regs.edx, dst.bytes,
kfraser@13624 2036 &dst.val, ctxt)) != 0 )
kfraser@13624 2037 goto done;
kfraser@13624 2038 register_address_increment(
kfraser@13624 2039 _regs.edi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
kfraser@13624 2040 break;
kfraser@13624 2041
kfraser@13624 2042 case 0x6e ... 0x6f: /* outs %esi,%dx */
kfraser@14034 2043 handle_rep_prefix();
kfraser@13624 2044 generate_exception_if(!mode_iopl(), EXC_GP);
kfraser@13624 2045 dst.bytes = !(b & 1) ? 1 : (op_bytes == 8) ? 4 : op_bytes;
kfraser@13624 2046 if ( (rc = ops->read(ea.mem.seg, truncate_ea(_regs.esi),
kfraser@13624 2047 &dst.val, dst.bytes, ctxt)) != 0 )
kfraser@13624 2048 goto done;
kfraser@13624 2049 fail_if(ops->write_io == NULL);
kfraser@13624 2050 if ( (rc = ops->write_io((uint16_t)_regs.edx, dst.bytes,
kfraser@13624 2051 dst.val, ctxt)) != 0 )
kfraser@13624 2052 goto done;
kfraser@13624 2053 register_address_increment(
kfraser@13624 2054 _regs.esi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
kfraser@13624 2055 break;
kfraser@13624 2056
kfraser@13328 2057 case 0x70 ... 0x7f: /* jcc (short) */ {
kfraser@13328 2058 int rel = insn_fetch_type(int8_t);
kfraser@13328 2059 if ( test_cc(b, _regs.eflags) )
kfraser@13328 2060 jmp_rel(rel);
kfraser@13328 2061 break;
kfraser@13328 2062 }
kfraser@13328 2063
kfraser@13282 2064 case 0x90: /* nop / xchg %%r8,%%rax */
kfraser@13282 2065 if ( !(rex_prefix & 1) )
kfraser@13282 2066 break; /* nop */
kfraser@13328 2067
kfraser@13282 2068 case 0x91 ... 0x97: /* xchg reg,%%rax */
kfraser@13317 2069 src.type = dst.type = OP_REG;
kfraser@13317 2070 src.bytes = dst.bytes = op_bytes;
kfraser@13282 2071 src.reg = (unsigned long *)&_regs.eax;
kfraser@13282 2072 src.val = *src.reg;
kfraser@13282 2073 dst.reg = decode_register(
kfraser@13282 2074 (b & 7) | ((rex_prefix & 1) << 3), &_regs, 0);
kfraser@13383 2075 dst.val = *dst.reg;
kfraser@13282 2076 goto xchg;
kfraser@13328 2077
kfraser@13393 2078 case 0x98: /* cbw/cwde/cdqe */
kfraser@13393 2079 switch ( op_bytes )
kfraser@13393 2080 {
kfraser@13393 2081 case 2: *(int16_t *)&_regs.eax = (int8_t)_regs.eax; break; /* cbw */
kfraser@13393 2082 case 4: _regs.eax = (uint32_t)(int16_t)_regs.eax; break; /* cwde */
kfraser@13393 2083 case 8: _regs.eax = (int32_t)_regs.eax; break; /* cdqe */
kfraser@13393 2084 }
kfraser@13393 2085 break;
kfraser@13393 2086
kfraser@13393 2087 case 0x99: /* cwd/cdq/cqo */
kfraser@13393 2088 switch ( op_bytes )
kfraser@13393 2089 {
kfraser@13393 2090 case 2:
kfraser@13393 2091 *(int16_t *)&_regs.edx = ((int16_t)_regs.eax < 0) ? -1 : 0;
kfraser@13393 2092 break;
kfraser@13393 2093 case 4:
kfraser@13393 2094 _regs.edx = (uint32_t)(((int32_t)_regs.eax < 0) ? -1 : 0);
kfraser@13393 2095 break;
kfraser@13393 2096 case 8:
kfraser@13393 2097 _regs.edx = (_regs.eax < 0) ? -1 : 0;
kfraser@13393 2098 break;
kfraser@13393 2099 }
kfraser@13393 2100 break;
kfraser@13393 2101
keir@16461 2102 case 0x9a: /* call (far, absolute) */ {
keir@16461 2103 struct segment_register reg;
keir@16461 2104 uint16_t sel;
keir@16461 2105 uint32_t eip;
keir@16461 2106
keir@16461 2107 fail_if(ops->read_segment == NULL);
keir@16461 2108 generate_exception_if(mode_64bit(), EXC_UD);
keir@16461 2109
keir@16461 2110 eip = insn_fetch_bytes(op_bytes);
keir@16461 2111 sel = insn_fetch_type(uint16_t);
keir@16461 2112
keir@16461 2113 if ( (rc = ops->read_segment(x86_seg_cs, &reg, ctxt)) ||
keir@16461 2114 (rc = ops->write(x86_seg_ss, sp_pre_dec(op_bytes),
keir@16461 2115 reg.sel, op_bytes, ctxt)) ||
keir@16461 2116 (rc = ops->write(x86_seg_ss, sp_pre_dec(op_bytes),
keir@16461 2117 _regs.eip, op_bytes, ctxt)) )
keir@16461 2118 goto done;
keir@16461 2119
keir@16461 2120 if ( (rc = load_seg(x86_seg_cs, sel, ctxt, ops)) != 0 )
keir@16461 2121 goto done;
keir@16461 2122 _regs.eip = eip;
keir@16461 2123 break;
keir@16461 2124 }
keir@16461 2125
keir@16463 2126 case 0x9c: /* pushf */
keir@16463 2127 src.val = _regs.eflags;
keir@16463 2128 goto push;
keir@16463 2129
keir@16463 2130 case 0x9d: /* popf */ {
keir@16463 2131 uint32_t mask = EFLG_VIP | EFLG_VIF | EFLG_VM;
keir@16463 2132 if ( !mode_iopl() )
keir@16463 2133 mask |= EFLG_IOPL;
keir@16463 2134 fail_if(ops->write_rflags == NULL);
keir@16463 2135 /* 64-bit mode: POP defaults to a 64-bit operand. */
keir@16463 2136 if ( mode_64bit() && (op_bytes == 4) )
keir@16463 2137 op_bytes = 8;
keir@16463 2138 if ( (rc = ops->read(x86_seg_ss, sp_post_inc(op_bytes),
keir@16463 2139 &dst.val, op_bytes, ctxt)) != 0 )
keir@16463 2140 goto done;
keir@16463 2141 if ( op_bytes == 2 )
keir@16463 2142 dst.val = (uint16_t)dst.val | (_regs.eflags & 0xffff0000u);
keir@16463 2143 dst.val &= 0x257fd5;
keir@16463 2144 _regs.eflags &= mask;
keir@16463 2145 _regs.eflags |= (uint32_t)(dst.val & ~mask) | 0x02;
keir@16463 2146 if ( (rc = ops->write_rflags(_regs.eflags, ctxt)) != 0 )
keir@16463 2147 goto done;
keir@16463 2148 break;
keir@16463 2149 }
keir@16463 2150
kfraser@13380 2151 case 0x9e: /* sahf */
kfraser@13380 2152 *(uint8_t *)_regs.eflags = (((uint8_t *)&_regs.eax)[1] & 0xd7) | 0x02;
kfraser@13380 2153 break;
kfraser@13380 2154
kfraser@13380 2155 case 0x9f: /* lahf */
kfraser@13380 2156 ((uint8_t *)&_regs.eax)[1] = (_regs.eflags & 0xd7) | 0x02;
kfraser@13380 2157 break;
kfraser@13380 2158
kfraser@13145 2159 case 0xa0 ... 0xa1: /* mov mem.offs,{%al,%ax,%eax,%rax} */
kfraser@12675 2160 /* Source EA is not encoded via ModRM. */
kfraser@12675 2161 dst.type = OP_REG;
kfraser@12675 2162 dst.reg = (unsigned long *)&_regs.eax;
kfraser@12675 2163 dst.bytes = (d & ByteOp) ? 1 : op_bytes;
kfraser@13145 2164 if ( (rc = ops->read(ea.mem.seg, insn_fetch_bytes(ad_bytes),
kfraser@12675 2165 &dst.val, dst.bytes, ctxt)) != 0 )
kfraser@12675 2166 goto done;
kfraser@12675 2167 break;
kfraser@13328 2168
kfraser@13145 2169 case 0xa2 ... 0xa3: /* mov {%al,%ax,%eax,%rax},mem.offs */
kfraser@12675 2170 /* Destination EA is not encoded via ModRM. */
kfraser@13145 2171 dst.type = OP_MEM;
kfraser@13145 2172 dst.mem.seg = ea.mem.seg;
kfraser@13145 2173 dst.mem.off = insn_fetch_bytes(ad_bytes);
kfraser@13145 2174 dst.bytes = (d & ByteOp) ? 1 : op_bytes;
kfraser@13145 2175 dst.val = (unsigned long)_regs.eax;
kfraser@12675 2176 break;
kfraser@13328 2177
kaf24@4047 2178 case 0xa4 ... 0xa5: /* movs */
kfraser@14034 2179 handle_rep_prefix();
kaf24@4047 2180 dst.type = OP_MEM;
kaf24@4047 2181 dst.bytes = (d & ByteOp) ? 1 : op_bytes;
kfraser@13145 2182 dst.mem.seg = x86_seg_es;
kfraser@13145 2183 dst.mem.off = truncate_ea(_regs.edi);
kfraser@13145 2184 if ( (rc = ops->read(ea.mem.seg, truncate_ea(_regs.esi),
kfraser@12675 2185 &dst.val, dst.bytes, ctxt)) != 0 )
kfraser@12675 2186 goto done;
kaf24@8447 2187 register_address_increment(
kfraser@10279 2188 _regs.esi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
kaf24@8447 2189 register_address_increment(
kfraser@10279 2190 _regs.edi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
kaf24@4047 2191 break;
kfraser@13328 2192
keir@16465 2193 case 0xa6 ... 0xa7: /* cmps */ {
keir@16465 2194 unsigned long next_eip = _regs.eip;
keir@16465 2195 handle_rep_prefix();
keir@16465 2196 src.bytes = dst.bytes = (d & ByteOp) ? 1 : op_bytes;
keir@16465 2197 if ( (rc = ops->read(ea.mem.seg, truncate_ea(_regs.esi),
keir@16465 2198 &dst.val, dst.bytes, ctxt)) ||
keir@16465 2199 (rc = ops->read(x86_seg_es, truncate_ea(_regs.edi),
keir@16465 2200 &src.val, src.bytes, ctxt)) )
keir@16465 2201 goto done;
keir@16465 2202 register_address_increment(
keir@16465 2203 _regs.esi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
keir@16465 2204 register_address_increment(
keir@16465 2205 _regs.edi, (_regs.eflags & EFLG_DF) ? -src.bytes : src.bytes);
keir@16465 2206 /* cmp: dst - src ==> src=*%%edi,dst=*%%esi ==> *%%esi - *%%edi */
keir@16465 2207 emulate_2op_SrcV("cmp", src, dst, _regs.eflags);
keir@16465 2208 if ( ((rep_prefix == REPE_PREFIX) && !(_regs.eflags & EFLG_ZF)) ||
keir@16465 2209 ((rep_prefix == REPNE_PREFIX) && (_regs.eflags & EFLG_ZF)) )
keir@16465 2210 _regs.eip = next_eip;
keir@16465 2211 break;
keir@16465 2212 }
keir@16465 2213
kaf24@4047 2214 case 0xaa ... 0xab: /* stos */
kfraser@14034 2215 handle_rep_prefix();
kaf24@4047 2216 dst.type = OP_MEM;
kaf24@4047 2217 dst.bytes = (d & ByteOp) ? 1 : op_bytes;
kfraser@13145 2218 dst.mem.seg = x86_seg_es;
kfraser@13145 2219 dst.mem.off = truncate_ea(_regs.edi);
kaf24@4047 2220 dst.val = _regs.eax;
kaf24@8447 2221 register_address_increment(
kfraser@10279 2222 _regs.edi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
kaf24@4047 2223 break;
kfraser@13328 2224
kaf24@4047 2225 case 0xac ... 0xad: /* lods */
kfraser@14034 2226 handle_rep_prefix();
kaf24@4047 2227 dst.type = OP_REG;
kaf24@4047 2228 dst.bytes = (d & ByteOp) ? 1 : op_bytes;
kfraser@12675 2229 dst.reg = (unsigned long *)&_regs.eax;
kfraser@13145 2230 if ( (rc = ops->read(ea.mem.seg, truncate_ea(_regs.esi),
kfraser@12675 2231 &dst.val, dst.bytes, ctxt)) != 0 )
kaf24@4047 2232 goto done;
kaf24@8447 2233 register_address_increment(
kfraser@10279 2234 _regs.esi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
kaf24@4047 2235 break;
kfraser@13328 2236
keir@16465 2237 case 0xae ... 0xaf: /* scas */ {
keir@16465 2238 unsigned long next_eip = _regs.eip;
keir@16465 2239 handle_rep_prefix();
keir@16465 2240 src.bytes = dst.bytes = (d & ByteOp) ? 1 : op_bytes;
keir@16465 2241 dst.val = _regs.eax;
keir@16465 2242 if ( (rc = ops->read(x86_seg_es, truncate_ea(_regs.edi),
keir@16465 2243 &src.val, src.bytes, ctxt)) != 0 )
keir@16465 2244 goto done;
keir@16465 2245 register_address_increment(
keir@16465 2246 _regs.edi, (_regs.eflags & EFLG_DF) ? -src.bytes : src.bytes);
keir@16465 2247 /* cmp: dst - src ==> src=*%%edi,dst=%%eax ==> %%eax - *%%edi */
keir@16465 2248 emulate_2op_SrcV("cmp", src, dst, _regs.eflags);
keir@16465 2249 if ( ((rep_prefix == REPE_PREFIX) && !(_regs.eflags & EFLG_ZF)) ||
keir@16465 2250 ((rep_prefix == REPNE_PREFIX) && (_regs.eflags & EFLG_ZF)) )
keir@16465 2251 _regs.eip = next_eip;
keir@16465 2252 break;
keir@16465 2253 }
keir@16465 2254
kfraser@13388 2255 case 0xc2: /* ret imm16 (near) */
kfraser@13388 2256 case 0xc3: /* ret (near) */ {
kfraser@13388 2257 int offset = (b == 0xc2) ? insn_fetch_type(uint16_t) : 0;
kfraser@13388 2258 op_bytes = mode_64bit() ? 8 : op_bytes;
kfraser@13443 2259 if ( (rc = ops->read(x86_seg_ss, sp_post_inc(op_bytes + offset),
kfraser@13388 2260 &dst.val, op_bytes, ctxt)) != 0 )
kfraser@13388 2261 goto done;
kfraser@13388 2262 _regs.eip = dst.val;
kfraser@13388 2263 break;
kfraser@13388 2264 }
kfraser@13388 2265
keir@16478 2266 case 0xca: /* ret imm16 (far) */
keir@16478 2267 case 0xcb: /* ret (far) */ {
keir@16478 2268 int offset = (b == 0xca) ? insn_fetch_type(uint16_t) : 0;
keir@16478 2269 op_bytes = mode_64bit() ? 8 : op_bytes;
keir@16478 2270 if ( (rc = ops->read(x86_seg_ss, sp_post_inc(op_bytes),
keir@16478 2271 &dst.val, op_bytes, ctxt)) ||
keir@16478 2272 (rc = ops->read(x86_seg_ss, sp_post_inc(op_bytes + offset),
keir@16478 2273 &src.val, op_bytes, ctxt)) ||
keir@16478 2274 (rc = load_seg(x86_seg_cs, (uint16_t)src.val, ctxt, ops)) )
keir@16478 2275 goto done;
keir@16478 2276 _regs.eip = dst.val;
keir@16478 2277 break;
keir@16478 2278 }
keir@16478 2279
keir@16462 2280 case 0xcc: /* int3 */
keir@16462 2281 src.val = EXC_BP;
keir@16462 2282 goto swint;
keir@16462 2283
keir@16462 2284 case 0xcd: /* int imm8 */
keir@16462 2285 src.val = insn_fetch_type(uint8_t);
keir@16462 2286 swint:
keir@16462 2287 fail_if(ops->inject_sw_interrupt == NULL);
keir@16462 2288 rc = ops->inject_sw_interrupt(src.val, _regs.eip - ctxt->regs->eip,
keir@16462 2289 ctxt) ? : X86EMUL_EXCEPTION;
keir@16462 2290 goto done;
keir@16462 2291
keir@16462 2292 case 0xce: /* into */
keir@16462 2293 generate_exception_if(mode_64bit(), EXC_UD);
keir@16462 2294 if ( !(_regs.eflags & EFLG_OF) )
keir@16462 2295 break;
keir@16462 2296 src.val = EXC_OF;
keir@16462 2297 goto swint;
keir@16462 2298
keir@16464 2299 case 0xcf: /* iret */ {
keir@16464 2300 unsigned long cs, eip, eflags;
keir@16464 2301 uint32_t mask = EFLG_VIP | EFLG_VIF | EFLG_VM;
keir@16464 2302 if ( !mode_iopl() )
keir@16464 2303 mask |= EFLG_IOPL;
keir@16464 2304 fail_if(!in_realmode(ctxt, ops));
keir@16464 2305 fail_if(ops->write_rflags == NULL);
keir@16464 2306 if ( (rc = ops->read(x86_seg_ss, sp_post_inc(op_bytes),
keir@16464 2307 &eip, op_bytes, ctxt)) ||
keir@16464 2308 (rc = ops->read(x86_seg_ss, sp_post_inc(op_bytes),
keir@16464 2309 &cs, op_bytes, ctxt)) ||
keir@16464 2310 (rc = ops->read(x86_seg_ss, sp_post_inc(op_bytes),
keir@16464 2311 &eflags, op_bytes, ctxt)) )
keir@16464 2312 goto done;
keir@16464 2313 if ( op_bytes == 2 )
keir@16464 2314 eflags = (uint16_t)eflags | (_regs.eflags & 0xffff0000u);
keir@16464 2315 eflags &= 0x257fd5;
keir@16464 2316 _regs.eflags &= mask;
keir@16464 2317 _regs.eflags |= (uint32_t)(eflags & ~mask) | 0x02;
keir@16464 2318 if ( (rc = ops->write_rflags(_regs.eflags, ctxt)) != 0 )
keir@16464 2319 goto done;
keir@16464 2320 _regs.eip = eip;
keir@16464 2321 if ( (rc = load_seg(x86_seg_cs, (uint16_t)cs, ctxt, ops)) != 0 )
keir@16464 2322 goto done;
keir@16464 2323 break;
keir@16464 2324 }
keir@16464 2325
kfraser@13334 2326 case 0xd4: /* aam */ {
kfraser@13334 2327 unsigned int base = insn_fetch_type(uint8_t);
kfraser@13334 2328 uint8_t al = _regs.eax;
kaf24@13428 2329 generate_exception_if(mode_64bit(), EXC_UD);
kfraser@13334 2330 generate_exception_if(base == 0, EXC_DE);
kfraser@13334 2331 *(uint16_t *)&_regs.eax = ((al / base) << 8) | (al % base);
kfraser@13334 2332 _regs.eflags &= ~(EFLG_SF|EFLG_ZF|EFLG_PF);
kfraser@13334 2333 _regs.eflags |= ((uint8_t)_regs.eax == 0) ? EFLG_ZF : 0;
kfraser@13334 2334 _regs.eflags |= (( int8_t)_regs.eax < 0) ? EFLG_SF : 0;
kfraser@13334 2335 _regs.eflags |= even_parity(_regs.eax) ? EFLG_PF : 0;
kfraser@13334 2336 break;
kfraser@13334 2337 }
kfraser@13334 2338
kfraser@13334 2339 case 0xd5: /* aad */ {
kfraser@13334 2340 unsigned int base = insn_fetch_type(uint8_t);
kfraser@13334 2341 uint16_t ax = _regs.eax;
kaf24@13428 2342 generate_exception_if(mode_64bit(), EXC_UD);
kfraser@13334 2343 *(uint16_t *)&_regs.eax = (uint8_t)(ax + ((ax >> 8) * base));
kfraser@13334 2344 _regs.eflags &= ~(EFLG_SF|EFLG_ZF|EFLG_PF);
kfraser@13334 2345 _regs.eflags |= ((uint8_t)_regs.eax == 0) ? EFLG_ZF : 0;
kfraser@13334 2346 _regs.eflags |= (( int8_t)_regs.eax < 0) ? EFLG_SF : 0;
kfraser@13334 2347 _regs.eflags |= even_parity(_regs.eax) ? EFLG_PF : 0;
kfraser@13334 2348 break;
kfraser@13334 2349 }
kfraser@13334 2350
kfraser@13334 2351 case 0xd6: /* salc */
kaf24@13428 2352 generate_exception_if(mode_64bit(), EXC_UD);
kfraser@13334 2353 *(uint8_t *)&_regs.eax = (_regs.eflags & EFLG_CF) ? 0xff : 0x00;
kfraser@13334 2354 break;
kfraser@13334 2355
kfraser@13334 2356 case 0xd7: /* xlat */ {
kfraser@13334 2357 unsigned long al = (uint8_t)_regs.eax;
kfraser@13334 2358 if ( (rc = ops->read(ea.mem.seg, truncate_ea(_regs.ebx + al),
kfraser@13334 2359 &al, 1, ctxt)) != 0 )
kfraser@13334 2360 goto done;
kfraser@13334 2361 *(uint8_t *)&_regs.eax = al;
kfraser@13334 2362 break;
kfraser@13334 2363 }
kfraser@13334 2364
kfraser@13393 2365 case 0xe0 ... 0xe2: /* loop{,z,nz} */ {
kfraser@13393 2366 int rel = insn_fetch_type(int8_t);
kfraser@13393 2367 int do_jmp = !(_regs.eflags & EFLG_ZF); /* loopnz */
kfraser@13393 2368 if ( b == 0xe1 )
kfraser@13393 2369 do_jmp = !do_jmp; /* loopz */
kfraser@13393 2370 else if ( b == 0xe2 )
kfraser@13393 2371 do_jmp = 1; /* loop */
kfraser@13393 2372 switch ( ad_bytes )
kfraser@13393 2373 {
kfraser@13393 2374 case 2:
kfraser@13393 2375 do_jmp &= --(*(uint16_t *)&_regs.ecx) != 0;
kfraser@13393 2376 break;
kfraser@13393 2377 case 4:
kfraser@13393 2378 do_jmp &= --(*(uint32_t *)&_regs.ecx) != 0;
kfraser@13393 2379 _regs.ecx = (uint32_t)_regs.ecx; /* zero extend in x86/64 mode */
kfraser@13393 2380 break;
kfraser@13393 2381 default: /* case 8: */
kfraser@13393 2382 do_jmp &= --_regs.ecx != 0;
kfraser@13393 2383 break;
kfraser@13393 2384 }
kfraser@13393 2385 if ( do_jmp )
kfraser@13393 2386 jmp_rel(rel);
kfraser@13393 2387 break;
kfraser@13393 2388 }
kfraser@13393 2389
kfraser@13328 2390 case 0xe3: /* jcxz/jecxz (short) */ {
kfraser@13328 2391 int rel = insn_fetch_type(int8_t);
kfraser@13328 2392 if ( (ad_bytes == 2) ? !(uint16_t)_regs.ecx :
kfraser@13328 2393 (ad_bytes == 4) ? !(uint32_t)_regs.ecx : !_regs.ecx )
kfraser@13328 2394 jmp_rel(rel);
kfraser@13328 2395 break;
kfraser@13328 2396 }
kfraser@13328 2397
kfraser@13624 2398 case 0xe4: /* in imm8,%al */
kfraser@13624 2399 case 0xe5: /* in imm8,%eax */
kfraser@13624 2400 case 0xe6: /* out %al,imm8 */
kfraser@13624 2401 case 0xe7: /* out %eax,imm8 */
kfraser@13624 2402 case 0xec: /* in %dx,%al */
kfraser@13624 2403 case 0xed: /* in %dx,%eax */
kfraser@13624 2404 case 0xee: /* out %al,%dx */
kfraser@13624 2405 case 0xef: /* out %eax,%dx */ {
kfraser@13624 2406 unsigned int port = ((b < 0xe8)
kfraser@13624 2407 ? insn_fetch_type(uint8_t)
kfraser@13624 2408 : (uint16_t)_regs.edx);
kfraser@13624 2409 generate_exception_if(!mode_iopl(), EXC_GP);
kfraser@13624 2410 op_bytes = !(b & 1) ? 1 : (op_bytes == 8) ? 4 : op_bytes;
kfraser@13624 2411 if ( b & 2 )
kfraser@13624 2412 {
kfraser@13624 2413 /* out */
kfraser@13624 2414 fail_if(ops->write_io == NULL);
kfraser@13624 2415 rc = ops->write_io(port, op_bytes, _regs.eax, ctxt);
kfraser@13624 2416
kfraser@13624 2417 }
kfraser@13624 2418 else
kfraser@13624 2419 {
kfraser@13624 2420 /* in */
kfraser@13624 2421 dst.type = OP_REG;
kfraser@13624 2422 dst.bytes = op_bytes;
kfraser@13624 2423 dst.reg = (unsigned long *)&_regs.eax;
kfraser@13624 2424 fail_if(ops->read_io == NULL);
kfraser@13624 2425 rc = ops->read_io(port, dst.bytes, &dst.val, ctxt);
kfraser@13624 2426 }
kfraser@13624 2427 if ( rc != 0 )
kfraser@13624 2428 goto done;
kfraser@13624 2429 break;
kfraser@13624 2430 }
kfraser@13624 2431
kfraser@13388 2432 case 0xe8: /* call (near) */ {
kfraser@13388 2433 int rel = (((op_bytes == 2) && !mode_64bit())
kfraser@13388 2434 ? (int32_t)insn_fetch_type(int16_t)
kfraser@13388 2435 : insn_fetch_type(int32_t));
kfraser@13388 2436 op_bytes = mode_64bit() ? 8 : op_bytes;
kfraser@13388 2437 src.val = _regs.eip;
kfraser@13388 2438 jmp_rel(rel);
kfraser@13388 2439 goto push;
kfraser@13388 2440 }
kfraser@13388 2441
kfraser@13388 2442 case 0xe9: /* jmp (near) */ {
kfraser@13388 2443 int rel = (((op_bytes == 2) && !mode_64bit())
kfraser@13388 2444 ? (int32_t)insn_fetch_type(int16_t)
kfraser@13388 2445 : insn_fetch_type(int32_t));
kfraser@13388 2446 jmp_rel(rel);
kfraser@13328 2447 break;
kfraser@13388 2448 }
kfraser@13328 2449
keir@16454 2450 case 0xea: /* jmp (far, absolute) */ {
keir@16454 2451 uint16_t sel;
keir@16454 2452 uint32_t eip;
keir@16454 2453 generate_exception_if(mode_64bit(), EXC_UD);
keir@16454 2454 eip = insn_fetch_bytes(op_bytes);
keir@16454 2455 sel = insn_fetch_type(uint16_t);
keir@16454 2456 if ( (rc = load_seg(x86_seg_cs, sel, ctxt, ops)) != 0 )
keir@16454 2457 goto done;
keir@16454 2458 _regs.eip = eip;
keir@16454 2459 break;
keir@16454 2460 }
keir@16454 2461
kfraser@13388 2462 case 0xeb: /* jmp (short) */
kfraser@13388 2463 jmp_rel(insn_fetch_type(int8_t));
kfraser@13328 2464 break;
kfraser@13328 2465
keir@16462 2466 case 0xf1: /* int1 (icebp) */
keir@16462 2467 src.val = EXC_DB;
keir@16462 2468 goto swint;
keir@16462 2469
keir@16468 2470 case 0xf4: /* hlt */
keir@16468 2471 fail_if(ops->hlt == NULL);
keir@16468 2472 if ( (rc = ops->hlt(ctxt)) != 0 )
keir@16468 2473 goto done;
keir@16468 2474 break;
keir@16468 2475
kfraser@13282 2476 case 0xf5: /* cmc */
kfraser@13282 2477 _regs.eflags ^= EFLG_CF;
kfraser@13282 2478 break;
kfraser@13328 2479
kfraser@13282 2480 case 0xf8: /* clc */
kfraser@13282 2481 _regs.eflags &= ~EFLG_CF;
kfraser@13282 2482 break;
kfraser@13328 2483
kfraser@13282 2484 case 0xf9: /* stc */
kfraser@13282 2485 _regs.eflags |= EFLG_CF;
kfraser@13282 2486 break;
kfraser@13328 2487
kfraser@13623 2488 case 0xfa: /* cli */
kfraser@13623 2489 case 0xfb: /* sti */
kfraser@13623 2490 generate_exception_if(!mode_iopl(), EXC_GP);
kfraser@13623 2491 fail_if(ops->write_rflags == NULL);
keir@16460 2492 _regs.eflags &= ~EFLG_IF;
keir@16460 2493 if ( b == 0xfb ) /* sti */
keir@16460 2494 _regs.eflags |= EFLG_IF;
keir@16460 2495 if ( (rc = ops->write_rflags(_regs.eflags, ctxt)) != 0 )
kfraser@13623 2496 goto done;
kfraser@13623 2497 break;
kfraser@13623 2498
kfraser@13282 2499 case 0xfc: /* cld */
kfraser@13282 2500 _regs.eflags &= ~EFLG_DF;
kfraser@13282 2501 break;
kfraser@13328 2502
kfraser@13282 2503 case 0xfd: /* std */
kfraser@13282 2504 _regs.eflags |= EFLG_DF;
kfraser@13282 2505 break;
kaf24@4047 2506 }
kaf24@4047 2507 goto writeback;
kaf24@4047 2508
kaf24@4047 2509 twobyte_insn:
kaf24@4047 2510 switch ( b )
kaf24@4047 2511 {
kfraser@13383 2512 case 0x40 ... 0x4f: /* cmovcc */
kfraser@13383 2513 dst.val = src.val;
kfraser@13383 2514 if ( !test_cc(b, _regs.eflags) )
kfraser@13383 2515 dst.type = OP_NONE;
kfraser@13383 2516 break;
kfraser@13383 2517
kfraser@13383 2518 case 0x90 ... 0x9f: /* setcc */
kfraser@13383 2519 dst.val = test_cc(b, _regs.eflags);
kaf24@4047 2520 break;
kfraser@13328 2521
kaf24@4047 2522 case 0xb0 ... 0xb1: /* cmpxchg */
kaf24@4047 2523 /* Save real source value, then compare EAX against destination. */
kaf24@4047 2524 src.orig_val = src.val;
kaf24@4047 2525 src.val = _regs.eax;
kaf24@4047 2526 emulate_2op_SrcV("cmp", src, dst, _regs.eflags);
kaf24@4047 2527 /* Always write back. The question is: where to? */
kaf24@4047 2528 d |= Mov;
kaf24@4047 2529 if ( _regs.eflags & EFLG_ZF )
kaf24@4047 2530 {
kaf24@4047 2531 /* Success: write back to memory. */
kaf24@4047 2532 dst.val = src.orig_val;
kaf24@4047 2533 }
kaf24@4047 2534 else
kaf24@4047 2535 {
kaf24@4047 2536 /* Failure: write the value we saw to EAX. */
kaf24@4047 2537 dst.type = OP_REG;
kfraser@12675 2538 dst.reg = (unsigned long *)&_regs.eax;
kaf24@4047 2539 }
kaf24@4047 2540 break;
kfraser@13328 2541
kaf24@4047 2542 case 0xa3: bt: /* bt */
kaf24@4047 2543 emulate_2op_SrcV_nobyte("bt", src, dst, _regs.eflags);
kaf24@4047 2544 break;
kfraser@13328 2545
kaf24@4047 2546 case 0xb3: btr: /* btr */
kaf24@4047 2547 emulate_2op_SrcV_nobyte("btr", src, dst, _regs.eflags);
kaf24@4047 2548 break;
kfraser@13328 2549
kaf24@4047 2550 case 0xab: bts: /* bts */
kaf24@4047 2551 emulate_2op_SrcV_nobyte("bts", src, dst, _regs.eflags);
kaf24@4047 2552 break;
kfraser@13328 2553
kaf24@13426 2554 case 0xaf: /* imul */
kaf24@13426 2555 _regs.eflags &= ~(EFLG_OF|EFLG_CF);
kaf24@13426 2556 switch ( dst.bytes )
kaf24@13426 2557 {
kaf24@13426 2558 case 2:
kaf24@13426 2559 dst.val = ((uint32_t)(int16_t)src.val *
kaf24@13426 2560 (uint32_t)(int16_t)dst.val);
kaf24@13426 2561 if ( (int16_t)dst.val != (uint32_t)dst.val )
kaf24@13426 2562 _regs.eflags |= EFLG_OF|EFLG_CF;
kaf24@13426 2563 break;
kaf24@13426 2564 #ifdef __x86_64__
kaf24@13426 2565 case 4:
kaf24@13426 2566 dst.val = ((uint64_t)(int32_t)src.val *
kaf24@13426 2567 (uint64_t)(int32_t)dst.val);
kaf24@13426 2568 if ( (int32_t)dst.val != dst.val )
kaf24@13426 2569 _regs.eflags |= EFLG_OF|EFLG_CF;
kaf24@13426 2570 break;
kaf24@13426 2571 #endif
kaf24@13426 2572 default: {
kaf24@13426 2573 unsigned long m[2] = { src.val, dst.val };
kaf24@13426 2574 if ( imul_dbl(m) )
kaf24@13426 2575 _regs.eflags |= EFLG_OF|EFLG_CF;
kaf24@13426 2576 dst.val = m[0];
kaf24@13426 2577 break;
kaf24@13426 2578 }
kaf24@13426 2579 }
kaf24@13426 2580 break;
kaf24@13426 2581
keir@16467 2582 case 0xb2: /* lss */
keir@16467 2583 dst.val = x86_seg_ss;
keir@16467 2584 goto les;
keir@16467 2585
keir@16467 2586 case 0xb4: /* lfs */
keir@16467 2587 dst.val = x86_seg_fs;
keir@16467 2588 goto les;
keir@16467 2589
keir@16467 2590 case 0xb5: /* lgs */
keir@16467 2591 dst.val = x86_seg_gs;
keir@16467 2592 goto les;
keir@16467 2593
kfraser@13145 2594 case 0xb6: /* movzx rm8,r{16,32,64} */
kfraser@13145 2595 /* Recompute DstReg as we may have decoded AH/BH/CH/DH. */
kfraser@13145 2596 dst.reg = decode_register(modrm_reg, &_regs, 0);
kaf24@8423 2597 dst.bytes = op_bytes;
kfraser@13145 2598 dst.val = (uint8_t)src.val;
kfraser@13145 2599 break;
kfraser@13328 2600
kaf24@13430 2601 case 0xbc: /* bsf */ {
kaf24@13430 2602 int zf;
kfraser@13442 2603 asm ( "bsf %2,%0; setz %b1"
kaf24@13430 2604 : "=r" (dst.val), "=q" (zf)
kaf24@13430 2605 : "r" (src.val), "1" (0) );
kaf24@13430 2606 _regs.eflags &= ~EFLG_ZF;
kaf24@13430 2607 _regs.eflags |= zf ? EFLG_ZF : 0;
kaf24@13430 2608 break;
kaf24@13430 2609 }
kaf24@13430 2610
kaf24@13430 2611 case 0xbd: /* bsr */ {
kaf24@13430 2612 int zf;
kfraser@13442 2613 asm ( "bsr %2,%0; setz %b1"
kaf24@13430 2614 : "=r" (dst.val), "=q" (zf)
kaf24@13430 2615 : "r" (src.val), "1" (0) );
kaf24@13430 2616 _regs.eflags &= ~EFLG_ZF;
kaf24@13430 2617 _regs.eflags |= zf ? EFLG_ZF : 0;
kaf24@13430 2618 break;
kaf24@13430 2619 }
kaf24@13430 2620
kfraser@13145 2621 case 0xb7: /* movzx rm16,r{16,32,64} */
kfraser@13145 2622 dst.val = (uint16_t)src.val;
kaf24@8423 2623 break;
kfraser@13328 2624
kaf24@4047 2625 case 0xbb: btc: /* btc */
kaf24@4047 2626 emulate_2op_SrcV_nobyte("btc", src, dst, _regs.eflags);
kaf24@4047 2627 break;
kfraser@13328 2628
kaf24@4047 2629 case 0xba: /* Grp8 */
kfraser@13462 2630 switch ( modrm_reg & 7 )
kaf24@4047 2631 {
kfraser@13462 2632 case 4: goto bt;
kfraser@13462 2633 case 5: goto bts;
kfraser@13462 2634 case 6: goto btr;
kfraser@13462 2635 case 7: goto btc;
kfraser@13462 2636 default: generate_exception_if(1, EXC_UD);
kaf24@4047 2637 }
kaf24@4047 2638 break;
kfraser@13328 2639
kfraser@13145 2640 case 0xbe: /* movsx rm8,r{16,32,64} */
kfraser@13145 2641 /* Recompute DstReg as we may have decoded AH/BH/CH/DH. */
kfraser@13145 2642 dst.reg = decode_register(modrm_reg, &_regs, 0);
kaf24@8423 2643 dst.bytes = op_bytes;
kfraser@13145 2644 dst.val = (int8_t)src.val;
kfraser@13145 2645 break;
kfraser@13328 2646
kfraser@13145 2647 case 0xbf: /* movsx rm16,r{16,32,64} */
kfraser@13145 2648 dst.val = (int16_t)src.val;
kaf24@8423 2649 break;
kfraser@13328 2650
kfraser@12746 2651 case 0xc0 ... 0xc1: /* xadd */
kfraser@12746 2652 /* Write back the register source. */
kfraser@12746 2653 switch ( dst.bytes )
kfraser@12746 2654 {
kfraser@12746 2655 case 1: *(uint8_t *)src.reg = (uint8_t)dst.val; break;
kfraser@12746 2656 case 2: *(uint16_t *)src.reg = (uint16_t)dst.val; break;
kfraser@12746 2657 case 4: *src.reg = (uint32_t)dst.val; break; /* 64b reg: zero-extend */
kfraser@12746 2658 case 8: *src.reg = dst.val; break;
kfraser@12746 2659 }
kfraser@12746 2660 goto add;
kaf24@4047 2661 }
kaf24@4047 2662 goto writeback;
kaf24@4047 2663
kaf24@4047 2664 twobyte_special_insn:
kaf24@4246 2665 switch ( b )
kaf24@4246 2666 {
keir@16454 2667 case 0x01: /* Grp7 */ {
keir@16454 2668 struct segment_register reg;
keir@16454 2669
keir@16454 2670 switch ( modrm_reg & 7 )
keir@16454 2671 {
keir@16454 2672 case 0: /* sgdt */
keir@16454 2673 case 1: /* sidt */
keir@16454 2674 generate_exception_if(ea.type != OP_MEM, EXC_UD);
keir@16454 2675 fail_if(ops->read_segment == NULL);
keir@16454 2676 if ( (rc = ops->read_segment((modrm_reg & 1) ?
keir@16454 2677 x86_seg_idtr : x86_seg_gdtr,
keir@16454 2678 &reg, ctxt)) )
keir@16454 2679 goto done;
keir@16454 2680 if ( op_bytes == 2 )
keir@16454 2681 reg.base &= 0xffffff;
keir@16454 2682 if ( (rc = ops->write(ea.mem.seg, ea.mem.off+0,
keir@16454 2683 reg.limit, 2, ctxt)) ||
keir@16454 2684 (rc = ops->write(ea.mem.seg, ea.mem.off+2,
keir@16454 2685 reg.base, mode_64bit() ? 8 : 4, ctxt)) )
keir@16454 2686 goto done;
keir@16454 2687 break;
keir@16454 2688 case 2: /* lgdt */
keir@16454 2689 case 3: /* lidt */
keir@16454 2690 generate_exception_if(ea.type != OP_MEM, EXC_UD);
keir@16454 2691 fail_if(ops->write_segment == NULL);
keir@16454 2692 memset(&reg, 0, sizeof(reg));
keir@16454 2693 if ( (rc = ops->read(ea.mem.seg, ea.mem.off+0,
keir@16454 2694 (unsigned long *)&reg.limit, 2, ctxt)) ||
keir@16454 2695 (rc = ops->read(ea.mem.seg, ea.mem.off+2,
keir@16454 2696 (unsigned long *)&reg.base,
keir@16454 2697 mode_64bit() ? 8 : 4, ctxt)) )
keir@16454 2698 goto done;
keir@16454 2699 if ( op_bytes == 2 )
keir@16454 2700 reg.base &= 0xffffff;
keir@16454 2701 if ( (rc = ops->write_segment((modrm_reg & 1) ?
keir@16454 2702 x86_seg_idtr : x86_seg_gdtr,
keir@16454 2703 &reg, ctxt)) )
keir@16454 2704 goto done;
keir@16454 2705 break;
keir@16454 2706 default:
keir@16454 2707 goto cannot_emulate;
keir@16454 2708 }
keir@16454 2709 break;
keir@16454 2710 }
keir@16454 2711
kfraser@13623 2712 case 0x06: /* clts */
kfraser@13623 2713 generate_exception_if(!mode_ring0(), EXC_GP);
kfraser@13623 2714 fail_if((ops->read_cr == NULL) || (ops->write_cr == NULL));
kfraser@13623 2715 if ( (rc = ops->read_cr(0, &dst.val, ctxt)) ||
kfraser@13624 2716 (rc = ops->write_cr(0, dst.val&~8, ctxt)) )
kfraser@13623 2717 goto done;
kfraser@13623 2718 break;
kfraser@13623 2719
kfraser@13623 2720 case 0x08: /* invd */
kfraser@13623 2721 case 0x09: /* wbinvd */
kfraser@13623 2722 generate_exception_if(!mode_ring0(), EXC_GP);
kfraser@13623 2723 fail_if(ops->wbinvd == NULL);
kfraser@13623 2724 if ( (rc = ops->wbinvd(ctxt)) != 0 )
kfraser@13623 2725 goto done;
kfraser@13623 2726 break;
kfraser@13623 2727
kaf24@4246 2728 case 0x0d: /* GrpP (prefetch) */
kaf24@4246 2729 case 0x18: /* Grp16 (prefetch/nop) */
kaf24@13429 2730 case 0x19 ... 0x1f: /* nop (amd-defined) */
kaf24@4246 2731 break;
kfraser@13328 2732
kfraser@13623 2733 case 0x20: /* mov cr,reg */
kfraser@13623 2734 case 0x21: /* mov dr,reg */
kfraser@13623 2735 case 0x22: /* mov reg,cr */
kfraser@13623 2736 case 0x23: /* mov reg,dr */
kfraser@13623 2737 generate_exception_if(!mode_ring0(), EXC_GP);
kfraser@13623 2738 modrm_rm |= (rex_prefix & 1) << 3;
kfraser@13623 2739 modrm_reg |= lock_prefix << 3;
kfraser@13623 2740 if ( b & 2 )
kfraser@13623 2741 {
kfraser@13623 2742 /* Write to CR/DR. */
kfraser@13623 2743 src.val = *(unsigned long *)decode_register(modrm_rm, &_regs, 0);
kfraser@13623 2744 if ( !mode_64bit() )
kfraser@13623 2745 src.val = (uint32_t)src.val;
kfraser@13623 2746 rc = ((b & 1)
kfraser@13623 2747 ? (ops->write_dr
kfraser@13623 2748 ? ops->write_dr(modrm_reg, src.val, ctxt)
kfraser@13623 2749 : X86EMUL_UNHANDLEABLE)
kfraser@13623 2750 : (ops->write_cr
keir@16453 2751 ? ops->write_cr(modrm_reg, src.val, ctxt)
kfraser@13623 2752 : X86EMUL_UNHANDLEABLE));
kfraser@13623 2753 }
kfraser@13623 2754 else
kfraser@13623 2755 {
kfraser@13623 2756 /* Read from CR/DR. */
kfraser@13623 2757 dst.type = OP_REG;
kfraser@13623 2758 dst.bytes = mode_64bit() ? 8 : 4;
kfraser@13623 2759 dst.reg = decode_register(modrm_rm, &_regs, 0);
kfraser@13623 2760 rc = ((b & 1)
kfraser@13623 2761 ? (ops->read_dr
kfraser@13623 2762 ? ops->read_dr(modrm_reg, &dst.val, ctxt)
kfraser@13623 2763 : X86EMUL_UNHANDLEABLE)
kfraser@13623 2764 : (ops->read_cr
keir@16453 2765 ? ops->read_cr(modrm_reg, &dst.val, ctxt)
kfraser@13623 2766 : X86EMUL_UNHANDLEABLE));
kfraser@13623 2767 }
kfraser@13623 2768 if ( rc != 0 )
kfraser@13623 2769 goto done;
kfraser@13623 2770 break;
kfraser@13623 2771
kfraser@13623 2772 case 0x30: /* wrmsr */ {
kfraser@13623 2773 uint64_t val = ((uint64_t)_regs.edx << 32) | (uint32_t)_regs.eax;
kfraser@13623 2774 generate_exception_if(!mode_ring0(), EXC_GP);
kfraser@13623 2775 fail_if(ops->write_msr == NULL);
kfraser@13623 2776 if ( (rc = ops->write_msr((uint32_t)_regs.ecx, val, ctxt)) != 0 )
kfraser@13623 2777 goto done;
kfraser@13623 2778 break;
kfraser@13623 2779 }
kfraser@13623 2780
kfraser@13623 2781 case 0x32: /* rdmsr */ {
kfraser@13623 2782 uint64_t val;
kfraser@13623 2783 generate_exception_if(!mode_ring0(), EXC_GP);
kfraser@13623 2784 fail_if(ops->read_msr == NULL);
kfraser@13623 2785 if ( (rc = ops->read_msr((uint32_t)_regs.ecx, &val, ctxt)) != 0 )
kfraser@13623 2786 goto done;
kfraser@13623 2787 _regs.edx = (uint32_t)(val >> 32);
kfraser@13623 2788 _regs.eax = (uint32_t)(val >> 0);
kfraser@13623 2789 break;
kfraser@13623 2790 }
kfraser@13623 2791
kfraser@13328 2792 case 0x80 ... 0x8f: /* jcc (near) */ {
kfraser@13388 2793 int rel = (((op_bytes == 2) && !mode_64bit())
kfraser@13388 2794 ? (int32_t)insn_fetch_type(int16_t)
kfraser@13388 2795 : insn_fetch_type(int32_t));
kfraser@13328 2796 if ( test_cc(b, _regs.eflags) )
kfraser@13328 2797 jmp_rel(rel);
kfraser@13328 2798 break;
kfraser@13328 2799 }
kfraser@13328 2800
keir@16454 2801 case 0xa0: /* push %%fs */
keir@16454 2802 src.val = x86_seg_fs;
keir@16454 2803 goto push_seg;
keir@16454 2804
keir@16454 2805 case 0xa1: /* pop %%fs */
keir@16454 2806 src.val = x86_seg_fs;
keir@16454 2807 goto pop_seg;
keir@16454 2808
keir@16468 2809 case 0xa2: /* cpuid */ {
keir@16468 2810 unsigned int eax = _regs.eax, ebx = _regs.ebx;
keir@16468 2811 unsigned int ecx = _regs.ecx, edx = _regs.edx;
keir@16468 2812 fail_if(ops->cpuid == NULL);
keir@16468 2813 if ( (rc = ops->cpuid(&eax, &ebx, &ecx, &edx, ctxt)) != 0 )
keir@16468 2814 goto done;
keir@16468 2815 _regs.eax = eax; _regs.ebx = ebx;
keir@16468 2816 _regs.ecx = ecx; _regs.edx = edx;
keir@16468 2817 break;
keir@16468 2818 }
keir@16468 2819
keir@16454 2820 case 0xa8: /* push %%gs */
keir@16454 2821 src.val = x86_seg_gs;
keir@16454 2822 goto push_seg;
keir@16454 2823
keir@16454 2824 case 0xa9: /* pop %%gs */
keir@16454 2825 src.val = x86_seg_gs;
keir@16454 2826 goto pop_seg;
keir@16454 2827
kaf24@4246 2828 case 0xc7: /* Grp9 (cmpxchg8b) */
kaf24@4246 2829 #if defined(__i386__)
kaf24@4246 2830 {
kaf24@4246 2831 unsigned long old_lo, old_hi;
kfraser@13462 2832 generate_exception_if((modrm_reg & 7) != 1, EXC_UD);
kfraser@13145 2833 if ( (rc = ops->read(ea.mem.seg, ea.mem.off+0, &old_lo, 4, ctxt)) ||
kfraser@13145 2834 (rc = ops->read(ea.mem.seg, ea.mem.off+4, &old_hi, 4, ctxt)) )
kaf24@4246 2835 goto done;
kaf24@4246 2836 if ( (old_lo != _regs.eax) || (old_hi != _regs.edx) )
kaf24@4246 2837 {
kaf24@4246 2838 _regs.eax = old_lo;
kaf24@4246 2839 _regs.edx = old_hi;
kaf24@4246 2840 _regs.eflags &= ~EFLG_ZF;
kaf24@4246 2841 }
kfraser@12675 2842 else if ( ops->cmpxchg8b == NULL )
kaf24@4246 2843 {
kaf24@4246 2844 rc = X86EMUL_UNHANDLEABLE;
kaf24@4246 2845 goto done;
kaf24@4246 2846 }
kaf24@4246 2847 else
kaf24@4246 2848 {
kfraser@13145 2849 if ( (rc = ops->cmpxchg8b(ea.mem.seg, ea.mem.off, old_lo, old_hi,
kfraser@12675 2850 _regs.ebx, _regs.ecx, ctxt)) != 0 )
kaf24@4246 2851 goto done;
kaf24@4246 2852 _regs.eflags |= EFLG_ZF;
kaf24@4246 2853 }
kaf24@4246 2854 break;
kaf24@4246 2855 }
kaf24@4246 2856 #elif defined(__x86_64__)
kaf24@4246 2857 {
kaf24@4246 2858 unsigned long old, new;
kfraser@13462 2859 generate_exception_if((modrm_reg & 7) != 1, EXC_UD);
kfraser@13145 2860 if ( (rc = ops->read(ea.mem.seg, ea.mem.off, &old, 8, ctxt)) != 0 )
kaf24@4246 2861 goto done;
kaf24@8423 2862 if ( ((uint32_t)(old>>0) != (uint32_t)_regs.eax) ||
kaf24@8423 2863 ((uint32_t)(old>>32) != (uint32_t)_regs.edx) )
kaf24@4246 2864 {
kaf24@8423 2865 _regs.eax = (uint32_t)(old>>0);
kaf24@8423 2866 _regs.edx = (uint32_t)(old>>32);
kaf24@4246 2867 _regs.eflags &= ~EFLG_ZF;
kaf24@4246 2868 }
kaf24@4246 2869 else
kaf24@4246 2870 {
kaf24@8423 2871 new = (_regs.ecx<<32)|(uint32_t)_regs.ebx;
kfraser@13145 2872 if ( (rc = ops->cmpxchg(ea.mem.seg, ea.mem.off, old,
kfraser@13145 2873 new, 8, ctxt)) != 0 )
kaf24@4246 2874 goto done;
kaf24@4246 2875 _regs.eflags |= EFLG_ZF;
kaf24@4246 2876 }
kaf24@4246 2877 break;
kaf24@4246 2878 }
kaf24@4246 2879 #endif
kfraser@13383 2880
kfraser@13383 2881 case 0xc8 ... 0xcf: /* bswap */
kfraser@14035 2882 dst.type = OP_REG;
kfraser@14035 2883 dst.reg = decode_register(
kfraser@14035 2884 (b & 7) | ((rex_prefix & 1) << 3), &_regs, 0);
kfraser@13383 2885 switch ( dst.bytes = op_bytes )
kfraser@13383 2886 {
kfraser@14035 2887 default: /* case 2: */
kfraser@14035 2888 /* Undefined behaviour. Writes zero on all tested CPUs. */
kfraser@14035 2889 dst.val = 0;
kfraser@13383 2890 break;
kfraser@13383 2891 case 4:
kfraser@14035 2892 #ifdef __x86_64__
kfraser@15872 2893 asm ( "bswap %k0" : "=r" (dst.val) : "0" (*dst.reg) );
kfraser@13383 2894 break;
kfraser@13383 2895 case 8:
kfraser@14035 2896 #endif
kfraser@15872 2897 asm ( "bswap %0" : "=r" (dst.val) : "0" (*dst.reg) );
kfraser@13383 2898 break;
kfraser@13383 2899 }
kfraser@13383 2900 break;
kaf24@4246 2901 }
kaf24@4047 2902 goto writeback;
kaf24@4047 2903
kaf24@4047 2904 cannot_emulate:
keir@14765 2905 #if 0
kfraser@12726 2906 gdprintk(XENLOG_DEBUG, "Instr:");
kfraser@13145 2907 for ( ea.mem.off = ctxt->regs->eip; ea.mem.off < _regs.eip; ea.mem.off++ )
kfraser@12726 2908 {
kfraser@12726 2909 unsigned long x;
kfraser@13145 2910 ops->insn_fetch(x86_seg_cs, ea.mem.off, &x, 1, ctxt);
kfraser@12726 2911 printk(" %02x", (uint8_t)x);
kfraser@12726 2912 }
kfraser@12726 2913 printk("\n");
kfraser@12726 2914 #endif
kfraser@14063 2915 return X86EMUL_UNHANDLEABLE;
kaf24@4047 2916 }