diff -uNr xen-unstable.hg-orig/xen/arch/x86/x86_emulate/x86_emulate.c xen-unstable.hg/xen/arch/x86/x86_emulate/x86_emulate.c --- xen-unstable.hg-orig/xen/arch/x86/x86_emulate/x86_emulate.c 2008-07-01 11:25:35.977291057 +0100 +++ xen-unstable.hg/xen/arch/x86/x86_emulate/x86_emulate.c 2008-07-01 12:30:38.914501703 +0100 @@ -146,8 +146,8 @@ ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, /* 0xD8 - 0xDF */ - 0, ImplicitOps|ModRM|Mov, 0, ImplicitOps|ModRM|Mov, - 0, ImplicitOps|ModRM|Mov, ImplicitOps|ModRM|Mov, ImplicitOps|ModRM|Mov, + ImplicitOps|ModRM|Mov, ImplicitOps|ModRM|Mov, ImplicitOps|ModRM|Mov, ImplicitOps|ModRM|Mov, + ImplicitOps|ModRM|Mov, ImplicitOps|ModRM|Mov, ImplicitOps|ModRM|Mov, ImplicitOps|ModRM|Mov, /* 0xE0 - 0xE7 */ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, @@ -247,7 +247,17 @@ struct operand { enum { OP_REG, OP_MEM, OP_IMM, OP_NONE } type; unsigned int bytes; - unsigned long val, orig_val; + + union { + unsigned long val; + uint32_t bigval[4]; + }; + + union { + unsigned long orig_val; + uint32_t orig_bigval[4]; + }; + union { /* OP_REG: Pointer to register field. */ unsigned long *reg; @@ -594,6 +604,19 @@ put_fpu(&fic); \ } while (0) +#define emulate_fpu_insn_memsrc(_op, _arg) \ +do{ struct fpu_insn_ctxt fic; \ + get_fpu(X86EMUL_FPU_fpu, &fic); \ + asm volatile ( \ + "movb $2f-1f,%0 \n" \ + "1: " _op " %1 \n" \ + "2: \n" \ + : "=m" (fic.insn_bytes) \ + : "m" (_arg) : "memory" ); \ + put_fpu(&fic); \ +} while (0) + + #define emulate_fpu_insn_stub(_bytes...) \ do{ uint8_t stub[] = { _bytes, 0xc3 }; \ struct fpu_insn_ctxt fic = { .insn_bytes = sizeof(stub)-1 }; \ @@ -2801,6 +2824,57 @@ break; } + case 0xd8: /* FPU 0xd8 */ + switch ( modrm ) + { + case 0xc0 ... 0xc7: /* fadd %stN,%stN */ + case 0xc8 ... 0xcf: /* fmul %stN,%stN */ + case 0xd0 ... 0xd7: /* fcom %stN,%stN */ + case 0xd8 ... 0xdf: /* fcomp %stN,%stN */ + case 0xe0 ... 0xe7: /* fsub %stN,%stN */ + case 0xe8 ... 0xef: /* fsubr %stN,%stN */ + case 0xf0 ... 0xf7: /* fdiv %stN,%stN */ + case 0xf8 ... 0xff: /* fdivr %stN,%stN */ + emulate_fpu_insn_stub(0xd8, modrm); + break; + default: + fail_if(modrm >= 0xc0); + ea.bytes = 4; + src = ea; + rc = ops->read(src.mem.seg, src.mem.off, &src.val, src.bytes, ctxt); + + switch ( modrm_reg & 7 ) + { + case 0: /* fadd */ + emulate_fpu_insn_memsrc("fadds", src.val); + break; + case 1: /* fmul */ + emulate_fpu_insn_memsrc("fmuls", src.val); + break; + case 2: /* fcom */ + emulate_fpu_insn_memsrc("fcoms", src.val); + break; + case 3: /* fcomp */ + emulate_fpu_insn_memsrc("fcomps", src.val); + break; + case 4: /* fsub */ + emulate_fpu_insn_memsrc("fsubs", src.val); + break; + case 5: /* fsubr */ + emulate_fpu_insn_memsrc("fsubrs", src.val); + break; + case 6: /* fdiv */ + emulate_fpu_insn_memsrc("fdivs", src.val); + break; + case 7: /* fdivr */ + emulate_fpu_insn_memsrc("fdivrs", src.val); + break; + default: + goto cannot_emulate; + } + } + break; + case 0xd9: /* FPU 0xd9 */ switch ( modrm ) { @@ -2837,29 +2911,263 @@ emulate_fpu_insn_stub(0xd9, modrm); break; default: - fail_if((modrm_reg & 7) != 7); fail_if(modrm >= 0xc0); + switch ( modrm_reg & 7 ) + { + case 0: /* fld m32fp */ + ea.bytes = 4; + src = ea; + rc = ops->read(src.mem.seg, src.mem.off, &src.val, src.bytes, ctxt); + emulate_fpu_insn_memsrc("flds", src.val); + break; + case 2: /* fstp m32fp */ + ea.bytes = 4; + dst = ea; + dst.type = OP_MEM; + emulate_fpu_insn_memdst("fsts", dst.val); + break; + case 3: /* fstp m32fp */ + ea.bytes = 4; + dst = ea; + dst.type = OP_MEM; + emulate_fpu_insn_memdst("fstps", dst.val); + break; + /* case 4: fldenv - TODO */ + case 5: + /* fldcw m2byte */ + ea.bytes = 2; + src = ea; + rc = ops->read(src.mem.seg, src.mem.off, &src.val, src.bytes, ctxt); + emulate_fpu_insn_memsrc("fldcw", src.val); + break; + /* case 6: fstenv - TODO */ + case 7: /* fnstcw m2byte */ ea.bytes = 2; dst = ea; + dst.type = OP_MEM; emulate_fpu_insn_memdst("fnstcw", dst.val); + break; + default: + goto cannot_emulate; + } + } + break; + + case 0xda: /* FPU 0xda */ + switch ( modrm ) + { + case 0xc0 ... 0xc7: /* fcmovb %stN */ + case 0xc8 ... 0xcf: /* fcmove %stN */ + case 0xd0 ... 0xd7: /* fcmovbe %stN */ + case 0xd8 ... 0xdf: /* fcmovu %stN */ + case 0xe9: /* fucompp */ + emulate_fpu_insn_stub(0xda, modrm); + break; + default: + fail_if(modrm >= 0xc0); + ea.bytes = 8; + src = ea; + rc = ops->read(src.mem.seg, src.mem.off, &src.val, src.bytes, ctxt); + + switch ( modrm_reg & 7 ) + { + case 0: /* fiadd m64i */ + emulate_fpu_insn_memsrc("fiaddl", src.val); + break; + case 1: /* fimul m64i */ + emulate_fpu_insn_memsrc("fimul", src.val); + break; + case 2: /* ficom m64i */ + emulate_fpu_insn_memsrc("ficoml", src.val); + break; + case 3: /* ficomp m64i */ + emulate_fpu_insn_memsrc("ficompl", src.val); + break; + case 4: /* fisub m64i */ + emulate_fpu_insn_memsrc("fisubl", src.val); + break; + case 5: /* fisubr m64i */ + emulate_fpu_insn_memsrc("fisubrl", src.val); + break; + case 6: /* fidiv m64i */ + emulate_fpu_insn_memsrc("fidivl", src.val); + break; + case 7: /* fidivr m64i */ + emulate_fpu_insn_memsrc("fidivrl", src.val); + break; + default: + goto cannot_emulate; + } } break; case 0xdb: /* FPU 0xdb */ - fail_if(modrm != 0xe3); - /* fninit */ - emulate_fpu_insn("fninit"); + switch ( modrm ) + { + case 0xc0 ... 0xc7: /* fcmovnb %stN */ + case 0xc8 ... 0xcf: /* fcmovne %stN */ + case 0xd0 ... 0xd7: /* fcmovnbe %stN */ + case 0xd8 ... 0xdf: /* fcmovnu %stN */ + emulate_fpu_insn_stub(0xdb, modrm); + break; + case 0xe2: /* fnclex */ + emulate_fpu_insn("fnclex"); + break; + case 0xe3: /* fninit */ + emulate_fpu_insn("fninit"); + break; + case 0xe4: /* fsetpm - 287 only, ignored by 387 */ + break; + case 0xe8 ... 0xef: /* fucomi %stN */ + case 0xf0 ... 0xf7: /* fcomi %stN */ + emulate_fpu_insn_stub(0xdb, modrm); + break; + default: + fail_if(modrm >= 0xc0); + switch ( modrm_reg & 7 ) + { + case 0: /* fild m32i */ + ea.bytes = 4; + src = ea; + rc = ops->read(src.mem.seg, src.mem.off, &src.val, src.bytes, ctxt); + emulate_fpu_insn_memsrc("fildl", src.val); + break; + case 1: /* fisttp m32i */ + ea.bytes = 4; + dst = ea; + dst.type = OP_MEM; + emulate_fpu_insn_memdst("fisttpl", dst.val); + break; + case 2: /* fist m32i */ + ea.bytes = 4; + dst = ea; + dst.type = OP_MEM; + emulate_fpu_insn_memdst("fistl", dst.val); + break; + case 3: /* fistp m32i */ + ea.bytes = 4; + dst = ea; + dst.type = OP_MEM; + emulate_fpu_insn_memdst("fistpl", dst.val); + break; + case 5: /* fld m80fp */ + ea.bytes = 10; + src = ea; + rc = ops->read(src.mem.seg, src.mem.off, + &src.val, src.bytes, ctxt); + emulate_fpu_insn_memdst("fldt", src.val); + break; + case 7: /* fstp m80fp */ + ea.bytes = 10; + dst.type = OP_MEM; + dst = ea; + emulate_fpu_insn_memdst("fstpt", dst.val); + break; + + default: + goto cannot_emulate; + } + } + break; + + case 0xdc: /* FPU 0xdc */ + switch ( modrm ) + { + case 0xc0 ... 0xc7: /* fadd %stN */ + case 0xc8 ... 0xcf: /* fmul %stN */ + case 0xe0 ... 0xe7: /* fsubr %stN */ + case 0xe8 ... 0xef: /* fsub %stN */ + case 0xf0 ... 0xf7: /* fdivr %stN */ + case 0xf8 ... 0xff: /* fdiv %stN */ + emulate_fpu_insn_stub(0xdc, modrm); + break; + default: + fail_if(modrm >= 0xc0); + ea.bytes = 8; + src = ea; + rc = ops->read(src.mem.seg, src.mem.off, &src.val, src.bytes, ctxt); + + switch ( modrm_reg & 7 ) + { + case 0: /* fadd m64fp */ + emulate_fpu_insn_memsrc("faddl", src.val); + break; + case 1: /* fmul m64fp */ + emulate_fpu_insn_memsrc("fmull", src.val); + break; + case 2: /* fcom m64fp */ + emulate_fpu_insn_memsrc("fcoml", src.val); + break; + case 3: /* fcomp m64fp */ + emulate_fpu_insn_memsrc("fcompl", src.val); + break; + case 4: /* fsub m64fp */ + emulate_fpu_insn_memsrc("fsubl", src.val); + break; + case 5: /* fsubr m64fp */ + emulate_fpu_insn_memsrc("fsubrl", src.val); + break; + case 6: /* fdiv m64fp */ + emulate_fpu_insn_memsrc("fdivl", src.val); + break; + case 7: /* fdivr m64fp */ + emulate_fpu_insn_memsrc("fdivrl", src.val); + break; + } + } break; case 0xdd: /* FPU 0xdd */ - fail_if((modrm_reg & 7) != 7); + switch ( modrm ) + { + case 0xc0 ... 0xc7: /* ffree %stN */ + case 0xd0 ... 0xd7: /* fst %stN */ + case 0xd8 ... 0xdf: /* fstp %stN */ + case 0xe0 ... 0xe7: /* fucom %stN */ + case 0xe8 ... 0xef: /* fucomp %stN */ + emulate_fpu_insn_stub(0xdd, modrm); + break; + default: fail_if(modrm >= 0xc0); - /* fnstsw m2byte */ + + switch ( modrm_reg & 7 ) + { + case 0: /* fld m64fp */; + ea.bytes = 8; + src = ea; + rc = ops->read(src.mem.seg, src.mem.off, &src.val, src.bytes, ctxt); + emulate_fpu_insn_memsrc("fldl", src.val); + break; + case 1: /* fisttp m64i */ + ea.bytes = 8; + dst = ea; + dst.type = OP_MEM; + emulate_fpu_insn_memdst("fisttpll", dst.val); + break; + case 2: /* fst m64fp */ + ea.bytes = 8; + dst = ea; + dst.type = OP_MEM; + emulate_fpu_insn_memsrc("fstl", dst.val); + break; + case 3: /* fstp m64fp */ + ea.bytes = 8; + dst = ea; + dst.type = OP_MEM; + emulate_fpu_insn_memdst("fstpl", dst.val); + break; + case 7: /* fnstsw m2byte */ ea.bytes = 2; dst = ea; + dst.type = OP_MEM; emulate_fpu_insn_memdst("fnstsw", dst.val); break; + default: + goto cannot_emulate; + } + } + break; case 0xde: /* FPU 0xde */ switch ( modrm ) @@ -2874,18 +3182,115 @@ emulate_fpu_insn_stub(0xde, modrm); break; default: + fail_if(modrm >= 0xc0); + ea.bytes = 2; + src = ea; + rc = ops->read(src.mem.seg, src.mem.off, &src.val, src.bytes, ctxt); + + switch ( modrm_reg & 7 ) + { + case 0: /* fiadd m16i */ + emulate_fpu_insn_memsrc("fiadd", src.val); + break; + case 1: /* fimul m16i */ + emulate_fpu_insn_memsrc("fimul", src.val); + break; + case 2: /* ficom m16i */ + emulate_fpu_insn_memsrc("ficom", src.val); + break; + case 3: /* ficomp m16i */ + emulate_fpu_insn_memsrc("ficomp", src.val); + break; + case 4: /* fisub m16i */ + emulate_fpu_insn_memsrc("fisub", src.val); + break; + case 5: /* fisubr m16i */ + emulate_fpu_insn_memsrc("fisubr", src.val); + break; + case 6: /* fidiv m16i */ + emulate_fpu_insn_memsrc("fidiv", src.val); + break; + case 7: /* fidivr m16i */ + emulate_fpu_insn_memsrc("fidivr", src.val); + break; + default: goto cannot_emulate; } + } break; case 0xdf: /* FPU 0xdf */ - fail_if(modrm != 0xe0); + switch ( modrm ) + { + case 0xe0: /* fnstsw %ax */ dst.bytes = 2; dst.type = OP_REG; dst.reg = (unsigned long *)&_regs.eax; emulate_fpu_insn_memdst("fnstsw", dst.val); break; + case 0xf0 ... 0xf7: /* fcomip %stN */ + case 0xf8 ... 0xff: /* fucomip %stN */ + emulate_fpu_insn_stub(0xdf, modrm); + break; + default: + fail_if(modrm >= 0xc0); + switch ( modrm_reg & 7 ) + { + case 0: /* fild m16i */ + ea.bytes = 2; + src = ea; + rc = ops->read(src.mem.seg, src.mem.off, &src.val, src.bytes, ctxt); + emulate_fpu_insn_memsrc("fild", src.val); + break; + case 1: /* fisttp m16i */ + ea.bytes = 2; + dst = ea; + dst.type = OP_MEM; + emulate_fpu_insn_memdst("fisttp", dst.val); + break; + case 2: /* fist m16i */ + ea.bytes = 2; + dst = ea; + dst.type = OP_MEM; + emulate_fpu_insn_memdst("fist", dst.val); + break; + case 3: /* fistp m16i */ + ea.bytes = 2; + dst = ea; + dst.type = OP_MEM; + emulate_fpu_insn_memdst("fistp", dst.val); + break; + case 4: /* fbld m80dec */ + ea.bytes = 10; + dst = ea; + rc = ops->read(src.mem.seg, src.mem.off, + &src.val, src.bytes, ctxt); + emulate_fpu_insn_memdst("fbld", src.val); + break; + case 5: /* fild m64i */ + ea.bytes = 8; + src = ea; + rc = ops->read(src.mem.seg, src.mem.off, &src.val, src.bytes, ctxt); + emulate_fpu_insn_memsrc("fildll", src.val); + break; + case 6: /* fbstp packed bcd */ + ea.bytes = 10; + dst = ea; + dst.type = OP_MEM; + emulate_fpu_insn_memdst("fbstp", dst.val); + break; + case 7: /* fistp m64i */ + ea.bytes = 8; + dst = ea; + dst.type = OP_MEM; + emulate_fpu_insn_memdst("fistpll", dst.val); + break; + default: + goto cannot_emulate; + } + } + break; case 0xe0 ... 0xe2: /* loop{,z,nz} */ { int rel = insn_fetch_type(int8_t);