1 /* SPDX-License-Identifier: GPL-2.0-only */ << 2 /* 1 /* 3 * Common Low Level Interrupts/Traps/Exception !! 2 * This file is subject to the terms and conditions of the GNU General Public 4 * (included from entry-<isa>.S !! 3 * License. See the file "COPYING" in the main directory of this archive >> 4 * for more details. 5 * 5 * 6 * Copyright (C) 2014-15 Synopsys, Inc. (www.s !! 6 * Copyright (C) 1994 - 2000, 2001, 2003 Ralf Baechle 7 * Copyright (C) 2004, 2007-2010, 2011-2012 Sy !! 7 * Copyright (C) 1999, 2000 Silicon Graphics, Inc. >> 8 * Copyright (C) 2001 MIPS Technologies, Inc. 8 */ 9 */ 9 10 10 /*-------------------------------------------- !! 11 #include <asm/asm.h> 11 * Function ABI !! 12 #include <asm/asmmacro.h> 12 *-------------------------------------------- !! 13 #include <asm/compiler.h> 13 * !! 14 #include <asm/irqflags.h> 14 * Arguments r0 - r !! 15 #include <asm/regdef.h> 15 * Caller Saved Registers r0 - r !! 16 #include <asm/mipsregs.h> 16 * Callee Saved Registers r13- r !! 17 #include <asm/stackframe.h> 17 * Global Pointer (gp) r26 !! 18 #include <asm/isadep.h> 18 * Frame Pointer (fp) r27 !! 19 #include <asm/thread_info.h> 19 * Stack Pointer (sp) r28 !! 20 20 * Branch link register (blink) r31 !! 21 #ifndef CONFIG_PREEMPTION 21 *-------------------------------------------- !! 22 #define resume_kernel restore_all 22 */ !! 23 #else 23 !! 24 #define __ret_from_irq ret_from_exception 24 ;################### Special Sys Call Wrappers !! 25 #endif 25 << 26 ENTRY(sys_clone_wrapper) << 27 SAVE_CALLEE_SAVED_USER << 28 bl @sys_clone << 29 DISCARD_CALLEE_SAVED_USER << 30 << 31 GET_CURR_THR_INFO_FLAGS r10 << 32 and.f 0, r10, _TIF_SYSCALL_WORK << 33 bnz tracesys_exit << 34 << 35 b .Lret_from_system_call << 36 END(sys_clone_wrapper) << 37 << 38 ENTRY(sys_clone3_wrapper) << 39 SAVE_CALLEE_SAVED_USER << 40 bl @sys_clone3 << 41 DISCARD_CALLEE_SAVED_USER << 42 << 43 GET_CURR_THR_INFO_FLAGS r10 << 44 and.f 0, r10, _TIF_SYSCALL_WORK << 45 bnz tracesys_exit << 46 << 47 b .Lret_from_system_call << 48 END(sys_clone3_wrapper) << 49 << 50 ENTRY(ret_from_fork) << 51 ; when the forked child comes here fro << 52 ; r0 has the last task pointer. << 53 ; put last task in scheduler queue << 54 jl @schedule_tail << 55 << 56 ld r9, [sp, PT_status32] << 57 brne r9, 0, 1f << 58 << 59 jl.d [r14] ; kernel threa << 60 mov r0, r13 ; (see PF_KTHR << 61 << 62 1: << 63 ; Return to user space << 64 ; 1. Any forked task (Reach here via B << 65 ; 2. First ever init task (Reach here << 66 ; This is the historic "kernel_exec << 67 ; user mode, in a round about way s << 68 ; a kernel thread which is executed << 69 ; out whenever kernel_execve (now i << 70 b ret_from_exception << 71 END(ret_from_fork) << 72 << 73 ;################### Non TLB Exception Handlin << 74 << 75 ; -------------------------------------------- << 76 ; Instruction Error Exception Handler << 77 ; -------------------------------------------- << 78 << 79 ENTRY(instr_service) << 80 << 81 EXCEPTION_PROLOGUE << 82 << 83 bl do_insterror_or_kprobe << 84 b ret_from_exception << 85 END(instr_service) << 86 << 87 ; -------------------------------------------- << 88 ; Machine Check Exception Handler << 89 ; -------------------------------------------- << 90 << 91 ENTRY(EV_MachineCheck) << 92 << 93 EXCEPTION_PROLOGUE_KEEP_AE ; ECR << 94 << 95 lr r0, [efa] << 96 mov r1, sp << 97 << 98 ; MC exceptions disable MMU << 99 ARC_MMU_REENABLE r3 << 100 << 101 lsr r3, r10, 8 << 102 bmsk r3, r3, 7 << 103 brne r3, ECR_C_MCHK_DUP_TLB, 1f << 104 << 105 bl do_tlb_overlap_fault << 106 b ret_from_exception << 107 << 108 1: << 109 ; DEAD END: can't do much, display Reg << 110 SAVE_CALLEE_SAVED_USER << 111 << 112 GET_CURR_TASK_FIELD_PTR TASK_THREAD, << 113 st sp, [r10, THREAD_CALLEE_REG] << 114 << 115 j do_machine_check_fault << 116 << 117 END(EV_MachineCheck) << 118 << 119 ; -------------------------------------------- << 120 ; Privilege Violation Exception Handler << 121 ; -------------------------------------------- << 122 ENTRY(EV_PrivilegeV) << 123 << 124 EXCEPTION_PROLOGUE << 125 << 126 bl do_privilege_fault << 127 b ret_from_exception << 128 END(EV_PrivilegeV) << 129 << 130 ; -------------------------------------------- << 131 ; Extension Instruction Exception Handler << 132 ; -------------------------------------------- << 133 ENTRY(EV_Extension) << 134 << 135 EXCEPTION_PROLOGUE << 136 << 137 bl do_extension_fault << 138 b ret_from_exception << 139 END(EV_Extension) << 140 << 141 ;################ Trap Handling (Syscall, Brea << 142 << 143 ; -------------------------------------------- << 144 ; syscall Tracing << 145 ; -------------------------------------------- << 146 tracesys: << 147 ; safekeep EFA (r12) if syscall tracer << 148 ; for traps, ERET is pre-commit so poi << 149 GET_CURR_TASK_FIELD_PTR TASK_THREAD, << 150 st r12, [r11, THREAD_FAULT_ADDR] << 151 << 152 ; PRE syscall trace hook << 153 mov r0, sp << 154 bl @syscall_trace_enter << 155 << 156 ; Tracing code now returns the syscall << 157 mov r8, r0 << 158 << 159 ; Do the Sys Call as we normally would << 160 cmp r8, NR_syscalls - 1 << 161 mov.hi r0, -ENOSYS << 162 bhi tracesys_exit << 163 << 164 ; Restore the sys-call args. Mere invo << 165 ; clobbered them (since they are in sc << 166 ; have deliberately changed the syscal << 167 ld r0, [sp, PT_r0] << 168 ld r1, [sp, PT_r1] << 169 ld r2, [sp, PT_r2] << 170 ld r3, [sp, PT_r3] << 171 ld r4, [sp, PT_r4] << 172 ld r5, [sp, PT_r5] << 173 ld r6, [sp, PT_r6] << 174 ld r7, [sp, PT_r7] << 175 ld.as r9, [sys_call_table, r8] << 176 jl [r9] << 177 << 178 tracesys_exit: << 179 st r0, [sp, PT_r0] << 180 << 181 ; POST syscall trace hook << 182 mov r0, sp ; pt_regs need << 183 bl @syscall_trace_exit << 184 << 185 ; don't call ret_from_system_call as i << 186 b ret_from_exception << 187 << 188 ; -------------------------------------------- << 189 ; Breakpoint TRAP << 190 ; -------------------------------------------- << 191 trap_with_param: << 192 mov r0, r12 ; EFA in case ptracer/ << 193 mov r1, sp ; pt_regs << 194 << 195 ; save callee regs in case tracer/gdb << 196 SAVE_CALLEE_SAVED_USER << 197 << 198 ; safekeep ref to callee regs << 199 GET_CURR_TASK_FIELD_PTR TASK_THREAD, << 200 st sp, [r10, THREAD_CALLEE_REG] << 201 << 202 ; call the non syscall trap handler << 203 bl do_non_swi_trap << 204 << 205 ; unwind stack to discard callee regs << 206 DISCARD_CALLEE_SAVED_USER << 207 << 208 b ret_from_exception << 209 << 210 ; -------------------------------------------- << 211 ; syscall TRAP << 212 ; ABI: (r0-r7) up to 8 args, (r8) syscall numb << 213 ; -------------------------------------------- << 214 << 215 ENTRY(EV_Trap) << 216 << 217 EXCEPTION_PROLOGUE_KEEP_AE << 218 << 219 lr r12, [efa] << 220 << 221 FAKE_RET_FROM_EXCPN << 222 << 223 ;============ TRAP N : breakpoints, kp << 224 bmsk.f 0, r10, 7 << 225 bnz trap_with_param << 226 << 227 ;============ TRAP 0 (no param): sysca << 228 << 229 ; syscall tracing ongoing, invoke pre- << 230 GET_CURR_THR_INFO_FLAGS r10 << 231 and.f 0, r10, _TIF_SYSCALL_WORK << 232 bnz tracesys ; this never comes bac << 233 << 234 ;============ Normal syscall case << 235 << 236 cmp r8, NR_syscalls - 1 << 237 mov.hi r0, -ENOSYS << 238 bhi .Lret_from_system_call << 239 << 240 ld.as r9,[sys_call_table, r8] << 241 jl [r9] << 242 << 243 .Lret_from_system_call: << 244 st r0, [sp, PT_r0] ; sys call ret << 245 << 246 ; fall through to ret_from_exception << 247 END(EV_Trap) << 248 << 249 ;############# Return from Intr/Excp/Trap (Lin << 250 ; << 251 ; If ret to user mode do we need to handle sig << 252 << 253 ENTRY(ret_from_exception) << 254 << 255 ; Pre-{IRQ,Trap,Exception} K/U mode fr << 256 ld r8, [sp, PT_status32] ; returnin << 257 << 258 bbit0 r8, STATUS_U_BIT, resume_kernel << 259 << 260 ; Before returning to User mode check- << 261 ; such as rescheduling/signal-delivery << 262 resume_user_mode_begin: << 263 << 264 ; Disable IRQs to ensures that chk for << 265 ; (and we don't end up missing a NEED_ << 266 ; interim IRQ). << 267 IRQ_DISABLE r10 << 268 << 269 ; Fast Path return to user mode if no << 270 GET_CURR_THR_INFO_FLAGS r9 << 271 and.f 0, r9, _TIF_WORK_MASK << 272 bz .Lrestore_regs << 273 << 274 ; --- (Slow Path #1) task preemption - << 275 bbit0 r9, TIF_NEED_RESCHED, .Lchk_pen << 276 mov blink, resume_user_mode_begin << 277 j @schedule ; BTST+Bnz cau << 278 << 279 .Lchk_pend_signals: << 280 IRQ_ENABLE r10 << 281 << 282 ; --- (Slow Path #2) pending signal - << 283 mov r0, sp ; pt_regs for arg to d << 284 << 285 GET_CURR_THR_INFO_FLAGS r9 << 286 and.f 0, r9, _TIF_SIGPENDING|_TIF_NO << 287 bz .Lchk_notify_resume << 288 << 289 ; Normal Trap/IRQ entry only saves Scr << 290 ; in pt_reg since the "C" ABI (kernel << 291 ; save/restore callee-saved regs. << 292 ; << 293 ; However, here we need to explicitly << 294 ; (i) If this signal causes coredump << 295 ; (ii) If signal is SIGTRAP/SIGSTOP, t << 296 ; tracer might call PEEKUSR(CALLE << 297 ; << 298 ; NOTE: SP will grow up by size of CAL << 299 SAVE_CALLEE_SAVED_USER << 300 << 301 ; save location of saved Callee Regs @ << 302 GET_CURR_TASK_FIELD_PTR TASK_THREAD, << 303 st sp, [r10, THREAD_CALLEE_REG] << 304 << 305 bl @do_signal << 306 << 307 ; Ideally we want to discard the Calle << 308 ; a tracing signal, tracer could have << 309 RESTORE_CALLEE_SAVED_USER << 310 << 311 b resume_user_mode_begin ; loop << 312 << 313 ; --- (Slow Path #3) notify_resume --- << 314 .Lchk_notify_resume: << 315 btst r9, TIF_NOTIFY_RESUME << 316 blnz @do_notify_resume << 317 b resume_user_mode_begin ; unco << 318 ; for << 319 << 320 resume_kernel_mode: << 321 26 322 ; Disable Interrupts from this point o !! 27 .text 323 ; CONFIG_PREEMPTION: This is a must fo !! 28 .align 5 324 ; !CONFIG_PREEMPTION: To ensure restor !! 29 #ifndef CONFIG_PREEMPTION 325 IRQ_DISABLE r9 !! 30 FEXPORT(ret_from_exception) >> 31 local_irq_disable # preempt stop >> 32 b __ret_from_irq >> 33 #endif >> 34 FEXPORT(ret_from_irq) >> 35 LONG_S s0, TI_REGS($28) >> 36 FEXPORT(__ret_from_irq) >> 37 /* >> 38 * We can be coming here from a syscall done in the kernel space, >> 39 * e.g. a failed kernel_execve(). >> 40 */ >> 41 resume_userspace_check: >> 42 LONG_L t0, PT_STATUS(sp) # returning to kernel mode? >> 43 andi t0, t0, KU_USER >> 44 beqz t0, resume_kernel >> 45 >> 46 resume_userspace: >> 47 local_irq_disable # make sure we dont miss an >> 48 # interrupt setting need_resched >> 49 # between sampling and return >> 50 LONG_L a2, TI_FLAGS($28) # current->work >> 51 andi t0, a2, _TIF_WORK_MASK # (ignoring syscall_trace) >> 52 bnez t0, work_pending >> 53 j restore_all 326 54 327 #ifdef CONFIG_PREEMPTION 55 #ifdef CONFIG_PREEMPTION >> 56 resume_kernel: >> 57 local_irq_disable >> 58 lw t0, TI_PRE_COUNT($28) >> 59 bnez t0, restore_all >> 60 LONG_L t0, TI_FLAGS($28) >> 61 andi t1, t0, _TIF_NEED_RESCHED >> 62 beqz t1, restore_all >> 63 LONG_L t0, PT_STATUS(sp) # Interrupts off? >> 64 andi t0, 1 >> 65 beqz t0, restore_all >> 66 PTR_LA ra, restore_all >> 67 j preempt_schedule_irq >> 68 #endif 328 69 329 ; Can't preempt if preemption disabled !! 70 FEXPORT(ret_from_kernel_thread) 330 GET_CURR_THR_INFO_FROM_SP r10 !! 71 jal schedule_tail # a0 = struct task_struct *prev 331 ld r8, [r10, THREAD_INFO_PREEMPT_COUN !! 72 move a0, s1 332 brne r8, 0, .Lrestore_regs !! 73 jal s0 333 !! 74 j syscall_exit 334 ; check if this task's NEED_RESCHED fl !! 75 335 ld r9, [r10, THREAD_INFO_FLAGS] !! 76 FEXPORT(ret_from_fork) 336 bbit0 r9, TIF_NEED_RESCHED, .Lrestore !! 77 jal schedule_tail # a0 = struct task_struct *prev 337 !! 78 338 ; Invoke PREEMPTION !! 79 FEXPORT(syscall_exit) 339 jl preempt_schedule_irq !! 80 #ifdef CONFIG_DEBUG_RSEQ 340 !! 81 move a0, sp 341 ; preempt_schedule_irq() always return !! 82 jal rseq_syscall >> 83 #endif >> 84 local_irq_disable # make sure need_resched and >> 85 # signals dont change between >> 86 # sampling and return >> 87 LONG_L a2, TI_FLAGS($28) # current->work >> 88 li t0, _TIF_ALLWORK_MASK >> 89 and t0, a2, t0 >> 90 bnez t0, syscall_exit_work >> 91 >> 92 restore_all: # restore full frame >> 93 .set noat >> 94 RESTORE_TEMP >> 95 RESTORE_AT >> 96 RESTORE_STATIC >> 97 restore_partial: # restore partial frame >> 98 #ifdef CONFIG_TRACE_IRQFLAGS >> 99 SAVE_STATIC >> 100 SAVE_AT >> 101 SAVE_TEMP >> 102 LONG_L v0, PT_STATUS(sp) >> 103 #if defined(CONFIG_CPU_R3000) >> 104 and v0, ST0_IEP >> 105 #else >> 106 and v0, ST0_IE 342 #endif 107 #endif >> 108 beqz v0, 1f >> 109 jal trace_hardirqs_on >> 110 b 2f >> 111 1: jal trace_hardirqs_off >> 112 2: >> 113 RESTORE_TEMP >> 114 RESTORE_AT >> 115 RESTORE_STATIC >> 116 #endif >> 117 RESTORE_SOME >> 118 RESTORE_SP_AND_RET >> 119 .set at >> 120 >> 121 work_pending: >> 122 andi t0, a2, _TIF_NEED_RESCHED # a2 is preloaded with TI_FLAGS >> 123 beqz t0, work_notifysig >> 124 work_resched: >> 125 TRACE_IRQS_OFF >> 126 jal schedule >> 127 >> 128 local_irq_disable # make sure need_resched and >> 129 # signals dont change between >> 130 # sampling and return >> 131 LONG_L a2, TI_FLAGS($28) >> 132 andi t0, a2, _TIF_WORK_MASK # is there any work to be done >> 133 # other than syscall tracing? >> 134 beqz t0, restore_all >> 135 andi t0, a2, _TIF_NEED_RESCHED >> 136 bnez t0, work_resched >> 137 >> 138 work_notifysig: # deal with pending signals and >> 139 # notify-resume requests >> 140 move a0, sp >> 141 li a1, 0 >> 142 jal do_notify_resume # a2 already loaded >> 143 j resume_userspace_check >> 144 >> 145 FEXPORT(syscall_exit_partial) >> 146 #ifdef CONFIG_DEBUG_RSEQ >> 147 move a0, sp >> 148 jal rseq_syscall >> 149 #endif >> 150 local_irq_disable # make sure need_resched doesn't >> 151 # change between and return >> 152 LONG_L a2, TI_FLAGS($28) # current->work >> 153 li t0, _TIF_ALLWORK_MASK >> 154 and t0, a2 >> 155 beqz t0, restore_partial >> 156 SAVE_STATIC >> 157 syscall_exit_work: >> 158 LONG_L t0, PT_STATUS(sp) # returning to kernel mode? >> 159 andi t0, t0, KU_USER >> 160 beqz t0, resume_kernel >> 161 li t0, _TIF_WORK_SYSCALL_EXIT >> 162 and t0, a2 # a2 is preloaded with TI_FLAGS >> 163 beqz t0, work_pending # trace bit set? >> 164 local_irq_enable # could let syscall_trace_leave() >> 165 # call schedule() instead >> 166 TRACE_IRQS_ON >> 167 move a0, sp >> 168 jal syscall_trace_leave >> 169 b resume_userspace 343 170 344 b .Lrestore_regs !! 171 #if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR5) || \ >> 172 defined(CONFIG_CPU_MIPSR6) || defined(CONFIG_MIPS_MT) 345 173 346 ##### DONT ADD CODE HERE - .Lrestore_regs actu !! 174 /* >> 175 * MIPS32R2 Instruction Hazard Barrier - must be called >> 176 * >> 177 * For C code use the inline version named instruction_hazard(). >> 178 */ >> 179 LEAF(mips_ihb) >> 180 .set MIPS_ISA_LEVEL_RAW >> 181 jr.hb ra >> 182 nop >> 183 END(mips_ihb) 347 184 >> 185 #endif /* CONFIG_CPU_MIPSR2 - CONFIG_CPU_MIPSR6 or CONFIG_MIPS_MT */
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.