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 * Hairy, the userspace application uses a different argument passing
11 * convention than the kernel, so we have to translate things from o32
12 * to ABI64 calling convention.  64-bit syscalls are also processed
13 * here for now.
14 */
15#include <asm/asm.h>
16#include <linux/errno.h>
17#include <asm/current.h>
18#include <asm/mipsregs.h>
19#include <asm/offset.h>
20#include <asm/regdef.h>
21#include <asm/stackframe.h>
22#include <asm/unistd.h>
23#include <asm/sysmips.h>
24
25	.align  5
26NESTED(handle_sys, PT_SIZE, sp)
27	.set	noat
28	SAVE_SOME
29	STI
30	.set	at
31	ld	t1, PT_EPC(sp)		# skip syscall on return
32
33	subu	t0, v0, __NR_O32_Linux	# check syscall number
34	sltiu	t0, t0, __NR_O32_Linux_syscalls + 1
35	daddiu	t1, 4			# skip to next instruction
36	sd	t1, PT_EPC(sp)
37	beqz	t0, not_o32_scall
38#if 0
39 SAVE_ALL
40 move a1, v0
41 PRINT("Scall %ld\n")
42 RESTORE_ALL
43#endif
44
45	sll	a0, a0, 0
46	sll	a1, a1, 0
47	sll	a2, a2, 0
48	sll	a3, a3, 0
49
50	/* XXX Put both in one cacheline, should save a bit. */
51	dsll	t0, v0, 3		# offset into table
52	ld	t2, (sys_call_table - (__NR_O32_Linux * 8))(t0)
53	lbu	t3, (sys_narg_table - __NR_O32_Linux)(v0)
54
55	subu	t0, t3, 5		# 5 or more arguments?
56	sd	a3, PT_R26(sp)		# save a3 for syscall restarting
57	bgez	t0, stackargs
58
59stack_done:
60		ld	t0, TASK_PTRACE($28)	# syscall tracing enabled?
61		andi	t0, _PT_TRACESYS
62		bnez	t0, trace_a_syscall
63
64		jalr	t2			# Do The Real Thing (TM)
65
66		li	t0, -EMAXERRNO - 1	# error?
67		sltu	t0, t0, v0
68		sd	t0, PT_R7(sp)		# set error flag
69		beqz	t0, 1f
70
71		negu	v0			# error
72		sd	v0, PT_R0(sp)		# flag for syscall restarting
731:		sd	v0, PT_R2(sp)		# result
74
75FEXPORT(o32_ret_from_sys_call)
76		mfc0	t0, CP0_STATUS	# need_resched and signals atomic test
77		ori	t0, t0, 1
78		xori	t0, t0, 1
79		mtc0	t0, CP0_STATUS
80		SSNOP; SSNOP; SSNOP
81
82		ld	t2, TASK_NEED_RESCHED($28)
83		bnez	t2, o32_reschedule
84		lw	v0, TASK_SIGPENDING($28)
85		bnez	v0, signal_return
86
87restore_all:	RESTORE_SOME
88		RESTORE_SP
89		.set	mips3
90		eret
91		.set	mips0
92
93signal_return:
94		.type	signal_return, @function
95
96		mfc0	t0, CP0_STATUS
97		ori	t0, t0, 1
98		mtc0	t0, CP0_STATUS
99
100		SAVE_STATIC
101		move	a0, zero
102		move	a1, sp
103		jal	do_signal
104		RESTORE_STATIC
105		b	restore_all
106
107o32_reschedule:
108		SAVE_STATIC
109		jal	schedule
110		j	ret_from_sys_call
111
112/* ------------------------------------------------------------------------ */
113
114trace_a_syscall:
115	SAVE_STATIC
116	sd	a4, PT_R8(sp)
117	sd	a5, PT_R9(sp)
118	sd	a6, PT_R10(sp)
119	sd	a7, PT_R11(sp)
120
121	sd	t2,PT_R1(sp)
122	jal	syscall_trace
123	ld	t2,PT_R1(sp)
124
125	ld	a0, PT_R4(sp)		# Restore argument registers
126	ld	a1, PT_R5(sp)
127	ld	a2, PT_R6(sp)
128	ld	a3, PT_R7(sp)
129	ld	a4, PT_R8(sp)
130	ld	a5, PT_R9(sp)
131
132	jalr	t2
133
134	li	t0, -EMAXERRNO - 1	# error?
135	sltu	t0, t0, v0
136	sd	t0, PT_R7(sp)		# set error flag
137	beqz	t0, 1f
138
139	negu	v0			# error
140	sd	v0, PT_R0(sp)		# set flag for syscall restarting
1411:	sd	v0, PT_R2(sp)		# result
142
143	jal	syscall_trace
144	j	o32_ret_from_sys_call
145
146/* ------------------------------------------------------------------------ */
147
148	/*
149	 * More than four arguments.  Try to deal with it by copying the
150	 * stack arguments from the user stack to the kernel stack.
151	 * This Sucks (TM).
152	 */
153stackargs:
154	ld	t0, PT_R29(sp)		# get old user stack pointer
155	subu	t3, 4
156	sll	t1, t3, 2		# stack valid?
157
158	addu	t1, t0			# end address
159	or	t0, t1
160	bltz	t0, bad_stack		# -> sp is bad
161
162	ld	t0, PT_R29(sp)		# get old user stack pointer
163	PTR_LA	t1, 3f			# copy 1 to 2 arguments
164	sll	t3, t3, 2
165	subu	t1, t3
166	jr	t1
167
168	/* Ok, copy the args from the luser stack to the kernel stack */
169	.set	push
170	.set	noreorder
171	.set	nomacro
1721:	lw	a5, 20(t0)		# argument #6 from usp
1732:	lw	a4, 16(t0)		# argument #5 from usp
1743:	.set	pop
175
176	j	stack_done		# go back
177
178	.section __ex_table,"a"
179	PTR	1b, bad_stack
180	PTR	2b, bad_stack
181	.previous
182
183	/*
184	 * The stackpointer for a call with more than 4 arguments is bad.
185	 */
186bad_stack:
187	negu	v0				# error
188	sd	v0, PT_R0(sp)
189	sd	v0, PT_R2(sp)
190	li	t0, 1				# set error flag
191	sd	t0, PT_R7(sp)
192	j	ret_from_sys_call
193
194not_o32_scall:
195	/* This is not an o32 compatibility syscall, pass it on to
196	   the 64-bit syscall handlers.  */
197#ifdef CONFIG_MIPS32_N32
198	j	handle_sysn32
199#else
200	j	handle_sys64
201#endif
202
203illegal_syscall:
204	/* This also isn't a 64-bit syscall, throw an error.  */
205	li	v0, ENOSYS			# error
206	sd	v0, PT_R2(sp)
207	li	t0, 1				# set error flag
208	sd	t0, PT_R7(sp)
209	j	ret_from_sys_call
210	END(handle_sys)
211
212LEAF(mips_atomic_set)
213	andi	v0, a1, 3			# must be word aligned
214	bnez	v0, bad_alignment
215
216	ld	v1, THREAD_CURDS($28)		# in legal address range?
217	daddiu	a0, a1, 4
218	or	a0, a0, a1
219	and	a0, a0, v1
220	bnez	a0, bad_address
221
222	/* Ok, this is the ll/sc case.  World is sane :-)  */
2231:	ll	v0, (a1)
224	move	a0, a2
2252:	sc	a0, (a1)
226	beqz	a0, 1b
227
228	.section __ex_table,"a"
229	PTR	1b, bad_stack
230	PTR	2b, bad_stack
231	.previous
232
2331:	sd	v0, PT_R2(sp)		# result
234
235	/* Success, so skip usual error handling garbage.  */
236	ld	t0, TASK_PTRACE($28)	# syscall tracing enabled?
237	andi	t0, _PT_TRACESYS
238	bnez	t0, 1f
239	b	o32_ret_from_sys_call
240
2411:	SAVE_STATIC
242	jal	syscall_trace
243	li	a3, 0			# success
244	j	ret_from_sys_call
245
246bad_address:
247	li	v0, -EFAULT
248	jr	ra
249
250bad_alignment:
251	li	v0, -EINVAL
252	jr	ra
253	END(mips_atomic_set)
254
255LEAF(sys32_sysmips)
256	beq	a0, MIPS_ATOMIC_SET, mips_atomic_set
257	j	sys_sysmips
258	END(sys32_sysmips)
259
260LEAF(sys32_syscall)
261	ld	t0, PT_R29(sp)		# user sp
262
263	sltu	v0, a0, __NR_O32_Linux + __NR_O32_Linux_syscalls + 1
264	beqz	v0, enosys
265
266	dsll	v0, a0, 3
267	dla	v1, sys32_syscall
268	ld	t2, (sys_call_table - (__NR_O32_Linux * 8))(v0)
269	lbu	t3, (sys_narg_table - __NR_O32_Linux)(a0)
270
271	li	v0, -EINVAL
272	beq	t2, v1, out		# do not recurse
273
274	beqz	t2, enosys		# null function pointer?
275
276	andi	v0, t0, 0x3		# unaligned stack pointer?
277	bnez	v0, sigsegv
278
279	daddiu	v0, t0, 16		# v0 = usp + 16
280	daddu	t1, v0, 12		# 3 32-bit arguments
281	ld	v1, THREAD_CURDS($28)
282	or	v0, v0, t1
283	and	v1, v1, v0
284	bnez	v1, efault
285
286	move	a0, a1			# shift argument registers
287	move	a1, a2
288	move	a2, a3
289
2901:	lw	a3, 16(t0)
2912:	lw	t3, 20(t0)
2923:	lw	t1, 24(t0)
293
294	.section __ex_table,"a"
295	PTR	1b, efault
296	PTR	2b, efault
297	PTR	3b, efault
298	.previous
299
300	sw	t3, 16(sp)		# put into new stackframe
301	sw	t1, 20(sp)
302
303	bnez	t1, 1f			# zero arguments?
304	daddu	a0, sp, 32		# then pass sp in a0
3051:
306
307	sw	t3, 16(sp)
308	sw	v1, 20(sp)
309	jr	t2
310	/* Unreached */
311
312enosys:	li	v0, -ENOSYS
313	b	out
314
315sigsegv:
316	li	a0, _SIGSEGV
317	move	a1, $28
318	jal	force_sig
319	/* Fall through */
320
321efault:	li	v0, -EFAULT
322
323out:	jr	ra
324	END(sys32_syscall)
325
326	.macro	syscalltable
327	sys	sys32_syscall	0			/* 4000 */
328	sys	sys_exit	1
329	sys	sys_fork	0
330	sys	sys_read	3
331	sys	sys_write	3
332	sys	sys_open	3			/* 4005 */
333	sys	sys_close	1
334	sys	sys_waitpid	3
335	sys	sys_creat	2
336	sys	sys_link	2
337	sys	sys_unlink	1			/* 4010 */
338	sys	sys32_execve	0
339	sys	sys_chdir	1
340	sys	sys_time	1
341	sys	sys_mknod	3
342	sys	sys_chmod	2			/* 4015 */
343	sys	sys_lchown	3
344	sys	sys_ni_syscall	0
345	sys	sys_ni_syscall	0			/* was sys_stat */
346	sys	sys_lseek	3
347	sys	sys_getpid	0			/* 4020 */
348	sys	sys_mount	5
349	sys	sys_oldumount	1
350	sys	sys_setuid	1
351	sys	sys_getuid	0
352	sys	sys_stime	1			/* 4025 */
353	sys	sys32_ptrace	4
354	sys	sys_alarm	1
355	sys	sys_ni_syscall	0			/* was sys_fstat */
356	sys	sys_pause	0
357	sys	sys32_utime	2			/* 4030 */
358	sys	sys_ni_syscall	0
359	sys	sys_ni_syscall	0
360	sys	sys_access	2
361	sys	sys_nice	1
362	sys	sys_ni_syscall	0			/* 4035 */
363	sys	sys_sync	0
364	sys	sys_kill	2
365	sys	sys_rename	2
366	sys	sys_mkdir	2
367	sys	sys_rmdir	1			/* 4040 */
368	sys	sys_dup		1
369	sys	sys_pipe	0
370	sys	sys32_times	1
371	sys	sys_ni_syscall	0
372	sys	sys_brk		1			/* 4045 */
373	sys	sys_setgid	1
374	sys	sys_getgid	0
375	sys	sys_ni_syscall	0	/* was signal	2 */
376	sys	sys_geteuid	0
377	sys	sys_getegid	0			/* 4050 */
378	sys	sys_acct	0
379	sys	sys_umount	2
380	sys	sys_ni_syscall	0
381	sys	sys32_ioctl	3
382	sys	sys32_fcntl	3			/* 4055 */
383	sys	sys_ni_syscall	2
384	sys	sys_setpgid	2
385	sys	sys_ni_syscall, 0
386	sys	sys_ni_syscall	0	/* was sys_olduname  */
387	sys	sys_umask	1			/* 4060 */
388	sys	sys_chroot	1
389	sys	sys32_ustat	2
390	sys	sys_dup2	2
391	sys	sys_getppid	0
392	sys	sys_getpgrp	0			/* 4065 */
393	sys	sys_setsid	0
394	sys	sys32_sigaction	3
395	sys	sys_sgetmask	0
396	sys	sys_ssetmask	1
397	sys	sys_setreuid	2			/* 4070 */
398	sys	sys_setregid	2
399	sys	sys32_sigsuspend	0
400	sys	sys32_sigpending	1
401	sys	sys_sethostname	2
402	sys	sys32_setrlimit	2			/* 4075 */
403	sys	sys32_getrlimit	2
404	sys	sys32_getrusage	2
405	sys	sys32_gettimeofday 2
406	sys	sys32_settimeofday 2
407	sys	sys_getgroups	2			/* 4080 */
408	sys	sys_setgroups	2
409	sys	sys_ni_syscall	0			/* old_select */
410	sys	sys_symlink	2
411	sys	sys_ni_syscall	0			/* was sys_lstat */
412	sys	sys_readlink	3			/* 4085 */
413	sys	sys_uselib	1
414	sys	sys_swapon	2
415	sys	sys_reboot	3
416	sys	sys32_readdir	3
417	sys	sys_mmap	6			/* 4090 */
418	sys	sys_munmap	2
419	sys	sys_truncate	2
420	sys	sys_ftruncate	2
421	sys	sys_fchmod	2
422	sys	sys_fchown	3			/* 4095 */
423	sys	sys_getpriority	2
424	sys	sys_setpriority	3
425	sys	sys_ni_syscall	0
426	sys	sys32_statfs	2
427	sys	sys32_fstatfs	2			/* 4100 */
428	sys	sys_ni_syscall	0	/* sys_ioperm */
429	sys	sys32_socketcall	2
430	sys	sys_syslog	3
431	sys	sys32_setitimer	3
432	sys	sys32_getitimer	2			/* 4105 */
433	sys	sys32_newstat	2
434	sys	sys32_newlstat	2
435	sys	sys32_newfstat	2
436	sys	sys_ni_syscall	0	/* was sys_uname */
437	sys	sys_ni_syscall	0	/* sys_ioperm  *//* 4110 */
438	sys	sys_vhangup	0
439	sys	sys_ni_syscall	0	/* was sys_idle	 */
440	sys	sys_ni_syscall	0	/* sys_vm86 */
441	sys	sys32_wait4	4
442	sys	sys_swapoff	1			/* 4115 */
443	sys	sys32_sysinfo	1
444	sys	sys32_ipc		6
445	sys	sys_fsync	1
446	sys	sys32_sigreturn	0
447	sys	sys_clone	0			/* 4120 */
448	sys	sys_setdomainname 2
449	sys	sys32_newuname	1
450	sys	sys_ni_syscall	0	/* sys_modify_ldt */
451	sys	sys32_adjtimex	1
452	sys	sys_mprotect	3			/* 4125 */
453	sys	sys32_sigprocmask	3
454	sys	sys32_create_module 2
455	sys	sys32_init_module	5
456	sys	sys32_delete_module 1
457	sys	sys32_get_kernel_syms 1			/* 4130 */
458	sys	sys_quotactl	0
459	sys	sys_getpgid	1
460	sys	sys_fchdir	1
461	sys	sys_bdflush	2
462	sys	sys_sysfs	3			/* 4135 */
463	sys	sys32_personality	1
464	sys	sys_ni_syscall	0 /* for afs_syscall */
465	sys	sys_setfsuid	1
466	sys	sys_setfsgid	1
467	sys	sys32_llseek	5			/* 4140 */
468	sys	sys32_getdents	3
469	sys	sys32_select	5
470	sys	sys_flock	2
471	sys	sys_msync	3
472	sys	sys32_readv	3			/* 4145 */
473	sys	sys32_writev	3
474	sys	sys_cacheflush	3
475	sys	sys_cachectl	3
476	sys	sys32_sysmips	4
477	sys	sys_ni_syscall	0			/* 4150 */
478	sys	sys_getsid	1
479	sys	sys_fdatasync	0
480	sys	sys32_sysctl	1
481	sys	sys_mlock	2
482	sys	sys_munlock	2			/* 4155 */
483	sys	sys_mlockall	1
484	sys	sys_munlockall	0
485	sys	sys_sched_setparam 2
486	sys	sys_sched_getparam 2
487	sys	sys_sched_setscheduler 3		/* 4160 */
488	sys	sys_sched_getscheduler 1
489	sys	sys_sched_yield	0
490	sys	sys_sched_get_priority_max 1
491	sys	sys_sched_get_priority_min 1
492	sys	sys32_sched_rr_get_interval 2		/* 4165 */
493	sys	sys32_nanosleep	2
494	sys	sys_mremap	4
495	sys	sys_accept	3
496	sys	sys_bind	3
497	sys	sys_connect	3			/* 4170 */
498	sys	sys_getpeername	3
499	sys	sys_getsockname	3
500	sys	sys_getsockopt	5
501	sys	sys_listen	2
502	sys	sys_recv	4			/* 4175 */
503	sys	sys_recvfrom	6
504	sys	sys32_recvmsg	3
505	sys	sys_send	4
506	sys	sys32_sendmsg	3
507	sys	sys_sendto	6			/* 4180 */
508	sys	sys32_setsockopt	5
509	sys	sys_shutdown	2
510	sys	sys_socket	3
511	sys	sys_socketpair	4
512	sys	sys_setresuid	3			/* 4185 */
513	sys	sys_getresuid	3
514	sys	sys32_query_module 5
515	sys	sys_poll	3
516	sys	sys_nfsservctl	3
517	sys	sys_setresgid	3			/* 4190 */
518	sys	sys_getresgid	3
519	sys	sys_prctl	5
520	sys	sys32_rt_sigreturn 0
521	sys	sys32_rt_sigaction 4
522	sys	sys32_rt_sigprocmask 4			/* 4195 */
523	sys	sys32_rt_sigpending 2
524	sys	sys32_rt_sigtimedwait 4
525	sys	sys32_rt_sigqueueinfo 3
526	sys	sys32_rt_sigsuspend 0
527	sys	sys32_pread	6			/* 4200 */
528	sys	sys32_pwrite	6
529	sys	sys_chown	3
530	sys	sys_getcwd	2
531	sys	sys_capget	2
532	sys	sys_capset	2			/* 4205 */
533	sys	sys32_sigaltstack	0
534	sys	sys32_sendfile	4
535	sys	sys_ni_syscall	0
536	sys	sys_ni_syscall	0
537	sys	sys32_mmap2	6			/* 4210 */
538	sys	sys32_truncate64	4
539	sys	sys32_ftruncate64	4
540	sys	sys_newstat	2
541	sys	sys_newlstat	2
542	sys	sys_newfstat	2			/* 4215 */
543	sys	sys_pivot_root	2
544	sys	sys_mincore	3
545	sys	sys_madvise	3
546	sys	sys_getdents64	3
547	sys	sys32_fcntl64	3			/* 4220 */
548	sys	sys_ni_syscall	0
549	sys	sys_gettid	0
550	sys	sys32_readahead	5
551	sys	sys_setxattr	5
552	sys	sys_lsetxattr	5		/* 4225 */
553	sys	sys_fsetxattr	5
554	sys	sys_getxattr	4
555	sys	sys_lgetxattr	4
556	sys	sys_fgetxattr	4
557	sys	sys_listxattr	3		/* 4230 */
558	sys	sys_llistxattr	3
559	sys	sys_flistxattr	3
560	sys	sys_removexattr	2
561	sys	sys_lremovexattr 2
562	sys	sys_fremovexattr 2		/* 4235 */
563	sys	sys_tkill, 2
564	sys	sys_sendfile64, 5
565	sys	sys_ni_syscall, 0		/* res. for futex */
566	sys	sys_ni_syscall, 0		/* res. for sched_setaffinity */
567	sys	sys_ni_syscall, 0		/* 4240 res. for sched_getaffinity */
568
569	.endm
570
571	.macro	sys function, nargs
572	PTR	\function
573	.endm
574
575	.align	3
576sys_call_table:
577	syscalltable
578
579	.macro	sys function, nargs
580	.byte	\nargs
581	.endm
582
583sys_narg_table:
584	syscalltable
585