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  */
sys_pipe(unsigned long * fildes)26 asmlinkage 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 
sys_mmap(unsigned long addr,unsigned long len,unsigned long prot,unsigned long flags,unsigned long fd,unsigned long off)39 long 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);
64 out:
65 	return error;
66 }
67 
68 
arch_get_unmapped_area(struct file * filp,unsigned long addr,unsigned long len,unsigned long pgoff,unsigned long flags)69 unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags)
70 {
71 	struct vm_area_struct *vma;
72 	unsigned long end = TASK_SIZE;
73 
74 	if (current->thread.flags & THREAD_IA32) {
75 		if (!addr)
76 			addr = TASK_UNMAPPED_32;
77 		end = 0xffff0000;
78 	} else if (flags & MAP_32BIT) {
79 		/* This is usually used needed to map code in small
80 		   model: it needs to be in the first 31bit. Limit it
81 		   to that.  This means we need to move the unmapped
82 		   base down for this case.  This may give conflicts
83 		   with the heap, but we assume that malloc falls back
84 		   to mmap. Give it 1GB of playground for now. -AK */
85 		if (!addr)
86 			addr = 0x40000000;
87 		end = 0x80000000;
88 	} else {
89 		if (!addr)
90 			addr = TASK_UNMAPPED_64;
91 		end = TASK_SIZE;
92 		}
93 
94 	if (len > end)
95 		return -ENOMEM;
96 	addr = PAGE_ALIGN(addr);
97 
98 	for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) {
99 		/* At this point:  (!vma || addr < vma->vm_end). */
100 		if (end - len < addr)
101 			return -ENOMEM;
102 		if (!vma || addr + len <= vma->vm_start)
103 			return addr;
104 		addr = vma->vm_end;
105 	}
106 }
107 
sys_uname(struct new_utsname * name)108 asmlinkage long sys_uname(struct new_utsname * name)
109 {
110 	int err;
111 	down_read(&uts_sem);
112 	err=copy_to_user(name, &system_utsname, sizeof (*name));
113 	up_read(&uts_sem);
114 	if (personality(current->personality) == PER_LINUX32)
115 		err = copy_to_user(name->machine, "i686", 5);
116 	return err?-EFAULT:0;
117 }
118 
sys_pause(void)119 asmlinkage long sys_pause(void)
120 {
121 	current->state = TASK_INTERRUPTIBLE;
122 	schedule();
123 	return -ERESTARTNOHAND;
124 }
125 
wrap_sys_shmat(int shmid,char * shmaddr,int shmflg)126 asmlinkage long wrap_sys_shmat(int shmid, char *shmaddr, int shmflg)
127 {
128 	unsigned long raddr;
129 	return sys_shmat(shmid,shmaddr,shmflg,&raddr) ?: raddr;
130 }
131 
sys_time64(long * tloc)132 asmlinkage long sys_time64(long * tloc)
133 {
134 	struct timeval now;
135 	int i;
136 
137 	do_gettimeofday(&now);
138 	i = now.tv_sec;
139 	if (tloc) {
140 		if (put_user(i,tloc))
141 			i = -EFAULT;
142 	}
143 	return i;
144 }
145