[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] x86_emulate: Implement a more dynamic interface for handling FPU



# 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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.