2005-04-16 15:20:36 -07:00
/*
2007-10-16 01:27:00 -07:00
* Copyright ( C ) 2003 - 2007 Jeff Dike ( jdike @ { addtoit , linux . intel } . com )
2005-04-16 15:20:36 -07:00
* Copyright 2003 PathScale , Inc .
*
* Licensed under the GPL
*/
2012-09-20 09:28:25 -04:00
# include <linux/sched.h>
2017-02-04 00:16:44 +01:00
# include <linux/sched/mm.h>
2017-03-20 01:16:21 -07:00
# include <linux/syscalls.h>
2015-05-12 00:13:05 +02:00
# include <linux/uaccess.h>
2012-09-20 09:28:25 -04:00
# include <asm/prctl.h> /* XXX This should get the constants from libc */
# include <os.h>
2005-04-16 15:20:36 -07:00
2017-03-20 16:05:35 -07:00
long arch_prctl ( struct task_struct * task , int option ,
2017-03-20 01:16:22 -07:00
unsigned long __user * arg2 )
2005-04-16 15:20:36 -07:00
{
2017-03-20 01:16:22 -07:00
unsigned long * ptr = arg2 , tmp ;
2007-02-10 01:44:29 -08:00
long ret ;
2007-10-16 01:27:06 -07:00
int pid = task - > mm - > context . id . u . pid ;
2005-04-16 15:20:36 -07:00
2007-02-10 01:44:29 -08:00
/*
* With ARCH_SET_FS ( and ARCH_SET_GS is treated similarly to
* be safe ) , we need to call arch_prctl on the host because
* setting % fs may result in something else happening ( like a
2007-02-10 01:44:30 -08:00
* GDT or thread . fs being set instead ) . So , we let the host
* fiddle the registers and thread struct and restore the
* registers afterwards .
2007-02-10 01:44:29 -08:00
*
* So , the saved registers are stored to the process ( this
* needed because a stub may have been the last thing to run ) ,
* arch_prctl is run on the host , then the registers are read
* back .
*/
2017-03-20 01:16:20 -07:00
switch ( option ) {
2005-04-16 15:20:36 -07:00
case ARCH_SET_FS :
2005-05-28 15:52:03 -07:00
case ARCH_SET_GS :
2008-02-04 22:30:58 -08:00
ret = restore_registers ( pid , & current - > thread . regs . regs ) ;
if ( ret )
return ret ;
2007-10-16 01:27:00 -07:00
break ;
case ARCH_GET_FS :
case ARCH_GET_GS :
/*
* With these two , we read to a local pointer and
* put_user it to the userspace pointer that we were
* given . If addr isn ' t valid ( because it hasn ' t been
* faulted in or is just bogus ) , we want put_user to
* fault it in ( or return - EFAULT ) instead of having
* the host return - EFAULT .
*/
ptr = & tmp ;
}
2007-02-10 01:44:29 -08:00
2017-03-20 01:16:20 -07:00
ret = os_arch_prctl ( pid , option , ptr ) ;
2007-10-16 01:27:00 -07:00
if ( ret )
return ret ;
2007-02-10 01:44:29 -08:00
2017-03-20 01:16:20 -07:00
switch ( option ) {
2007-02-10 01:44:29 -08:00
case ARCH_SET_FS :
2007-03-07 20:41:26 -08:00
current - > thread . arch . fs = ( unsigned long ) ptr ;
2008-02-04 22:30:58 -08:00
ret = save_registers ( pid , & current - > thread . regs . regs ) ;
2007-03-07 20:41:26 -08:00
break ;
2007-02-10 01:44:29 -08:00
case ARCH_SET_GS :
2008-02-04 22:30:58 -08:00
ret = save_registers ( pid , & current - > thread . regs . regs ) ;
2005-05-28 15:52:03 -07:00
break ;
2005-04-16 15:20:36 -07:00
case ARCH_GET_FS :
2017-03-20 01:16:22 -07:00
ret = put_user ( tmp , arg2 ) ;
2007-10-16 01:27:00 -07:00
break ;
2005-04-16 15:20:36 -07:00
case ARCH_GET_GS :
2017-03-20 01:16:22 -07:00
ret = put_user ( tmp , arg2 ) ;
2007-10-16 01:27:00 -07:00
break ;
2005-04-16 15:20:36 -07:00
}
2007-02-10 01:44:29 -08:00
return ret ;
2005-04-16 15:20:36 -07:00
}
2017-03-20 01:16:22 -07:00
SYSCALL_DEFINE2 ( arch_prctl , int , option , unsigned long , arg2 )
2005-04-16 15:20:36 -07:00
{
2017-03-20 01:16:22 -07:00
return arch_prctl ( current , option , ( unsigned long __user * ) arg2 ) ;
2005-04-16 15:20:36 -07:00
}
2008-02-04 22:30:49 -08:00
void arch_switch_to ( struct task_struct * to )
2007-02-10 01:44:29 -08:00
{
2007-10-16 01:27:00 -07:00
if ( ( to - > thread . arch . fs = = 0 ) | | ( to - > mm = = NULL ) )
return ;
2007-02-10 01:44:29 -08:00
2007-10-16 01:27:00 -07:00
arch_prctl ( to , ARCH_SET_FS , ( void __user * ) to - > thread . arch . fs ) ;
2005-04-16 15:20:36 -07:00
}