diff --git a/vm/os-linux-x86.32.hpp b/vm/os-linux-x86.32.hpp index 1db87f995d..8fa7eff842 100644 --- a/vm/os-linux-x86.32.hpp +++ b/vm/os-linux-x86.32.hpp @@ -3,6 +3,32 @@ namespace factor { +// glibc lies about the contents of the fpstate the kernel provides, hiding the FXSR +// environment +struct _fpstate { + /* Regular FPU environment */ + unsigned long cw; + unsigned long sw; + unsigned long tag; + unsigned long ipoff; + unsigned long cssel; + unsigned long dataoff; + unsigned long datasel; + struct _fpreg _st[8]; + unsigned short status; + unsigned short magic; /* 0xffff = regular FPU data only */ + + /* FXSR FPU environment */ + unsigned long _fxsr_env[6]; /* FXSR FPU env is ignored */ + unsigned long mxcsr; + unsigned long reserved; + struct _fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */ + struct _xmmreg _xmm[8]; + unsigned long padding[56]; +}; + +#define X86_FXSR_MAGIC 0x0000 + inline static void *ucontext_stack_pointer(void *uap) { ucontext_t *ucontext = (ucontext_t *)uap; @@ -11,15 +37,21 @@ inline static void *ucontext_stack_pointer(void *uap) inline static unsigned int uap_fpu_status(void *uap) { - // XXX mxcsr not available in i386 ucontext ucontext_t *ucontext = (ucontext_t *)uap; - return ucontext->uc_mcontext.fpregs->sw; + struct _fpstate *fpregs = (struct _fpstate *)uap->uc_mcontext.fpregs; + if (fpregs->magic == X86_FXSR_MAGIC) + return fpregs->sw | fpregs->mxcsr; + else + return fpregs->sw; } inline static void uap_clear_fpu_status(void *uap) { ucontext_t *ucontext = (ucontext_t *)uap; - ucontext->uc_mcontext.fpregs->sw = 0; + struct _fpstate *fpregs = (struct _fpstate *)uap->uc_mcontext.fpregs; + fpregs->sw = 0; + if (fpregs->magic == X86_FXSR_MAGIC) + fpregs->mxcsr &= 0xffffffc0; } #define UAP_PROGRAM_COUNTER(ucontext) \