1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (C) 2005-2017 Andes Technology Corporation
4 #include <linux/linkage.h>
5 #include <asm/unistd.h>
6 #include <asm/assembler.h>
8 #include <asm/asm-offsets.h>
9 #include <asm/thread_info.h>
10 #include <asm/current.h>
22 .macro restore_user_regs_first
26 addi $sp, $sp, FUCOP_CTL_OFFSET
28 lmw.adm $r12, [$sp], $r24, #0x0
40 lmw.adm $sp, [$sp], $sp, #0xe
43 .macro restore_user_regs_last
52 .macro restore_user_regs
53 restore_user_regs_first
54 lmw.adm $r0, [$sp], $r25, #0x0
55 addi $sp, $sp, OSP_OFFSET
56 restore_user_regs_last
59 .macro fast_restore_user_regs
60 restore_user_regs_first
61 lmw.adm $r1, [$sp], $r25, #0x0
62 addi $sp, $sp, OSP_OFFSET-4
63 restore_user_regs_last
74 #define resume_kernel no_work_pending
77 ENTRY(ret_from_exception)
82 * judge Kernel or user mode
85 lwi $p0, [$sp+(#IPSW_OFFSET)] ! Check if in nested interrupt
86 andi $p0, $p0, #PSW_mskINTL
87 bnez $p0, resume_kernel ! done with iret
92 * This is the fast syscall return path. We do as little as
93 * possible here, and this includes saving $r0 back into the SVC
95 * fixed: tsk - $r25, syscall # - $r7, syscall table pointer - $r8
97 ENTRY(ret_fast_syscall)
99 lwi $r1, [tsk+#TSK_TI_FLAGS]
100 andi $p1, $r1, #_TIF_WORK_MASK
101 bnez $p1, fast_work_pending
102 fast_restore_user_regs ! iret
105 * Ok, we need to do extra processing,
106 * enter the slow path returning from syscall, while pending work.
109 swi $r0, [$sp+(#R0_OFFSET)] ! what is different from ret_from_exception
111 andi $p1, $r1, #_TIF_NEED_RESCHED
112 bnez $p1, work_resched
114 andi $p1, $r1, #_TIF_SIGPENDING|#_TIF_NOTIFY_RESUME
115 beqz $p1, no_work_pending
117 move $r0, $sp ! 'regs'
122 bal schedule ! path, return to user mode
125 * "slow" syscall return path.
127 ENTRY(resume_userspace)
128 ENTRY(ret_slow_syscall)
130 lwi $p0, [$sp+(#IPSW_OFFSET)] ! Check if in nested interrupt
131 andi $p0, $p0, #PSW_mskINTL
132 bnez $p0, no_work_pending ! done with iret
133 lwi $r1, [tsk+#TSK_TI_FLAGS]
134 andi $p1, $r1, #_TIF_WORK_MASK
135 bnez $p1, work_pending ! handle work_resched, sig_pend
138 #ifdef CONFIG_TRACE_IRQFLAGS
139 lwi $p0, [$sp+(#IPSW_OFFSET)]
141 la $r10, __trace_hardirqs_off
142 la $r9, __trace_hardirqs_on
146 restore_user_regs ! return from iret
152 #ifdef CONFIG_PREEMPT
155 lwi $t0, [tsk+#TSK_TI_PREEMPT]
156 bnez $t0, no_work_pending
158 lwi $t0, [tsk+#TSK_TI_FLAGS]
159 andi $p1, $t0, #_TIF_NEED_RESCHED
160 beqz $p1, no_work_pending
162 lwi $t0, [$sp+(#IPSW_OFFSET)] ! Interrupts off?
164 beqz $t0, no_work_pending
166 jal preempt_schedule_irq
171 * This is how we return from a fork.
175 beqz $r6, 1f ! r6 stores fn for kernel thread
176 move $r0, $r7 ! prepare kernel thread arg
179 lwi $r1, [tsk+#TSK_TI_FLAGS] ! check for syscall tracing
180 andi $p1, $r1, #_TIF_WORK_SYSCALL_LEAVE ! are we tracing syscalls?
181 beqz $p1, ret_slow_syscall
183 bal syscall_trace_leave