Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0-only */
0002 /*
0003  * Common Low Level Interrupts/Traps/Exceptions(non-TLB) Handling for ARC
0004  * (included from entry-<isa>.S
0005  *
0006  * Copyright (C) 2014-15 Synopsys, Inc. (www.synopsys.com)
0007  * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
0008  */
0009 
0010 /*------------------------------------------------------------------
0011  *    Function                            ABI
0012  *------------------------------------------------------------------
0013  *
0014  *  Arguments                           r0 - r7
0015  *  Caller Saved Registers              r0 - r12
0016  *  Callee Saved Registers              r13- r25
0017  *  Global Pointer (gp)                 r26
0018  *  Frame Pointer (fp)                  r27
0019  *  Stack Pointer (sp)                  r28
0020  *  Branch link register (blink)        r31
0021  *------------------------------------------------------------------
0022  */
0023 
0024 ;################### Special Sys Call Wrappers ##########################
0025 
0026 ENTRY(sys_clone_wrapper)
0027     SAVE_CALLEE_SAVED_USER
0028     bl  @sys_clone
0029     DISCARD_CALLEE_SAVED_USER
0030 
0031     GET_CURR_THR_INFO_FLAGS   r10
0032     and.f 0, r10, _TIF_SYSCALL_WORK
0033     bnz   tracesys_exit
0034 
0035     b .Lret_from_system_call
0036 END(sys_clone_wrapper)
0037 
0038 ENTRY(sys_clone3_wrapper)
0039     SAVE_CALLEE_SAVED_USER
0040     bl  @sys_clone3
0041     DISCARD_CALLEE_SAVED_USER
0042 
0043     GET_CURR_THR_INFO_FLAGS   r10
0044     and.f 0, r10, _TIF_SYSCALL_WORK
0045     bnz   tracesys_exit
0046 
0047     b .Lret_from_system_call
0048 END(sys_clone3_wrapper)
0049 
0050 ENTRY(ret_from_fork)
0051     ; when the forked child comes here from the __switch_to function
0052     ; r0 has the last task pointer.
0053     ; put last task in scheduler queue
0054     jl   @schedule_tail
0055 
0056     ld   r9, [sp, PT_status32]
0057     brne r9, 0, 1f
0058 
0059     jl.d [r14]      ; kernel thread entry point
0060     mov  r0, r13        ; (see PF_KTHREAD block in copy_thread)
0061 
0062 1:
0063     ; Return to user space
0064     ; 1. Any forked task (Reach here via BRne above)
0065     ; 2. First ever init task (Reach here via return from JL above)
0066     ;    This is the historic "kernel_execve" use-case, to return to init
0067     ;    user mode, in a round about way since that is always done from
0068     ;    a kernel thread which is executed via JL above but always returns
0069     ;    out whenever kernel_execve (now inline do_fork()) is involved
0070     b    ret_from_exception
0071 END(ret_from_fork)
0072 
0073 ;################### Non TLB Exception Handling #############################
0074 
0075 ; ---------------------------------------------
0076 ; Instruction Error Exception Handler
0077 ; ---------------------------------------------
0078 
0079 ENTRY(instr_service)
0080 
0081     EXCEPTION_PROLOGUE
0082 
0083     lr  r0, [efa]
0084     mov r1, sp
0085 
0086     FAKE_RET_FROM_EXCPN
0087 
0088     bl  do_insterror_or_kprobe
0089     b   ret_from_exception
0090 END(instr_service)
0091 
0092 ; ---------------------------------------------
0093 ; Machine Check Exception Handler
0094 ; ---------------------------------------------
0095 
0096 ENTRY(EV_MachineCheck)
0097 
0098     EXCEPTION_PROLOGUE
0099 
0100     lr  r2, [ecr]
0101     lr  r0, [efa]
0102     mov r1, sp
0103 
0104     ; MC excpetions disable MMU
0105     ARC_MMU_REENABLE r3
0106 
0107     lsr     r3, r2, 8
0108     bmsk    r3, r3, 7
0109     brne    r3, ECR_C_MCHK_DUP_TLB, 1f
0110 
0111     bl      do_tlb_overlap_fault
0112     b       ret_from_exception
0113 
0114 1:
0115     ; DEAD END: can't do much, display Regs and HALT
0116     SAVE_CALLEE_SAVED_USER
0117 
0118     GET_CURR_TASK_FIELD_PTR   TASK_THREAD, r10
0119     st  sp, [r10, THREAD_CALLEE_REG]
0120 
0121     j  do_machine_check_fault
0122 
0123 END(EV_MachineCheck)
0124 
0125 ; ---------------------------------------------
0126 ; Privilege Violation Exception Handler
0127 ; ---------------------------------------------
0128 ENTRY(EV_PrivilegeV)
0129 
0130     EXCEPTION_PROLOGUE
0131 
0132     lr  r0, [efa]
0133     mov r1, sp
0134 
0135     FAKE_RET_FROM_EXCPN
0136 
0137     bl  do_privilege_fault
0138     b   ret_from_exception
0139 END(EV_PrivilegeV)
0140 
0141 ; ---------------------------------------------
0142 ; Extension Instruction Exception Handler
0143 ; ---------------------------------------------
0144 ENTRY(EV_Extension)
0145 
0146     EXCEPTION_PROLOGUE
0147 
0148     lr  r0, [efa]
0149     mov r1, sp
0150 
0151     FAKE_RET_FROM_EXCPN
0152 
0153     bl  do_extension_fault
0154     b   ret_from_exception
0155 END(EV_Extension)
0156 
0157 ;################ Trap Handling (Syscall, Breakpoint) ##################
0158 
0159 ; ---------------------------------------------
0160 ; syscall Tracing
0161 ; ---------------------------------------------
0162 tracesys:
0163     ; save EFA in case tracer wants the PC of traced task
0164     ; using ERET won't work since next-PC has already committed
0165     GET_CURR_TASK_FIELD_PTR   TASK_THREAD, r11
0166     st  r12, [r11, THREAD_FAULT_ADDR]   ; thread.fault_address
0167 
0168     ; PRE Sys Call Ptrace hook
0169     mov r0, sp          ; pt_regs needed
0170     bl  @syscall_trace_entry
0171 
0172     ; Tracing code now returns the syscall num (orig or modif)
0173     mov r8, r0
0174 
0175     ; Do the Sys Call as we normally would.
0176     ; Validate the Sys Call number
0177     cmp     r8,  NR_syscalls - 1
0178     mov.hi  r0, -ENOSYS
0179     bhi     tracesys_exit
0180 
0181     ; Restore the sys-call args. Mere invocation of the hook abv could have
0182     ; clobbered them (since they are in scratch regs). The tracer could also
0183     ; have deliberately changed the syscall args: r0-r7
0184     ld  r0, [sp, PT_r0]
0185     ld  r1, [sp, PT_r1]
0186     ld  r2, [sp, PT_r2]
0187     ld  r3, [sp, PT_r3]
0188     ld  r4, [sp, PT_r4]
0189     ld  r5, [sp, PT_r5]
0190     ld  r6, [sp, PT_r6]
0191     ld  r7, [sp, PT_r7]
0192     ld.as   r9, [sys_call_table, r8]
0193     jl      [r9]        ; Entry into Sys Call Handler
0194 
0195 tracesys_exit:
0196     st  r0, [sp, PT_r0]     ; sys call return value in pt_regs
0197 
0198     ;POST Sys Call Ptrace Hook
0199     mov r0, sp      ; pt_regs needed
0200     bl  @syscall_trace_exit
0201     b   ret_from_exception ; NOT ret_from_system_call at is saves r0 which
0202     ; we'd done before calling post hook above
0203 
0204 ; ---------------------------------------------
0205 ; Breakpoint TRAP
0206 ; ---------------------------------------------
0207 trap_with_param:
0208     mov r0, r12 ; EFA in case ptracer/gdb wants stop_pc
0209     mov r1, sp
0210 
0211     ; Save callee regs in case gdb wants to have a look
0212     ; SP will grow up by size of CALLEE Reg-File
0213     ; NOTE: clobbers r12
0214     SAVE_CALLEE_SAVED_USER
0215 
0216     ; save location of saved Callee Regs @ thread_struct->pc
0217     GET_CURR_TASK_FIELD_PTR   TASK_THREAD, r10
0218     st  sp, [r10, THREAD_CALLEE_REG]
0219 
0220     ; Call the trap handler
0221     bl  do_non_swi_trap
0222 
0223     ; unwind stack to discard Callee saved Regs
0224     DISCARD_CALLEE_SAVED_USER
0225 
0226     b   ret_from_exception
0227 
0228 ; ---------------------------------------------
0229 ; syscall TRAP
0230 ; ABI: (r0-r7) upto 8 args, (r8) syscall number
0231 ; ---------------------------------------------
0232 
0233 ENTRY(EV_Trap)
0234 
0235     EXCEPTION_PROLOGUE
0236 
0237     lr  r12, [efa]
0238 
0239     FAKE_RET_FROM_EXCPN
0240 
0241     ;============ TRAP 1   :breakpoints
0242     ; Check ECR for trap with arg (PROLOGUE ensures r10 has ECR)
0243     bmsk.f 0, r10, 7
0244     bnz    trap_with_param
0245 
0246     ;============ TRAP  (no param): syscall top level
0247 
0248     ; If syscall tracing ongoing, invoke pre-post-hooks
0249     GET_CURR_THR_INFO_FLAGS   r10
0250     and.f 0, r10, _TIF_SYSCALL_WORK
0251     bnz   tracesys  ; this never comes back
0252 
0253     ;============ Normal syscall case
0254 
0255     ; syscall num shd not exceed the total system calls avail
0256     cmp     r8,  NR_syscalls - 1
0257     mov.hi  r0, -ENOSYS
0258     bhi     .Lret_from_system_call
0259 
0260     ; Offset into the syscall_table and call handler
0261     ld.as   r9,[sys_call_table, r8]
0262     jl      [r9]        ; Entry into Sys Call Handler
0263 
0264 .Lret_from_system_call:
0265 
0266     st  r0, [sp, PT_r0]     ; sys call return value in pt_regs
0267 
0268     ; fall through to ret_from_exception
0269 END(EV_Trap)
0270 
0271 ;############# Return from Intr/Excp/Trap (Linux Specifics) ##############
0272 ;
0273 ; If ret to user mode do we need to handle signals, schedule() et al.
0274 
0275 ENTRY(ret_from_exception)
0276 
0277     ; Pre-{IRQ,Trap,Exception} K/U mode from pt_regs->status32
0278     ld  r8, [sp, PT_status32]   ; returning to User/Kernel Mode
0279 
0280     bbit0  r8, STATUS_U_BIT, resume_kernel_mode
0281 
0282     ; Before returning to User mode check-for-and-complete any pending work
0283     ; such as rescheduling/signal-delivery etc.
0284 resume_user_mode_begin:
0285 
0286     ; Disable IRQs to ensures that chk for pending work itself is atomic
0287     ; (and we don't end up missing a NEED_RESCHED/SIGPENDING due to an
0288     ; interim IRQ).
0289     IRQ_DISABLE r10
0290 
0291     ; Fast Path return to user mode if no pending work
0292     GET_CURR_THR_INFO_FLAGS   r9
0293     and.f  0,  r9, _TIF_WORK_MASK
0294     bz     .Lrestore_regs
0295 
0296     ; --- (Slow Path #1) task preemption ---
0297     bbit0  r9, TIF_NEED_RESCHED, .Lchk_pend_signals
0298     mov    blink, resume_user_mode_begin  ; tail-call to U mode ret chks
0299     j      @schedule    ; BTST+Bnz causes relo error in link
0300 
0301 .Lchk_pend_signals:
0302     IRQ_ENABLE  r10
0303 
0304     ; --- (Slow Path #2) pending signal  ---
0305     mov r0, sp  ; pt_regs for arg to do_signal()/do_notify_resume()
0306 
0307     GET_CURR_THR_INFO_FLAGS   r9
0308     and.f  0,  r9, _TIF_SIGPENDING|_TIF_NOTIFY_SIGNAL
0309     bz .Lchk_notify_resume
0310 
0311     ; Normal Trap/IRQ entry only saves Scratch (caller-saved) regs
0312     ; in pt_reg since the "C" ABI (kernel code) will automatically
0313     ; save/restore callee-saved regs.
0314     ;
0315     ; However, here we need to explicitly save callee regs because
0316     ; (i)  If this signal causes coredump - full regfile needed
0317     ; (ii) If signal is SIGTRAP/SIGSTOP, task is being traced thus
0318     ;      tracer might call PEEKUSR(CALLEE reg)
0319     ;
0320     ; NOTE: SP will grow up by size of CALLEE Reg-File
0321     SAVE_CALLEE_SAVED_USER      ; clobbers r12
0322 
0323     ; save location of saved Callee Regs @ thread_struct->callee
0324     GET_CURR_TASK_FIELD_PTR   TASK_THREAD, r10
0325     st  sp, [r10, THREAD_CALLEE_REG]
0326 
0327     bl  @do_signal
0328 
0329     ; Ideally we want to discard the Callee reg above, however if this was
0330     ; a tracing signal, tracer could have done a POKEUSR(CALLEE reg)
0331     RESTORE_CALLEE_SAVED_USER
0332 
0333     b      resume_user_mode_begin   ; loop back to start of U mode ret
0334 
0335     ; --- (Slow Path #3) notify_resume ---
0336 .Lchk_notify_resume:
0337     btst   r9, TIF_NOTIFY_RESUME
0338     blnz   @do_notify_resume
0339     b      resume_user_mode_begin   ; unconditionally back to U mode ret chks
0340                     ; for single exit point from this block
0341 
0342 resume_kernel_mode:
0343 
0344     ; Disable Interrupts from this point on
0345     ; CONFIG_PREEMPTION: This is a must for preempt_schedule_irq()
0346     ; !CONFIG_PREEMPTION: To ensure restore_regs is intr safe
0347     IRQ_DISABLE r9
0348 
0349 #ifdef CONFIG_PREEMPTION
0350 
0351     ; Can't preempt if preemption disabled
0352     GET_CURR_THR_INFO_FROM_SP   r10
0353     ld  r8, [r10, THREAD_INFO_PREEMPT_COUNT]
0354     brne  r8, 0, .Lrestore_regs
0355 
0356     ; check if this task's NEED_RESCHED flag set
0357     ld  r9, [r10, THREAD_INFO_FLAGS]
0358     bbit0  r9, TIF_NEED_RESCHED, .Lrestore_regs
0359 
0360     ; Invoke PREEMPTION
0361     jl      preempt_schedule_irq
0362 
0363     ; preempt_schedule_irq() always returns with IRQ disabled
0364 #endif
0365 
0366     b   .Lrestore_regs
0367 
0368 ##### DONT ADD CODE HERE - .Lrestore_regs actually follows in entry-<isa>.S
0369