2005-04-17 02:20:36 +04:00
/*
2007-10-16 12:27:00 +04:00
* Copyright ( C ) 2003 - 2007 Jeff Dike ( jdike @ { addtoit , linux . intel } . com )
2005-04-17 02:20:36 +04:00
* Copyright 2003 PathScale , Inc .
*
* Licensed under the GPL
*/
2012-09-20 17:28:25 +04:00
# include <linux/sched.h>
2017-02-04 02:16:44 +03:00
# include <linux/sched/mm.h>
2017-03-20 11:16:21 +03:00
# include <linux/syscalls.h>
2015-05-12 01:13:05 +03:00
# include <linux/uaccess.h>
2012-09-20 17:28:25 +04:00
# include <asm/prctl.h> /* XXX This should get the constants from libc */
2021-09-21 00:32:50 +03:00
# include <registers.h>
2012-09-20 17:28:25 +04:00
# include <os.h>
2005-04-17 02:20:36 +04:00
2017-03-21 02:05:35 +03:00
long arch_prctl ( struct task_struct * task , int option ,
2017-03-20 11:16:22 +03:00
unsigned long __user * arg2 )
2005-04-17 02:20:36 +04:00
{
2017-03-20 11:16:22 +03:00
unsigned long * ptr = arg2 , tmp ;
2007-02-10 12:44:29 +03:00
long ret ;
2007-10-16 12:27:06 +04:00
int pid = task - > mm - > context . id . u . pid ;
2005-04-17 02:20:36 +04:00
2007-02-10 12:44:29 +03: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 12:44:30 +03: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 12:44:29 +03: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 11:16:20 +03:00
switch ( option ) {
2005-04-17 02:20:36 +04:00
case ARCH_SET_FS :
2005-05-29 02:52:03 +04:00
case ARCH_SET_GS :
2021-09-13 09:12:52 +03:00
ret = restore_pid_registers ( pid , & current - > thread . regs . regs ) ;
2008-02-05 09:30:58 +03:00
if ( ret )
return ret ;
2007-10-16 12:27:00 +04: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 12:44:29 +03:00
2017-03-20 11:16:20 +03:00
ret = os_arch_prctl ( pid , option , ptr ) ;
2007-10-16 12:27:00 +04:00
if ( ret )
return ret ;
2007-02-10 12:44:29 +03:00
2017-03-20 11:16:20 +03:00
switch ( option ) {
2007-02-10 12:44:29 +03:00
case ARCH_SET_FS :
2007-03-08 07:41:26 +03:00
current - > thread . arch . fs = ( unsigned long ) ptr ;
2008-02-05 09:30:58 +03:00
ret = save_registers ( pid , & current - > thread . regs . regs ) ;
2007-03-08 07:41:26 +03:00
break ;
2007-02-10 12:44:29 +03:00
case ARCH_SET_GS :
2008-02-05 09:30:58 +03:00
ret = save_registers ( pid , & current - > thread . regs . regs ) ;
2005-05-29 02:52:03 +04:00
break ;
2005-04-17 02:20:36 +04:00
case ARCH_GET_FS :
2017-03-20 11:16:22 +03:00
ret = put_user ( tmp , arg2 ) ;
2007-10-16 12:27:00 +04:00
break ;
2005-04-17 02:20:36 +04:00
case ARCH_GET_GS :
2017-03-20 11:16:22 +03:00
ret = put_user ( tmp , arg2 ) ;
2007-10-16 12:27:00 +04:00
break ;
2005-04-17 02:20:36 +04:00
}
2007-02-10 12:44:29 +03:00
return ret ;
2005-04-17 02:20:36 +04:00
}
2017-03-20 11:16:22 +03:00
SYSCALL_DEFINE2 ( arch_prctl , int , option , unsigned long , arg2 )
2005-04-17 02:20:36 +04:00
{
2017-03-20 11:16:22 +03:00
return arch_prctl ( current , option , ( unsigned long __user * ) arg2 ) ;
2005-04-17 02:20:36 +04:00
}
2008-02-05 09:30:49 +03:00
void arch_switch_to ( struct task_struct * to )
2007-02-10 12:44:29 +03:00
{
2007-10-16 12:27:00 +04:00
if ( ( to - > thread . arch . fs = = 0 ) | | ( to - > mm = = NULL ) )
return ;
2007-02-10 12:44:29 +03:00
2007-10-16 12:27:00 +04:00
arch_prctl ( to , ARCH_SET_FS , ( void __user * ) to - > thread . arch . fs ) ;
2005-04-17 02:20:36 +04:00
}
2021-09-21 00:32:48 +03:00
SYSCALL_DEFINE6 ( mmap , unsigned long , addr , unsigned long , len ,
unsigned long , prot , unsigned long , flags ,
unsigned long , fd , unsigned long , off )
{
if ( off & ~ PAGE_MASK )
return - EINVAL ;
return ksys_mmap_pgoff ( addr , len , prot , flags , fd , off > > PAGE_SHIFT ) ;
}