2005-04-17 02:20:36 +04:00
/*
* This file contains various system calls that have different calling
* conventions on different platforms .
*
* Copyright ( C ) 1999 - 2000 , 2002 - 2003 , 2005 Hewlett - Packard Co
* David Mosberger - Tang < davidm @ hpl . hp . com >
*/
# include <linux/errno.h>
# include <linux/fs.h>
# include <linux/mm.h>
# include <linux/mman.h>
# include <linux/sched.h>
# include <linux/shm.h>
# include <linux/file.h> /* doh, must come after sched.h... */
# include <linux/smp.h>
# include <linux/syscalls.h>
# include <linux/highuid.h>
# include <linux/hugetlb.h>
# include <asm/shmparam.h>
# include <asm/uaccess.h>
unsigned long
arch_get_unmapped_area ( struct file * filp , unsigned long addr , unsigned long len ,
unsigned long pgoff , unsigned long flags )
{
long map_shared = ( flags & MAP_SHARED ) ;
unsigned long start_addr , align_mask = PAGE_SIZE - 1 ;
struct mm_struct * mm = current - > mm ;
struct vm_area_struct * vma ;
if ( len > RGN_MAP_LIMIT )
return - ENOMEM ;
2007-05-07 01:50:09 +04:00
/* handle fixed mapping: prevent overlap with huge pages */
if ( flags & MAP_FIXED ) {
if ( is_hugepage_only_range ( mm , addr , len ) )
return - EINVAL ;
return addr ;
}
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_HUGETLB_PAGE
2005-08-17 06:54:00 +04:00
if ( REGION_NUMBER ( addr ) = = RGN_HPAGE )
2005-04-17 02:20:36 +04:00
addr = 0 ;
# endif
if ( ! addr )
addr = mm - > free_area_cache ;
if ( map_shared & & ( TASK_SIZE > 0xfffffffful ) )
/*
* For 64 - bit tasks , align shared segments to 1 MB to avoid potential
* performance penalty due to virtual aliasing ( see ASDM ) . For 32 - bit
* tasks , we prefer to avoid exhausting the address space too quickly by
* limiting alignment to a single page .
*/
align_mask = SHMLBA - 1 ;
full_search :
start_addr = addr = ( addr + align_mask ) & ~ align_mask ;
for ( vma = find_vma ( mm , addr ) ; ; vma = vma - > vm_next ) {
/* At this point: (!vma || addr < vma->vm_end). */
if ( TASK_SIZE - len < addr | | RGN_MAP_LIMIT - len < REGION_OFFSET ( addr ) ) {
if ( start_addr ! = TASK_UNMAPPED_BASE ) {
/* Start a new search --- just in case we missed some holes. */
addr = TASK_UNMAPPED_BASE ;
goto full_search ;
}
return - ENOMEM ;
}
if ( ! vma | | addr + len < = vma - > vm_start ) {
/* Remember the address where we stopped this search: */
mm - > free_area_cache = addr + len ;
return addr ;
}
addr = ( vma - > vm_end + align_mask ) & ~ align_mask ;
}
}
asmlinkage long
ia64_getpriority ( int which , int who )
{
long prio ;
prio = sys_getpriority ( which , who ) ;
if ( prio > = 0 ) {
force_successful_syscall_return ( ) ;
prio = 20 - prio ;
}
return prio ;
}
/* XXX obsolete, but leave it here until the old libc is gone... */
asmlinkage unsigned long
sys_getpagesize ( void )
{
return PAGE_SIZE ;
}
asmlinkage unsigned long
ia64_brk ( unsigned long brk )
{
2009-12-04 03:59:24 +03:00
unsigned long retval = sys_brk ( brk ) ;
2005-04-17 02:20:36 +04:00
force_successful_syscall_return ( ) ;
return retval ;
}
/*
* On IA - 64 , we return the two file descriptors in ret0 and ret1 ( r8
* and r9 ) as this is faster than doing a copy_to_user ( ) .
*/
asmlinkage long
2009-01-14 16:13:56 +03:00
sys_ia64_pipe ( void )
2005-04-17 02:20:36 +04:00
{
2006-01-12 12:06:06 +03:00
struct pt_regs * regs = task_pt_regs ( current ) ;
2005-04-17 02:20:36 +04:00
int fd [ 2 ] ;
int retval ;
2008-07-24 08:29:30 +04:00
retval = do_pipe_flags ( fd , 0 ) ;
2005-04-17 02:20:36 +04:00
if ( retval )
goto out ;
retval = fd [ 0 ] ;
regs - > r9 = fd [ 1 ] ;
out :
return retval ;
}
2006-09-07 14:17:04 +04:00
int ia64_mmap_check ( unsigned long addr , unsigned long len ,
unsigned long flags )
{
unsigned long roff ;
/*
* Don ' t permit mappings into unmapped space , the virtual page table
* of a region , or across a region boundary . Note : RGN_MAP_LIMIT is
* equal to 2 ^ n - PAGE_SIZE ( for some integer n < = 61 ) and len > 0.
*/
roff = REGION_OFFSET ( addr ) ;
if ( ( len > RGN_MAP_LIMIT ) | | ( roff > ( RGN_MAP_LIMIT - len ) ) )
return - EINVAL ;
return 0 ;
}
2005-04-17 02:20:36 +04:00
/*
* mmap2 ( ) is like mmap ( ) except that the offset is expressed in units
* of PAGE_SIZE ( instead of bytes ) . This allows to mmap2 ( ) ( pieces
* of ) files that are larger than the address space of the CPU .
*/
asmlinkage unsigned long
sys_mmap2 ( unsigned long addr , unsigned long len , int prot , int flags , int fd , long pgoff )
{
2009-12-01 01:37:04 +03:00
addr = sys_mmap_pgoff ( addr , len , prot , flags , fd , pgoff ) ;
2005-04-17 02:20:36 +04:00
if ( ! IS_ERR ( ( void * ) addr ) )
force_successful_syscall_return ( ) ;
return addr ;
}
asmlinkage unsigned long
sys_mmap ( unsigned long addr , unsigned long len , int prot , int flags , int fd , long off )
{
if ( offset_in_page ( off ) ! = 0 )
return - EINVAL ;
2009-12-01 01:37:04 +03:00
addr = sys_mmap_pgoff ( addr , len , prot , flags , fd , off > > PAGE_SHIFT ) ;
2005-04-17 02:20:36 +04:00
if ( ! IS_ERR ( ( void * ) addr ) )
force_successful_syscall_return ( ) ;
return addr ;
}
asmlinkage unsigned long
ia64_mremap ( unsigned long addr , unsigned long old_len , unsigned long new_len , unsigned long flags ,
unsigned long new_addr )
{
extern unsigned long do_mremap ( unsigned long addr ,
unsigned long old_len ,
unsigned long new_len ,
unsigned long flags ,
unsigned long new_addr ) ;
down_write ( & current - > mm - > mmap_sem ) ;
{
addr = do_mremap ( addr , old_len , new_len , flags , new_addr ) ;
}
up_write ( & current - > mm - > mmap_sem ) ;
if ( IS_ERR ( ( void * ) addr ) )
return addr ;
force_successful_syscall_return ( ) ;
return addr ;
}
# ifndef CONFIG_PCI
asmlinkage long
sys_pciconfig_read ( unsigned long bus , unsigned long dfn , unsigned long off , unsigned long len ,
void * buf )
{
return - ENOSYS ;
}
asmlinkage long
sys_pciconfig_write ( unsigned long bus , unsigned long dfn , unsigned long off , unsigned long len ,
void * buf )
{
return - ENOSYS ;
}
# endif /* CONFIG_PCI */