File: /usr/src/linux/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/linkage.h>
18 #include <linux/mm.h>
19 #include <linux/smp.h>
20 #include <linux/smp_lock.h>
21 #include <linux/mman.h>
22 #include <linux/sched.h>
23 #include <linux/file.h>
24 #include <linux/slab.h>
25 #include <linux/utsname.h>
26 #include <linux/unistd.h>
27 #include <asm/branch.h>
28 #include <asm/offset.h>
29 #include <asm/ptrace.h>
30 #include <asm/signal.h>
31 #include <asm/stackframe.h>
32 #include <asm/uaccess.h>
33
34 extern asmlinkage void syscall_trace(void);
35 typedef asmlinkage int (*syscall_t)(void *a0,...);
36 extern asmlinkage int (*do_syscalls)(struct pt_regs *regs, syscall_t fun,
37 int narg);
38 extern syscall_t sys_call_table[];
39 extern unsigned char sys_narg_table[];
40
41 asmlinkage int sys_pipe(struct pt_regs regs)
42 {
43 int fd[2];
44 int error, res;
45
46 error = do_pipe(fd);
47 if (error) {
48 res = error;
49 goto out;
50 }
51 regs.regs[3] = fd[1];
52 res = fd[0];
53 out:
54 return res;
55 }
56
57 /* common code for old and new mmaps */
58 static inline long
59 do_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
60 unsigned long flags, unsigned long fd, unsigned long pgoff)
61 {
62 int error = -EBADF;
63 struct file * file = NULL;
64
65 flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
66 if (!(flags & MAP_ANONYMOUS)) {
67 file = fget(fd);
68 if (!file)
69 goto out;
70 }
71
72 down_write(¤t->mm->mmap_sem);
73 error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
74 up_write(¤t->mm->mmap_sem);
75
76 if (file)
77 fput(file);
78 out:
79 return error;
80 }
81
82 asmlinkage unsigned long old_mmap(unsigned long addr, size_t len, int prot,
83 int flags, int fd, off_t offset)
84 {
85 return do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
86 }
87
88 asmlinkage long
89 sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
90 unsigned long flags, unsigned long fd, unsigned long pgoff)
91 {
92 return do_mmap2(addr, len, prot, flags, fd, pgoff);
93 }
94
95 save_static_function(sys_fork);
96 static_unused int _sys_fork(struct pt_regs regs)
97 {
98 int res;
99
100 res = do_fork(SIGCHLD, regs.regs[29], ®s, 0);
101 return res;
102 }
103
104
105 save_static_function(sys_clone);
106 static_unused int _sys_clone(struct pt_regs regs)
107 {
108 unsigned long clone_flags;
109 unsigned long newsp;
110 int res;
111
112 clone_flags = regs.regs[4];
113 newsp = regs.regs[5];
114 if (!newsp)
115 newsp = regs.regs[29];
116 res = do_fork(clone_flags, newsp, ®s, 0);
117 return res;
118 }
119
120 /*
121 * sys_execve() executes a new program.
122 */
123 asmlinkage int sys_execve(struct pt_regs regs)
124 {
125 int error;
126 char * filename;
127
128 filename = getname((char *) (long)regs.regs[4]);
129 error = PTR_ERR(filename);
130 if (IS_ERR(filename))
131 goto out;
132 error = do_execve(filename, (char **) (long)regs.regs[5],
133 (char **) (long)regs.regs[6], ®s);
134 putname(filename);
135
136 out:
137 return error;
138 }
139
140 /*
141 * Compacrapability ...
142 */
143 asmlinkage int sys_uname(struct old_utsname * name)
144 {
145 if (name && !copy_to_user(name, &system_utsname, sizeof (*name)))
146 return 0;
147 return -EFAULT;
148 }
149
150 /*
151 * Compacrapability ...
152 */
153 asmlinkage int sys_olduname(struct oldold_utsname * name)
154 {
155 int error;
156
157 if (!name)
158 return -EFAULT;
159 if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
160 return -EFAULT;
161
162 error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
163 error -= __put_user(0,name->sysname+__OLD_UTS_LEN);
164 error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
165 error -= __put_user(0,name->nodename+__OLD_UTS_LEN);
166 error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
167 error -= __put_user(0,name->release+__OLD_UTS_LEN);
168 error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
169 error -= __put_user(0,name->version+__OLD_UTS_LEN);
170 error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
171 error = __put_user(0,name->machine+__OLD_UTS_LEN);
172 error = error ? -EFAULT : 0;
173
174 return error;
175 }
176
177 /*
178 * Do the indirect syscall syscall.
179 * Don't care about kernel locking; the actual syscall will do it.
180 *
181 * XXX This is borken.
182 */
183 asmlinkage int sys_syscall(struct pt_regs regs)
184 {
185 syscall_t syscall;
186 unsigned long syscallnr = regs.regs[4];
187 unsigned long a0, a1, a2, a3, a4, a5, a6;
188 int nargs, errno;
189
190 if (syscallnr > __NR_Linux + __NR_Linux_syscalls)
191 return -ENOSYS;
192
193 syscall = sys_call_table[syscallnr];
194 nargs = sys_narg_table[syscallnr];
195 /*
196 * Prevent stack overflow by recursive
197 * syscall(__NR_syscall, __NR_syscall,...);
198 */
199 if (syscall == (syscall_t) sys_syscall) {
200 return -EINVAL;
201 }
202
203 if (syscall == NULL) {
204 return -ENOSYS;
205 }
206
207 if(nargs > 3) {
208 unsigned long usp = regs.regs[29];
209 unsigned long *sp = (unsigned long *) usp;
210 if(usp & 3) {
211 printk("unaligned usp -EFAULT\n");
212 force_sig(SIGSEGV, current);
213 return -EFAULT;
214 }
215 errno = verify_area(VERIFY_READ, (void *) (usp + 16),
216 (nargs - 3) * sizeof(unsigned long));
217 if(errno) {
218 return -EFAULT;
219 }
220 switch(nargs) {
221 case 7:
222 a3 = sp[4]; a4 = sp[5]; a5 = sp[6]; a6 = sp[7];
223 break;
224 case 6:
225 a3 = sp[4]; a4 = sp[5]; a5 = sp[6]; a6 = 0;
226 break;
227 case 5:
228 a3 = sp[4]; a4 = sp[5]; a5 = a6 = 0;
229 break;
230 case 4:
231 a3 = sp[4]; a4 = a5 = a6 = 0;
232 break;
233
234 default:
235 a3 = a4 = a5 = a6 = 0;
236 break;
237 }
238 } else {
239 a3 = a4 = a5 = a6 = 0;
240 }
241 a0 = regs.regs[5]; a1 = regs.regs[6]; a2 = regs.regs[7];
242 if(nargs == 0)
243 a0 = (unsigned long) ®s;
244 return syscall((void *)a0, a1, a2, a3, a4, a5, a6);
245 }
246
247 /*
248 * If we ever come here the user sp is bad. Zap the process right away.
249 * Due to the bad stack signaling wouldn't work.
250 * XXX kernel locking???
251 */
252 asmlinkage void bad_stack(void)
253 {
254 do_exit(SIGSEGV);
255 }
256
257 /*
258 * Build the string table for the builtin "poor man's strace".
259 */
260 #ifdef CONF_PRINT_SYSCALLS
261 #define SYS(fun, narg) #fun,
262 static char *sfnames[] = {
263 #include "syscalls.h"
264 };
265 #endif
266
267 #if defined(CONFIG_BINFMT_IRIX) && defined(CONF_DEBUG_IRIX)
268 #define SYS(fun, narg) #fun,
269 static char *irix_sys_names[] = {
270 #include "irix5sys.h"
271 };
272 #endif
273