diff options
author | Keir Fraser <keir.fraser@citrix.com> | 2008-04-16 16:10:41 +0100 |
---|---|---|
committer | Keir Fraser <keir.fraser@citrix.com> | 2008-04-16 16:10:41 +0100 |
commit | a6836b4fdd40e84ef453a23fc298486049d26ef7 (patch) | |
tree | 7dc43533c1fffaefc55e4de38e3c3264d0f02037 | |
parent | 8415719513ba048939d0ded7565cd9cba7c306c4 (diff) | |
download | xen-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.c | 6 | ||||
-rw-r--r-- | xen/arch/x86/Makefile | 2 | ||||
-rw-r--r-- | xen/arch/x86/hvm/emulate.c | 19 | ||||
-rw-r--r-- | xen/arch/x86/traps.c | 9 | ||||
-rw-r--r-- | xen/arch/x86/x86_emulate.c | 18 | ||||
-rw-r--r-- | xen/arch/x86/x86_emulate/x86_emulate.c | 82 | ||||
-rw-r--r-- | xen/arch/x86/x86_emulate/x86_emulate.h | 14 | ||||
-rw-r--r-- | xen/include/asm-x86/hvm/vcpu.h | 3 |
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__ */ |