File: /usr/src/linux/arch/mips64/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, 2001 by Ralf Baechle
7      * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
8      * Copyright (C) 2001 MIPS Technologies, Inc.
9      */
10     #include <linux/errno.h>
11     #include <linux/linkage.h>
12     #include <linux/mm.h>
13     #include <linux/smp.h>
14     #include <linux/smp_lock.h>
15     #include <linux/mman.h>
16     #include <linux/sched.h>
17     #include <linux/string.h>
18     #include <linux/file.h>
19     #include <linux/utsname.h>
20     #include <linux/unistd.h>
21     #include <linux/sem.h>
22     #include <linux/msg.h>
23     #include <linux/shm.h>
24     #include <linux/slab.h>
25     #include <asm/ipc.h>
26     #include <asm/cachectl.h>
27     #include <asm/offset.h>
28     #include <asm/pgalloc.h>
29     #include <asm/ptrace.h>
30     #include <asm/signal.h>
31     #include <asm/stackframe.h>
32     #include <asm/sysmips.h>
33     #include <asm/uaccess.h>
34     
35     extern asmlinkage void syscall_trace(void);
36     
37     asmlinkage int sys_pipe(abi64_no_regargs, struct pt_regs regs)
38     {
39     	int fd[2];
40     	int error, res;
41     
42     	error = do_pipe(fd);
43     	if (error) {
44     		res = error;
45     		goto out;
46     	}
47     	regs.regs[3] = fd[1];
48     	res = fd[0];
49     out:
50     	return res;
51     }
52     
53     asmlinkage unsigned long
54     sys_mmap(unsigned long addr, size_t len, unsigned long prot,
55              unsigned long flags, unsigned long fd, off_t offset)
56     {
57     	struct file * file = NULL;
58     	unsigned long error = -EFAULT;
59     
60     	if (!(flags & MAP_ANONYMOUS)) {
61     		error = -EBADF;
62     		file = fget(fd);
63     		if (!file)
64     			goto out;
65     	}
66             flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
67     
68     	down_write(&current->mm->mmap_sem);
69             error = do_mmap(file, addr, len, prot, flags, offset);
70     	up_write(&current->mm->mmap_sem);
71             if (file)
72                     fput(file);
73     out:
74     
75     	return error;
76     }
77     
78     asmlinkage int sys_fork(abi64_no_regargs, struct pt_regs regs)
79     {
80     	int res;
81     
82     	save_static(&regs);
83     	res = do_fork(SIGCHLD, regs.regs[29], &regs, 0);
84     	return res;
85     }
86     
87     asmlinkage int sys_clone(abi64_no_regargs, struct pt_regs regs)
88     {
89     	unsigned long clone_flags;
90     	unsigned long newsp;
91     	int res;
92     
93     	save_static(&regs);
94     	clone_flags = regs.regs[4];
95     	newsp = regs.regs[5];
96     	if (!newsp)
97     		newsp = regs.regs[29];
98     	res = do_fork(clone_flags, newsp, &regs, 0);
99     	return res;
100     }
101     
102     /*
103      * sys_execve() executes a new program.
104      */
105     asmlinkage int sys_execve(abi64_no_regargs, struct pt_regs regs)
106     {
107     	int error;
108     	char * filename;
109     
110     	filename = getname((char *) (long)regs.regs[4]);
111     	error = PTR_ERR(filename);
112     	if (IS_ERR(filename))
113     		goto out;
114     	error = do_execve(filename, (char **) (long)regs.regs[5],
115     	                  (char **) (long)regs.regs[6], &regs);
116     	putname(filename);
117     
118     out:
119     	return error;
120     }
121     
122     /*
123      * Do the indirect syscall syscall.
124      *
125      * XXX This is borken.
126      */
127     asmlinkage int sys_syscall(abi64_no_regargs, struct pt_regs regs)
128     {
129     	return -ENOSYS;
130     }
131     
132     asmlinkage int
133     _sys_sysmips(int cmd, long arg1, int arg2, int arg3)
134     {
135     	int	*p;
136     	char	*name;
137     	int	tmp, len, errno;
138     
139     	switch(cmd) {
140     	case SETNAME: {
141     		char nodename[__NEW_UTS_LEN + 1];
142     
143     		if (!capable(CAP_SYS_ADMIN))
144     			return -EPERM;
145     
146     		name = (char *) arg1;
147     
148     		len = strncpy_from_user(nodename, name, sizeof(nodename));
149     		if (len < 0)
150     			return -EFAULT;
151     
152     		down_write(&uts_sem);
153     		strncpy(system_utsname.nodename, name, len);
154     		up_write(&uts_sem);
155     		system_utsname.nodename[len] = '\0';
156     		return 0;
157     	}
158     
159     	case MIPS_ATOMIC_SET:
160     		printk(KERN_CRIT "How did I get here?\n");
161     		return -EINVAL;
162     
163     	case MIPS_FIXADE:
164     		tmp = current->thread.mflags & ~3;
165     		current->thread.mflags = tmp | (arg1 & 3);
166     		return 0;
167     
168     	case FLUSH_CACHE:
169     		_flush_cache_l2();
170     		return 0;
171     
172     	case MIPS_RDNVRAM:
173     		return -EIO;
174     	}
175     
176     	return -EINVAL;
177     }
178     
179     /*
180      * sys_ipc() is the de-multiplexer for the SysV IPC calls..
181      *
182      * This is really horribly ugly.
183      */
184     asmlinkage int sys_ipc (uint call, int first, int second,
185     			unsigned long third, void *ptr, long fifth)
186     {
187     	int version, ret;
188     
189     	version = call >> 16; /* hack for backward compatibility */
190     	call &= 0xffff;
191     
192     	switch (call) {
193     	case SEMOP:
194     		return sys_semop (first, (struct sembuf *)ptr, second);
195     	case SEMGET:
196     		return sys_semget (first, second, third);
197     	case SEMCTL: {
198     		union semun fourth;
199     		if (!ptr)
200     			return -EINVAL;
201     		if (get_user(fourth.__pad, (void **) ptr))
202     			return -EFAULT;
203     		return sys_semctl (first, second, third, fourth);
204     	}
205     
206     	case MSGSND:
207     		return sys_msgsnd (first, (struct msgbuf *) ptr, 
208     				   second, third);
209     	case MSGRCV:
210     		switch (version) {
211     		case 0: {
212     			struct ipc_kludge tmp;
213     			if (!ptr)
214     				return -EINVAL;
215     			
216     			if (copy_from_user(&tmp,
217     					   (struct ipc_kludge *) ptr, 
218     					   sizeof (tmp)))
219     				return -EFAULT;
220     			return sys_msgrcv (first, tmp.msgp, second,
221     					   tmp.msgtyp, third);
222     		}
223     		default:
224     			return sys_msgrcv (first,
225     					   (struct msgbuf *) ptr,
226     					   second, fifth, third);
227     		}
228     	case MSGGET:
229     		return sys_msgget ((key_t) first, second);
230     	case MSGCTL:
231     		return sys_msgctl (first, second, (struct msqid_ds *) ptr);
232     
233     	case SHMAT:
234     		switch (version) {
235     		default: {
236     			ulong raddr;
237     			ret = sys_shmat (first, (char *) ptr, second, &raddr);
238     			if (ret)
239     				return ret;
240     			return put_user (raddr, (ulong *) third);
241     		}
242     		case 1:	/* iBCS2 emulator entry point */
243     			if (!segment_eq(get_fs(), get_ds()))
244     				return -EINVAL;
245     			return sys_shmat (first, (char *) ptr, second, (ulong *) third);
246     		}
247     	case SHMDT: 
248     		return sys_shmdt ((char *)ptr);
249     	case SHMGET:
250     		return sys_shmget (first, second, third);
251     	case SHMCTL:
252     		return sys_shmctl (first, second,
253     				   (struct shmid_ds *) ptr);
254     	default:
255     		return -EINVAL;
256     	}
257     }
258     
259     /*
260      * No implemented yet ...
261      */
262     asmlinkage int
263     sys_cachectl(char *addr, int nbytes, int op)
264     {
265     	return -ENOSYS;
266     }
267     
268     /*
269      * If we ever come here the user sp is bad.  Zap the process right away.
270      * Due to the bad stack signaling wouldn't work.
271      */
272     asmlinkage void bad_stack(void)
273     {
274     	do_exit(SIGSEGV);
275     }
276     
277     asmlinkage int sys_pause(void)
278     {
279     	current->state = TASK_INTERRUPTIBLE;
280     	schedule();
281     	return -ERESTARTNOHAND;
282     }
283