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