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