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-99, 2000- 02, 06 Ralf Baechle <ralf@linux-mips.org>
7  * Copyright (C) 2001 MIPS Technologies, Inc.
8  * Copyright (C) 2004 Thiemo Seufer
9  * Copyright (C) 2014 Imagination Technologies Ltd.
10  */
11 #include <linux/errno.h>
12 #include <asm/asm.h>
13 #include <asm/asmmacro.h>
14 #include <asm/irqflags.h>
15 #include <asm/mipsregs.h>
16 #include <asm/regdef.h>
17 #include <asm/stackframe.h>
18 #include <asm/isadep.h>
19 #include <asm/sysmips.h>
20 #include <asm/thread_info.h>
21 #include <asm/unistd.h>
22 #include <asm/war.h>
23 #include <asm/asm-offsets.h>
24 
25 	.align	5
26 NESTED(handle_sys, PT_SIZE, sp)
27 	.set	noat
28 	SAVE_SOME
29 	TRACE_IRQS_ON_RELOAD
30 	STI
31 	.set	at
32 
33 	lw	t1, PT_EPC(sp)		# skip syscall on return
34 
35 	addiu	t1, 4			# skip to next instruction
36 	sw	t1, PT_EPC(sp)
37 
38 	sw	a3, PT_R26(sp)		# save a3 for syscall restarting
39 
40 	/*
41 	 * More than four arguments.  Try to deal with it by copying the
42 	 * stack arguments from the user stack to the kernel stack.
43 	 * This Sucks (TM).
44 	 */
45 	lw	t0, PT_R29(sp)		# get old user stack pointer
46 
47 	/*
48 	 * We intentionally keep the kernel stack a little below the top of
49 	 * userspace so we don't have to do a slower byte accurate check here.
50 	 */
51 	lw	t5, TI_ADDR_LIMIT($28)
52 	addu	t4, t0, 32
53 	and	t5, t4
54 	bltz	t5, bad_stack		# -> sp is bad
55 
56 	/*
57 	 * Ok, copy the args from the luser stack to the kernel stack.
58 	 */
59 
60 	.set    push
61 	.set    noreorder
62 	.set	nomacro
63 
64 load_a4: user_lw(t5, 16(t0))		# argument #5 from usp
65 load_a5: user_lw(t6, 20(t0))		# argument #6 from usp
66 load_a6: user_lw(t7, 24(t0))		# argument #7 from usp
67 load_a7: user_lw(t8, 28(t0))		# argument #8 from usp
68 loads_done:
69 
70 	sw	t5, 16(sp)		# argument #5 to ksp
71 	sw	t6, 20(sp)		# argument #6 to ksp
72 	sw	t7, 24(sp)		# argument #7 to ksp
73 	sw	t8, 28(sp)		# argument #8 to ksp
74 	.set	pop
75 
76 	.section __ex_table,"a"
77 	PTR	load_a4, bad_stack_a4
78 	PTR	load_a5, bad_stack_a5
79 	PTR	load_a6, bad_stack_a6
80 	PTR	load_a7, bad_stack_a7
81 	.previous
82 
83 	lw	t0, TI_FLAGS($28)	# syscall tracing enabled?
84 	li	t1, _TIF_WORK_SYSCALL_ENTRY
85 	and	t0, t1
86 	bnez	t0, syscall_trace_entry # -> yes
87 syscall_common:
88 	subu	v0, v0, __NR_O32_Linux	# check syscall number
89 	sltiu	t0, v0, __NR_O32_Linux_syscalls
90 	beqz	t0, illegal_syscall
91 
92 	sll	t0, v0, 2
93 	la	t1, sys_call_table
94 	addu	t1, t0
95 	lw	t2, (t1)		# syscall routine
96 
97 	beqz	t2, illegal_syscall
98 
99 	jalr	t2			# Do The Real Thing (TM)
100 
101 	li	t0, -EMAXERRNO - 1	# error?
102 	sltu	t0, t0, v0
103 	sw	t0, PT_R7(sp)		# set error flag
104 	beqz	t0, 1f
105 
106 	lw	t1, PT_R2(sp)		# syscall number
107 	negu	v0			# error
108 	sw	t1, PT_R0(sp)		# save it for syscall restarting
109 1:	sw	v0, PT_R2(sp)		# result
110 
111 o32_syscall_exit:
112 	j	syscall_exit_partial
113 
114 /* ------------------------------------------------------------------------ */
115 
116 syscall_trace_entry:
117 	SAVE_STATIC
118 	move	a0, sp
119 
120 	/*
121 	 * syscall number is in v0 unless we called syscall(__NR_###)
122 	 * where the real syscall number is in a0
123 	 */
124 	move	a1, v0
125 	subu	t2, v0,  __NR_O32_Linux
126 	bnez	t2, 1f /* __NR_syscall at offset 0 */
127 	lw	a1, PT_R4(sp)
128 
129 1:	jal	syscall_trace_enter
130 
131 	bltz	v0, 1f			# seccomp failed? Skip syscall
132 
133 	RESTORE_STATIC
134 	lw	v0, PT_R2(sp)		# Restore syscall (maybe modified)
135 	lw	a0, PT_R4(sp)		# Restore argument registers
136 	lw	a1, PT_R5(sp)
137 	lw	a2, PT_R6(sp)
138 	lw	a3, PT_R7(sp)
139 	j	syscall_common
140 
141 1:	j	syscall_exit
142 
143 /* ------------------------------------------------------------------------ */
144 
145 	/*
146 	 * Our open-coded access area sanity test for the stack pointer
147 	 * failed. We probably should handle this case a bit more drastic.
148 	 */
149 bad_stack:
150 	li	v0, EFAULT
151 	sw	v0, PT_R2(sp)
152 	li	t0, 1				# set error flag
153 	sw	t0, PT_R7(sp)
154 	j	o32_syscall_exit
155 
156 bad_stack_a4:
157 	li	t5, 0
158 	b	load_a5
159 
160 bad_stack_a5:
161 	li	t6, 0
162 	b	load_a6
163 
164 bad_stack_a6:
165 	li	t7, 0
166 	b	load_a7
167 
168 bad_stack_a7:
169 	li	t8, 0
170 	b	loads_done
171 
172 	/*
173 	 * The system call does not exist in this kernel
174 	 */
175 illegal_syscall:
176 	li	v0, ENOSYS			# error
177 	sw	v0, PT_R2(sp)
178 	li	t0, 1				# set error flag
179 	sw	t0, PT_R7(sp)
180 	j	o32_syscall_exit
181 	END(handle_sys)
182 
183 	LEAF(sys_syscall)
184 	subu	t0, a0, __NR_O32_Linux	# check syscall number
185 	sltiu	v0, t0, __NR_O32_Linux_syscalls
186 	beqz	t0, einval		# do not recurse
187 	sll	t1, t0, 2
188 	beqz	v0, einval
189 	lw	t2, sys_call_table(t1)		# syscall routine
190 
191 	move	a0, a1				# shift argument registers
192 	move	a1, a2
193 	move	a2, a3
194 	lw	a3, 16(sp)
195 	lw	t4, 20(sp)
196 	lw	t5, 24(sp)
197 	lw	t6, 28(sp)
198 	sw	t4, 16(sp)
199 	sw	t5, 20(sp)
200 	sw	t6, 24(sp)
201 	jr	t2
202 	/* Unreached */
203 
204 einval: li	v0, -ENOSYS
205 	jr	ra
206 	END(sys_syscall)
207 
208 #ifdef CONFIG_MIPS_MT_FPAFF
209 	/*
210 	 * For FPU affinity scheduling on MIPS MT processors, we need to
211 	 * intercept sys_sched_xxxaffinity() calls until we get a proper hook
212 	 * in kernel/sched/core.c.  Considered only temporary we only support
213 	 * these hooks for the 32-bit kernel - there is no MIPS64 MT processor
214 	 * atm.
215 	 */
216 #define sys_sched_setaffinity	mipsmt_sys_sched_setaffinity
217 #define sys_sched_getaffinity	mipsmt_sys_sched_getaffinity
218 #endif /* CONFIG_MIPS_MT_FPAFF */
219 
220 #define __SYSCALL(nr, entry) 	PTR entry
221 	.align	2
222 	.type	sys_call_table, @object
223 EXPORT(sys_call_table)
224 #include <asm/syscall_table_32_o32.h>
225 #undef __SYSCALL
226