2015-04-30 12:45:38 +02:00
/*
* FPU signal frame handling routines .
*/
# include <linux/compat.h>
# include <linux/cpu.h>
# include <asm/fpu/internal.h>
# include <asm/fpu/signal.h>
# include <asm/fpu/regset.h>
2016-05-20 10:47:08 -07:00
# include <asm/fpu/xstate.h>
2015-04-30 12:45:38 +02:00
# include <asm/sigframe.h>
2016-06-01 10:42:20 -07:00
# include <asm/trace/fpu.h>
2015-04-30 12:45:38 +02:00
static struct _fpx_sw_bytes fx_sw_reserved , fx_sw_reserved_ia32 ;
/*
* Check for the presence of extended state information in the
* user fpstate pointer in the sigcontext .
*/
2015-04-30 17:15:32 +02:00
static inline int check_for_xstate ( struct fxregs_state __user * buf ,
2015-04-30 12:45:38 +02:00
void __user * fpstate ,
struct _fpx_sw_bytes * fx_sw )
{
2015-04-30 17:15:32 +02:00
int min_xstate_size = sizeof ( struct fxregs_state ) +
2015-04-30 12:45:38 +02:00
sizeof ( struct xstate_header ) ;
unsigned int magic2 ;
if ( __copy_from_user ( fx_sw , & buf - > sw_reserved [ 0 ] , sizeof ( * fx_sw ) ) )
return - 1 ;
/* Check for the first magic field and other error scenarios. */
if ( fx_sw - > magic1 ! = FP_XSTATE_MAGIC1 | |
fx_sw - > xstate_size < min_xstate_size | |
2016-05-20 10:47:05 -07:00
fx_sw - > xstate_size > fpu_user_xstate_size | |
2015-04-30 12:45:38 +02:00
fx_sw - > xstate_size > fx_sw - > extended_size )
return - 1 ;
/*
* Check for the presence of second magic word at the end of memory
* layout . This detects the case where the user just copied the legacy
* fpstate layout with out copying the extended state information
* in the memory layout .
*/
if ( __get_user ( magic2 , ( __u32 __user * ) ( fpstate + fx_sw - > xstate_size ) )
| | magic2 ! = FP_XSTATE_MAGIC2 )
return - 1 ;
return 0 ;
}
/*
* Signal frame handlers .
*/
static inline int save_fsave_header ( struct task_struct * tsk , void __user * buf )
{
if ( use_fxsr ( ) ) {
2015-04-30 17:15:32 +02:00
struct xregs_state * xsave = & tsk - > thread . fpu . state . xsave ;
2015-04-30 12:45:38 +02:00
struct user_i387_ia32_struct env ;
2015-09-05 09:32:36 +02:00
struct _fpstate_32 __user * fp = buf ;
2015-04-30 12:45:38 +02:00
convert_from_fxsr ( & env , tsk ) ;
if ( __copy_to_user ( buf , & env , sizeof ( env ) ) | |
__put_user ( xsave - > i387 . swd , & fp - > status ) | |
__put_user ( X86_FXSR_MAGIC , & fp - > magic ) )
return - 1 ;
} else {
2015-04-30 17:15:32 +02:00
struct fregs_state __user * fp = buf ;
2015-04-30 12:45:38 +02:00
u32 swd ;
if ( __get_user ( swd , & fp - > swd ) | | __put_user ( swd , & fp - > status ) )
return - 1 ;
}
return 0 ;
}
static inline int save_xstate_epilog ( void __user * buf , int ia32_frame )
{
2015-04-30 17:15:32 +02:00
struct xregs_state __user * x = buf ;
2015-04-30 12:45:38 +02:00
struct _fpx_sw_bytes * sw_bytes ;
u32 xfeatures ;
int err ;
/* Setup the bytes not touched by the [f]xsave and reserved for SW. */
sw_bytes = ia32_frame ? & fx_sw_reserved_ia32 : & fx_sw_reserved ;
err = __copy_to_user ( & x - > i387 . sw_reserved , sw_bytes , sizeof ( * sw_bytes ) ) ;
if ( ! use_xsave ( ) )
return err ;
2016-05-20 10:47:05 -07:00
err | = __put_user ( FP_XSTATE_MAGIC2 ,
( __u32 * ) ( buf + fpu_user_xstate_size ) ) ;
2015-04-30 12:45:38 +02:00
/*
* Read the xfeatures which we copied ( directly from the cpu or
* from the state in task struct ) to the user buffers .
*/
err | = __get_user ( xfeatures , ( __u32 * ) & x - > header . xfeatures ) ;
/*
* For legacy compatible , we always set FP / SSE bits in the bit
* vector while saving the state to the user context . This will
* enable us capturing any changes ( during sigreturn ) to
* the FP / SSE bits by the legacy applications which don ' t touch
* xfeatures in the xsave header .
*
* xsave aware apps can change the xfeatures in the xsave
* header as well as change any contents in the memory layout .
* xrestore as part of sigreturn will capture all the changes .
*/
2015-09-02 16:31:26 -07:00
xfeatures | = XFEATURE_MASK_FPSSE ;
2015-04-30 12:45:38 +02:00
err | = __put_user ( xfeatures , ( __u32 * ) & x - > header . xfeatures ) ;
return err ;
}
2015-04-30 17:15:32 +02:00
static inline int copy_fpregs_to_sigframe ( struct xregs_state __user * buf )
2015-04-30 12:45:38 +02:00
{
int err ;
if ( use_xsave ( ) )
err = copy_xregs_to_user ( buf ) ;
else if ( use_fxsr ( ) )
2015-04-30 17:15:32 +02:00
err = copy_fxregs_to_user ( ( struct fxregs_state __user * ) buf ) ;
2015-04-30 12:45:38 +02:00
else
2015-04-30 17:15:32 +02:00
err = copy_fregs_to_user ( ( struct fregs_state __user * ) buf ) ;
2015-04-30 12:45:38 +02:00
2016-05-20 10:47:05 -07:00
if ( unlikely ( err ) & & __clear_user ( buf , fpu_user_xstate_size ) )
2015-04-30 12:45:38 +02:00
err = - EFAULT ;
return err ;
}
/*
* Save the fpu , extended register state to the user signal frame .
*
* ' buf_fx ' is the 64 - byte aligned pointer at which the [ f | fx | x ] save
* state is copied .
* ' buf ' points to the ' buf_fx ' or to the fsave header followed by ' buf_fx ' .
*
* buf = = buf_fx for 64 - bit frames and 32 - bit fsave frame .
* buf ! = buf_fx for 32 - bit frames with fxstate .
*
* If the fpu , extended register state is live , save the state directly
* to the user frame pointed by the aligned pointer ' buf_fx ' . Otherwise ,
* copy the thread ' s fpu state to the user frame starting at ' buf_fx ' .
*
* If this is a 32 - bit frame with fxstate , put a fsave header before
* the aligned state at ' buf_fx ' .
*
* For [ f ] xsave state , update the SW reserved fields in the [ f ] xsave frame
* indicating the absence / presence of the extended state to the user .
*/
int copy_fpstate_to_sigframe ( void __user * buf , void __user * buf_fx , int size )
{
2015-04-30 17:15:32 +02:00
struct xregs_state * xsave = & current - > thread . fpu . state . xsave ;
2015-04-30 12:45:38 +02:00
struct task_struct * tsk = current ;
int ia32_fxstate = ( buf ! = buf_fx ) ;
ia32_fxstate & = ( config_enabled ( CONFIG_X86_32 ) | |
config_enabled ( CONFIG_IA32_EMULATION ) ) ;
if ( ! access_ok ( VERIFY_WRITE , buf , size ) )
return - EACCES ;
if ( ! static_cpu_has ( X86_FEATURE_FPU ) )
return fpregs_soft_get ( current , NULL , 0 ,
sizeof ( struct user_i387_ia32_struct ) , NULL ,
2015-09-05 09:32:36 +02:00
( struct _fpstate_32 __user * ) buf ) ? - 1 : 1 ;
2015-04-30 12:45:38 +02:00
2016-05-20 10:47:08 -07:00
if ( fpregs_active ( ) | | using_compacted_format ( ) ) {
2015-04-30 12:45:38 +02:00
/* Save the live register state to the user directly. */
if ( copy_fpregs_to_sigframe ( buf_fx ) )
return - 1 ;
/* Update the thread's fxstate to save the fsave header. */
if ( ia32_fxstate )
copy_fxregs_to_kernel ( & tsk - > thread . fpu ) ;
} else {
2016-05-20 10:47:05 -07:00
/*
* It is a * bug * if kernel uses compacted - format for xsave
* area and we copy it out directly to a signal frame . It
* should have been handled above by saving the registers
* directly .
*/
if ( boot_cpu_has ( X86_FEATURE_XSAVES ) ) {
WARN_ONCE ( 1 , " x86/fpu: saving compacted-format xsave area to a signal frame! \n " ) ;
return - 1 ;
}
2015-04-30 12:45:38 +02:00
fpstate_sanitize_xstate ( & tsk - > thread . fpu ) ;
2016-05-20 10:47:05 -07:00
if ( __copy_to_user ( buf_fx , xsave , fpu_user_xstate_size ) )
2015-04-30 12:45:38 +02:00
return - 1 ;
}
/* Save the fsave header for the 32-bit frames. */
if ( ( ia32_fxstate | | ! use_fxsr ( ) ) & & save_fsave_header ( tsk , buf ) )
return - 1 ;
if ( use_fxsr ( ) & & save_xstate_epilog ( buf_fx , ia32_fxstate ) )
return - 1 ;
return 0 ;
}
static inline void
sanitize_restored_xstate ( struct task_struct * tsk ,
struct user_i387_ia32_struct * ia32_env ,
u64 xfeatures , int fx_only )
{
2015-04-30 17:15:32 +02:00
struct xregs_state * xsave = & tsk - > thread . fpu . state . xsave ;
2015-04-30 12:45:38 +02:00
struct xstate_header * header = & xsave - > header ;
if ( use_xsave ( ) ) {
/* These bits must be zero. */
memset ( header - > reserved , 0 , 48 ) ;
/*
* Init the state that is not present in the memory
* layout and not enabled by the OS .
*/
if ( fx_only )
2015-09-02 16:31:26 -07:00
header - > xfeatures = XFEATURE_MASK_FPSSE ;
2015-04-30 12:45:38 +02:00
else
header - > xfeatures & = ( xfeatures_mask & xfeatures ) ;
}
if ( use_fxsr ( ) ) {
/*
* mscsr reserved bits must be masked to zero for security
* reasons .
*/
xsave - > i387 . mxcsr & = mxcsr_feature_mask ;
convert_to_fxsr ( tsk , ia32_env ) ;
}
}
/*
* Restore the extended state if present . Otherwise , restore the FP / SSE state .
*/
static inline int copy_user_to_fpregs_zeroing ( void __user * buf , u64 xbv , int fx_only )
{
if ( use_xsave ( ) ) {
if ( ( unsigned long ) buf % 64 | | fx_only ) {
2015-09-02 16:31:26 -07:00
u64 init_bv = xfeatures_mask & ~ XFEATURE_MASK_FPSSE ;
2015-04-30 12:45:38 +02:00
copy_kernel_to_xregs ( & init_fpstate . xsave , init_bv ) ;
return copy_user_to_fxregs ( buf ) ;
} else {
u64 init_bv = xfeatures_mask & ~ xbv ;
if ( unlikely ( init_bv ) )
copy_kernel_to_xregs ( & init_fpstate . xsave , init_bv ) ;
return copy_user_to_xregs ( buf , xbv ) ;
}
} else if ( use_fxsr ( ) ) {
return copy_user_to_fxregs ( buf ) ;
} else
return copy_user_to_fregs ( buf ) ;
}
static int __fpu__restore_sig ( void __user * buf , void __user * buf_fx , int size )
{
int ia32_fxstate = ( buf ! = buf_fx ) ;
struct task_struct * tsk = current ;
struct fpu * fpu = & tsk - > thread . fpu ;
2016-05-20 10:47:06 -07:00
int state_size = fpu_kernel_xstate_size ;
2015-04-30 12:45:38 +02:00
u64 xfeatures = 0 ;
int fx_only = 0 ;
ia32_fxstate & = ( config_enabled ( CONFIG_X86_32 ) | |
config_enabled ( CONFIG_IA32_EMULATION ) ) ;
if ( ! buf ) {
fpu__clear ( fpu ) ;
return 0 ;
}
if ( ! access_ok ( VERIFY_READ , buf , size ) )
return - EACCES ;
fpu__activate_curr ( fpu ) ;
if ( ! static_cpu_has ( X86_FEATURE_FPU ) )
return fpregs_soft_set ( current , NULL ,
0 , sizeof ( struct user_i387_ia32_struct ) ,
NULL , buf ) ! = 0 ;
if ( use_xsave ( ) ) {
struct _fpx_sw_bytes fx_sw_user ;
if ( unlikely ( check_for_xstate ( buf_fx , buf_fx , & fx_sw_user ) ) ) {
/*
* Couldn ' t find the extended state information in the
* memory layout . Restore just the FP / SSE and init all
* the other extended state .
*/
2015-04-30 17:15:32 +02:00
state_size = sizeof ( struct fxregs_state ) ;
2015-04-30 12:45:38 +02:00
fx_only = 1 ;
2016-06-01 10:42:20 -07:00
trace_x86_fpu_xstate_check_failed ( fpu ) ;
2015-04-30 12:45:38 +02:00
} else {
state_size = fx_sw_user . xstate_size ;
xfeatures = fx_sw_user . xfeatures ;
}
}
if ( ia32_fxstate ) {
/*
* For 32 - bit frames with fxstate , copy the user state to the
* thread ' s fpu state , reconstruct fxstate from the fsave
* header . Sanitize the copied state etc .
*/
struct fpu * fpu = & tsk - > thread . fpu ;
struct user_i387_ia32_struct env ;
int err = 0 ;
/*
* Drop the current fpu which clears fpu - > fpstate_active . This ensures
* that any context - switch during the copy of the new state ,
* avoids the intermediate state from getting restored / saved .
* Thus avoiding the new restored state from getting corrupted .
* We will be ready to restore / save the state only after
* fpu - > fpstate_active is again set .
*/
fpu__drop ( fpu ) ;
2016-07-11 09:18:54 -07:00
if ( using_compacted_format ( ) ) {
err = copyin_to_xsaves ( NULL , buf_fx ,
& fpu - > state . xsave ) ;
} else {
err = __copy_from_user ( & fpu - > state . xsave ,
buf_fx , state_size ) ;
}
if ( err | | __copy_from_user ( & env , buf , sizeof ( env ) ) ) {
2015-04-30 12:45:38 +02:00
fpstate_init ( & fpu - > state ) ;
2016-06-01 10:42:20 -07:00
trace_x86_fpu_init_state ( fpu ) ;
2015-04-30 12:45:38 +02:00
err = - 1 ;
} else {
sanitize_restored_xstate ( tsk , & env , xfeatures , fx_only ) ;
}
fpu - > fpstate_active = 1 ;
if ( use_eager_fpu ( ) ) {
preempt_disable ( ) ;
2015-05-04 11:49:58 +02:00
fpu__restore ( fpu ) ;
2015-04-30 12:45:38 +02:00
preempt_enable ( ) ;
}
return err ;
} else {
/*
* For 64 - bit frames and 32 - bit fsave frames , restore the user
* state to the registers directly ( with exceptions handled ) .
*/
user_fpu_begin ( ) ;
if ( copy_user_to_fpregs_zeroing ( buf_fx , xfeatures , fx_only ) ) {
fpu__clear ( fpu ) ;
return - 1 ;
}
}
return 0 ;
}
static inline int xstate_sigframe_size ( void )
{
2016-05-20 10:47:05 -07:00
return use_xsave ( ) ? fpu_user_xstate_size + FP_XSTATE_MAGIC2_SIZE :
fpu_user_xstate_size ;
2015-04-30 12:45:38 +02:00
}
/*
* Restore FPU state from a sigframe :
*/
int fpu__restore_sig ( void __user * buf , int ia32_frame )
{
void __user * buf_fx = buf ;
int size = xstate_sigframe_size ( ) ;
if ( ia32_frame & & use_fxsr ( ) ) {
2015-04-30 17:15:32 +02:00
buf_fx = buf + sizeof ( struct fregs_state ) ;
size + = sizeof ( struct fregs_state ) ;
2015-04-30 12:45:38 +02:00
}
return __fpu__restore_sig ( buf , buf_fx , size ) ;
}
unsigned long
fpu__alloc_mathframe ( unsigned long sp , int ia32_frame ,
unsigned long * buf_fx , unsigned long * size )
{
unsigned long frame_size = xstate_sigframe_size ( ) ;
* buf_fx = sp = round_down ( sp - frame_size , 64 ) ;
if ( ia32_frame & & use_fxsr ( ) ) {
2015-04-30 17:15:32 +02:00
frame_size + = sizeof ( struct fregs_state ) ;
sp - = sizeof ( struct fregs_state ) ;
2015-04-30 12:45:38 +02:00
}
* size = frame_size ;
return sp ;
}
/*
* Prepare the SW reserved portion of the fxsave memory layout , indicating
* the presence of the extended state information in the memory layout
* pointed by the fpstate pointer in the sigcontext .
* This will be saved when ever the FP and extended state context is
* saved on the user stack during the signal handler delivery to the user .
*/
void fpu__init_prepare_fx_sw_frame ( void )
{
2016-05-20 10:47:05 -07:00
int size = fpu_user_xstate_size + FP_XSTATE_MAGIC2_SIZE ;
2015-04-30 12:45:38 +02:00
fx_sw_reserved . magic1 = FP_XSTATE_MAGIC1 ;
fx_sw_reserved . extended_size = size ;
fx_sw_reserved . xfeatures = xfeatures_mask ;
2016-05-20 10:47:05 -07:00
fx_sw_reserved . xstate_size = fpu_user_xstate_size ;
2015-04-30 12:45:38 +02:00
2015-11-10 16:23:54 -08:00
if ( config_enabled ( CONFIG_IA32_EMULATION ) | |
config_enabled ( CONFIG_X86_32 ) ) {
int fsave_header_size = sizeof ( struct fregs_state ) ;
2015-04-30 12:45:38 +02:00
fx_sw_reserved_ia32 = fx_sw_reserved ;
2015-11-10 16:23:54 -08:00
fx_sw_reserved_ia32 . extended_size = size + fsave_header_size ;
2015-04-30 12:45:38 +02:00
}
}