ia64/xen-unstable
changeset 17938:6685c412698f
x86_emulate: (Almost) complete FPU emulation.
Provide emulation for all FPU instructions except fsave/frstore &
fnstenv/fldenv.
While the main purpose of the patch is to avoid current and future
"gotchas" on FPU intructions used by various OS boot-loaders, it is
complete enough to run DOS realmode FPU applications and benchmarks,
but don't expect to set any speed records.
Signed-off-by: Trolle Selander <trolle.selander@eu.citrix.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
Provide emulation for all FPU instructions except fsave/frstore &
fnstenv/fldenv.
While the main purpose of the patch is to avoid current and future
"gotchas" on FPU intructions used by various OS boot-loaders, it is
complete enough to run DOS realmode FPU applications and benchmarks,
but don't expect to set any speed records.
Signed-off-by: Trolle Selander <trolle.selander@eu.citrix.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author | Keir Fraser <keir.fraser@citrix.com> |
---|---|
date | Tue Jul 01 13:27:41 2008 +0100 (2008-07-01) |
parents | d4cf12d128ed |
children | 19970181d6a4 |
files | xen/arch/x86/x86_emulate/x86_emulate.c |
line diff
1.1 --- a/xen/arch/x86/x86_emulate/x86_emulate.c Tue Jul 01 11:41:43 2008 +0100 1.2 +++ b/xen/arch/x86/x86_emulate/x86_emulate.c Tue Jul 01 13:27:41 2008 +0100 1.3 @@ -142,12 +142,14 @@ static uint8_t opcode_table[256] = { 1.4 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, 1.5 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, 1.6 /* 0xD0 - 0xD7 */ 1.7 - ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM, 1.8 - ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM, 1.9 + ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM, 1.10 + ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM, 1.11 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, 1.12 /* 0xD8 - 0xDF */ 1.13 - 0, ImplicitOps|ModRM|Mov, 0, ImplicitOps|ModRM|Mov, 1.14 - 0, ImplicitOps|ModRM|Mov, ImplicitOps|ModRM|Mov, ImplicitOps|ModRM|Mov, 1.15 + ImplicitOps|ModRM|Mov, ImplicitOps|ModRM|Mov, 1.16 + ImplicitOps|ModRM|Mov, ImplicitOps|ModRM|Mov, 1.17 + ImplicitOps|ModRM|Mov, ImplicitOps|ModRM|Mov, 1.18 + ImplicitOps|ModRM|Mov, ImplicitOps|ModRM|Mov, 1.19 /* 0xE0 - 0xE7 */ 1.20 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, 1.21 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, 1.22 @@ -216,7 +218,7 @@ static uint8_t twobyte_table[256] = { 1.23 ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov, 1.24 /* 0xA0 - 0xA7 */ 1.25 ImplicitOps, ImplicitOps, ImplicitOps, DstBitBase|SrcReg|ModRM, 1.26 - DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, 0, 0, 1.27 + DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, 0, 0, 1.28 /* 0xA8 - 0xAF */ 1.29 ImplicitOps, ImplicitOps, 0, DstBitBase|SrcReg|ModRM, 1.30 DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, 0, DstReg|SrcMem|ModRM, 1.31 @@ -246,8 +248,20 @@ static uint8_t twobyte_table[256] = { 1.32 /* Type, address-of, and value of an instruction's operand. */ 1.33 struct operand { 1.34 enum { OP_REG, OP_MEM, OP_IMM, OP_NONE } type; 1.35 - unsigned int bytes; 1.36 - unsigned long val, orig_val; 1.37 + unsigned int bytes; 1.38 + 1.39 + /* Up to 128-byte operand value, addressable as ulong or uint32_t[]. */ 1.40 + union { 1.41 + unsigned long val; 1.42 + uint32_t bigval[4]; 1.43 + }; 1.44 + 1.45 + /* Up to 128-byte operand value, addressable as ulong or uint32_t[]. */ 1.46 + union { 1.47 + unsigned long orig_val; 1.48 + uint32_t orig_bigval[4]; 1.49 + }; 1.50 + 1.51 union { 1.52 /* OP_REG: Pointer to register field. */ 1.53 unsigned long *reg; 1.54 @@ -594,6 +608,18 @@ do{ struct fpu_insn_ctxt fic; 1.55 put_fpu(&fic); \ 1.56 } while (0) 1.57 1.58 +#define emulate_fpu_insn_memsrc(_op, _arg) \ 1.59 +do{ struct fpu_insn_ctxt fic; \ 1.60 + get_fpu(X86EMUL_FPU_fpu, &fic); \ 1.61 + asm volatile ( \ 1.62 + "movb $2f-1f,%0 \n" \ 1.63 + "1: " _op " %1 \n" \ 1.64 + "2: \n" \ 1.65 + : "=m" (fic.insn_bytes) \ 1.66 + : "m" (_arg) : "memory" ); \ 1.67 + put_fpu(&fic); \ 1.68 +} while (0) 1.69 + 1.70 #define emulate_fpu_insn_stub(_bytes...) \ 1.71 do{ uint8_t stub[] = { _bytes, 0xc3 }; \ 1.72 struct fpu_insn_ctxt fic = { .insn_bytes = sizeof(stub)-1 }; \ 1.73 @@ -1007,14 +1033,15 @@ protmode_load_seg( 1.74 if ( (desc.b & (5u<<9)) == (4u<<9) ) 1.75 goto raise_exn; 1.76 /* Non-conforming segment: check DPL against RPL and CPL. */ 1.77 - if ( ((desc.b & (6u<<9)) != (6u<<9)) && ((dpl < cpl) || (dpl < rpl)) ) 1.78 + if ( ((desc.b & (6u<<9)) != (6u<<9)) && 1.79 + ((dpl < cpl) || (dpl < rpl)) ) 1.80 goto raise_exn; 1.81 break; 1.82 } 1.83 1.84 /* Ensure Accessed flag is set. */ 1.85 new_desc_b = desc.b | 0x100; 1.86 - rc = ((desc.b & 0x100) ? X86EMUL_OKAY : 1.87 + rc = ((desc.b & 0x100) ? X86EMUL_OKAY : 1.88 ops->cmpxchg( 1.89 x86_seg_none, desctab.base + (sel & 0xfff8) + 4, 1.90 &desc.b, &new_desc_b, 4, ctxt)); 1.91 @@ -1076,16 +1103,16 @@ decode_register( 1.92 case 2: p = ®s->edx; break; 1.93 case 3: p = ®s->ebx; break; 1.94 case 4: p = (highbyte_regs ? 1.95 - ((unsigned char *)®s->eax + 1) : 1.96 + ((unsigned char *)®s->eax + 1) : 1.97 (unsigned char *)®s->esp); break; 1.98 case 5: p = (highbyte_regs ? 1.99 - ((unsigned char *)®s->ecx + 1) : 1.100 + ((unsigned char *)®s->ecx + 1) : 1.101 (unsigned char *)®s->ebp); break; 1.102 case 6: p = (highbyte_regs ? 1.103 - ((unsigned char *)®s->edx + 1) : 1.104 + ((unsigned char *)®s->edx + 1) : 1.105 (unsigned char *)®s->esi); break; 1.106 case 7: p = (highbyte_regs ? 1.107 - ((unsigned char *)®s->ebx + 1) : 1.108 + ((unsigned char *)®s->ebx + 1) : 1.109 (unsigned char *)®s->edi); break; 1.110 #if defined(__x86_64__) 1.111 case 8: p = ®s->r8; break; 1.112 @@ -2708,7 +2735,7 @@ x86_emulate( 1.113 int offset = (b == 0xca) ? insn_fetch_type(uint16_t) : 0; 1.114 op_bytes = mode_64bit() ? 8 : op_bytes; 1.115 if ( (rc = read_ulong(x86_seg_ss, sp_post_inc(op_bytes), 1.116 - &dst.val, op_bytes, ctxt, ops)) || 1.117 + &dst.val, op_bytes, ctxt, ops)) || 1.118 (rc = read_ulong(x86_seg_ss, sp_post_inc(op_bytes + offset), 1.119 &src.val, op_bytes, ctxt, ops)) || 1.120 (rc = load_seg(x86_seg_cs, (uint16_t)src.val, ctxt, ops)) ) 1.121 @@ -2801,6 +2828,58 @@ x86_emulate( 1.122 break; 1.123 } 1.124 1.125 + case 0xd8: /* FPU 0xd8 */ 1.126 + switch ( modrm ) 1.127 + { 1.128 + case 0xc0 ... 0xc7: /* fadd %stN,%stN */ 1.129 + case 0xc8 ... 0xcf: /* fmul %stN,%stN */ 1.130 + case 0xd0 ... 0xd7: /* fcom %stN,%stN */ 1.131 + case 0xd8 ... 0xdf: /* fcomp %stN,%stN */ 1.132 + case 0xe0 ... 0xe7: /* fsub %stN,%stN */ 1.133 + case 0xe8 ... 0xef: /* fsubr %stN,%stN */ 1.134 + case 0xf0 ... 0xf7: /* fdiv %stN,%stN */ 1.135 + case 0xf8 ... 0xff: /* fdivr %stN,%stN */ 1.136 + emulate_fpu_insn_stub(0xd8, modrm); 1.137 + break; 1.138 + default: 1.139 + fail_if(modrm >= 0xc0); 1.140 + ea.bytes = 4; 1.141 + src = ea; 1.142 + if ( (rc = ops->read(src.mem.seg, src.mem.off, &src.val, 1.143 + src.bytes, ctxt)) != 0 ) 1.144 + goto done; 1.145 + switch ( modrm_reg & 7 ) 1.146 + { 1.147 + case 0: /* fadd */ 1.148 + emulate_fpu_insn_memsrc("fadds", src.val); 1.149 + break; 1.150 + case 1: /* fmul */ 1.151 + emulate_fpu_insn_memsrc("fmuls", src.val); 1.152 + break; 1.153 + case 2: /* fcom */ 1.154 + emulate_fpu_insn_memsrc("fcoms", src.val); 1.155 + break; 1.156 + case 3: /* fcomp */ 1.157 + emulate_fpu_insn_memsrc("fcomps", src.val); 1.158 + break; 1.159 + case 4: /* fsub */ 1.160 + emulate_fpu_insn_memsrc("fsubs", src.val); 1.161 + break; 1.162 + case 5: /* fsubr */ 1.163 + emulate_fpu_insn_memsrc("fsubrs", src.val); 1.164 + break; 1.165 + case 6: /* fdiv */ 1.166 + emulate_fpu_insn_memsrc("fdivs", src.val); 1.167 + break; 1.168 + case 7: /* fdivr */ 1.169 + emulate_fpu_insn_memsrc("fdivrs", src.val); 1.170 + break; 1.171 + default: 1.172 + goto cannot_emulate; 1.173 + } 1.174 + } 1.175 + break; 1.176 + 1.177 case 0xd9: /* FPU 0xd9 */ 1.178 switch ( modrm ) 1.179 { 1.180 @@ -2837,28 +2916,269 @@ x86_emulate( 1.181 emulate_fpu_insn_stub(0xd9, modrm); 1.182 break; 1.183 default: 1.184 - fail_if((modrm_reg & 7) != 7); 1.185 fail_if(modrm >= 0xc0); 1.186 - /* fnstcw m2byte */ 1.187 - ea.bytes = 2; 1.188 - dst = ea; 1.189 - emulate_fpu_insn_memdst("fnstcw", dst.val); 1.190 + switch ( modrm_reg & 7 ) 1.191 + { 1.192 + case 0: /* fld m32fp */ 1.193 + ea.bytes = 4; 1.194 + src = ea; 1.195 + if ( (rc = ops->read(ea.mem.seg, ea.mem.off, &src.val, 1.196 + src.bytes, ctxt)) != 0 ) 1.197 + goto done; 1.198 + emulate_fpu_insn_memsrc("flds", src.val); 1.199 + break; 1.200 + case 2: /* fstp m32fp */ 1.201 + ea.bytes = 4; 1.202 + dst = ea; 1.203 + dst.type = OP_MEM; 1.204 + emulate_fpu_insn_memdst("fsts", dst.val); 1.205 + break; 1.206 + case 3: /* fstp m32fp */ 1.207 + ea.bytes = 4; 1.208 + dst = ea; 1.209 + dst.type = OP_MEM; 1.210 + emulate_fpu_insn_memdst("fstps", dst.val); 1.211 + break; 1.212 + /* case 4: fldenv - TODO */ 1.213 + case 5: /* fldcw m2byte */ 1.214 + ea.bytes = 2; 1.215 + src = ea; 1.216 + if ( (rc = ops->read(src.mem.seg, src.mem.off, &src.val, 1.217 + src.bytes, ctxt)) != 0 ) 1.218 + goto done; 1.219 + emulate_fpu_insn_memsrc("fldcw", src.val); 1.220 + break; 1.221 + /* case 6: fstenv - TODO */ 1.222 + case 7: /* fnstcw m2byte */ 1.223 + ea.bytes = 2; 1.224 + dst = ea; 1.225 + dst.type = OP_MEM; 1.226 + emulate_fpu_insn_memdst("fnstcw", dst.val); 1.227 + break; 1.228 + default: 1.229 + goto cannot_emulate; 1.230 + } 1.231 + } 1.232 + break; 1.233 + 1.234 + case 0xda: /* FPU 0xda */ 1.235 + switch ( modrm ) 1.236 + { 1.237 + case 0xc0 ... 0xc7: /* fcmovb %stN */ 1.238 + case 0xc8 ... 0xcf: /* fcmove %stN */ 1.239 + case 0xd0 ... 0xd7: /* fcmovbe %stN */ 1.240 + case 0xd8 ... 0xdf: /* fcmovu %stN */ 1.241 + case 0xe9: /* fucompp */ 1.242 + emulate_fpu_insn_stub(0xda, modrm); 1.243 + break; 1.244 + default: 1.245 + fail_if(modrm >= 0xc0); 1.246 + ea.bytes = 8; 1.247 + src = ea; 1.248 + if ( (rc = ops->read(src.mem.seg, src.mem.off, &src.val, 1.249 + src.bytes, ctxt)) != 0 ) 1.250 + goto done; 1.251 + switch ( modrm_reg & 7 ) 1.252 + { 1.253 + case 0: /* fiadd m64i */ 1.254 + emulate_fpu_insn_memsrc("fiaddl", src.val); 1.255 + break; 1.256 + case 1: /* fimul m64i */ 1.257 + emulate_fpu_insn_memsrc("fimul", src.val); 1.258 + break; 1.259 + case 2: /* ficom m64i */ 1.260 + emulate_fpu_insn_memsrc("ficoml", src.val); 1.261 + break; 1.262 + case 3: /* ficomp m64i */ 1.263 + emulate_fpu_insn_memsrc("ficompl", src.val); 1.264 + break; 1.265 + case 4: /* fisub m64i */ 1.266 + emulate_fpu_insn_memsrc("fisubl", src.val); 1.267 + break; 1.268 + case 5: /* fisubr m64i */ 1.269 + emulate_fpu_insn_memsrc("fisubrl", src.val); 1.270 + break; 1.271 + case 6: /* fidiv m64i */ 1.272 + emulate_fpu_insn_memsrc("fidivl", src.val); 1.273 + break; 1.274 + case 7: /* fidivr m64i */ 1.275 + emulate_fpu_insn_memsrc("fidivrl", src.val); 1.276 + break; 1.277 + default: 1.278 + goto cannot_emulate; 1.279 + } 1.280 } 1.281 break; 1.282 1.283 case 0xdb: /* FPU 0xdb */ 1.284 - fail_if(modrm != 0xe3); 1.285 - /* fninit */ 1.286 - emulate_fpu_insn("fninit"); 1.287 + switch ( modrm ) 1.288 + { 1.289 + case 0xc0 ... 0xc7: /* fcmovnb %stN */ 1.290 + case 0xc8 ... 0xcf: /* fcmovne %stN */ 1.291 + case 0xd0 ... 0xd7: /* fcmovnbe %stN */ 1.292 + case 0xd8 ... 0xdf: /* fcmovnu %stN */ 1.293 + emulate_fpu_insn_stub(0xdb, modrm); 1.294 + break; 1.295 + case 0xe2: /* fnclex */ 1.296 + emulate_fpu_insn("fnclex"); 1.297 + break; 1.298 + case 0xe3: /* fninit */ 1.299 + emulate_fpu_insn("fninit"); 1.300 + break; 1.301 + case 0xe4: /* fsetpm - 287 only, ignored by 387 */ 1.302 + break; 1.303 + case 0xe8 ... 0xef: /* fucomi %stN */ 1.304 + case 0xf0 ... 0xf7: /* fcomi %stN */ 1.305 + emulate_fpu_insn_stub(0xdb, modrm); 1.306 + break; 1.307 + default: 1.308 + fail_if(modrm >= 0xc0); 1.309 + switch ( modrm_reg & 7 ) 1.310 + { 1.311 + case 0: /* fild m32i */ 1.312 + ea.bytes = 4; 1.313 + src = ea; 1.314 + if ( (rc = ops->read(src.mem.seg, src.mem.off, &src.val, 1.315 + src.bytes, ctxt)) != 0 ) 1.316 + goto done; 1.317 + emulate_fpu_insn_memsrc("fildl", src.val); 1.318 + break; 1.319 + case 1: /* fisttp m32i */ 1.320 + ea.bytes = 4; 1.321 + dst = ea; 1.322 + dst.type = OP_MEM; 1.323 + emulate_fpu_insn_memdst("fisttpl", dst.val); 1.324 + break; 1.325 + case 2: /* fist m32i */ 1.326 + ea.bytes = 4; 1.327 + dst = ea; 1.328 + dst.type = OP_MEM; 1.329 + emulate_fpu_insn_memdst("fistl", dst.val); 1.330 + break; 1.331 + case 3: /* fistp m32i */ 1.332 + ea.bytes = 4; 1.333 + dst = ea; 1.334 + dst.type = OP_MEM; 1.335 + emulate_fpu_insn_memdst("fistpl", dst.val); 1.336 + break; 1.337 + case 5: /* fld m80fp */ 1.338 + ea.bytes = 10; 1.339 + src = ea; 1.340 + if ( (rc = ops->read(src.mem.seg, src.mem.off, 1.341 + &src.val, src.bytes, ctxt)) != 0 ) 1.342 + goto done; 1.343 + emulate_fpu_insn_memdst("fldt", src.val); 1.344 + break; 1.345 + case 7: /* fstp m80fp */ 1.346 + ea.bytes = 10; 1.347 + dst.type = OP_MEM; 1.348 + dst = ea; 1.349 + emulate_fpu_insn_memdst("fstpt", dst.val); 1.350 + break; 1.351 + default: 1.352 + goto cannot_emulate; 1.353 + } 1.354 + } 1.355 + break; 1.356 + 1.357 + case 0xdc: /* FPU 0xdc */ 1.358 + switch ( modrm ) 1.359 + { 1.360 + case 0xc0 ... 0xc7: /* fadd %stN */ 1.361 + case 0xc8 ... 0xcf: /* fmul %stN */ 1.362 + case 0xe0 ... 0xe7: /* fsubr %stN */ 1.363 + case 0xe8 ... 0xef: /* fsub %stN */ 1.364 + case 0xf0 ... 0xf7: /* fdivr %stN */ 1.365 + case 0xf8 ... 0xff: /* fdiv %stN */ 1.366 + emulate_fpu_insn_stub(0xdc, modrm); 1.367 + break; 1.368 + default: 1.369 + fail_if(modrm >= 0xc0); 1.370 + ea.bytes = 8; 1.371 + src = ea; 1.372 + if ( (rc = ops->read(src.mem.seg, src.mem.off, &src.val, 1.373 + src.bytes, ctxt)) != 0 ) 1.374 + goto done; 1.375 + switch ( modrm_reg & 7 ) 1.376 + { 1.377 + case 0: /* fadd m64fp */ 1.378 + emulate_fpu_insn_memsrc("faddl", src.val); 1.379 + break; 1.380 + case 1: /* fmul m64fp */ 1.381 + emulate_fpu_insn_memsrc("fmull", src.val); 1.382 + break; 1.383 + case 2: /* fcom m64fp */ 1.384 + emulate_fpu_insn_memsrc("fcoml", src.val); 1.385 + break; 1.386 + case 3: /* fcomp m64fp */ 1.387 + emulate_fpu_insn_memsrc("fcompl", src.val); 1.388 + break; 1.389 + case 4: /* fsub m64fp */ 1.390 + emulate_fpu_insn_memsrc("fsubl", src.val); 1.391 + break; 1.392 + case 5: /* fsubr m64fp */ 1.393 + emulate_fpu_insn_memsrc("fsubrl", src.val); 1.394 + break; 1.395 + case 6: /* fdiv m64fp */ 1.396 + emulate_fpu_insn_memsrc("fdivl", src.val); 1.397 + break; 1.398 + case 7: /* fdivr m64fp */ 1.399 + emulate_fpu_insn_memsrc("fdivrl", src.val); 1.400 + break; 1.401 + } 1.402 + } 1.403 break; 1.404 1.405 case 0xdd: /* FPU 0xdd */ 1.406 - fail_if((modrm_reg & 7) != 7); 1.407 - fail_if(modrm >= 0xc0); 1.408 - /* fnstsw m2byte */ 1.409 - ea.bytes = 2; 1.410 - dst = ea; 1.411 - emulate_fpu_insn_memdst("fnstsw", dst.val); 1.412 + switch ( modrm ) 1.413 + { 1.414 + case 0xc0 ... 0xc7: /* ffree %stN */ 1.415 + case 0xd0 ... 0xd7: /* fst %stN */ 1.416 + case 0xd8 ... 0xdf: /* fstp %stN */ 1.417 + case 0xe0 ... 0xe7: /* fucom %stN */ 1.418 + case 0xe8 ... 0xef: /* fucomp %stN */ 1.419 + emulate_fpu_insn_stub(0xdd, modrm); 1.420 + break; 1.421 + default: 1.422 + fail_if(modrm >= 0xc0); 1.423 + switch ( modrm_reg & 7 ) 1.424 + { 1.425 + case 0: /* fld m64fp */; 1.426 + ea.bytes = 8; 1.427 + src = ea; 1.428 + if ( (rc = ops->read(src.mem.seg, src.mem.off, &src.val, 1.429 + src.bytes, ctxt)) != 0 ) 1.430 + goto done; 1.431 + emulate_fpu_insn_memsrc("fldl", src.val); 1.432 + break; 1.433 + case 1: /* fisttp m64i */ 1.434 + ea.bytes = 8; 1.435 + dst = ea; 1.436 + dst.type = OP_MEM; 1.437 + emulate_fpu_insn_memdst("fisttpll", dst.val); 1.438 + break; 1.439 + case 2: /* fst m64fp */ 1.440 + ea.bytes = 8; 1.441 + dst = ea; 1.442 + dst.type = OP_MEM; 1.443 + emulate_fpu_insn_memsrc("fstl", dst.val); 1.444 + break; 1.445 + case 3: /* fstp m64fp */ 1.446 + ea.bytes = 8; 1.447 + dst = ea; 1.448 + dst.type = OP_MEM; 1.449 + emulate_fpu_insn_memdst("fstpl", dst.val); 1.450 + break; 1.451 + case 7: /* fnstsw m2byte */ 1.452 + ea.bytes = 2; 1.453 + dst = ea; 1.454 + dst.type = OP_MEM; 1.455 + emulate_fpu_insn_memdst("fnstsw", dst.val); 1.456 + break; 1.457 + default: 1.458 + goto cannot_emulate; 1.459 + } 1.460 + } 1.461 break; 1.462 1.463 case 0xde: /* FPU 0xde */ 1.464 @@ -2874,17 +3194,120 @@ x86_emulate( 1.465 emulate_fpu_insn_stub(0xde, modrm); 1.466 break; 1.467 default: 1.468 - goto cannot_emulate; 1.469 + fail_if(modrm >= 0xc0); 1.470 + ea.bytes = 2; 1.471 + src = ea; 1.472 + if ( (rc = ops->read(src.mem.seg, src.mem.off, &src.val, 1.473 + src.bytes, ctxt)) != 0 ) 1.474 + goto done; 1.475 + switch ( modrm_reg & 7 ) 1.476 + { 1.477 + case 0: /* fiadd m16i */ 1.478 + emulate_fpu_insn_memsrc("fiadd", src.val); 1.479 + break; 1.480 + case 1: /* fimul m16i */ 1.481 + emulate_fpu_insn_memsrc("fimul", src.val); 1.482 + break; 1.483 + case 2: /* ficom m16i */ 1.484 + emulate_fpu_insn_memsrc("ficom", src.val); 1.485 + break; 1.486 + case 3: /* ficomp m16i */ 1.487 + emulate_fpu_insn_memsrc("ficomp", src.val); 1.488 + break; 1.489 + case 4: /* fisub m16i */ 1.490 + emulate_fpu_insn_memsrc("fisub", src.val); 1.491 + break; 1.492 + case 5: /* fisubr m16i */ 1.493 + emulate_fpu_insn_memsrc("fisubr", src.val); 1.494 + break; 1.495 + case 6: /* fidiv m16i */ 1.496 + emulate_fpu_insn_memsrc("fidiv", src.val); 1.497 + break; 1.498 + case 7: /* fidivr m16i */ 1.499 + emulate_fpu_insn_memsrc("fidivr", src.val); 1.500 + break; 1.501 + default: 1.502 + goto cannot_emulate; 1.503 + } 1.504 } 1.505 break; 1.506 1.507 case 0xdf: /* FPU 0xdf */ 1.508 - fail_if(modrm != 0xe0); 1.509 - /* fnstsw %ax */ 1.510 - dst.bytes = 2; 1.511 - dst.type = OP_REG; 1.512 - dst.reg = (unsigned long *)&_regs.eax; 1.513 - emulate_fpu_insn_memdst("fnstsw", dst.val); 1.514 + switch ( modrm ) 1.515 + { 1.516 + case 0xe0: 1.517 + /* fnstsw %ax */ 1.518 + dst.bytes = 2; 1.519 + dst.type = OP_REG; 1.520 + dst.reg = (unsigned long *)&_regs.eax; 1.521 + emulate_fpu_insn_memdst("fnstsw", dst.val); 1.522 + break; 1.523 + case 0xf0 ... 0xf7: /* fcomip %stN */ 1.524 + case 0xf8 ... 0xff: /* fucomip %stN */ 1.525 + emulate_fpu_insn_stub(0xdf, modrm); 1.526 + break; 1.527 + default: 1.528 + fail_if(modrm >= 0xc0); 1.529 + switch ( modrm_reg & 7 ) 1.530 + { 1.531 + case 0: /* fild m16i */ 1.532 + ea.bytes = 2; 1.533 + src = ea; 1.534 + if ( (rc = ops->read(src.mem.seg, src.mem.off, &src.val, 1.535 + src.bytes, ctxt)) != 0 ) 1.536 + goto done; 1.537 + emulate_fpu_insn_memsrc("fild", src.val); 1.538 + break; 1.539 + case 1: /* fisttp m16i */ 1.540 + ea.bytes = 2; 1.541 + dst = ea; 1.542 + dst.type = OP_MEM; 1.543 + emulate_fpu_insn_memdst("fisttp", dst.val); 1.544 + break; 1.545 + case 2: /* fist m16i */ 1.546 + ea.bytes = 2; 1.547 + dst = ea; 1.548 + dst.type = OP_MEM; 1.549 + emulate_fpu_insn_memdst("fist", dst.val); 1.550 + break; 1.551 + case 3: /* fistp m16i */ 1.552 + ea.bytes = 2; 1.553 + dst = ea; 1.554 + dst.type = OP_MEM; 1.555 + emulate_fpu_insn_memdst("fistp", dst.val); 1.556 + break; 1.557 + case 4: /* fbld m80dec */ 1.558 + ea.bytes = 10; 1.559 + dst = ea; 1.560 + if ( (rc = ops->read(src.mem.seg, src.mem.off, 1.561 + &src.val, src.bytes, ctxt)) != 0 ) 1.562 + goto done; 1.563 + emulate_fpu_insn_memdst("fbld", src.val); 1.564 + break; 1.565 + case 5: /* fild m64i */ 1.566 + ea.bytes = 8; 1.567 + src = ea; 1.568 + if ( (rc = ops->read(src.mem.seg, src.mem.off, &src.val, 1.569 + src.bytes, ctxt)) != 0 ) 1.570 + goto done; 1.571 + emulate_fpu_insn_memsrc("fildll", src.val); 1.572 + break; 1.573 + case 6: /* fbstp packed bcd */ 1.574 + ea.bytes = 10; 1.575 + dst = ea; 1.576 + dst.type = OP_MEM; 1.577 + emulate_fpu_insn_memdst("fbstp", dst.val); 1.578 + break; 1.579 + case 7: /* fistp m64i */ 1.580 + ea.bytes = 8; 1.581 + dst = ea; 1.582 + dst.type = OP_MEM; 1.583 + emulate_fpu_insn_memdst("fistpll", dst.val); 1.584 + break; 1.585 + default: 1.586 + goto cannot_emulate; 1.587 + } 1.588 + } 1.589 break; 1.590 1.591 case 0xe0 ... 0xe2: /* loop{,z,nz} */ { 1.592 @@ -2939,7 +3362,6 @@ x86_emulate( 1.593 /* out */ 1.594 fail_if(ops->write_io == NULL); 1.595 rc = ops->write_io(port, op_bytes, _regs.eax, ctxt); 1.596 - 1.597 } 1.598 else 1.599 {