GNU Linux-libre 6.9.1-gnu
[releases.git] / arch / mips / kernel / scall64-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 - 2000, 2001 by Ralf Baechle
7  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
8  * Copyright (C) 2001 MIPS Technologies, Inc.
9  * Copyright (C) 2004 Thiemo Seufer
10  *
11  * Hairy, the userspace application uses a different argument passing
12  * convention than the kernel, so we have to translate things from o32
13  * to ABI64 calling convention.  64-bit syscalls are also processed
14  * here for now.
15  */
16 #include <linux/errno.h>
17 #include <asm/asm.h>
18 #include <asm/asmmacro.h>
19 #include <asm/irqflags.h>
20 #include <asm/mipsregs.h>
21 #include <asm/regdef.h>
22 #include <asm/stackframe.h>
23 #include <asm/thread_info.h>
24 #include <asm/unistd.h>
25 #include <asm/sysmips.h>
26
27         .align  5
28 NESTED(handle_sys, PT_SIZE, sp)
29         .set    noat
30         SAVE_SOME
31         TRACE_IRQS_ON_RELOAD
32         STI
33         .set    at
34         ld      t1, PT_EPC(sp)          # skip syscall on return
35
36         dsubu   t0, v0, __NR_O32_Linux  # check syscall number
37         sltiu   t0, t0, __NR_O32_Linux_syscalls
38         daddiu  t1, 4                   # skip to next instruction
39         sd      t1, PT_EPC(sp)
40         beqz    t0, not_o32_scall
41 #if 0
42  SAVE_ALL
43  move a1, v0
44  ASM_PRINT("Scall %ld\n")
45  RESTORE_ALL
46 #endif
47
48         /* We don't want to stumble over broken sign extensions from
49            userland. O32 does never use the upper half. */
50         sll     a0, a0, 0
51         sll     a1, a1, 0
52         sll     a2, a2, 0
53         sll     a3, a3, 0
54
55         sd      a3, PT_R26(sp)          # save a3 for syscall restarting
56
57         /*
58          * More than four arguments.  Try to deal with it by copying the
59          * stack arguments from the user stack to the kernel stack.
60          * This Sucks (TM).
61          *
62          * We intentionally keep the kernel stack a little below the top of
63          * userspace so we don't have to do a slower byte accurate check here.
64          */
65         ld      t0, PT_R29(sp)          # get old user stack pointer
66         daddu   t1, t0, 32
67         bltz    t1, bad_stack
68
69 load_a4: lw     a4, 16(t0)              # argument #5 from usp
70 load_a5: lw     a5, 20(t0)              # argument #6 from usp
71 load_a6: lw     a6, 24(t0)              # argument #7 from usp
72 load_a7: lw     a7, 28(t0)              # argument #8 from usp
73 loads_done:
74
75         .section __ex_table,"a"
76         PTR_WD  load_a4, bad_stack_a4
77         PTR_WD  load_a5, bad_stack_a5
78         PTR_WD  load_a6, bad_stack_a6
79         PTR_WD  load_a7, bad_stack_a7
80         .previous
81
82         /*
83          * absolute syscall number is in v0 unless we called syscall(__NR_###)
84          * where the real syscall number is in a0
85          * note: NR_syscall is the first O32 syscall but the macro is
86          * only defined when compiling with -mabi=32 (CONFIG_32BIT)
87          * therefore __NR_O32_Linux is used (4000)
88          */
89
90         subu    t2, v0,  __NR_O32_Linux
91         bnez    t2, 1f /* __NR_syscall at offset 0 */
92         LONG_S  a0, TI_SYSCALL($28)     # Save a0 as syscall number
93         b       2f
94 1:
95         LONG_S  v0, TI_SYSCALL($28)     # Save v0 as syscall number
96 2:
97
98         li      t1, _TIF_WORK_SYSCALL_ENTRY
99         LONG_L  t0, TI_FLAGS($28)       # syscall tracing enabled?
100         and     t0, t1, t0
101         bnez    t0, trace_a_syscall
102
103 syscall_common:
104         dsll    t0, v0, 3               # offset into table
105         ld      t2, (sys32_call_table - (__NR_O32_Linux * 8))(t0)
106
107         jalr    t2                      # Do The Real Thing (TM)
108
109         li      t0, -EMAXERRNO - 1      # error?
110         sltu    t0, t0, v0
111         sd      t0, PT_R7(sp)           # set error flag
112         beqz    t0, 1f
113
114         ld      t1, PT_R2(sp)           # syscall number
115         dnegu   v0                      # error
116         sd      t1, PT_R0(sp)           # save it for syscall restarting
117 1:      sd      v0, PT_R2(sp)           # result
118
119 o32_syscall_exit:
120         j       syscall_exit_partial
121
122 /* ------------------------------------------------------------------------ */
123
124 trace_a_syscall:
125         SAVE_STATIC
126         sd      a4, PT_R8(sp)           # Save argument registers
127         sd      a5, PT_R9(sp)
128         sd      a6, PT_R10(sp)
129         sd      a7, PT_R11(sp)          # For indirect syscalls
130
131         move    a0, sp
132         jal     syscall_trace_enter
133
134         bltz    v0, 1f                  # seccomp failed? Skip syscall
135
136         RESTORE_STATIC
137         ld      v0, PT_R2(sp)           # Restore syscall (maybe modified)
138         ld      a0, PT_R4(sp)           # Restore argument registers
139         ld      a1, PT_R5(sp)
140         ld      a2, PT_R6(sp)
141         ld      a3, PT_R7(sp)
142         ld      a4, PT_R8(sp)
143         ld      a5, PT_R9(sp)
144         ld      a6, PT_R10(sp)
145         ld      a7, PT_R11(sp)          # For indirect syscalls
146
147         dsubu   t0, v0, __NR_O32_Linux  # check (new) syscall number
148         sltiu   t0, t0, __NR_O32_Linux_syscalls
149         beqz    t0, not_o32_scall
150
151         j       syscall_common
152
153 1:      j       syscall_exit
154
155 /* ------------------------------------------------------------------------ */
156
157         /*
158          * The stackpointer for a call with more than 4 arguments is bad.
159          */
160 bad_stack:
161         li      v0, EFAULT
162         sd      v0, PT_R2(sp)
163         li      t0, 1                   # set error flag
164         sd      t0, PT_R7(sp)
165         j       o32_syscall_exit
166
167 bad_stack_a4:
168         li      a4, 0
169         b       load_a5
170
171 bad_stack_a5:
172         li      a5, 0
173         b       load_a6
174
175 bad_stack_a6:
176         li      a6, 0
177         b       load_a7
178
179 bad_stack_a7:
180         li      a7, 0
181         b       loads_done
182
183 not_o32_scall:
184         /*
185          * This is not an o32 compatibility syscall, pass it on
186          * to the 64-bit syscall handlers.
187          */
188 #ifdef CONFIG_MIPS32_N32
189         j       handle_sysn32
190 #else
191         j       handle_sys64
192 #endif
193         END(handle_sys)
194
195 LEAF(sys32_syscall)
196         subu    t0, a0, __NR_O32_Linux  # check syscall number
197         sltiu   v0, t0, __NR_O32_Linux_syscalls
198         beqz    t0, einval              # do not recurse
199         dsll    t1, t0, 3
200         beqz    v0, einval
201         ld      t2, sys32_call_table(t1)                # syscall routine
202
203         move    a0, a1                  # shift argument registers
204         move    a1, a2
205         move    a2, a3
206         move    a3, a4
207         move    a4, a5
208         move    a5, a6
209         move    a6, a7
210         jr      t2
211         /* Unreached */
212
213 einval: li      v0, -ENOSYS
214         jr      ra
215         END(sys32_syscall)
216
217 #define __SYSCALL_WITH_COMPAT(nr, native, compat)       __SYSCALL(nr, compat)
218 #define __SYSCALL(nr, entry)    PTR_WD entry
219         .align  3
220         .type   sys32_call_table,@object
221 EXPORT(sys32_call_table)
222 #include <asm/syscall_table_o32.h>