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/asm-offsets.h> |
23 | |
24 | .align 5 |
25 | NESTED(handle_sys, PT_SIZE, sp) |
26 | .set noat |
27 | SAVE_SOME |
28 | TRACE_IRQS_ON_RELOAD |
29 | STI |
30 | .set at |
31 | |
32 | lw t1, PT_EPC(sp) # skip syscall on return |
33 | |
34 | addiu t1, 4 # skip to next instruction |
35 | sw t1, PT_EPC(sp) |
36 | |
37 | sw a3, PT_R26(sp) # save a3 for syscall restarting |
38 | |
39 | /* |
40 | * More than four arguments. Try to deal with it by copying the |
41 | * stack arguments from the user stack to the kernel stack. |
42 | * This Sucks (TM). |
43 | */ |
44 | lw t0, PT_R29(sp) # get old user stack pointer |
45 | |
46 | /* |
47 | * We intentionally keep the kernel stack a little below the top of |
48 | * userspace so we don't have to do a slower byte accurate check here. |
49 | */ |
50 | addu t4, t0, 32 |
51 | bltz t4, bad_stack # -> sp is bad |
52 | |
53 | /* |
54 | * Ok, copy the args from the luser stack to the kernel stack. |
55 | */ |
56 | |
57 | .set push |
58 | .set noreorder |
59 | .set nomacro |
60 | |
61 | load_a4: user_lw(t5, 16(t0)) # argument #5 from usp |
62 | load_a5: user_lw(t6, 20(t0)) # argument #6 from usp |
63 | load_a6: user_lw(t7, 24(t0)) # argument #7 from usp |
64 | load_a7: user_lw(t8, 28(t0)) # argument #8 from usp |
65 | loads_done: |
66 | |
67 | sw t5, 16(sp) # argument #5 to ksp |
68 | sw t6, 20(sp) # argument #6 to ksp |
69 | sw t7, 24(sp) # argument #7 to ksp |
70 | sw t8, 28(sp) # argument #8 to ksp |
71 | .set pop |
72 | |
73 | .section __ex_table,"a" |
74 | PTR_WD load_a4, bad_stack_a4 |
75 | PTR_WD load_a5, bad_stack_a5 |
76 | PTR_WD load_a6, bad_stack_a6 |
77 | PTR_WD load_a7, bad_stack_a7 |
78 | .previous |
79 | |
80 | /* |
81 | * syscall number is in v0 unless we called syscall(__NR_###) |
82 | * where the real syscall number is in a0 |
83 | */ |
84 | subu t2, v0, __NR_O32_Linux |
85 | bnez t2, 1f /* __NR_syscall at offset 0 */ |
86 | LONG_S a0, TI_SYSCALL($28) # Save a0 as syscall number |
87 | b 2f |
88 | 1: |
89 | LONG_S v0, TI_SYSCALL($28) # Save v0 as syscall number |
90 | 2: |
91 | |
92 | lw t0, TI_FLAGS($28) # syscall tracing enabled? |
93 | li t1, _TIF_WORK_SYSCALL_ENTRY |
94 | and t0, t1 |
95 | bnez t0, syscall_trace_entry # -> yes |
96 | syscall_common: |
97 | subu v0, v0, __NR_O32_Linux # check syscall number |
98 | sltiu t0, v0, __NR_O32_Linux_syscalls |
99 | beqz t0, illegal_syscall |
100 | |
101 | sll t0, v0, 2 |
102 | la t1, sys_call_table |
103 | addu t1, t0 |
104 | lw t2, (t1) # syscall routine |
105 | |
106 | beqz t2, illegal_syscall |
107 | |
108 | jalr t2 # Do The Real Thing (TM) |
109 | |
110 | li t0, -EMAXERRNO - 1 # error? |
111 | sltu t0, t0, v0 |
112 | sw t0, PT_R7(sp) # set error flag |
113 | beqz t0, 1f |
114 | |
115 | lw t1, PT_R2(sp) # syscall number |
116 | negu v0 # error |
117 | sw t1, PT_R0(sp) # save it for syscall restarting |
118 | 1: sw v0, PT_R2(sp) # result |
119 | |
120 | o32_syscall_exit: |
121 | j syscall_exit_partial |
122 | |
123 | /* ------------------------------------------------------------------------ */ |
124 | |
125 | syscall_trace_entry: |
126 | SAVE_STATIC |
127 | move a0, sp |
128 | |
129 | 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_WITH_COMPAT(nr, native, compat) __SYSCALL(nr, native) |
221 | #define __SYSCALL(nr, entry) PTR_WD entry |
222 | .align 2 |
223 | .type sys_call_table, @object |
224 | EXPORT(sys_call_table) |
225 | #include <asm/syscall_table_o32.h> |
226 | |