# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1208358641 -3600
# Node ID defbab4dba1a40ce08ed5b9331cfaf7a4422853e
# Parent 837ea1f0aa8ab3446cfb8bf3ab9d68e258d08785
x86_emulate: Implement a more dynamic interface for handling FPU
exceptions, which will allow emulation stubs to be built dynamically
in a future patch.
Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx>
---
tools/tests/x86_emulate.c | 6 --
xen/arch/x86/Makefile | 2
xen/arch/x86/hvm/emulate.c | 23 +++++++--
xen/arch/x86/traps.c | 9 +++
xen/arch/x86/x86_emulate.c | 18 -------
xen/arch/x86/x86_emulate/x86_emulate.c | 82 ++++++++++++++++++++++-----------
xen/arch/x86/x86_emulate/x86_emulate.h | 14 ++++-
xen/include/asm-x86/hvm/vcpu.h | 3 +
8 files changed, 100 insertions(+), 57 deletions(-)
diff -r 837ea1f0aa8a -r defbab4dba1a tools/tests/x86_emulate.c
--- a/tools/tests/x86_emulate.c Wed Apr 16 13:43:23 2008 +0100
+++ b/tools/tests/x86_emulate.c Wed Apr 16 16:10:41 2008 +0100
@@ -4,10 +4,4 @@
#include <public/xen.h>
#include "x86_emulate/x86_emulate.h"
-
-#define __emulate_fpu_insn(_op) \
-do{ rc = X86EMUL_UNHANDLEABLE; \
- goto done; \
-} while (0)
-
#include "x86_emulate/x86_emulate.c"
diff -r 837ea1f0aa8a -r defbab4dba1a xen/arch/x86/Makefile
--- a/xen/arch/x86/Makefile Wed Apr 16 13:43:23 2008 +0100
+++ b/xen/arch/x86/Makefile Wed Apr 16 16:10:41 2008 +0100
@@ -52,6 +52,8 @@ obj-y += tboot.o
obj-$(crash_debug) += gdbstub.o
+x86_emulate.o: x86_emulate/x86_emulate.c x86_emulate/x86_emulate.h
+
$(TARGET): $(TARGET)-syms boot/mkelf32
./boot/mkelf32 $(TARGET)-syms $(TARGET) 0x100000 \
`$(NM) -nr $(TARGET)-syms | head -n 1 | sed -e 's/^\([^ ]*\).*/0x\1/'`
diff -r 837ea1f0aa8a -r defbab4dba1a xen/arch/x86/hvm/emulate.c
--- a/xen/arch/x86/hvm/emulate.c Wed Apr 16 13:43:23 2008 +0100
+++ b/xen/arch/x86/hvm/emulate.c Wed Apr 16 16:10:41 2008 +0100
@@ -674,11 +674,23 @@ static int hvmemul_inject_sw_interrupt(
return X86EMUL_OKAY;
}
-static void hvmemul_load_fpu_ctxt(
- struct x86_emulate_ctxt *ctxt)
-{
- if ( !current->fpu_dirtied )
+static void hvmemul_get_fpu(
+ void (*exception_callback)(void *, struct cpu_user_regs *),
+ void *exception_callback_arg,
+ struct x86_emulate_ctxt *ctxt)
+{
+ struct vcpu *curr = current;
+ if ( !curr->fpu_dirtied )
hvm_funcs.fpu_dirty_intercept();
+ curr->arch.hvm_vcpu.fpu_exception_callback = exception_callback;
+ curr->arch.hvm_vcpu.fpu_exception_callback_arg = exception_callback_arg;
+}
+
+static void hvmemul_put_fpu(
+ struct x86_emulate_ctxt *ctxt)
+{
+ struct vcpu *curr = current;
+ curr->arch.hvm_vcpu.fpu_exception_callback = NULL;
}
static int hvmemul_invlpg(
@@ -720,7 +732,8 @@ static struct x86_emulate_ops hvm_emulat
.cpuid = hvmemul_cpuid,
.inject_hw_exception = hvmemul_inject_hw_exception,
.inject_sw_interrupt = hvmemul_inject_sw_interrupt,
- .load_fpu_ctxt = hvmemul_load_fpu_ctxt,
+ .get_fpu = hvmemul_get_fpu,
+ .put_fpu = hvmemul_put_fpu,
.invlpg = hvmemul_invlpg
};
diff -r 837ea1f0aa8a -r defbab4dba1a xen/arch/x86/traps.c
--- a/xen/arch/x86/traps.c Wed Apr 16 13:43:23 2008 +0100
+++ b/xen/arch/x86/traps.c Wed Apr 16 16:10:41 2008 +0100
@@ -479,6 +479,7 @@ static inline void do_trap(
static inline void do_trap(
int trapnr, struct cpu_user_regs *regs, int use_error_code)
{
+ struct vcpu *curr = current;
unsigned long fixup;
DEBUGGER_trap_entry(trapnr, regs);
@@ -494,6 +495,14 @@ static inline void do_trap(
dprintk(XENLOG_ERR, "Trap %d: %p -> %p\n",
trapnr, _p(regs->eip), _p(fixup));
regs->eip = fixup;
+ return;
+ }
+
+ if ( ((trapnr == TRAP_copro_error) || (trapnr == TRAP_simd_error)) &&
+ is_hvm_vcpu(curr) && curr->arch.hvm_vcpu.fpu_exception_callback )
+ {
+ curr->arch.hvm_vcpu.fpu_exception_callback(
+ curr->arch.hvm_vcpu.fpu_exception_callback_arg, regs);
return;
}
diff -r 837ea1f0aa8a -r defbab4dba1a xen/arch/x86/x86_emulate.c
--- a/xen/arch/x86/x86_emulate.c Wed Apr 16 13:43:23 2008 +0100
+++ b/xen/arch/x86/x86_emulate.c Wed Apr 16 16:10:41 2008 +0100
@@ -11,23 +11,7 @@
#include <asm/x86_emulate.h>
+/* Avoid namespace pollution. */
#undef cmpxchg
-#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)
-
#include "x86_emulate/x86_emulate.c"
diff -r 837ea1f0aa8a -r defbab4dba1a xen/arch/x86/x86_emulate/x86_emulate.c
--- a/xen/arch/x86/x86_emulate/x86_emulate.c Wed Apr 16 13:43:23 2008 +0100
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c Wed Apr 16 16:10:41 2008 +0100
@@ -544,6 +544,45 @@ do {
if ( !mode_64bit() ) \
_regs.eip = ((op_bytes == 2) \
? (uint16_t)_regs.eip : (uint32_t)_regs.eip); \
+} while (0)
+
+struct fpu_insn_ctxt {
+ uint8_t insn_bytes;
+ uint8_t exn_raised;
+};
+
+static void fpu_handle_exception(void *_fic, struct cpu_user_regs *regs)
+{
+ struct fpu_insn_ctxt *fic = _fic;
+ fic->exn_raised = 1;
+ regs->eip += fic->insn_bytes;
+}
+
+#define __emulate_fpu_insn(_op) \
+do{ struct fpu_insn_ctxt fic = { 0 }; \
+ fail_if(ops->get_fpu == NULL); \
+ ops->get_fpu(fpu_handle_exception, &fic, ctxt); \
+ asm volatile ( \
+ "movb $2f-1f,%0 \n" \
+ "1: " _op " \n" \
+ "2: \n" \
+ : "=m" (fic.insn_bytes) : : "memory" ); \
+ ops->put_fpu(ctxt); \
+ generate_exception_if(fic.exn_raised, EXC_MF, -1); \
+} while (0)
+
+#define __emulate_fpu_insn_memdst(_op, _arg) \
+do{ struct fpu_insn_ctxt fic = { 0 }; \
+ fail_if(ops->get_fpu == NULL); \
+ ops->get_fpu(fpu_handle_exception, &fic, ctxt); \
+ asm volatile ( \
+ "movb $2f-1f,%0 \n" \
+ "1: " _op " %1 \n" \
+ "2: \n" \
+ : "=m" (fic.insn_bytes), "=m" (_arg) \
+ : : "memory" ); \
+ ops->put_fpu(ctxt); \
+ generate_exception_if(fic.exn_raised, EXC_MF, -1); \
} while (0)
static unsigned long __get_rep_prefix(
@@ -2399,8 +2438,6 @@ x86_emulate(
}
case 0x9b: /* wait/fwait */
- fail_if(ops->load_fpu_ctxt == NULL);
- ops->load_fpu_ctxt(ctxt);
__emulate_fpu_insn("fwait");
break;
@@ -2721,53 +2758,46 @@ x86_emulate(
}
case 0xd9: /* FPU 0xd9 */
- fail_if(ops->load_fpu_ctxt == NULL);
- ops->load_fpu_ctxt(ctxt);
switch ( modrm )
{
- case 0xc0: __emulate_fpu_insn(".byte 0xd9,0xc0"); break;
- case 0xc1: __emulate_fpu_insn(".byte 0xd9,0xc1"); break;
- case 0xc2: __emulate_fpu_insn(".byte 0xd9,0xc2"); break;
- case 0xc3: __emulate_fpu_insn(".byte 0xd9,0xc3"); break;
- case 0xc4: __emulate_fpu_insn(".byte 0xd9,0xc4"); break;
- case 0xc5: __emulate_fpu_insn(".byte 0xd9,0xc5"); break;
- case 0xc6: __emulate_fpu_insn(".byte 0xd9,0xc6"); break;
- case 0xc7: __emulate_fpu_insn(".byte 0xd9,0xc7"); break;
- case 0xe0: __emulate_fpu_insn(".byte 0xd9,0xe0"); break;
- case 0xe8: __emulate_fpu_insn(".byte 0xd9,0xe8"); break;
- case 0xee: __emulate_fpu_insn(".byte 0xd9,0xee"); break;
+ case 0xc0: __emulate_fpu_insn(".byte 0xd9,0xc0"); break; /* fld %st0 */
+ case 0xc1: __emulate_fpu_insn(".byte 0xd9,0xc1"); break; /* fld %st1 */
+ case 0xc2: __emulate_fpu_insn(".byte 0xd9,0xc2"); break; /* fld %st2 */
+ case 0xc3: __emulate_fpu_insn(".byte 0xd9,0xc3"); break; /* fld %st3 */
+ case 0xc4: __emulate_fpu_insn(".byte 0xd9,0xc4"); break; /* fld %st4 */
+ case 0xc5: __emulate_fpu_insn(".byte 0xd9,0xc5"); break; /* fld %st5 */
+ case 0xc6: __emulate_fpu_insn(".byte 0xd9,0xc6"); break; /* fld %st6 */
+ case 0xc7: __emulate_fpu_insn(".byte 0xd9,0xc7"); break; /* fld %st7 */
+ case 0xe0: __emulate_fpu_insn(".byte 0xd9,0xe0"); break; /* fchs */
+ case 0xe1: __emulate_fpu_insn(".byte 0xd9,0xe1"); break; /* fabs */
+ case 0xe8: __emulate_fpu_insn(".byte 0xd9,0xe8"); break; /* fld1 */
+ case 0xee: __emulate_fpu_insn(".byte 0xd9,0xee"); break; /* fldz */
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) );
+ __emulate_fpu_insn_memdst("fnstcw", dst.val);
}
break;
case 0xdb: /* FPU 0xdb */
- fail_if(ops->load_fpu_ctxt == NULL);
- ops->load_fpu_ctxt(ctxt);
fail_if(modrm != 0xe3);
/* fninit */
- asm volatile ( "fninit" );
+ __emulate_fpu_insn("fninit");
break;
case 0xdd: /* FPU 0xdd */
- fail_if(ops->load_fpu_ctxt == NULL);
- ops->load_fpu_ctxt(ctxt);
fail_if((modrm_reg & 7) != 7);
fail_if(modrm >= 0xc0);
/* fnstsw m2byte */
ea.bytes = 2;
dst = ea;
- asm volatile ( "fnstsw %0" : "=m" (dst.val) );
+ __emulate_fpu_insn_memdst("fnstsw", 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(".byte 0xde,0xd9"); break;
@@ -2784,14 +2814,12 @@ x86_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) );
+ __emulate_fpu_insn_memdst("fnstsw", dst.val);
break;
case 0xe0 ... 0xe2: /* loop{,z,nz} */ {
diff -r 837ea1f0aa8a -r defbab4dba1a xen/arch/x86/x86_emulate/x86_emulate.h
--- a/xen/arch/x86/x86_emulate/x86_emulate.h Wed Apr 16 13:43:23 2008 +0100
+++ b/xen/arch/x86/x86_emulate/x86_emulate.h Wed Apr 16 16:10:41 2008 +0100
@@ -342,8 +342,18 @@ struct x86_emulate_ops
uint8_t insn_len,
struct x86_emulate_ctxt *ctxt);
- /* load_fpu_ctxt: Load emulated environment's FPU state onto processor. */
- void (*load_fpu_ctxt)(
+ /*
+ * get_fpu: Load emulated environment's FPU state onto processor.
+ * @exn_callback: On any FPU or SIMD exception, pass control to
+ * (*exception_callback)(exception_callback_arg, regs).
+ */
+ void (*get_fpu)(
+ void (*exception_callback)(void *, struct cpu_user_regs *),
+ void *exception_callback_arg,
+ struct x86_emulate_ctxt *ctxt);
+
+ /* put_fpu: Relinquish the FPU. Unhook from FPU/SIMD exception handlers. */
+ void (*put_fpu)(
struct x86_emulate_ctxt *ctxt);
/* invlpg: Invalidate paging structures which map addressed byte. */
diff -r 837ea1f0aa8a -r defbab4dba1a xen/include/asm-x86/hvm/vcpu.h
--- a/xen/include/asm-x86/hvm/vcpu.h Wed Apr 16 13:43:23 2008 +0100
+++ b/xen/include/asm-x86/hvm/vcpu.h Wed Apr 16 16:10:41 2008 +0100
@@ -83,6 +83,9 @@ struct hvm_vcpu {
*/
unsigned long mmio_gva;
unsigned long mmio_gpfn;
+
+ void (*fpu_exception_callback)(void *, struct cpu_user_regs *);
+ void *fpu_exception_callback_arg;
};
#endif /* __ASM_X86_HVM_VCPU_H__ */
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|