aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2008-04-16 16:10:41 +0100
committerKeir Fraser <keir.fraser@citrix.com>2008-04-16 16:10:41 +0100
commita6836b4fdd40e84ef453a23fc298486049d26ef7 (patch)
tree7dc43533c1fffaefc55e4de38e3c3264d0f02037
parent8415719513ba048939d0ded7565cd9cba7c306c4 (diff)
downloadxen-a6836b4fdd40e84ef453a23fc298486049d26ef7.tar.gz
xen-a6836b4fdd40e84ef453a23fc298486049d26ef7.tar.bz2
xen-a6836b4fdd40e84ef453a23fc298486049d26ef7.zip
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@citrix.com>
-rw-r--r--tools/tests/x86_emulate.c6
-rw-r--r--xen/arch/x86/Makefile2
-rw-r--r--xen/arch/x86/hvm/emulate.c19
-rw-r--r--xen/arch/x86/traps.c9
-rw-r--r--xen/arch/x86/x86_emulate.c18
-rw-r--r--xen/arch/x86/x86_emulate/x86_emulate.c82
-rw-r--r--xen/arch/x86/x86_emulate/x86_emulate.h14
-rw-r--r--xen/include/asm-x86/hvm/vcpu.h3
8 files changed, 98 insertions, 55 deletions
diff --git a/tools/tests/x86_emulate.c b/tools/tests/x86_emulate.c
index d58f65a38e..a58a7b8178 100644
--- a/tools/tests/x86_emulate.c
+++ b/tools/tests/x86_emulate.c
@@ -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 --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile
index 334a996eb6..b94fb78d21 100644
--- a/xen/arch/x86/Makefile
+++ b/xen/arch/x86/Makefile
@@ -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 --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c
index b1d4bb8034..5e50fc6f61 100644
--- a/xen/arch/x86/hvm/emulate.c
+++ b/xen/arch/x86/hvm/emulate.c
@@ -674,11 +674,23 @@ static int hvmemul_inject_sw_interrupt(
return X86EMUL_OKAY;
}
-static void hvmemul_load_fpu_ctxt(
+static void hvmemul_get_fpu(
+ void (*exception_callback)(void *, struct cpu_user_regs *),
+ void *exception_callback_arg,
struct x86_emulate_ctxt *ctxt)
{
- if ( !current->fpu_dirtied )
+ 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_emulate_ops = {
.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 --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
index 94fb3a3d1f..75997500bc 100644
--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -479,6 +479,7 @@ asmlinkage int set_guest_nmi_trapbounce(void)
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);
@@ -497,6 +498,14 @@ static inline void do_trap(
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;
+ }
+
DEBUGGER_trap_fatal(trapnr, regs);
show_execution_state(regs);
diff --git a/xen/arch/x86/x86_emulate.c b/xen/arch/x86/x86_emulate.c
index f743650a5d..e69deb1ed8 100644
--- a/xen/arch/x86/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate.c
@@ -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 --git a/xen/arch/x86/x86_emulate/x86_emulate.c b/xen/arch/x86/x86_emulate/x86_emulate.c
index 9983a72904..42e5301aea 100644
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -546,6 +546,45 @@ do { \
? (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(
struct cpu_user_regs *int_regs,
struct cpu_user_regs *ext_regs,
@@ -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 --git a/xen/arch/x86/x86_emulate/x86_emulate.h b/xen/arch/x86/x86_emulate/x86_emulate.h
index 4ffdac75f3..09856d3cca 100644
--- a/xen/arch/x86/x86_emulate/x86_emulate.h
+++ b/xen/arch/x86/x86_emulate/x86_emulate.h
@@ -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 --git a/xen/include/asm-x86/hvm/vcpu.h b/xen/include/asm-x86/hvm/vcpu.h
index c4592d9c1e..6ff8de5fc4 100644
--- a/xen/include/asm-x86/hvm/vcpu.h
+++ b/xen/include/asm-x86/hvm/vcpu.h
@@ -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__ */