diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2007-10-11 11:17:24 +0200 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2007-10-11 11:17:24 +0200 |
commit | 250c22777fe1ccd7ac588579a6c16db4c0161cc5 (patch) | |
tree | 55c317efb7d792ec6fdae1d1937c67a502c48dec /arch/x86/kernel/sys_x86_64.c | |
parent | x86_64: move ia32 (diff) | |
download | linux-250c22777fe1ccd7ac588579a6c16db4c0161cc5.tar.xz linux-250c22777fe1ccd7ac588579a6c16db4c0161cc5.zip |
x86_64: move kernel
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/sys_x86_64.c')
-rw-r--r-- | arch/x86/kernel/sys_x86_64.c | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c new file mode 100644 index 000000000000..4770b7a2052c --- /dev/null +++ b/arch/x86/kernel/sys_x86_64.c @@ -0,0 +1,159 @@ +/* + * linux/arch/x86_64/kernel/sys_x86_64.c + */ + +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/syscalls.h> +#include <linux/mm.h> +#include <linux/fs.h> +#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/file.h> +#include <linux/utsname.h> +#include <linux/personality.h> + +#include <asm/uaccess.h> +#include <asm/ia32.h> + +/* + * sys_pipe() is the normal C calling standard for creating + * a pipe. It's not the way Unix traditionally does this, though. + */ +asmlinkage long sys_pipe(int __user *fildes) +{ + int fd[2]; + int error; + + error = do_pipe(fd); + if (!error) { + if (copy_to_user(fildes, fd, 2*sizeof(int))) + error = -EFAULT; + } + return error; +} + +asmlinkage long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long off) +{ + long error; + struct file * file; + + error = -EINVAL; + if (off & ~PAGE_MASK) + goto out; + + error = -EBADF; + file = NULL; + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + if (!(flags & MAP_ANONYMOUS)) { + file = fget(fd); + if (!file) + goto out; + } + down_write(¤t->mm->mmap_sem); + error = do_mmap_pgoff(file, addr, len, prot, flags, off >> PAGE_SHIFT); + up_write(¤t->mm->mmap_sem); + + if (file) + fput(file); +out: + return error; +} + +static void find_start_end(unsigned long flags, unsigned long *begin, + unsigned long *end) +{ + if (!test_thread_flag(TIF_IA32) && (flags & MAP_32BIT)) { + /* This is usually used needed to map code in small + model, so it needs to be in the first 31bit. Limit + it to that. This means we need to move the + unmapped base down for this case. This can give + conflicts with the heap, but we assume that glibc + malloc knows how to fall back to mmap. Give it 1GB + of playground for now. -AK */ + *begin = 0x40000000; + *end = 0x80000000; + } else { + *begin = TASK_UNMAPPED_BASE; + *end = TASK_SIZE; + } +} + +unsigned long +arch_get_unmapped_area(struct file *filp, unsigned long addr, + unsigned long len, unsigned long pgoff, unsigned long flags) +{ + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + unsigned long start_addr; + unsigned long begin, end; + + if (flags & MAP_FIXED) + return addr; + + find_start_end(flags, &begin, &end); + + if (len > end) + return -ENOMEM; + + if (addr) { + addr = PAGE_ALIGN(addr); + vma = find_vma(mm, addr); + if (end - len >= addr && + (!vma || addr + len <= vma->vm_start)) + return addr; + } + if (((flags & MAP_32BIT) || test_thread_flag(TIF_IA32)) + && len <= mm->cached_hole_size) { + mm->cached_hole_size = 0; + mm->free_area_cache = begin; + } + addr = mm->free_area_cache; + if (addr < begin) + addr = begin; + start_addr = addr; + +full_search: + for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { + /* At this point: (!vma || addr < vma->vm_end). */ + if (end - len < addr) { + /* + * Start a new search - just in case we missed + * some holes. + */ + if (start_addr != begin) { + start_addr = addr = begin; + mm->cached_hole_size = 0; + goto full_search; + } + return -ENOMEM; + } + if (!vma || addr + len <= vma->vm_start) { + /* + * Remember the place where we stopped the search: + */ + mm->free_area_cache = addr + len; + return addr; + } + if (addr + mm->cached_hole_size < vma->vm_start) + mm->cached_hole_size = vma->vm_start - addr; + + addr = vma->vm_end; + } +} + +asmlinkage long sys_uname(struct new_utsname __user * name) +{ + int err; + down_read(&uts_sem); + err = copy_to_user(name, utsname(), sizeof (*name)); + up_read(&uts_sem); + if (personality(current->personality) == PER_LINUX32) + err |= copy_to_user(&name->machine, "i686", 5); + return err ? -EFAULT : 0; +} |