Something went wrong. Try again.
Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348/* SPDX-License-Identifier: GPL-2.0-only *//* * Common Low Level Interrupts/Traps/Exceptions(non-TLB) Handling for ARC * (included from entry-<isa>.S * * Copyright (C) 2014-15 Synopsys, Inc. (www.synopsys.com) * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) */
/*------------------------------------------------------------------ * Function ABI *------------------------------------------------------------------ * * Arguments r0 - r7 * Caller Saved Registers r0 - r12 * Callee Saved Registers r13- r25 * Global Pointer (gp) r26 * Frame Pointer (fp) r27 * Stack Pointer (sp) r28 * Branch link register (blink) r31 *------------------------------------------------------------------ */
;################### Special Sys Call Wrappers ##########################
ENTRY(sys_clone_wrapper) SAVE_CALLEE_SAVED_USER bl @sys_clone DISCARD_CALLEE_SAVED_USER
GET_CURR_THR_INFO_FLAGS r10 and.f 0, r10, _TIF_SYSCALL_WORK bnz tracesys_exit
b .Lret_from_system_callEND(sys_clone_wrapper)
ENTRY(sys_clone3_wrapper) SAVE_CALLEE_SAVED_USER bl @sys_clone3 DISCARD_CALLEE_SAVED_USER
GET_CURR_THR_INFO_FLAGS r10 and.f 0, r10, _TIF_SYSCALL_WORK bnz tracesys_exit
b .Lret_from_system_callEND(sys_clone3_wrapper)
ENTRY(ret_from_fork) ; when the forked child comes here from the __switch_to function ; r0 has the last task pointer. ; put last task in scheduler queue jl @schedule_tail
ld r9, [sp, PT_status32] brne r9, 0, 1f
jl.d [r14] ; kernel thread entry point mov r0, r13 ; (see PF_KTHREAD block in copy_thread)
1: ; Return to user space ; 1. Any forked task (Reach here via BRne above) ; 2. First ever init task (Reach here via return from JL above) ; This is the historic "kernel_execve" use-case, to return to init ; user mode, in a round about way since that is always done from ; a kernel thread which is executed via JL above but always returns ; out whenever kernel_execve (now inline do_fork()) is involved b ret_from_exceptionEND(ret_from_fork)
;################### Non TLB Exception Handling #############################
; ---------------------------------------------; Instruction Error Exception Handler; ---------------------------------------------
ENTRY(instr_service)
EXCEPTION_PROLOGUE
bl do_insterror_or_kprobe b ret_from_exceptionEND(instr_service)
; ---------------------------------------------; Machine Check Exception Handler; ---------------------------------------------
ENTRY(EV_MachineCheck)
EXCEPTION_PROLOGUE_KEEP_AE ; ECR returned in r10
lr r0, [efa] mov r1, sp
; MC exceptions disable MMU ARC_MMU_REENABLE r3
lsr r3, r10, 8 bmsk r3, r3, 7 brne r3, ECR_C_MCHK_DUP_TLB, 1f
bl do_tlb_overlap_fault b ret_from_exception
1: ; DEAD END: can't do much, display Regs and HALT SAVE_CALLEE_SAVED_USER
GET_CURR_TASK_FIELD_PTR TASK_THREAD, r10 st sp, [r10, THREAD_CALLEE_REG]
j do_machine_check_fault
END(EV_MachineCheck)
; ---------------------------------------------; Privilege Violation Exception Handler; ---------------------------------------------ENTRY(EV_PrivilegeV)
EXCEPTION_PROLOGUE
bl do_privilege_fault b ret_from_exceptionEND(EV_PrivilegeV)
; ---------------------------------------------; Extension Instruction Exception Handler; ---------------------------------------------ENTRY(EV_Extension)
EXCEPTION_PROLOGUE
bl do_extension_fault b ret_from_exceptionEND(EV_Extension)
;################ Trap Handling (Syscall, Breakpoint) ##################
; ---------------------------------------------; syscall Tracing; ---------------------------------------------tracesys: ; safekeep EFA (r12) if syscall tracer wanted PC ; for traps, ERET is pre-commit so points to next-PC GET_CURR_TASK_FIELD_PTR TASK_THREAD, r11 st r12, [r11, THREAD_FAULT_ADDR] ; thread.fault_address
; PRE syscall trace hook mov r0, sp ; pt_regs bl @syscall_trace_enter
; Tracing code now returns the syscall num (orig or modif) mov r8, r0
; Do the Sys Call as we normally would. cmp r8, NR_syscalls - 1 mov.hi r0, -ENOSYS bhi tracesys_exit
; Restore the sys-call args. Mere invocation of the hook abv could have ; clobbered them (since they are in scratch regs). The tracer could also ; have deliberately changed the syscall args: r0-r7 ld r0, [sp, PT_r0] ld r1, [sp, PT_r1] ld r2, [sp, PT_r2] ld r3, [sp, PT_r3] ld r4, [sp, PT_r4] ld r5, [sp, PT_r5] ld r6, [sp, PT_r6] ld r7, [sp, PT_r7] ld.as r9, [sys_call_table, r8] jl [r9]
tracesys_exit: st r0, [sp, PT_r0]
; POST syscall trace hook mov r0, sp ; pt_regs needed bl @syscall_trace_exit
; don't call ret_from_system_call as it saves r0, already done above b ret_from_exception
; ---------------------------------------------; Breakpoint TRAP; ---------------------------------------------trap_with_param: mov r0, r12 ; EFA in case ptracer/gdb wants stop_pc mov r1, sp ; pt_regs
; save callee regs in case tracer/gdb wants to peek SAVE_CALLEE_SAVED_USER
; safekeep ref to callee regs GET_CURR_TASK_FIELD_PTR TASK_THREAD, r10 st sp, [r10, THREAD_CALLEE_REG]
; call the non syscall trap handler bl do_non_swi_trap
; unwind stack to discard callee regs DISCARD_CALLEE_SAVED_USER
b ret_from_exception
; ---------------------------------------------; syscall TRAP; ABI: (r0-r7) up to 8 args, (r8) syscall number; ---------------------------------------------
ENTRY(EV_Trap)
EXCEPTION_PROLOGUE_KEEP_AE
lr r12, [efa]
FAKE_RET_FROM_EXCPN
;============ TRAP N : breakpoints, kprobes etc bmsk.f 0, r10, 7 bnz trap_with_param
;============ TRAP 0 (no param): syscall
; syscall tracing ongoing, invoke pre-post-hooks around syscall GET_CURR_THR_INFO_FLAGS r10 and.f 0, r10, _TIF_SYSCALL_WORK bnz tracesys ; this never comes back
;============ Normal syscall case
cmp r8, NR_syscalls - 1 mov.hi r0, -ENOSYS bhi .Lret_from_system_call
ld.as r9,[sys_call_table, r8] jl [r9]
.Lret_from_system_call: st r0, [sp, PT_r0] ; sys call return value in pt_regs
; fall through to ret_from_exceptionEND(EV_Trap)
;############# Return from Intr/Excp/Trap (Linux Specifics) ##############;; If ret to user mode do we need to handle signals, schedule() et al.
ENTRY(ret_from_exception)
; Pre-{IRQ,Trap,Exception} K/U mode from pt_regs->status32 ld r8, [sp, PT_status32] ; returning to User/Kernel Mode
bbit0 r8, STATUS_U_BIT, resume_kernel_mode
; Before returning to User mode check-for-and-complete any pending work ; such as rescheduling/signal-delivery etc.resume_user_mode_begin:
; Disable IRQs to ensures that chk for pending work itself is atomic ; (and we don't end up missing a NEED_RESCHED/SIGPENDING due to an ; interim IRQ). IRQ_DISABLE r10
; Fast Path return to user mode if no pending work GET_CURR_THR_INFO_FLAGS r9 and.f 0, r9, _TIF_WORK_MASK bz .Lrestore_regs
; --- (Slow Path #1) task preemption --- bbit0 r9, TIF_NEED_RESCHED, .Lchk_pend_signals mov blink, resume_user_mode_begin ; tail-call to U mode ret chks j @schedule ; BTST+Bnz causes relo error in link
.Lchk_pend_signals: IRQ_ENABLE r10
; --- (Slow Path #2) pending signal --- mov r0, sp ; pt_regs for arg to do_signal()/do_notify_resume()
GET_CURR_THR_INFO_FLAGS r9 and.f 0, r9, _TIF_SIGPENDING|_TIF_NOTIFY_SIGNAL bz .Lchk_notify_resume
; Normal Trap/IRQ entry only saves Scratch (caller-saved) regs ; in pt_reg since the "C" ABI (kernel code) will automatically ; save/restore callee-saved regs. ; ; However, here we need to explicitly save callee regs because ; (i) If this signal causes coredump - full regfile needed ; (ii) If signal is SIGTRAP/SIGSTOP, task is being traced thus ; tracer might call PEEKUSR(CALLEE reg) ; ; NOTE: SP will grow up by size of CALLEE Reg-File SAVE_CALLEE_SAVED_USER
; save location of saved Callee Regs @ thread_struct->callee GET_CURR_TASK_FIELD_PTR TASK_THREAD, r10 st sp, [r10, THREAD_CALLEE_REG]
bl @do_signal
; Ideally we want to discard the Callee reg above, however if this was ; a tracing signal, tracer could have done a POKEUSR(CALLEE reg) RESTORE_CALLEE_SAVED_USER
b resume_user_mode_begin ; loop back to start of U mode ret
; --- (Slow Path #3) notify_resume ---.Lchk_notify_resume: btst r9, TIF_NOTIFY_RESUME blnz @do_notify_resume b resume_user_mode_begin ; unconditionally back to U mode ret chks ; for single exit point from this block
resume_kernel_mode:
; Disable Interrupts from this point on ; CONFIG_PREEMPTION: This is a must for preempt_schedule_irq() ; !CONFIG_PREEMPTION: To ensure restore_regs is intr safe IRQ_DISABLE r9
#ifdef CONFIG_PREEMPTION
; Can't preempt if preemption disabled GET_CURR_THR_INFO_FROM_SP r10 ld r8, [r10, THREAD_INFO_PREEMPT_COUNT] brne r8, 0, .Lrestore_regs
; check if this task's NEED_RESCHED flag set ld r9, [r10, THREAD_INFO_FLAGS] bbit0 r9, TIF_NEED_RESCHED, .Lrestore_regs
; Invoke PREEMPTION jl preempt_schedule_irq
; preempt_schedule_irq() always returns with IRQ disabled#endif
b .Lrestore_regs
##### DONT ADD CODE HERE - .Lrestore_regs actually follows in entry-<isa>.S