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, 1996, 1997, 2000, 2001, 05 by Ralf Baechle
7 * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
8 * Copyright (C) 2001 MIPS Technologies, Inc.
9 */
10#include <linux/a.out.h>
11#include <linux/capability.h>
12#include <linux/errno.h>
13#include <linux/linkage.h>
14#include <linux/mm.h>
15#include <linux/smp.h>
16#include <linux/mman.h>
17#include <linux/ptrace.h>
18#include <linux/sched.h>
19#include <linux/string.h>
20#include <linux/syscalls.h>
21#include <linux/file.h>
22#include <linux/slab.h>
23#include <linux/utsname.h>
24#include <linux/unistd.h>
25#include <linux/sem.h>
26#include <linux/msg.h>
27#include <linux/shm.h>
28#include <linux/compiler.h>
29#include <linux/module.h>
30
31#include <asm/branch.h>
32#include <asm/cachectl.h>
33#include <asm/cacheflush.h>
34#include <asm/ipc.h>
35#include <asm/asm-offsets.h>
36#include <asm/signal.h>
37#include <asm/sim.h>
38#include <asm/shmparam.h>
39#include <asm/sysmips.h>
40#include <asm/uaccess.h>
41
42asmlinkage int sys_pipe(nabi_no_regargs 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];
54out:
55	return res;
56}
57
58unsigned long shm_align_mask = PAGE_SIZE - 1;	/* Sane caches */
59
60EXPORT_SYMBOL(shm_align_mask);
61
62#define COLOUR_ALIGN(addr,pgoff)				\
63	((((addr) + shm_align_mask) & ~shm_align_mask) +	\
64	 (((pgoff) << PAGE_SHIFT) & shm_align_mask))
65
66unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
67	unsigned long len, unsigned long pgoff, unsigned long flags)
68{
69	struct vm_area_struct * vmm;
70	int do_color_align;
71	unsigned long task_size;
72
73	task_size = STACK_TOP;
74
75	if (flags & MAP_FIXED) {
76		/*
77		 * We do not accept a shared mapping if it would violate
78		 * cache aliasing constraints.
79		 */
80		if ((flags & MAP_SHARED) && (addr & shm_align_mask))
81			return -EINVAL;
82		return addr;
83	}
84
85	if (len > task_size)
86		return -ENOMEM;
87	do_color_align = 0;
88	if (filp || (flags & MAP_SHARED))
89		do_color_align = 1;
90	if (addr) {
91		if (do_color_align)
92			addr = COLOUR_ALIGN(addr, pgoff);
93		else
94			addr = PAGE_ALIGN(addr);
95		vmm = find_vma(current->mm, addr);
96		if (task_size - len >= addr &&
97		    (!vmm || addr + len <= vmm->vm_start))
98			return addr;
99	}
100	addr = TASK_UNMAPPED_BASE;
101	if (do_color_align)
102		addr = COLOUR_ALIGN(addr, pgoff);
103	else
104		addr = PAGE_ALIGN(addr);
105
106	for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
107		/* At this point:  (!vmm || addr < vmm->vm_end). */
108		if (task_size - len < addr)
109			return -ENOMEM;
110		if (!vmm || addr + len <= vmm->vm_start)
111			return addr;
112		addr = vmm->vm_end;
113		if (do_color_align)
114			addr = COLOUR_ALIGN(addr, pgoff);
115	}
116}
117
118/* common code for old and new mmaps */
119static inline unsigned long
120do_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
121        unsigned long flags, unsigned long fd, unsigned long pgoff)
122{
123	unsigned long error = -EBADF;
124	struct file * file = NULL;
125
126	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
127	if (!(flags & MAP_ANONYMOUS)) {
128		file = fget(fd);
129		if (!file)
130			goto out;
131	}
132
133	down_write(&current->mm->mmap_sem);
134	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
135	up_write(&current->mm->mmap_sem);
136
137	if (file)
138		fput(file);
139out:
140	return error;
141}
142
143asmlinkage unsigned long
144old_mmap(unsigned long addr, unsigned long len, int prot,
145	int flags, int fd, off_t offset)
146{
147	unsigned long result;
148
149	result = -EINVAL;
150	if (offset & ~PAGE_MASK)
151		goto out;
152
153	result = do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
154
155out:
156	return result;
157}
158
159asmlinkage unsigned long
160sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
161          unsigned long flags, unsigned long fd, unsigned long pgoff)
162{
163	if (pgoff & (~PAGE_MASK >> 12))
164		return -EINVAL;
165
166	return do_mmap2(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT-12));
167}
168
169save_static_function(sys_fork);
170__attribute_used__ noinline static int
171_sys_fork(nabi_no_regargs struct pt_regs regs)
172{
173	return do_fork(SIGCHLD, regs.regs[29], &regs, 0, NULL, NULL);
174}
175
176save_static_function(sys_clone);
177__attribute_used__ noinline static int
178_sys_clone(nabi_no_regargs struct pt_regs regs)
179{
180	unsigned long clone_flags;
181	unsigned long newsp;
182	int __user *parent_tidptr, *child_tidptr;
183
184	clone_flags = regs.regs[4];
185	newsp = regs.regs[5];
186	if (!newsp)
187		newsp = regs.regs[29];
188	parent_tidptr = (int __user *) regs.regs[6];
189#ifdef CONFIG_32BIT
190	/* We need to fetch the fifth argument off the stack.  */
191	child_tidptr = NULL;
192	if (clone_flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) {
193		int __user *__user *usp = (int __user *__user *) regs.regs[29];
194		if (regs.regs[2] == __NR_syscall) {
195			if (get_user (child_tidptr, &usp[5]))
196				return -EFAULT;
197		}
198		else if (get_user (child_tidptr, &usp[4]))
199			return -EFAULT;
200	}
201#else
202	child_tidptr = (int __user *) regs.regs[8];
203#endif
204	return do_fork(clone_flags, newsp, &regs, 0,
205	               parent_tidptr, child_tidptr);
206}
207
208/*
209 * sys_execve() executes a new program.
210 */
211asmlinkage int sys_execve(nabi_no_regargs struct pt_regs regs)
212{
213	int error;
214	char * filename;
215
216	filename = getname((char __user *) (long)regs.regs[4]);
217	error = PTR_ERR(filename);
218	if (IS_ERR(filename))
219		goto out;
220	error = do_execve(filename, (char __user *__user *) (long)regs.regs[5],
221	                  (char __user *__user *) (long)regs.regs[6], &regs);
222	putname(filename);
223
224out:
225	return error;
226}
227
228/*
229 * Compacrapability ...
230 */
231asmlinkage int sys_uname(struct old_utsname __user * name)
232{
233	if (name && !copy_to_user(name, utsname(), sizeof (*name)))
234		return 0;
235	return -EFAULT;
236}
237
238/*
239 * Compacrapability ...
240 */
241asmlinkage int sys_olduname(struct oldold_utsname __user * name)
242{
243	int error;
244
245	if (!name)
246		return -EFAULT;
247	if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
248		return -EFAULT;
249
250	error = __copy_to_user(&name->sysname, &utsname()->sysname,
251			       __OLD_UTS_LEN);
252	error -= __put_user(0, name->sysname + __OLD_UTS_LEN);
253	error -= __copy_to_user(&name->nodename, &utsname()->nodename,
254				__OLD_UTS_LEN);
255	error -= __put_user(0, name->nodename + __OLD_UTS_LEN);
256	error -= __copy_to_user(&name->release, &utsname()->release,
257				__OLD_UTS_LEN);
258	error -= __put_user(0, name->release + __OLD_UTS_LEN);
259	error -= __copy_to_user(&name->version, &utsname()->version,
260				__OLD_UTS_LEN);
261	error -= __put_user(0, name->version + __OLD_UTS_LEN);
262	error -= __copy_to_user(&name->machine, &utsname()->machine,
263				__OLD_UTS_LEN);
264	error = __put_user(0, name->machine + __OLD_UTS_LEN);
265	error = error ? -EFAULT : 0;
266
267	return error;
268}
269
270asmlinkage int sys_set_thread_area(unsigned long addr)
271{
272	struct thread_info *ti = task_thread_info(current);
273
274	ti->tp_value = addr;
275
276	/* If some future MIPS implementation has this register in hardware,
277	 * we will need to update it here (and in context switches).  */
278
279	return 0;
280}
281
282asmlinkage int _sys_sysmips(int cmd, long arg1, int arg2, int arg3)
283{
284	int	tmp;
285
286	switch(cmd) {
287	case MIPS_ATOMIC_SET:
288		printk(KERN_CRIT "How did I get here?\n");
289		return -EINVAL;
290
291	case MIPS_FIXADE:
292		tmp = current->thread.mflags & ~3;
293		current->thread.mflags = tmp | (arg1 & 3);
294		return 0;
295
296	case FLUSH_CACHE:
297		__flush_cache_all();
298		return 0;
299	}
300
301	return -EINVAL;
302}
303
304/*
305 * sys_ipc() is the de-multiplexer for the SysV IPC calls..
306 *
307 * This is really horribly ugly.
308 */
309asmlinkage int sys_ipc (unsigned int call, int first, int second,
310			unsigned long third, void __user *ptr, long fifth)
311{
312	int version, ret;
313
314	version = call >> 16; /* hack for backward compatibility */
315	call &= 0xffff;
316
317	switch (call) {
318	case SEMOP:
319		return sys_semtimedop (first, (struct sembuf __user *)ptr,
320		                       second, NULL);
321	case SEMTIMEDOP:
322		return sys_semtimedop (first, (struct sembuf __user *)ptr,
323				       second,
324				       (const struct timespec __user *)fifth);
325	case SEMGET:
326		return sys_semget (first, second, third);
327	case SEMCTL: {
328		union semun fourth;
329		if (!ptr)
330			return -EINVAL;
331		if (get_user(fourth.__pad, (void __user *__user *) ptr))
332			return -EFAULT;
333		return sys_semctl (first, second, third, fourth);
334	}
335
336	case MSGSND:
337		return sys_msgsnd (first, (struct msgbuf __user *) ptr,
338				   second, third);
339	case MSGRCV:
340		switch (version) {
341		case 0: {
342			struct ipc_kludge tmp;
343			if (!ptr)
344				return -EINVAL;
345
346			if (copy_from_user(&tmp,
347					   (struct ipc_kludge __user *) ptr,
348					   sizeof (tmp)))
349				return -EFAULT;
350			return sys_msgrcv (first, tmp.msgp, second,
351					   tmp.msgtyp, third);
352		}
353		default:
354			return sys_msgrcv (first,
355					   (struct msgbuf __user *) ptr,
356					   second, fifth, third);
357		}
358	case MSGGET:
359		return sys_msgget ((key_t) first, second);
360	case MSGCTL:
361		return sys_msgctl (first, second,
362				   (struct msqid_ds __user *) ptr);
363
364	case SHMAT:
365		switch (version) {
366		default: {
367			unsigned long raddr;
368			ret = do_shmat (first, (char __user *) ptr, second,
369					&raddr);
370			if (ret)
371				return ret;
372			return put_user (raddr, (unsigned long __user *) third);
373		}
374		case 1:	/* iBCS2 emulator entry point */
375			if (!segment_eq(get_fs(), get_ds()))
376				return -EINVAL;
377			return do_shmat (first, (char __user *) ptr, second,
378					 (unsigned long *) third);
379		}
380	case SHMDT:
381		return sys_shmdt ((char __user *)ptr);
382	case SHMGET:
383		return sys_shmget (first, second, third);
384	case SHMCTL:
385		return sys_shmctl (first, second,
386				   (struct shmid_ds __user *) ptr);
387	default:
388		return -ENOSYS;
389	}
390}
391
392/*
393 * No implemented yet ...
394 */
395asmlinkage int sys_cachectl(char *addr, int nbytes, int op)
396{
397	return -ENOSYS;
398}
399
400/*
401 * If we ever come here the user sp is bad.  Zap the process right away.
402 * Due to the bad stack signaling wouldn't work.
403 */
404asmlinkage void bad_stack(void)
405{
406	do_exit(SIGSEGV);
407}
408
409/*
410 * Do a system call from kernel instead of calling sys_execve so we
411 * end up with proper pt_regs.
412 */
413int kernel_execve(const char *filename, char *const argv[], char *const envp[])
414{
415	register unsigned long __a0 asm("$4") = (unsigned long) filename;
416	register unsigned long __a1 asm("$5") = (unsigned long) argv;
417	register unsigned long __a2 asm("$6") = (unsigned long) envp;
418	register unsigned long __a3 asm("$7");
419	unsigned long __v0;
420
421	__asm__ volatile ("					\n"
422	"	.set	noreorder				\n"
423	"	li	$2, %5		# __NR_execve		\n"
424	"	syscall						\n"
425	"	move	%0, $2					\n"
426	"	.set	reorder					\n"
427	: "=&r" (__v0), "=r" (__a3)
428	: "r" (__a0), "r" (__a1), "r" (__a2), "i" (__NR_execve)
429	: "$2", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24",
430	  "memory");
431
432	if (__a3 == 0)
433		return __v0;
434
435	return -__v0;
436}
437
438/*
439 * Build the string table for the builtin "poor man's strace".
440 */
441#ifdef CONFIG_PRINT_SYSCALLS
442#define SYS(fun, narg) #fun,
443static char *sfnames[] = {
444#include "syscalls.h"
445};
446
447#ifdef	CONFIG_HWSIM
448int do_strace = 1;
449#else
450int do_strace = 0;
451#endif
452
453asmlinkage void strace(struct pt_regs *regs)
454{
455	int i;
456	unsigned long scn, narg, *pa0;
457	char *name, space[16];
458	extern char sys_call_table[];
459
460	if (do_strace == 0)
461		return;
462
463	scn = regs->regs[2];
464	pa0 = &regs->regs[4];
465
466	if ((scn >= __NR_Linux)  && (scn < (__NR_Linux + __NR_Linux_syscalls))) {
467		name = sfnames[scn - __NR_Linux];
468		narg = *(unsigned long *)(((char *)(&sys_call_table[scn])) + 4);
469	} else {
470		sprintf(space, "sc%lu", scn);
471		name = space;
472		narg = 0;
473	}
474
475	printk("%lu[%s:%d]@0x%08lx: %s(", jiffies, current->comm, current->pid, regs->cp0_epc, name);
476
477	if (narg > 6) narg = 6;
478
479	for (i = 0; i < narg; i++) {
480		if (i) printk(", ");
481		if (i < 4)
482			printk("0x%08lx", pa0[i]);
483		else
484			printk("0x%08lx", regs->pad0[i]);
485	}
486
487	printk(")\n");
488}
489#endif
490