2005-04-17 02:20:36 +04:00
/*
2005-10-17 14:10:13 +04:00
* Implementation of various system calls for Linux / PowerPC
2005-04-17 02:20:36 +04:00
*
* Copyright ( C ) 1995 - 1996 Gary Thomas ( gdt @ linuxppc . org )
*
* Derived from " arch/i386/kernel/sys_i386.c "
* Adapted from the i386 version by Gary Thomas
* Modified by Cort Dougan ( cort @ cs . nmt . edu )
* and Paul Mackerras ( paulus @ cs . anu . edu . au ) .
*
* This file contains various random system calls that
* have a non - standard calling sequence on the Linux / PPC
* platform .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*
*/
# include <linux/errno.h>
# include <linux/sched.h>
# include <linux/syscalls.h>
# include <linux/mm.h>
2007-07-30 02:36:13 +04:00
# include <linux/fs.h>
2005-04-17 02:20:36 +04:00
# include <linux/smp.h>
# include <linux/sem.h>
# include <linux/msg.h>
# include <linux/shm.h>
# include <linux/stat.h>
# include <linux/mman.h>
# include <linux/sys.h>
# include <linux/ipc.h>
# include <linux/utsname.h>
# include <linux/file.h>
# include <linux/personality.h>
# include <asm/uaccess.h>
2006-03-23 02:00:08 +03:00
# include <asm/syscalls.h>
2005-04-17 02:20:36 +04:00
# include <asm/time.h>
# include <asm/unistd.h>
2005-10-17 14:10:13 +04:00
static inline unsigned long do_mmap2 ( unsigned long addr , size_t len ,
unsigned long prot , unsigned long flags ,
unsigned long fd , unsigned long off , int shift )
2005-04-17 02:20:36 +04:00
{
2005-10-21 10:01:34 +04:00
unsigned long ret = - EINVAL ;
2005-04-17 02:20:36 +04:00
2008-07-07 18:28:54 +04:00
if ( ! arch_validate_prot ( prot ) )
goto out ;
2005-10-17 14:10:13 +04:00
if ( shift ) {
if ( off & ( ( 1 < < shift ) - 1 ) )
goto out ;
off > > = shift ;
}
2009-12-01 01:37:04 +03:00
ret = sys_mmap_pgoff ( addr , len , prot , flags , fd , off ) ;
2005-04-17 02:20:36 +04:00
out :
return ret ;
}
2005-10-17 14:10:13 +04:00
unsigned long sys_mmap2 ( unsigned long addr , size_t len ,
unsigned long prot , unsigned long flags ,
unsigned long fd , unsigned long pgoff )
{
return do_mmap2 ( addr , len , prot , flags , fd , pgoff , PAGE_SHIFT - 12 ) ;
}
unsigned long sys_mmap ( unsigned long addr , size_t len ,
unsigned long prot , unsigned long flags ,
unsigned long fd , off_t offset )
{
return do_mmap2 ( addr , len , prot , flags , fd , offset , PAGE_SHIFT ) ;
}
# ifdef CONFIG_PPC32
/*
* Due to some executables calling the wrong select we sometimes
* get wrong args . This determines how the args are being passed
* ( a single ptr to them all args passed ) then calls
* sys_select ( ) with the appropriate args . - - Cort
*/
int
ppc_select ( int n , fd_set __user * inp , fd_set __user * outp , fd_set __user * exp , struct timeval __user * tvp )
{
if ( ( unsigned long ) n > = 4096 )
{
unsigned long __user * buffer = ( unsigned long __user * ) n ;
if ( ! access_ok ( VERIFY_READ , buffer , 5 * sizeof ( unsigned long ) )
| | __get_user ( n , buffer )
| | __get_user ( inp , ( ( fd_set __user * __user * ) ( buffer + 1 ) ) )
| | __get_user ( outp , ( ( fd_set __user * __user * ) ( buffer + 2 ) ) )
| | __get_user ( exp , ( ( fd_set __user * __user * ) ( buffer + 3 ) ) )
| | __get_user ( tvp , ( ( struct timeval __user * __user * ) ( buffer + 4 ) ) ) )
return - EFAULT ;
}
return sys_select ( n , inp , outp , exp , tvp ) ;
}
# endif
# ifdef CONFIG_PPC64
2005-06-08 15:59:15 +04:00
long ppc64_personality ( unsigned long personality )
2005-04-17 02:20:36 +04:00
{
2005-06-08 15:59:15 +04:00
long ret ;
if ( personality ( current - > personality ) = = PER_LINUX32
2012-08-13 07:18:28 +04:00
& & personality ( personality ) = = PER_LINUX )
personality = ( personality & ~ PER_MASK ) | PER_LINUX32 ;
2005-06-08 15:59:15 +04:00
ret = sys_personality ( personality ) ;
2012-08-13 07:18:28 +04:00
if ( personality ( ret ) = = PER_LINUX32 )
ret = ( ret & ~ PER_MASK ) | PER_LINUX ;
2005-06-08 15:59:15 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
2005-10-17 14:10:13 +04:00
# endif
2005-10-18 08:19:41 +04:00
long ppc_fadvise64_64 ( int fd , int advice , u32 offset_high , u32 offset_low ,
u32 len_high , u32 len_low )
{
return sys_fadvise64 ( fd , ( u64 ) offset_high < < 32 | offset_low ,
( u64 ) len_high < < 32 | len_low , advice ) ;
}
powerpc: Add a proper syscall for switching endianness
We currently have a "special" syscall for switching endianness. This is
syscall number 0x1ebe, which is handled explicitly in the 64-bit syscall
exception entry.
That has a few problems, firstly the syscall number is outside of the
usual range, which confuses various tools. For example strace doesn't
recognise the syscall at all.
Secondly it's handled explicitly as a special case in the syscall
exception entry, which is complicated enough without it.
As a first step toward removing the special syscall, we need to add a
regular syscall that implements the same functionality.
The logic is simple, it simply toggles the MSR_LE bit in the userspace
MSR. This is the same as the special syscall, with the caveat that the
special syscall clobbers fewer registers.
This version clobbers r9-r12, XER, CTR, and CR0-1,5-7.
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
2015-03-28 13:35:16 +03:00
long sys_switch_endian ( void )
{
struct thread_info * ti ;
current - > thread . regs - > msr ^ = MSR_LE ;
/*
* Set TIF_RESTOREALL so that r3 isn ' t clobbered on return to
* userspace . That also has the effect of restoring the non - volatile
* GPRs , so we saved them on the way in here .
*/
ti = current_thread_info ( ) ;
ti - > flags | = _TIF_RESTOREALL ;
return 0 ;
}