1/*
2 * linux/arch/x86_64/kernel/sys_x86_64.c
3 */
4
5#include <linux/errno.h>
6#include <linux/sched.h>
7#include <linux/mm.h>
8#include <linux/smp.h>
9#include <linux/smp_lock.h>
10#include <linux/sem.h>
11#include <linux/msg.h>
12#include <linux/shm.h>
13#include <linux/stat.h>
14#include <linux/mman.h>
15#include <linux/file.h>
16#include <linux/utsname.h>
17#include <linux/personality.h>
18
19#include <asm/uaccess.h>
20#include <asm/ipc.h>
21
22/*
23 * sys_pipe() is the normal C calling standard for creating
24 * a pipe. It's not the way Unix traditionally does this, though.
25 */
26asmlinkage long sys_pipe(unsigned long * fildes)
27{
28	int fd[2];
29	int error;
30
31	error = do_pipe(fd);
32	if (!error) {
33		if (copy_to_user(fildes, fd, 2*sizeof(int)))
34			error = -EFAULT;
35	}
36	return error;
37}
38
39long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
40	unsigned long fd, unsigned long off)
41{
42	long error;
43	struct file * file;
44
45	error = -EINVAL;
46	if (off & ~PAGE_MASK)
47		goto out;
48
49	error = -EBADF;
50	file = NULL;
51	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
52	if (!(flags & MAP_ANONYMOUS)) {
53		file = fget(fd);
54		if (!file)
55			goto out;
56	}
57
58	down_write(&current->mm->mmap_sem);
59	error = do_mmap_pgoff(file, addr, len, prot, flags, off >> PAGE_SHIFT);
60	up_write(&current->mm->mmap_sem);
61
62	if (file)
63		fput(file);
64out:
65	return error;
66}
67
68unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags)
69{
70	struct vm_area_struct *vma;
71	unsigned long end = TASK_SIZE;
72
73	if (current->thread.flags & THREAD_IA32)
74		flags |= MAP_32BIT;
75	if (flags & MAP_32BIT)
76		end = 0xffffffff-1;
77	if (len > end)
78		return -ENOMEM;
79	if (!addr) {
80		addr = TASK_UNMAPPED_64;
81		if (flags & MAP_32BIT) {
82			addr = TASK_UNMAPPED_32;
83		}
84	}
85	addr = PAGE_ALIGN(addr);
86
87	for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) {
88		/* At this point:  (!vma || addr < vma->vm_end). */
89		if (end - len < addr)
90			return -ENOMEM;
91		if (!vma || addr + len <= vma->vm_start)
92			return addr;
93		addr = vma->vm_end;
94	}
95}
96
97asmlinkage long sys_uname(struct new_utsname * name)
98{
99	int err;
100	down_read(&uts_sem);
101	err=copy_to_user(name, &system_utsname, sizeof (*name));
102	up_read(&uts_sem);
103	if (personality(current->personality) == PER_LINUX32)
104		err = copy_to_user(name->machine, "i686", 5);
105	return err?-EFAULT:0;
106}
107
108asmlinkage long sys_pause(void)
109{
110	current->state = TASK_INTERRUPTIBLE;
111	schedule();
112	return -ERESTARTNOHAND;
113}
114
115asmlinkage long wrap_sys_shmat(int shmid, char *shmaddr, int shmflg)
116{
117	unsigned long raddr;
118	return sys_shmat(shmid,shmaddr,shmflg,&raddr) ?: raddr;
119}
120