Alexandre Julliard : ntdll: Linux support for saving and restoring the extended FPU context on exceptions .
Alexandre Julliard
julliard at winehq.org
Wed Jan 16 07:09:30 CST 2008
Module: wine
Branch: master
Commit: bd352bcd1c98ed91bdb337e73cddfd8ceac095d6
URL: http://source.winehq.org/git/wine.git/?a=commit;h=bd352bcd1c98ed91bdb337e73cddfd8ceac095d6
Author: Alexandre Julliard <julliard at winehq.org>
Date: Tue Jan 15 18:08:29 2008 +0100
ntdll: Linux support for saving and restoring the extended FPU context on exceptions.
---
dlls/ntdll/signal_i386.c | 119 +++++++++++++++++++++++++++++++++++++++-------
1 files changed, 101 insertions(+), 18 deletions(-)
diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c
index f70544d..b07715c 100644
--- a/dlls/ntdll/signal_i386.c
+++ b/dlls/ntdll/signal_i386.c
@@ -68,6 +68,33 @@
#undef ERR /* Solaris needs to define this */
+/* not defined for x86, so copy the x86_64 definition */
+typedef struct DECLSPEC_ALIGN(16) _M128A
+{
+ ULONGLONG Low;
+ LONGLONG High;
+} M128A;
+
+typedef struct
+{
+ WORD ControlWord;
+ WORD StatusWord;
+ BYTE TagWord;
+ BYTE Reserved1;
+ WORD ErrorOpcode;
+ DWORD ErrorOffset;
+ WORD ErrorSelector;
+ WORD Reserved2;
+ DWORD DataOffset;
+ WORD DataSelector;
+ WORD Reserved3;
+ DWORD MxCsr;
+ DWORD MxCsr_Mask;
+ M128A FloatRegisters[8];
+ M128A XmmRegisters[16];
+ BYTE Reserved4[96];
+} XMM_SAVE_AREA32;
+
/***********************************************************************
* signal context platform-specific definitions
*/
@@ -98,6 +125,7 @@ typedef ucontext_t SIGCONTEXT;
#define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
#define FPU_sig(context) ((FLOATING_SAVE_AREA*)((context)->uc_mcontext.fpregs))
+#define FPUX_sig(context) ((context)->uc_mcontext.fpregs->status >> 16 ? NULL : (XMM_SAVE_AREA32 *)(FPU_sig(context) + 1))
#define VM86_EAX 0 /* the %eax value while vm86_enter is executing */
@@ -165,6 +193,9 @@ typedef struct trapframe SIGCONTEXT;
#define EIP_sig(context) (*((unsigned long*)&(context)->tf_eip))
#define ESP_sig(context) (*((unsigned long*)&(context)->tf_esp))
+#define FPU_sig(context) NULL /* FIXME */
+#define FPUX_sig(context) NULL /* FIXME */
+
#endif /* bsdi */
#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__)
@@ -193,6 +224,9 @@ typedef struct sigcontext SIGCONTEXT;
#define EIP_sig(context) ((context)->sc_eip)
#define ESP_sig(context) ((context)->sc_esp)
+#define FPU_sig(context) NULL /* FIXME */
+#define FPUX_sig(context) NULL /* FIXME */
+
#endif /* *BSD */
#if defined(__svr4__) || defined(_SCO_DS) || defined(__sun)
@@ -240,6 +274,9 @@ typedef struct ucontext SIGCONTEXT;
#define TRAP_sig(context) ((context)->uc_mcontext.gregs[TRAPNO])
#endif
+#define FPU_sig(context) NULL /* FIXME */
+#define FPUX_sig(context) NULL /* FIXME */
+
#endif /* svr4 || SCO_DS */
#ifdef __APPLE__
@@ -288,6 +325,9 @@ typedef ucontext_t SIGCONTEXT;
#define ERROR_sig(context) ((context)->uc_mcontext->es.err)
#endif
+#define FPU_sig(context) NULL /* FIXME */
+#define FPUX_sig(context) NULL /* FIXME */
+
#endif /* __APPLE__ */
WINE_DEFAULT_DEBUG_CHANNEL(seh);
@@ -299,6 +339,8 @@ static size_t signal_stack_size;
static wine_signal_handler handlers[256];
+static int fpux_support; /* whether the CPU support extended fpu context */
+
extern void DECLSPEC_NORETURN __wine_call_from_32_restore_regs( const CONTEXT *context );
enum i386_trap_code
@@ -606,6 +648,25 @@ static inline void save_fpu( CONTEXT *context )
/***********************************************************************
+ * save_fpux
+ *
+ * Save the thread FPU extended context.
+ */
+static inline void save_fpux( CONTEXT *context )
+{
+#ifdef __GNUC__
+ /* we have to enforce alignment by hand */
+ char buffer[sizeof(XMM_SAVE_AREA32) + 16];
+ XMM_SAVE_AREA32 *state = (XMM_SAVE_AREA32 *)(((ULONG_PTR)buffer + 15) & ~15);
+
+ __asm__ __volatile__( "fxsave %0" : "=m" (*state) );
+ context->ContextFlags |= CONTEXT_EXTENDED_REGISTERS;
+ memcpy( context->ExtendedRegisters, state, sizeof(*state) );
+#endif
+}
+
+
+/***********************************************************************
* restore_fpu
*
* Restore the FPU context to a sigcontext.
@@ -622,6 +683,26 @@ static inline void restore_fpu( const CONTEXT *context )
/***********************************************************************
+ * restore_fpux
+ *
+ * Restore the FPU extended context to a sigcontext.
+ */
+static inline void restore_fpux( const CONTEXT *context )
+{
+#ifdef __GNUC__
+ /* we have to enforce alignment by hand */
+ char buffer[sizeof(XMM_SAVE_AREA32) + 16];
+ XMM_SAVE_AREA32 *state = (XMM_SAVE_AREA32 *)(((ULONG_PTR)buffer + 15) & ~15);
+
+ memcpy( state, context->ExtendedRegisters, sizeof(*state) );
+ /* reset the current interrupt status */
+ state->StatusWord &= state->ControlWord | 0xff80;
+ __asm__ __volatile__( "fxrstor %0" : : "m" (*state) );
+#endif
+}
+
+
+/***********************************************************************
* save_context
*
* Build a context structure from the signal info.
@@ -629,6 +710,8 @@ static inline void restore_fpu( const CONTEXT *context )
static inline void save_context( CONTEXT *context, const SIGCONTEXT *sigcontext, WORD fs, WORD gs )
{
struct ntdll_thread_regs * const regs = ntdll_get_thread_regs();
+ FLOATING_SAVE_AREA *fpu = FPU_sig(sigcontext);
+ XMM_SAVE_AREA32 *fpux = FPUX_sig(sigcontext);
memset(context, 0, sizeof(*context));
context->ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
@@ -655,17 +738,20 @@ static inline void save_context( CONTEXT *context, const SIGCONTEXT *sigcontext,
context->Dr6 = regs->dr6;
context->Dr7 = regs->dr7;
-#ifdef FPU_sig
- if (FPU_sig(sigcontext))
+ if (fpu)
{
context->ContextFlags |= CONTEXT_FLOATING_POINT;
- context->FloatSave = *FPU_sig(sigcontext);
+ context->FloatSave = *fpu;
}
- else
-#endif
+ if (fpux)
{
- save_fpu( context );
+ save_fpux( context );
+ context->ContextFlags |= CONTEXT_EXTENDED_REGISTERS;
+ memcpy( context->ExtendedRegisters, fpux, sizeof(*fpux) );
+ fpux_support = 1;
+ /* FIXME: convert fpux to fpu */
}
+ if (!fpu && !fpux) save_fpu( context );
}
@@ -677,6 +763,8 @@ static inline void save_context( CONTEXT *context, const SIGCONTEXT *sigcontext,
static inline void restore_context( const CONTEXT *context, SIGCONTEXT *sigcontext )
{
struct ntdll_thread_regs * const regs = ntdll_get_thread_regs();
+ FLOATING_SAVE_AREA *fpu = FPU_sig(sigcontext);
+ XMM_SAVE_AREA32 *fpux = FPUX_sig(sigcontext);
regs->dr0 = context->Dr0;
regs->dr1 = context->Dr1;
@@ -709,16 +797,9 @@ static inline void restore_context( const CONTEXT *context, SIGCONTEXT *sigconte
wine_set_fs( context->SegFs );
#endif
-#ifdef FPU_sig
- if (FPU_sig(sigcontext))
- {
- *FPU_sig(sigcontext) = context->FloatSave;
- }
- else
-#endif
- {
- restore_fpu( context );
- }
+ if (fpu) *fpu = context->FloatSave;
+ if (fpux) memcpy( fpux, context->ExtendedRegisters, sizeof(*fpux) );
+ if (!fpu && !fpux) restore_fpu( context );
}
@@ -730,7 +811,8 @@ static inline void restore_context( const CONTEXT *context, SIGCONTEXT *sigconte
void WINAPI __regs_get_cpu_context( CONTEXT *context, CONTEXT *regs )
{
*context = *regs;
- save_fpu( context );
+ if (fpux_support) save_fpux( context );
+ else save_fpu( context );
}
DEFINE_REGS_ENTRYPOINT( get_cpu_context, 4, 4 )
@@ -744,7 +826,8 @@ void set_cpu_context( const CONTEXT *context )
{
DWORD flags = context->ContextFlags & ~CONTEXT_i386;
- if (flags & CONTEXT_FLOATING_POINT) restore_fpu( context );
+ if (flags & CONTEXT_EXTENDED_REGISTERS) restore_fpux( context );
+ else if (flags & CONTEXT_FLOATING_POINT) restore_fpu( context );
if (flags & CONTEXT_DEBUG_REGISTERS)
{
More information about the wine-cvs
mailing list