patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / arch / x86_64 / kernel / sys_x86_64.c
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/syscalls.h>
8 #include <linux/mm.h>
9 #include <linux/smp.h>
10 #include <linux/smp_lock.h>
11 #include <linux/sem.h>
12 #include <linux/msg.h>
13 #include <linux/shm.h>
14 #include <linux/stat.h>
15 #include <linux/mman.h>
16 #include <linux/file.h>
17 #include <linux/utsname.h>
18 #include <linux/personality.h>
19 #include <linux/vs_cvirt.h>
20
21 #include <asm/uaccess.h>
22 #include <asm/ipc.h>
23 #include <asm/ia32.h>
24
25 /*
26  * sys_pipe() is the normal C calling standard for creating
27  * a pipe. It's not the way Unix traditionally does this, though.
28  */
29 asmlinkage long sys_pipe(int __user *fildes)
30 {
31         int fd[2];
32         int error;
33
34         error = do_pipe(fd);
35         if (!error) {
36                 if (copy_to_user(fildes, fd, 2*sizeof(int)))
37                         error = -EFAULT;
38         }
39         return error;
40 }
41
42 long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
43         unsigned long fd, unsigned long off)
44 {
45         long error;
46         struct file * file;
47
48         error = -EINVAL;
49         if (off & ~PAGE_MASK)
50                 goto out;
51
52         error = -EBADF;
53         file = NULL;
54         flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
55         if (!(flags & MAP_ANONYMOUS)) {
56                 file = fget(fd);
57                 if (!file)
58                         goto out;
59         }
60         down_write(&current->mm->mmap_sem);
61         error = do_mmap_pgoff(file, addr, len, prot, flags, off >> PAGE_SHIFT);
62         up_write(&current->mm->mmap_sem);
63
64         if (file)
65                 fput(file);
66 out:
67         return error;
68 }
69
70 static void find_start_end(unsigned long flags, unsigned long *begin,
71                            unsigned long *end)
72 {
73 #ifdef CONFIG_IA32_EMULATION
74         if (test_thread_flag(TIF_IA32)) { 
75                 *begin = TASK_UNMAPPED_32;
76                 *end = IA32_PAGE_OFFSET; 
77         } else 
78 #endif
79         if (flags & MAP_32BIT) { 
80                 /* This is usually used needed to map code in small
81                    model, so it needs to be in the first 31bit. Limit
82                    it to that.  This means we need to move the
83                    unmapped base down for this case. This can give
84                    conflicts with the heap, but we assume that glibc
85                    malloc knows how to fall back to mmap. Give it 1GB
86                    of playground for now. -AK */ 
87                 *begin = 0x40000000; 
88                 *end = 0x80000000;              
89         } else { 
90                 *begin = TASK_UNMAPPED_64; 
91                 *end = TASK_SIZE; 
92                 }
93
94
95 unsigned long
96 arch_get_unmapped_area(struct file *filp, unsigned long addr,
97                 unsigned long len, unsigned long pgoff, unsigned long flags)
98 {
99         struct mm_struct *mm = current->mm;
100         struct vm_area_struct *vma;
101         unsigned long start_addr;
102         unsigned long begin, end;
103         
104         find_start_end(flags, &begin, &end); 
105
106         if (len > end)
107                 return -ENOMEM;
108
109         if (addr) {
110                 addr = PAGE_ALIGN(addr);
111                 vma = find_vma(mm, addr);
112                 if (end - len >= addr &&
113                     (!vma || addr + len <= vma->vm_start))
114                         return addr;
115         }
116         addr = mm->free_area_cache;
117         if (addr < begin) 
118                 addr = begin; 
119         start_addr = addr;
120
121 full_search:
122         for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {
123                 /* At this point:  (!vma || addr < vma->vm_end). */
124                 if (end - len < addr) {
125                         /*
126                          * Start a new search - just in case we missed
127                          * some holes.
128                          */
129                         if (start_addr != begin) {
130                                 start_addr = addr = begin;
131                                 goto full_search;
132                         }
133                         return -ENOMEM;
134                 }
135                 if (!vma || addr + len <= vma->vm_start) {
136                         /*
137                          * Remember the place where we stopped the search:
138                          */
139                         mm->free_area_cache = addr + len;
140                         return addr;
141                 }
142                 addr = vma->vm_end;
143         }
144 }
145
146 asmlinkage long sys_uname(struct new_utsname __user * name)
147 {
148         int err;
149         down_read(&uts_sem);
150         err = copy_to_user(name, vx_new_utsname(), sizeof (*name));
151         up_read(&uts_sem);
152         if (personality(current->personality) == PER_LINUX32) 
153                 err |= copy_to_user(&name->machine, "i686", 5);                 
154         return err ? -EFAULT : 0;
155 }
156
157 asmlinkage long wrap_sys_shmat(int shmid, char __user *shmaddr, int shmflg)
158 {
159         unsigned long raddr;
160         return do_shmat(shmid,shmaddr,shmflg,&raddr) ?: (long)raddr;
161 }
162
163 asmlinkage long sys_time64(long __user * tloc)
164 {
165         struct timeval now; 
166         int i; 
167
168         do_gettimeofday(&now);
169         i = now.tv_sec;
170         if (tloc) {
171                 if (put_user(i,tloc))
172                         i = -EFAULT;
173         }
174         return i;
175 }