aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/x86_emulate.c
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2008-03-03 13:13:55 +0000
committerKeir Fraser <keir.fraser@citrix.com>2008-03-03 13:13:55 +0000
commita285868402b206fcdea0b91d7a4eb5a4841454a2 (patch)
treed474d3079bd939ac1ba8163a8276c9a0fd84df52 /xen/arch/x86/x86_emulate.c
parentaa92127b227c6369a78c0fb56ca81dc0399998de (diff)
downloadxen-a285868402b206fcdea0b91d7a4eb5a4841454a2.tar.gz
xen-a285868402b206fcdea0b91d7a4eb5a4841454a2.tar.bz2
xen-a285868402b206fcdea0b91d7a4eb5a4841454a2.zip
x86_emulate: More FPU instructions.
Enables booting OS/2 as a HVM guest on Intel/VT hardware with full real-mode emulation (no vmxassist). Signed-off-by: Trolle Selander <trolle.selander@gmail.com> Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
Diffstat (limited to 'xen/arch/x86/x86_emulate.c')
-rw-r--r--xen/arch/x86/x86_emulate.c91
1 files changed, 83 insertions, 8 deletions
diff --git a/xen/arch/x86/x86_emulate.c b/xen/arch/x86/x86_emulate.c
index a9f60faacf..805a525fe2 100644
--- a/xen/arch/x86/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate.c
@@ -127,7 +127,7 @@ static uint8_t opcode_table[256] = {
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
/* 0x98 - 0x9F */
- ImplicitOps, ImplicitOps, ImplicitOps, 0,
+ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
/* 0xA0 - 0xA7 */
ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,
@@ -160,7 +160,8 @@ static uint8_t opcode_table[256] = {
ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM,
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
/* 0xD8 - 0xDF */
- 0, ImplicitOps|ModRM, 0, ImplicitOps|ModRM, 0, ImplicitOps|ModRM, 0, 0,
+ 0, ImplicitOps|ModRM|Mov, 0, ImplicitOps|ModRM|Mov,
+ 0, ImplicitOps|ModRM|Mov, ImplicitOps|ModRM|Mov, ImplicitOps|ModRM|Mov,
/* 0xE0 - 0xE7 */
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
@@ -309,6 +310,7 @@ struct operand {
#define EXC_SS 12
#define EXC_GP 13
#define EXC_PF 14
+#define EXC_MF 16
/*
* Instruction emulation:
@@ -476,6 +478,31 @@ do{ asm volatile ( \
#define __emulate_1op_8byte(_op, _dst, _eflags)
#endif /* __i386__ */
+#ifdef __XEN__
+#define __emulate_fpu_insn(_op) \
+do{ int _exn; \
+ asm volatile ( \
+ "1: " _op "\n" \
+ "2: \n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: mov $1,%0\n" \
+ " jmp 2b\n" \
+ ".previous\n" \
+ ".section __ex_table,\"a\"\n" \
+ " "__FIXUP_ALIGN"\n" \
+ " "__FIXUP_WORD" 1b,3b\n" \
+ ".previous" \
+ : "=r" (_exn) : "0" (0) ); \
+ generate_exception_if(_exn, EXC_MF, -1); \
+} while (0)
+#else
+#define __emulate_fpu_insn(_op) \
+do{ rc = X86EMUL_UNHANDLEABLE; \
+ goto done; \
+} while (0)
+#endif
+
+
/* Fetch next part of the instruction being emulated. */
#define insn_fetch_bytes(_size) \
({ unsigned long _x, _eip = _regs.eip; \
@@ -2355,6 +2382,10 @@ x86_emulate(
break;
}
+ case 0x9b: /* wait/fwait */
+ __emulate_fpu_insn("fwait");
+ break;
+
case 0x9c: /* pushf */
src.val = _regs.eflags;
goto push;
@@ -2670,12 +2701,27 @@ x86_emulate(
case 0xd9: /* FPU 0xd9 */
fail_if(ops->load_fpu_ctxt == NULL);
ops->load_fpu_ctxt(ctxt);
- fail_if((modrm_reg & 7) != 7);
- fail_if(modrm >= 0xc0);
- /* fnstcw m2byte */
- ea.bytes = 2;
- dst = ea;
- asm volatile ( "fnstcw %0" : "=m" (dst.val) );
+ switch ( modrm )
+ {
+ case 0xc0: __emulate_fpu_insn("fld %%st(0)"); break;
+ case 0xc1: __emulate_fpu_insn("fld %%st(1)"); break;
+ case 0xc2: __emulate_fpu_insn("fld %%st(2)"); break;
+ case 0xc3: __emulate_fpu_insn("fld %%st(3)"); break;
+ case 0xc4: __emulate_fpu_insn("fld %%st(4)"); break;
+ case 0xc5: __emulate_fpu_insn("fld %%st(5)"); break;
+ case 0xc6: __emulate_fpu_insn("fld %%st(6)"); break;
+ case 0xc7: __emulate_fpu_insn("fld %%st(7)"); break;
+ case 0xe0: __emulate_fpu_insn("fchs"); break;
+ case 0xe8: __emulate_fpu_insn("fld1"); break;
+ case 0xee: __emulate_fpu_insn("fldz"); break;
+ default:
+ fail_if((modrm_reg & 7) != 7);
+ fail_if(modrm >= 0xc0);
+ /* fnstcw m2byte */
+ ea.bytes = 2;
+ dst = ea;
+ asm volatile ( "fnstcw %0" : "=m" (dst.val) );
+ }
break;
case 0xdb: /* FPU 0xdb */
@@ -2697,6 +2743,35 @@ x86_emulate(
asm volatile ( "fnstsw %0" : "=m" (dst.val) );
break;
+ case 0xde: /* FPU 0xde */
+ fail_if(ops->load_fpu_ctxt == NULL);
+ ops->load_fpu_ctxt(ctxt);
+ switch ( modrm )
+ {
+ case 0xd9: __emulate_fpu_insn("fcompp"); break;
+ case 0xf8: __emulate_fpu_insn("fdivp %%st(0),%%st(0)"); break;
+ case 0xf9: __emulate_fpu_insn("fdivp %%st(1),%%st(0)"); break;
+ case 0xfa: __emulate_fpu_insn("fdivp %%st(2),%%st(0)"); break;
+ case 0xfb: __emulate_fpu_insn("fdivp %%st(3),%%st(0)"); break;
+ case 0xfc: __emulate_fpu_insn("fdivp %%st(4),%%st(0)"); break;
+ case 0xfd: __emulate_fpu_insn("fdivp %%st(5),%%st(0)"); break;
+ case 0xfe: __emulate_fpu_insn("fdivp %%st(6),%%st(0)"); break;
+ case 0xff: __emulate_fpu_insn("fdivp %%st(7),%%st(0)"); break;
+ default: goto cannot_emulate;
+ }
+ break;
+
+ case 0xdf: /* FPU 0xdf */
+ fail_if(ops->load_fpu_ctxt == NULL);
+ ops->load_fpu_ctxt(ctxt);
+ fail_if(modrm != 0xe0);
+ /* fnstsw %ax */
+ dst.bytes = 2;
+ dst.type = OP_REG;
+ dst.reg = (unsigned long *)&_regs.eax;
+ asm volatile ( "fnstsw %0" : "=m" (dst.val) );
+ break;
+
case 0xe0 ... 0xe2: /* loop{,z,nz} */ {
int rel = insn_fetch_type(int8_t);
int do_jmp = !(_regs.eflags & EFLG_ZF); /* loopnz */