GNU Linux-libre 6.9.1-gnu
[releases.git] / arch / mips / kernel / scall32-o32.S
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>