diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-02-24 00:12:35 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-02-24 00:12:35 +0000 |
commit | 482368b1a8e45430672c58c9a42e7d2004367126 (patch) | |
tree | ce2a1a567d4d62dee7c2e71a46a99cf72cf1d606 /arch/sparc64/kernel/sys_sparc.c | |
parent | e4d0251c6f56ab2e191afb70f80f382793e23f74 (diff) |
Merge with 2.3.47. Guys, this is buggy as shit. You've been warned.
Diffstat (limited to 'arch/sparc64/kernel/sys_sparc.c')
-rw-r--r-- | arch/sparc64/kernel/sys_sparc.c | 114 |
1 files changed, 93 insertions, 21 deletions
diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c index be2638ec9..81b4c4de1 100644 --- a/arch/sparc64/kernel/sys_sparc.c +++ b/arch/sparc64/kernel/sys_sparc.c @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.35 2000/01/29 07:40:12 davem Exp $ +/* $Id: sys_sparc.c,v 1.36 2000/02/16 07:31:35 davem Exp $ * linux/arch/sparc64/kernel/sys_sparc.c * * This file contains various random system calls that @@ -39,17 +39,49 @@ asmlinkage unsigned long sys_getpagesize(void) return PAGE_SIZE; } +unsigned long get_unmapped_area(unsigned long addr, unsigned long len) +{ + struct vm_area_struct * vmm; + unsigned long task_size = TASK_SIZE; + + if (current->thread.flags & SPARC_FLAG_32BIT) + task_size = 0xf0000000UL; + if (len > task_size || len > -PAGE_OFFSET) + return 0; + if (!addr) + addr = TASK_UNMAPPED_BASE; + addr = PAGE_ALIGN(addr); + + task_size -= len; + + for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) { + /* At this point: (!vmm || addr < vmm->vm_end). */ + if (addr < PAGE_OFFSET && -PAGE_OFFSET - len < addr) { + addr = PAGE_OFFSET; + vmm = find_vma(current->mm, PAGE_OFFSET); + } + if (task_size < addr) + return 0; + if (!vmm || addr + len <= vmm->vm_start) + return addr; + addr = vmm->vm_end; + } +} + extern asmlinkage unsigned long sys_brk(unsigned long brk); asmlinkage unsigned long sparc_brk(unsigned long brk) { - if((brk >= 0x80000000000UL && brk < PAGE_OFFSET) || - (brk - current->mm->brk > 0x80000000000UL && - brk - current->mm->brk < PAGE_OFFSET)) /* VM hole */ + /* People could try to be nasty and use ta 0x6d in 32bit programs */ + if ((current->thread.flags & SPARC_FLAG_32BIT) && + brk >= 0xf0000000UL) + return current->mm->brk; + + if ((current->mm->brk & PAGE_OFFSET) != (brk & PAGE_OFFSET)) return current->mm->brk; return sys_brk(brk); } - + /* * sys_pipe() is the normal C calling standard for creating * a pipe. It's not the way unix traditionally does this, though. @@ -164,30 +196,21 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, goto out; } flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - retval = -ENOMEM; len = PAGE_ALIGN(len); + retval = -EINVAL; + down(¤t->mm->mmap_sem); lock_kernel(); - if(!(flags & MAP_FIXED) && !addr) { - addr = get_unmapped_area(addr, len); - if(!addr) - goto out_putf; - } - retval = -EINVAL; if (current->thread.flags & SPARC_FLAG_32BIT) { - if (len > 0xf0000000UL || addr > 0xf0000000UL - len) + if (len > 0xf0000000UL || + ((flags & MAP_FIXED) && addr > 0xf0000000UL - len)) goto out_putf; } else { - if (len >= 0x80000000000UL || - (addr < 0x80000000000UL && - addr > 0x80000000000UL-len)) + if (len > -PAGE_OFFSET || + ((flags & MAP_FIXED) && + addr < PAGE_OFFSET && addr + len > -PAGE_OFFSET)) goto out_putf; - if (addr >= 0x80000000000UL && addr < PAGE_OFFSET) { - /* VM hole */ - retval = current->mm->brk; - goto out_putf; - } } retval = do_mmap(file, addr, len, prot, flags, off); @@ -201,6 +224,55 @@ out: return retval; } +asmlinkage long sys64_munmap(unsigned long addr, size_t len) +{ + long ret; + + if (len > -PAGE_OFFSET || + (addr < PAGE_OFFSET && addr + len > -PAGE_OFFSET)) + return -EINVAL; + down(¤t->mm->mmap_sem); + ret = do_munmap(addr, len); + up(¤t->mm->mmap_sem); + return ret; +} + +extern unsigned long do_mremap(unsigned long addr, + unsigned long old_len, unsigned long new_len, + unsigned long flags, unsigned long new_addr); + +asmlinkage unsigned long sys64_mremap(unsigned long addr, + unsigned long old_len, unsigned long new_len, + unsigned long flags, unsigned long new_addr) +{ + unsigned long ret = -EINVAL; + if (current->thread.flags & SPARC_FLAG_32BIT) + goto out; + if (old_len > -PAGE_OFFSET || new_len > -PAGE_OFFSET) + goto out; + if (addr < PAGE_OFFSET && addr + old_len > -PAGE_OFFSET) + goto out; + down(¤t->mm->mmap_sem); + if (flags & MREMAP_FIXED) { + if (new_addr < PAGE_OFFSET && + new_addr + new_len > -PAGE_OFFSET) + goto out_sem; + } else if (addr < PAGE_OFFSET && addr + new_len > -PAGE_OFFSET) { + ret = -ENOMEM; + if (!(flags & MREMAP_MAYMOVE)) + goto out_sem; + new_addr = get_unmapped_area (addr, new_len); + if (!new_addr) + goto out_sem; + flags |= MREMAP_FIXED; + } + ret = do_mremap(addr, old_len, new_len, flags, new_addr); +out_sem: + up(¤t->mm->mmap_sem); +out: + return ret; +} + /* we come to here via sys_nis_syscall so it can setup the regs argument */ asmlinkage unsigned long c_sys_nis_syscall (struct pt_regs *regs) |