2005-04-17 02:20:36 +04:00
/*
* linux / arch / sh / kernel / sys_sh . c
*
* This file contains various random system calls that
* have a non - standard calling sequence on the Linux / SuperH
* platform .
*
* Taken from i386 version .
*/
# include <linux/errno.h>
# include <linux/sched.h>
# include <linux/mm.h>
# include <linux/smp.h>
# include <linux/sem.h>
# include <linux/msg.h>
# include <linux/shm.h>
# include <linux/stat.h>
# include <linux/syscalls.h>
# include <linux/mman.h>
# include <linux/file.h>
# include <linux/utsname.h>
2006-09-27 13:36:17 +04:00
# include <linux/module.h>
2007-07-31 08:01:43 +04:00
# include <linux/fs.h>
2007-10-17 10:29:24 +04:00
# include <linux/ipc.h>
2008-09-04 13:53:58 +04:00
# include <asm/syscalls.h>
2005-04-17 02:20:36 +04:00
# include <asm/uaccess.h>
2006-10-02 13:18:34 +04:00
# include <asm/unistd.h>
2009-08-24 13:16:56 +04:00
# include <asm/cacheflush.h>
# include <asm/cachectl.h>
2005-04-17 02:20:36 +04:00
static inline long
2007-11-20 09:50:59 +03:00
do_mmap2 ( unsigned long addr , unsigned long len , unsigned long prot ,
2005-04-17 02:20:36 +04:00
unsigned long flags , int fd , unsigned long pgoff )
{
int error = - EBADF ;
struct file * file = NULL ;
flags & = ~ ( MAP_EXECUTABLE | MAP_DENYWRITE ) ;
if ( ! ( flags & MAP_ANONYMOUS ) ) {
file = fget ( fd ) ;
if ( ! file )
goto out ;
}
down_write ( & current - > mm - > mmap_sem ) ;
error = do_mmap_pgoff ( file , addr , len , prot , flags , pgoff ) ;
up_write ( & current - > mm - > mmap_sem ) ;
if ( file )
fput ( file ) ;
out :
return error ;
}
asmlinkage int old_mmap ( unsigned long addr , unsigned long len ,
unsigned long prot , unsigned long flags ,
int fd , unsigned long off )
{
if ( off & ~ PAGE_MASK )
return - EINVAL ;
return do_mmap2 ( addr , len , prot , flags , fd , off > > PAGE_SHIFT ) ;
}
asmlinkage long sys_mmap2 ( unsigned long addr , unsigned long len ,
unsigned long prot , unsigned long flags ,
unsigned long fd , unsigned long pgoff )
{
2009-04-21 02:34:53 +04:00
/*
* The shift for mmap2 is constant , regardless of PAGE_SIZE
* setting .
*/
if ( pgoff & ( ( 1 < < ( PAGE_SHIFT - 12 ) ) - 1 ) )
return - EINVAL ;
pgoff > > = PAGE_SHIFT - 12 ;
2005-04-17 02:20:36 +04:00
return do_mmap2 ( addr , len , prot , flags , fd , pgoff ) ;
}
/*
* sys_ipc ( ) is the de - multiplexer for the SysV IPC calls . .
*
* This is really horribly ugly .
*/
asmlinkage int sys_ipc ( uint call , int first , int second ,
int third , void __user * ptr , long fifth )
{
int version , ret ;
version = call > > 16 ; /* hack for backward compatibility */
call & = 0xffff ;
2008-08-27 15:16:46 +04:00
if ( call < = SEMTIMEDOP )
2005-04-17 02:20:36 +04:00
switch ( call ) {
case SEMOP :
2007-11-20 09:50:59 +03:00
return sys_semtimedop ( first ,
( struct sembuf __user * ) ptr ,
2005-04-17 02:20:36 +04:00
second , NULL ) ;
case SEMTIMEDOP :
2007-11-20 09:50:59 +03:00
return sys_semtimedop ( first ,
( struct sembuf __user * ) ptr , second ,
( const struct timespec __user * ) fifth ) ;
2005-04-17 02:20:36 +04:00
case SEMGET :
return sys_semget ( first , second , third ) ;
case SEMCTL : {
union semun fourth ;
if ( ! ptr )
return - EINVAL ;
2008-09-04 13:53:58 +04:00
if ( get_user ( fourth . __pad , ( void __user * __user * ) ptr ) )
2005-04-17 02:20:36 +04:00
return - EFAULT ;
return sys_semctl ( first , second , third , fourth ) ;
}
default :
return - EINVAL ;
}
2007-11-20 09:50:59 +03:00
if ( call < = MSGCTL )
2005-04-17 02:20:36 +04:00
switch ( call ) {
case MSGSND :
2007-11-20 09:50:59 +03:00
return sys_msgsnd ( first , ( struct msgbuf __user * ) ptr ,
2005-04-17 02:20:36 +04:00
second , third ) ;
case MSGRCV :
switch ( version ) {
2007-11-20 09:50:59 +03:00
case 0 :
{
2005-04-17 02:20:36 +04:00
struct ipc_kludge tmp ;
2007-11-20 09:50:59 +03:00
2005-04-17 02:20:36 +04:00
if ( ! ptr )
return - EINVAL ;
2007-11-20 09:50:59 +03:00
2005-04-17 02:20:36 +04:00
if ( copy_from_user ( & tmp ,
2007-11-20 09:50:59 +03:00
( struct ipc_kludge __user * ) ptr ,
2005-04-17 02:20:36 +04:00
sizeof ( tmp ) ) )
return - EFAULT ;
2007-11-20 09:50:59 +03:00
2005-04-17 02:20:36 +04:00
return sys_msgrcv ( first , tmp . msgp , second ,
tmp . msgtyp , third ) ;
2007-11-20 09:50:59 +03:00
}
2005-04-17 02:20:36 +04:00
default :
return sys_msgrcv ( first ,
( struct msgbuf __user * ) ptr ,
second , fifth , third ) ;
}
case MSGGET :
return sys_msgget ( ( key_t ) first , second ) ;
case MSGCTL :
return sys_msgctl ( first , second ,
( struct msqid_ds __user * ) ptr ) ;
default :
return - EINVAL ;
}
2007-11-20 09:50:59 +03:00
if ( call < = SHMCTL )
2005-04-17 02:20:36 +04:00
switch ( call ) {
case SHMAT :
switch ( version ) {
default : {
ulong raddr ;
ret = do_shmat ( first , ( char __user * ) ptr ,
second , & raddr ) ;
if ( ret )
return ret ;
return put_user ( raddr , ( ulong __user * ) third ) ;
}
case 1 : /* iBCS2 emulator entry point */
if ( ! segment_eq ( get_fs ( ) , get_ds ( ) ) )
return - EINVAL ;
return do_shmat ( first , ( char __user * ) ptr ,
second , ( ulong * ) third ) ;
}
2007-11-20 09:50:59 +03:00
case SHMDT :
2005-04-17 02:20:36 +04:00
return sys_shmdt ( ( char __user * ) ptr ) ;
case SHMGET :
return sys_shmget ( first , second , third ) ;
case SHMCTL :
return sys_shmctl ( first , second ,
( struct shmid_ds __user * ) ptr ) ;
default :
return - EINVAL ;
}
2007-11-20 09:50:59 +03:00
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
2009-08-24 13:16:56 +04:00
/* sys_cacheflush -- flush (part of) the processor cache. */
asmlinkage int sys_cacheflush ( unsigned long addr , unsigned long len , int op )
{
struct vm_area_struct * vma ;
2009-08-24 13:59:09 +04:00
if ( ( op < = 0 ) | | ( op > ( CACHEFLUSH_D_PURGE | CACHEFLUSH_I ) ) )
2009-08-24 13:16:56 +04:00
return - EINVAL ;
/*
* Verify that the specified address region actually belongs
* to this process .
*/
if ( addr + len < addr )
return - EFAULT ;
down_read ( & current - > mm - > mmap_sem ) ;
vma = find_vma ( current - > mm , addr ) ;
if ( vma = = NULL | | addr < vma - > vm_start | | addr + len > vma - > vm_end ) {
up_read ( & current - > mm - > mmap_sem ) ;
return - EFAULT ;
}
switch ( op & CACHEFLUSH_D_PURGE ) {
case CACHEFLUSH_D_INVAL :
__flush_invalidate_region ( ( void * ) addr , len ) ;
break ;
case CACHEFLUSH_D_WB :
__flush_wback_region ( ( void * ) addr , len ) ;
break ;
case CACHEFLUSH_D_PURGE :
__flush_purge_region ( ( void * ) addr , len ) ;
break ;
}
if ( op & CACHEFLUSH_I )
flush_cache_all ( ) ;
up_read ( & current - > mm - > mmap_sem ) ;
return 0 ;
}
2008-09-04 13:53:58 +04:00
asmlinkage int sys_uname ( struct old_utsname __user * name )
2005-04-17 02:20:36 +04:00
{
int err ;
if ( ! name )
return - EFAULT ;
down_read ( & uts_sem ) ;
2008-09-04 13:53:58 +04:00
err = copy_to_user ( name , utsname ( ) , sizeof ( * name ) ) ;
2005-04-17 02:20:36 +04:00
up_read ( & uts_sem ) ;
return err ? - EFAULT : 0 ;
}