2005-04-16 15:20:36 -07:00
/*
* PARISC specific syscalls
*
* Copyright ( C ) 1999 - 2003 Matthew Wilcox < willy at parisc - linux . org >
* Copyright ( C ) 2000 - 2003 Paul Bame < bame at parisc - linux . org >
* Copyright ( C ) 2001 Thomas Bogendoerfer < tsbogend at parisc - linux . org >
*
*
* 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 .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include <asm/uaccess.h>
# include <linux/file.h>
# include <linux/fs.h>
# include <linux/linkage.h>
# include <linux/mm.h>
# include <linux/mman.h>
# include <linux/shm.h>
# include <linux/syscalls.h>
2006-08-27 11:12:13 -04:00
# include <linux/utsname.h>
# include <linux/personality.h>
2005-04-16 15:20:36 -07:00
static unsigned long get_unshared_area ( unsigned long addr , unsigned long len )
{
2013-02-27 17:02:40 -08:00
struct vm_unmapped_area_info info ;
2005-04-16 15:20:36 -07:00
2013-02-27 17:02:40 -08:00
info . flags = 0 ;
info . length = len ;
info . low_limit = PAGE_ALIGN ( addr ) ;
info . high_limit = TASK_SIZE ;
info . align_mask = 0 ;
info . align_offset = 0 ;
return vm_unmapped_area ( & info ) ;
2005-04-16 15:20:36 -07:00
}
/*
* We need to know the offset to use . Old scheme was to look for
* existing mapping and use the same offset . New scheme is to use the
* address of the kernel data structure as the seed for the offset .
* We ' ll see how that works . . .
*
* The mapping is cacheline aligned , so there ' s no information in the bottom
* few bits of the address . We ' re looking for 10 bits ( 4 MB / 4 k ) , so let ' s
* drop the bottom 8 bits and use bits 8 - 17.
*/
static int get_offset ( struct address_space * mapping )
{
2013-02-27 17:02:40 -08:00
return ( unsigned long ) mapping > > 8 ;
2005-04-16 15:20:36 -07:00
}
parisc: fix mmap(MAP_FIXED|MAP_SHARED) to already mmapped address
locale-gen on Debian showed a strange problem on parisc:
mmap2(NULL, 536870912, PROT_NONE, MAP_SHARED, 3, 0) = 0x42a54000
mmap2(0x42a54000, 103860, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, 3, 0) = -1 EINVAL (Invalid argument)
Basically it was just trying to re-mmap() a file at the same address
which it was given by a previous mmap() call. But this remapping failed
with EINVAL.
The problem is, that when MAP_FIXED and MAP_SHARED flags were used, we didn't
included the mapping-based offset when we verified the alignment of the given
fixed address against the offset which we calculated it in the previous call.
Signed-off-by: Helge Deller <deller@gmx.de>
Cc: <stable@vger.kernel.org> # 3.10+
2013-11-20 23:07:42 +01:00
static unsigned long shared_align_offset ( struct file * filp , unsigned long pgoff )
{
struct address_space * mapping = filp ? filp - > f_mapping : NULL ;
return ( get_offset ( mapping ) + pgoff ) < < PAGE_SHIFT ;
}
static unsigned long get_shared_area ( struct file * filp , unsigned long addr ,
unsigned long len , unsigned long pgoff )
2005-04-16 15:20:36 -07:00
{
2013-02-27 17:02:40 -08:00
struct vm_unmapped_area_info info ;
2005-04-16 15:20:36 -07:00
2013-02-27 17:02:40 -08:00
info . flags = 0 ;
info . length = len ;
info . low_limit = PAGE_ALIGN ( addr ) ;
info . high_limit = TASK_SIZE ;
info . align_mask = PAGE_MASK & ( SHMLBA - 1 ) ;
parisc: fix mmap(MAP_FIXED|MAP_SHARED) to already mmapped address
locale-gen on Debian showed a strange problem on parisc:
mmap2(NULL, 536870912, PROT_NONE, MAP_SHARED, 3, 0) = 0x42a54000
mmap2(0x42a54000, 103860, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, 3, 0) = -1 EINVAL (Invalid argument)
Basically it was just trying to re-mmap() a file at the same address
which it was given by a previous mmap() call. But this remapping failed
with EINVAL.
The problem is, that when MAP_FIXED and MAP_SHARED flags were used, we didn't
included the mapping-based offset when we verified the alignment of the given
fixed address against the offset which we calculated it in the previous call.
Signed-off-by: Helge Deller <deller@gmx.de>
Cc: <stable@vger.kernel.org> # 3.10+
2013-11-20 23:07:42 +01:00
info . align_offset = shared_align_offset ( filp , pgoff ) ;
2013-02-27 17:02:40 -08:00
return vm_unmapped_area ( & info ) ;
2005-04-16 15:20:36 -07:00
}
unsigned long arch_get_unmapped_area ( struct file * filp , unsigned long addr ,
unsigned long len , unsigned long pgoff , unsigned long flags )
{
if ( len > TASK_SIZE )
return - ENOMEM ;
2013-02-02 23:44:59 +00:00
if ( flags & MAP_FIXED ) {
if ( ( flags & MAP_SHARED ) & &
parisc: fix mmap(MAP_FIXED|MAP_SHARED) to already mmapped address
locale-gen on Debian showed a strange problem on parisc:
mmap2(NULL, 536870912, PROT_NONE, MAP_SHARED, 3, 0) = 0x42a54000
mmap2(0x42a54000, 103860, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, 3, 0) = -1 EINVAL (Invalid argument)
Basically it was just trying to re-mmap() a file at the same address
which it was given by a previous mmap() call. But this remapping failed
with EINVAL.
The problem is, that when MAP_FIXED and MAP_SHARED flags were used, we didn't
included the mapping-based offset when we verified the alignment of the given
fixed address against the offset which we calculated it in the previous call.
Signed-off-by: Helge Deller <deller@gmx.de>
Cc: <stable@vger.kernel.org> # 3.10+
2013-11-20 23:07:42 +01:00
( addr - shared_align_offset ( filp , pgoff ) ) & ( SHMLBA - 1 ) )
2013-02-02 23:44:59 +00:00
return - EINVAL ;
2007-05-06 14:50:09 -07:00
return addr ;
2013-02-02 23:44:59 +00:00
}
2005-04-16 15:20:36 -07:00
if ( ! addr )
addr = TASK_UNMAPPED_BASE ;
parisc: fix mmap(MAP_FIXED|MAP_SHARED) to already mmapped address
locale-gen on Debian showed a strange problem on parisc:
mmap2(NULL, 536870912, PROT_NONE, MAP_SHARED, 3, 0) = 0x42a54000
mmap2(0x42a54000, 103860, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, 3, 0) = -1 EINVAL (Invalid argument)
Basically it was just trying to re-mmap() a file at the same address
which it was given by a previous mmap() call. But this remapping failed
with EINVAL.
The problem is, that when MAP_FIXED and MAP_SHARED flags were used, we didn't
included the mapping-based offset when we verified the alignment of the given
fixed address against the offset which we calculated it in the previous call.
Signed-off-by: Helge Deller <deller@gmx.de>
Cc: <stable@vger.kernel.org> # 3.10+
2013-11-20 23:07:42 +01:00
if ( filp | | ( flags & MAP_SHARED ) )
addr = get_shared_area ( filp , addr , len , pgoff ) ;
else
2005-04-16 15:20:36 -07:00
addr = get_unshared_area ( addr , len ) ;
parisc: fix mmap(MAP_FIXED|MAP_SHARED) to already mmapped address
locale-gen on Debian showed a strange problem on parisc:
mmap2(NULL, 536870912, PROT_NONE, MAP_SHARED, 3, 0) = 0x42a54000
mmap2(0x42a54000, 103860, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, 3, 0) = -1 EINVAL (Invalid argument)
Basically it was just trying to re-mmap() a file at the same address
which it was given by a previous mmap() call. But this remapping failed
with EINVAL.
The problem is, that when MAP_FIXED and MAP_SHARED flags were used, we didn't
included the mapping-based offset when we verified the alignment of the given
fixed address against the offset which we calculated it in the previous call.
Signed-off-by: Helge Deller <deller@gmx.de>
Cc: <stable@vger.kernel.org> # 3.10+
2013-11-20 23:07:42 +01:00
2005-04-16 15:20:36 -07:00
return addr ;
}
asmlinkage unsigned long sys_mmap2 ( unsigned long addr , unsigned long len ,
unsigned long prot , unsigned long flags , unsigned long fd ,
unsigned long pgoff )
{
/* Make sure the shift for mmap2 is constant (12), no matter what PAGE_SIZE
we have . */
2009-11-30 17:37:04 -05:00
return sys_mmap_pgoff ( addr , len , prot , flags , fd ,
pgoff > > ( PAGE_SHIFT - 12 ) ) ;
2005-04-16 15:20:36 -07:00
}
asmlinkage unsigned long sys_mmap ( unsigned long addr , unsigned long len ,
unsigned long prot , unsigned long flags , unsigned long fd ,
unsigned long offset )
{
if ( ! ( offset & ~ PAGE_MASK ) ) {
2009-11-30 17:37:04 -05:00
return sys_mmap_pgoff ( addr , len , prot , flags , fd ,
offset > > PAGE_SHIFT ) ;
2005-04-16 15:20:36 -07:00
} else {
return - EINVAL ;
}
}
/* Fucking broken ABI */
# ifdef CONFIG_64BIT
asmlinkage long parisc_truncate64 ( const char __user * path ,
unsigned int high , unsigned int low )
{
return sys_truncate ( path , ( long ) high < < 32 | low ) ;
}
asmlinkage long parisc_ftruncate64 ( unsigned int fd ,
unsigned int high , unsigned int low )
{
return sys_ftruncate ( fd , ( long ) high < < 32 | low ) ;
}
/* stubs for the benefit of the syscall_table since truncate64 and truncate
* are identical on LP64 */
asmlinkage long sys_truncate64 ( const char __user * path , unsigned long length )
{
return sys_truncate ( path , length ) ;
}
asmlinkage long sys_ftruncate64 ( unsigned int fd , unsigned long length )
{
return sys_ftruncate ( fd , length ) ;
}
asmlinkage long sys_fcntl64 ( unsigned int fd , unsigned int cmd , unsigned long arg )
{
return sys_fcntl ( fd , cmd , arg ) ;
}
# else
asmlinkage long parisc_truncate64 ( const char __user * path ,
unsigned int high , unsigned int low )
{
return sys_truncate64 ( path , ( loff_t ) high < < 32 | low ) ;
}
asmlinkage long parisc_ftruncate64 ( unsigned int fd ,
unsigned int high , unsigned int low )
{
return sys_ftruncate64 ( fd , ( loff_t ) high < < 32 | low ) ;
}
# endif
asmlinkage ssize_t parisc_pread64 ( unsigned int fd , char __user * buf , size_t count ,
unsigned int high , unsigned int low )
{
return sys_pread64 ( fd , buf , count , ( loff_t ) high < < 32 | low ) ;
}
asmlinkage ssize_t parisc_pwrite64 ( unsigned int fd , const char __user * buf ,
size_t count , unsigned int high , unsigned int low )
{
return sys_pwrite64 ( fd , buf , count , ( loff_t ) high < < 32 | low ) ;
}
asmlinkage ssize_t parisc_readahead ( int fd , unsigned int high , unsigned int low ,
size_t count )
{
return sys_readahead ( fd , ( loff_t ) high < < 32 | low , count ) ;
}
asmlinkage long parisc_fadvise64_64 ( int fd ,
unsigned int high_off , unsigned int low_off ,
unsigned int high_len , unsigned int low_len , int advice )
{
return sys_fadvise64_64 ( fd , ( loff_t ) high_off < < 32 | low_off ,
( loff_t ) high_len < < 32 | low_len , advice ) ;
}
2006-04-20 04:44:07 +00:00
asmlinkage long parisc_sync_file_range ( int fd ,
u32 hi_off , u32 lo_off , u32 hi_nbytes , u32 lo_nbytes ,
unsigned int flags )
{
return sys_sync_file_range ( fd , ( loff_t ) hi_off < < 32 | lo_off ,
( loff_t ) hi_nbytes < < 32 | lo_nbytes , flags ) ;
}
2013-02-19 21:23:59 +01:00
asmlinkage long parisc_fallocate ( int fd , int mode , u32 offhi , u32 offlo ,
u32 lenhi , u32 lenlo )
{
return sys_fallocate ( fd , mode , ( ( u64 ) offhi < < 32 ) | offlo ,
( ( u64 ) lenhi < < 32 ) | lenlo ) ;
}
2005-04-16 15:20:36 -07:00
asmlinkage unsigned long sys_alloc_hugepages ( int key , unsigned long addr , unsigned long len , int prot , int flag )
{
return - ENOMEM ;
}
asmlinkage int sys_free_hugepages ( unsigned long addr )
{
return - EINVAL ;
}
2006-08-27 11:12:13 -04:00
long parisc_personality ( unsigned long personality )
{
long err ;
if ( personality ( current - > personality ) = = PER_LINUX32
2012-08-02 15:33:59 +02:00
& & personality ( personality ) = = PER_LINUX )
personality = ( personality & ~ PER_MASK ) | PER_LINUX32 ;
2006-08-27 11:12:13 -04:00
err = sys_personality ( personality ) ;
2012-08-02 15:33:59 +02:00
if ( personality ( err ) = = PER_LINUX32 )
err = ( err & ~ PER_MASK ) | PER_LINUX ;
2006-08-27 11:12:13 -04:00
return err ;
}