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