import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / arch / mips / kernel / syscall.c
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 1995 - 2000 by Ralf Baechle
7  * Copyright (C) 2000 Silicon Graphics, Inc.
8  *
9  * TODO:  Implement the compatibility syscalls.
10  *        Don't waste that much memory for empty entries in the syscall
11  *        table.
12  */
13 #undef CONF_PRINT_SYSCALLS
14 #undef CONF_DEBUG_IRIX
15
16 #include <linux/config.h>
17 #include <linux/compiler.h>
18 #include <linux/linkage.h>
19 #include <linux/mm.h>
20 #include <linux/smp.h>
21 #include <linux/smp_lock.h>
22 #include <linux/mman.h>
23 #include <linux/sched.h>
24 #include <linux/file.h>
25 #include <linux/slab.h>
26 #include <linux/utsname.h>
27 #include <linux/unistd.h>
28 #include <asm/branch.h>
29 #include <asm/offset.h>
30 #include <asm/ptrace.h>
31 #include <asm/signal.h>
32 #include <asm/shmparam.h>
33 #include <asm/uaccess.h>
34
35 extern asmlinkage void syscall_trace(void);
36 typedef asmlinkage int (*syscall_t)(void *a0,...);
37 extern asmlinkage int (*do_syscalls)(struct pt_regs *regs, syscall_t fun,
38                                      int narg);
39 extern syscall_t sys_call_table[];
40 extern unsigned char sys_narg_table[];
41
42 asmlinkage int sys_pipe(volatile struct pt_regs regs)
43 {
44         int fd[2];
45         int error, res;
46
47         error = do_pipe(fd);
48         if (error) {
49                 res = error;
50                 goto out;
51         }
52         regs.regs[3] = fd[1];
53         res = fd[0];
54 out:
55         return res;
56 }
57
58 unsigned long shm_align_mask = PAGE_SIZE - 1;   /* Sane caches */
59
60 #define COLOUR_ALIGN(addr,pgoff)                                \
61         ((((addr) + shm_align_mask) & ~shm_align_mask) +        \
62          (((pgoff) << PAGE_SHIFT) & shm_align_mask))
63
64 unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
65         unsigned long len, unsigned long pgoff, unsigned long flags)
66 {
67         struct vm_area_struct * vmm;
68         int do_color_align;
69
70         if (flags & MAP_FIXED) {
71                 /*
72                  * We do not accept a shared mapping if it would violate
73                  * cache aliasing constraints.
74                  */
75                 if ((flags & MAP_SHARED) && (addr & shm_align_mask))
76                         return -EINVAL;
77                 return addr;
78         }
79
80         if (len > TASK_SIZE)
81                 return -ENOMEM;
82         do_color_align = 0;
83         if (filp || (flags & MAP_SHARED))
84                 do_color_align = 1;
85         if (addr) {
86                 if (do_color_align)
87                         addr = COLOUR_ALIGN(addr, pgoff);
88                 else
89                         addr = PAGE_ALIGN(addr);
90                 vmm = find_vma(current->mm, addr);
91                 if (TASK_SIZE - len >= addr &&
92                     (!vmm || addr + len <= vmm->vm_start))
93                         return addr;
94         }
95         addr = TASK_UNMAPPED_BASE;
96         if (do_color_align)
97                 addr = COLOUR_ALIGN(addr, pgoff);
98         else
99                 addr = PAGE_ALIGN(addr);
100
101         for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
102                 /* At this point:  (!vmm || addr < vmm->vm_end). */
103                 if (TASK_SIZE - len < addr)
104                         return -ENOMEM;
105                 if (!vmm || addr + len <= vmm->vm_start)
106                         return addr;
107                 addr = vmm->vm_end;
108                 if (do_color_align)
109                         addr = COLOUR_ALIGN(addr, pgoff);
110         }
111 }
112
113 /* common code for old and new mmaps */
114 static inline long
115 do_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
116         unsigned long flags, unsigned long fd, unsigned long pgoff)
117 {
118         int error = -EBADF;
119         struct file * file = NULL;
120
121         flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
122         if (!(flags & MAP_ANONYMOUS)) {
123                 file = fget(fd);
124                 if (!file)
125                         goto out;
126         }
127
128         down_write(&current->mm->mmap_sem);
129         error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
130         up_write(&current->mm->mmap_sem);
131
132         if (file)
133                 fput(file);
134 out:
135         return error;
136 }
137
138 asmlinkage unsigned long old_mmap(unsigned long addr, size_t len, int prot,
139                                   int flags, int fd, off_t offset)
140 {
141         int result;
142
143         result = -EINVAL;
144         if (offset & ~PAGE_MASK)
145                 goto out;
146
147         result = do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
148
149 out:
150         return result;
151 }
152
153 asmlinkage long
154 sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
155           unsigned long flags, unsigned long fd, unsigned long pgoff)
156 {
157         return do_mmap2(addr, len, prot, flags, fd, pgoff);
158 }
159
160 save_static_function(sys_fork);
161 static_unused int _sys_fork(struct pt_regs regs)
162 {
163         int res;
164
165         res = do_fork(SIGCHLD, regs.regs[29], &regs, 0);
166         return res;
167 }
168
169
170 save_static_function(sys_clone);
171 static_unused int _sys_clone(struct pt_regs regs)
172 {
173         unsigned long clone_flags;
174         unsigned long newsp;
175         int res;
176
177         clone_flags = regs.regs[4];
178         newsp = regs.regs[5];
179         if (!newsp)
180                 newsp = regs.regs[29];
181         res = do_fork(clone_flags, newsp, &regs, 0);
182         return res;
183 }
184
185 /*
186  * sys_execve() executes a new program.
187  */
188 asmlinkage int sys_execve(struct pt_regs regs)
189 {
190         int error;
191         char * filename;
192
193         filename = getname((char *) (long)regs.regs[4]);
194         error = PTR_ERR(filename);
195         if (IS_ERR(filename))
196                 goto out;
197         error = do_execve(filename, (char **) (long)regs.regs[5],
198                           (char **) (long)regs.regs[6], &regs);
199         putname(filename);
200
201 out:
202         return error;
203 }
204
205 /*
206  * Compacrapability ...
207  */
208 asmlinkage int sys_uname(struct old_utsname * name)
209 {
210         if (name && !copy_to_user(name, &system_utsname, sizeof (*name)))
211                 return 0;
212         return -EFAULT;
213 }
214
215 /*
216  * Compacrapability ...
217  */
218 asmlinkage int sys_olduname(struct oldold_utsname * name)
219 {
220         int error;
221
222         if (!name)
223                 return -EFAULT;
224         if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
225                 return -EFAULT;
226
227         error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
228         error -= __put_user(0,name->sysname+__OLD_UTS_LEN);
229         error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
230         error -= __put_user(0,name->nodename+__OLD_UTS_LEN);
231         error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
232         error -= __put_user(0,name->release+__OLD_UTS_LEN);
233         error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
234         error -= __put_user(0,name->version+__OLD_UTS_LEN);
235         error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
236         error = __put_user(0,name->machine+__OLD_UTS_LEN);
237         error = error ? -EFAULT : 0;
238
239         return error;
240 }
241
242 /*
243  * If we ever come here the user sp is bad.  Zap the process right away.
244  * Due to the bad stack signaling wouldn't work.
245  * XXX kernel locking???
246  */
247 asmlinkage void bad_stack(void)
248 {
249         do_exit(SIGSEGV);
250 }
251
252 /*
253  * Build the string table for the builtin "poor man's strace".
254  */
255 #ifdef CONF_PRINT_SYSCALLS
256 #define SYS(fun, narg) #fun,
257 static char *sfnames[] = {
258 #include "syscalls.h"
259 };
260 #endif
261
262 #if defined(CONFIG_BINFMT_IRIX) && defined(CONF_DEBUG_IRIX)
263 #define SYS(fun, narg) #fun,
264 static char *irix_sys_names[] = {
265 #include "irix5sys.h"
266 };
267 #endif