From: Matthew Dillon Date: Thu, 22 Dec 2011 19:21:41 +0000 (-0800) Subject: kernel - Fix floating point save state structure and minor npx issues X-Git-Tag: v3.0.0~328 X-Git-Url: http://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/9e6e869e8ae3b41257bc4cb2ef8565828e90ea41 kernel - Fix floating point save state structure and minor npx issues * The floating point save structure(s) used by the kernel and possibly also userland were too large for x86-64 due to a porting error where 'long' variables were left intact that should have been turned into 32-bit variables. No known adverse effect to the too-large structures but we have to get it right. * npxexit() was not being called in a kernel thread exit case. Kernel threads do not use the FP unit so the case was never hit, but fix it anyway. * Move a critical section to cover a flags test to handle a very rare preemptive thread switch issue. Since the preempting thread is a kernel thread which does not use the FP unit this case was never hit, but fix it anyway. --- diff --git a/sys/cpu/x86_64/include/npx.h b/sys/cpu/x86_64/include/npx.h index 35f8184ff6..2c36be7994 100644 --- a/sys/cpu/x86_64/include/npx.h +++ b/sys/cpu/x86_64/include/npx.h @@ -52,21 +52,21 @@ /* Environment information of floating point unit */ struct env87 { - long en_cw; /* control word (16bits) */ - long en_sw; /* status word (16bits) */ - long en_tw; /* tag word (16bits) */ - long en_fip; /* floating point instruction pointer */ + int32_t en_cw; /* control word (16bits) */ + int32_t en_sw; /* status word (16bits) */ + int32_t en_tw; /* tag word (16bits) */ + int32_t en_fip; /* floating point instruction pointer */ u_short en_fcs; /* floating code segment selector */ u_short en_opcode; /* opcode last executed (11 bits ) */ - long en_foo; /* floating operand offset */ - long en_fos; /* floating operand segment selector */ + int32_t en_foo; /* floating operand offset */ + int32_t en_fos; /* floating operand segment selector */ }; /* Contents of each floating point accumulator */ struct fpacc87 { #ifdef dontdef /* too unportable */ - u_long fp_mantlo; /* mantissa low (31:0) */ - u_long fp_manthi; /* mantissa high (63:32) */ + u_int32_t fp_mantlo; /* mantissa low (31:0) */ + u_int32_t fp_manthi; /* mantissa high (63:32) */ int fp_exp:15; /* exponent */ int fp_sgn:1; /* mantissa sign */ #else @@ -78,7 +78,7 @@ struct fpacc87 { struct save87 { struct env87 sv_env; /* floating point control/status */ struct fpacc87 sv_ac[8]; /* accumulator contents, 0-7 */ - u_long sv_unused001; + u_int32_t sv_unused001; /* * Bogus padding for emulators. Emulators should use their own * struct and arrange to store into this struct (ending here) @@ -120,7 +120,7 @@ struct savexmm { u_char fp_pad[6]; /* 6 (padding) */ } sv_fp[8]; struct xmmacc sv_xmm[8]; /* 128 */ - u_long sv_unused001; + u_int32_t sv_unused001; u_char sv_pad[220]; } __attribute__((aligned(16))); diff --git a/sys/platform/pc32/i386/vm_machdep.c b/sys/platform/pc32/i386/vm_machdep.c index c8cd5f8bd6..a1040c1366 100644 --- a/sys/platform/pc32/i386/vm_machdep.c +++ b/sys/platform/pc32/i386/vm_machdep.c @@ -274,10 +274,6 @@ cpu_lwp_exit(void) struct pcb *pcb; struct pcb_ext *ext; -#if NNPX > 0 - npxexit(); -#endif /* NNPX */ - /* * If we were using a private TSS do a forced-switch to ourselves * to switch back to the common TSS before freeing it. @@ -320,6 +316,9 @@ cpu_lwp_exit(void) void cpu_thread_exit(void) { +#if NNPX > 0 + npxexit(); +#endif curthread->td_switch = cpu_exit_switch; curthread->td_flags |= TDF_EXITING; lwkt_switch(); diff --git a/sys/platform/pc64/x86_64/npx.c b/sys/platform/pc64/x86_64/npx.c index e3de3c8a80..5920a75dcb 100644 --- a/sys/platform/pc64/x86_64/npx.c +++ b/sys/platform/pc64/x86_64/npx.c @@ -328,6 +328,7 @@ npxdna(void) * used the FP unit. This also occurs when a thread pushes a * signal handler and uses FP in the handler. */ + crit_enter(); if ((td->td_flags & (TDF_USINGFP | TDF_KERNELFP)) == 0) { td->td_flags |= TDF_USINGFP; npxinit(__INITIAL_NPXCW__); @@ -341,7 +342,6 @@ npxdna(void) * and then restore the garbage rather then the originally saved * fpstate. */ - crit_enter(); stop_emulating(); /* * Record new context early in case frstor causes an IRQ13. diff --git a/sys/platform/pc64/x86_64/vm_machdep.c b/sys/platform/pc64/x86_64/vm_machdep.c index 0a3797dcfb..890ccc1065 100644 --- a/sys/platform/pc64/x86_64/vm_machdep.c +++ b/sys/platform/pc64/x86_64/vm_machdep.c @@ -254,7 +254,6 @@ cpu_lwp_exit(void) struct thread *td = curthread; struct pcb *pcb; - npxexit(); pcb = td->td_pcb; /* Some i386 functionality was dropped */ @@ -289,6 +288,7 @@ cpu_lwp_exit(void) void cpu_thread_exit(void) { + npxexit(); curthread->td_switch = cpu_exit_switch; curthread->td_flags |= TDF_EXITING; lwkt_switch(); diff --git a/sys/platform/vkernel/i386/vm_machdep.c b/sys/platform/vkernel/i386/vm_machdep.c index a6408f7478..3f25eb1bde 100644 --- a/sys/platform/vkernel/i386/vm_machdep.c +++ b/sys/platform/vkernel/i386/vm_machdep.c @@ -274,10 +274,6 @@ cpu_lwp_exit(void) struct pcb *pcb; struct pcb_ext *ext; -#if NNPX > 0 - npxexit(); -#endif /* NNPX */ - /* * If we were using a private TSS do a forced-switch to ourselves * to switch back to the common TSS before freeing it. @@ -320,6 +316,9 @@ cpu_lwp_exit(void) void cpu_thread_exit(void) { +#if NNPX > 0 + npxexit(); +#endif curthread->td_switch = cpu_exit_switch; curthread->td_flags |= TDF_EXITING; lwkt_switch(); diff --git a/sys/platform/vkernel64/x86_64/vm_machdep.c b/sys/platform/vkernel64/x86_64/vm_machdep.c index dcab9292dd..5191810cca 100644 --- a/sys/platform/vkernel64/x86_64/vm_machdep.c +++ b/sys/platform/vkernel64/x86_64/vm_machdep.c @@ -254,7 +254,7 @@ cpu_lwp_exit(void) { struct thread *td = curthread; struct pcb *pcb; - npxexit(); + pcb = td->td_pcb; /* Some i386 functionality was dropped */ @@ -289,6 +289,7 @@ cpu_lwp_exit(void) void cpu_thread_exit(void) { + npxexit(); curthread->td_switch = cpu_exit_switch; curthread->td_flags |= TDF_EXITING; lwkt_switch();