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(&current->mm->mmap_sem);
73     	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
74     	up_write(&current->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], &regs, 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, &regs, 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], &regs);
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) &regs;
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