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(¤t->mm->mmap_sem);
59 error = do_mmap_pgoff(file, addr, len, prot, flags, off >> PAGE_SHIFT);
60 up_write(¤t->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