blob: db07793f7b43c1e350403ad135733d70465a6c7e [file] [log] [blame]
Kyle Swenson8d8f6542021-03-15 11:02:55 -06001/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 1994 - 2000, 2001, 2003 Ralf Baechle
7 * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
8 * Copyright (C) 2001 MIPS Technologies, Inc.
9 */
10
11#include <asm/asm.h>
12#include <asm/asmmacro.h>
13#include <asm/compiler.h>
14#include <asm/irqflags.h>
15#include <asm/regdef.h>
16#include <asm/mipsregs.h>
17#include <asm/stackframe.h>
18#include <asm/isadep.h>
19#include <asm/thread_info.h>
20#include <asm/war.h>
21
22#ifndef CONFIG_PREEMPT
23#define resume_kernel restore_all
24#else
25#define __ret_from_irq ret_from_exception
26#endif
27
28 .text
29 .align 5
30#ifndef CONFIG_PREEMPT
31FEXPORT(ret_from_exception)
32 local_irq_disable # preempt stop
33 b __ret_from_irq
34#endif
35FEXPORT(ret_from_irq)
36 LONG_S s0, TI_REGS($28)
37FEXPORT(__ret_from_irq)
38/*
39 * We can be coming here from a syscall done in the kernel space,
40 * e.g. a failed kernel_execve().
41 */
42resume_userspace_check:
43 LONG_L t0, PT_STATUS(sp) # returning to kernel mode?
44 andi t0, t0, KU_USER
45 beqz t0, resume_kernel
46
47resume_userspace:
48 local_irq_disable # make sure we dont miss an
49 # interrupt setting need_resched
50 # between sampling and return
51#ifdef CONFIG_MIPSR2_TO_R6_EMULATOR
52 lw k0, TI_R2_EMUL_RET($28)
53 bnez k0, restore_all_from_r2_emul
54#endif
55
56 LONG_L a2, TI_FLAGS($28) # current->work
57 andi t0, a2, _TIF_WORK_MASK # (ignoring syscall_trace)
58 bnez t0, work_pending
59 j restore_all
60
61#ifdef CONFIG_PREEMPT
62resume_kernel:
63 local_irq_disable
64 lw t0, TI_PRE_COUNT($28)
65 bnez t0, restore_all
66need_resched:
67 LONG_L t0, TI_FLAGS($28)
68 andi t1, t0, _TIF_NEED_RESCHED
69 beqz t1, restore_all
70 LONG_L t0, PT_STATUS(sp) # Interrupts off?
71 andi t0, 1
72 beqz t0, restore_all
73 jal preempt_schedule_irq
74 b need_resched
75#endif
76
77FEXPORT(ret_from_kernel_thread)
78 jal schedule_tail # a0 = struct task_struct *prev
79 move a0, s1
80 jal s0
81 j syscall_exit
82
83FEXPORT(ret_from_fork)
84 jal schedule_tail # a0 = struct task_struct *prev
85
86FEXPORT(syscall_exit)
87 local_irq_disable # make sure need_resched and
88 # signals dont change between
89 # sampling and return
90 LONG_L a2, TI_FLAGS($28) # current->work
91 li t0, _TIF_ALLWORK_MASK
92 and t0, a2, t0
93 bnez t0, syscall_exit_work
94
95restore_all: # restore full frame
96 .set noat
97 RESTORE_TEMP
98 RESTORE_AT
99 RESTORE_STATIC
100restore_partial: # restore partial frame
101#ifdef CONFIG_TRACE_IRQFLAGS
102 SAVE_STATIC
103 SAVE_AT
104 SAVE_TEMP
105 LONG_L v0, PT_STATUS(sp)
106#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
107 and v0, ST0_IEP
108#else
109 and v0, ST0_IE
110#endif
111 beqz v0, 1f
112 jal trace_hardirqs_on
113 b 2f
1141: jal trace_hardirqs_off
1152:
116 RESTORE_TEMP
117 RESTORE_AT
118 RESTORE_STATIC
119#endif
120 RESTORE_SOME
121 RESTORE_SP_AND_RET
122 .set at
123
124#ifdef CONFIG_MIPSR2_TO_R6_EMULATOR
125restore_all_from_r2_emul: # restore full frame
126 .set noat
127 sw zero, TI_R2_EMUL_RET($28) # reset it
128 RESTORE_TEMP
129 RESTORE_AT
130 RESTORE_STATIC
131 RESTORE_SOME
132 LONG_L sp, PT_R29(sp)
133 eretnc
134 .set at
135#endif
136
137work_pending:
138 andi t0, a2, _TIF_NEED_RESCHED # a2 is preloaded with TI_FLAGS
139 beqz t0, work_notifysig
140work_resched:
141 TRACE_IRQS_OFF
142 jal schedule
143
144 local_irq_disable # make sure need_resched and
145 # signals dont change between
146 # sampling and return
147 LONG_L a2, TI_FLAGS($28)
148 andi t0, a2, _TIF_WORK_MASK # is there any work to be done
149 # other than syscall tracing?
150 beqz t0, restore_all
151 andi t0, a2, _TIF_NEED_RESCHED
152 bnez t0, work_resched
153
154work_notifysig: # deal with pending signals and
155 # notify-resume requests
156 move a0, sp
157 li a1, 0
158 jal do_notify_resume # a2 already loaded
159 j resume_userspace_check
160
161FEXPORT(syscall_exit_partial)
162 local_irq_disable # make sure need_resched doesn't
163 # change between and return
164 LONG_L a2, TI_FLAGS($28) # current->work
165 li t0, _TIF_ALLWORK_MASK
166 and t0, a2
167 beqz t0, restore_partial
168 SAVE_STATIC
169syscall_exit_work:
170 LONG_L t0, PT_STATUS(sp) # returning to kernel mode?
171 andi t0, t0, KU_USER
172 beqz t0, resume_kernel
173 li t0, _TIF_WORK_SYSCALL_EXIT
174 and t0, a2 # a2 is preloaded with TI_FLAGS
175 beqz t0, work_pending # trace bit set?
176 local_irq_enable # could let syscall_trace_leave()
177 # call schedule() instead
178 TRACE_IRQS_ON
179 move a0, sp
180 jal syscall_trace_leave
181 b resume_userspace
182
183#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) || \
184 defined(CONFIG_MIPS_MT)
185
186/*
187 * MIPS32R2 Instruction Hazard Barrier - must be called
188 *
189 * For C code use the inline version named instruction_hazard().
190 */
191LEAF(mips_ihb)
192 .set MIPS_ISA_LEVEL_RAW
193 jr.hb ra
194 nop
195 END(mips_ihb)
196
197#endif /* CONFIG_CPU_MIPSR2 or CONFIG_CPU_MIPSR6 or CONFIG_MIPS_MT */