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>
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 = &regs->edx; break;
    1.93      case  3: p = &regs->ebx; break;
    1.94      case  4: p = (highbyte_regs ?
    1.95 -                  ((unsigned char *)&regs->eax + 1) : 
    1.96 +                  ((unsigned char *)&regs->eax + 1) :
    1.97                    (unsigned char *)&regs->esp); break;
    1.98      case  5: p = (highbyte_regs ?
    1.99 -                  ((unsigned char *)&regs->ecx + 1) : 
   1.100 +                  ((unsigned char *)&regs->ecx + 1) :
   1.101                    (unsigned char *)&regs->ebp); break;
   1.102      case  6: p = (highbyte_regs ?
   1.103 -                  ((unsigned char *)&regs->edx + 1) : 
   1.104 +                  ((unsigned char *)&regs->edx + 1) :
   1.105                    (unsigned char *)&regs->esi); break;
   1.106      case  7: p = (highbyte_regs ?
   1.107 -                  ((unsigned char *)&regs->ebx + 1) : 
   1.108 +                  ((unsigned char *)&regs->ebx + 1) :
   1.109                    (unsigned char *)&regs->edi); break;
   1.110  #if defined(__x86_64__)
   1.111      case  8: p = &regs->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          {