Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
9d42c84f | 2 | /* |
6d1a20b1 VG |
3 | * Common Low Level Interrupts/Traps/Exceptions(non-TLB) Handling for ARC |
4 | * (included from entry-<isa>.S | |
9d42c84f | 5 | * |
6d1a20b1 | 6 | * Copyright (C) 2014-15 Synopsys, Inc. (www.synopsys.com) |
9d42c84f | 7 | * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) |
9d42c84f VG |
8 | */ |
9 | ||
10 | /*------------------------------------------------------------------ | |
11 | * Function ABI | |
12 | *------------------------------------------------------------------ | |
13 | * | |
14 | * Arguments r0 - r7 | |
15 | * Caller Saved Registers r0 - r12 | |
16 | * Callee Saved Registers r13- r25 | |
17 | * Global Pointer (gp) r26 | |
18 | * Frame Pointer (fp) r27 | |
19 | * Stack Pointer (sp) r28 | |
9d42c84f VG |
20 | * Branch link register (blink) r31 |
21 | *------------------------------------------------------------------ | |
22 | */ | |
23 | ||
c7e6d792 VG |
24 | ;################### Special Sys Call Wrappers ########################## |
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 | |
fb0b5490 SM |
32 | and.f 0, r10, _TIF_SYSCALL_WORK |
33 | bnz tracesys_exit | |
c7e6d792 | 34 | |
2dad1122 | 35 | b .Lret_from_system_call |
c7e6d792 VG |
36 | END(sys_clone_wrapper) |
37 | ||
bd71c453 VG |
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 | |
fb0b5490 SM |
44 | and.f 0, r10, _TIF_SYSCALL_WORK |
45 | bnz tracesys_exit | |
bd71c453 VG |
46 | |
47 | b .Lret_from_system_call | |
48 | END(sys_clone3_wrapper) | |
49 | ||
c7e6d792 VG |
50 | ENTRY(ret_from_fork) |
51 | ; when the forked child comes here from the __switch_to function | |
52 | ; r0 has the last task pointer. | |
53 | ; put last task in scheduler queue | |
6de6066c | 54 | jl @schedule_tail |
c7e6d792 VG |
55 | |
56 | ld r9, [sp, PT_status32] | |
57 | brne r9, 0, 1f | |
58 | ||
59 | jl.d [r14] ; kernel thread entry point | |
60 | mov r0, r13 ; (see PF_KTHREAD block in copy_thread) | |
61 | ||
62 | 1: | |
63 | ; Return to user space | |
64 | ; 1. Any forked task (Reach here via BRne above) | |
65 | ; 2. First ever init task (Reach here via return from JL above) | |
66 | ; This is the historic "kernel_execve" use-case, to return to init | |
67 | ; user mode, in a round about way since that is always done from | |
68 | ; a kernel thread which is executed via JL above but always returns | |
69 | ; out whenever kernel_execve (now inline do_fork()) is involved | |
70 | b ret_from_exception | |
71 | END(ret_from_fork) | |
72 | ||
9d42c84f VG |
73 | ;################### Non TLB Exception Handling ############################# |
74 | ||
75 | ; --------------------------------------------- | |
76 | ; Instruction Error Exception Handler | |
77 | ; --------------------------------------------- | |
78 | ||
ec7ac6af | 79 | ENTRY(instr_service) |
9d42c84f | 80 | |
37f3ac49 | 81 | EXCEPTION_PROLOGUE |
9d42c84f | 82 | |
9d42c84f VG |
83 | bl do_insterror_or_kprobe |
84 | b ret_from_exception | |
ec7ac6af | 85 | END(instr_service) |
9d42c84f | 86 | |
9d42c84f VG |
87 | ; --------------------------------------------- |
88 | ; Machine Check Exception Handler | |
89 | ; --------------------------------------------- | |
90 | ||
ec7ac6af | 91 | ENTRY(EV_MachineCheck) |
9d42c84f | 92 | |
13347c10 | 93 | EXCEPTION_PROLOGUE_KEEP_AE ; ECR returned in r10 |
9d42c84f | 94 | |
38a9ff6d VG |
95 | lr r0, [efa] |
96 | mov r1, sp | |
9d42c84f | 97 | |
ebfc2fd8 | 98 | ; MC exceptions disable MMU |
a79a9c76 | 99 | ARC_MMU_REENABLE r3 |
1ee55a8f | 100 | |
0e93ecae | 101 | lsr r3, r10, 8 |
1898a959 VG |
102 | bmsk r3, r3, 7 |
103 | brne r3, ECR_C_MCHK_DUP_TLB, 1f | |
104 | ||
9d42c84f VG |
105 | bl do_tlb_overlap_fault |
106 | b ret_from_exception | |
107 | ||
108 | 1: | |
109 | ; DEAD END: can't do much, display Regs and HALT | |
110 | SAVE_CALLEE_SAVED_USER | |
111 | ||
112 | GET_CURR_TASK_FIELD_PTR TASK_THREAD, r10 | |
113 | st sp, [r10, THREAD_CALLEE_REG] | |
114 | ||
115 | j do_machine_check_fault | |
116 | ||
ec7ac6af | 117 | END(EV_MachineCheck) |
9d42c84f | 118 | |
9d42c84f VG |
119 | ; --------------------------------------------- |
120 | ; Privilege Violation Exception Handler | |
121 | ; --------------------------------------------- | |
ec7ac6af | 122 | ENTRY(EV_PrivilegeV) |
9d42c84f | 123 | |
37f3ac49 | 124 | EXCEPTION_PROLOGUE |
9d42c84f | 125 | |
9d42c84f VG |
126 | bl do_privilege_fault |
127 | b ret_from_exception | |
ec7ac6af | 128 | END(EV_PrivilegeV) |
9d42c84f VG |
129 | |
130 | ; --------------------------------------------- | |
131 | ; Extension Instruction Exception Handler | |
132 | ; --------------------------------------------- | |
ec7ac6af | 133 | ENTRY(EV_Extension) |
9d42c84f | 134 | |
37f3ac49 | 135 | EXCEPTION_PROLOGUE |
9d42c84f | 136 | |
9d42c84f VG |
137 | bl do_extension_fault |
138 | b ret_from_exception | |
ec7ac6af | 139 | END(EV_Extension) |
9d42c84f | 140 | |
4bf4564b | 141 | ;################ Trap Handling (Syscall, Breakpoint) ################## |
547f1125 | 142 | |
4bf4564b VG |
143 | ; --------------------------------------------- |
144 | ; syscall Tracing | |
145 | ; --------------------------------------------- | |
547f1125 | 146 | tracesys: |
c505b0da VG |
147 | ; safekeep EFA (r12) if syscall tracer wanted PC |
148 | ; for traps, ERET is pre-commit so points to next-PC | |
547f1125 | 149 | GET_CURR_TASK_FIELD_PTR TASK_THREAD, r11 |
367f3fcd | 150 | st r12, [r11, THREAD_FAULT_ADDR] ; thread.fault_address |
547f1125 | 151 | |
c505b0da VG |
152 | ; PRE syscall trace hook |
153 | mov r0, sp ; pt_regs | |
154 | bl @syscall_trace_enter | |
547f1125 VG |
155 | |
156 | ; Tracing code now returns the syscall num (orig or modif) | |
157 | mov r8, r0 | |
158 | ||
159 | ; Do the Sys Call as we normally would. | |
3433adc8 | 160 | cmp r8, NR_syscalls - 1 |
547f1125 VG |
161 | mov.hi r0, -ENOSYS |
162 | bhi tracesys_exit | |
163 | ||
164 | ; Restore the sys-call args. Mere invocation of the hook abv could have | |
165 | ; clobbered them (since they are in scratch regs). The tracer could also | |
166 | ; have deliberately changed the syscall args: r0-r7 | |
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] | |
c505b0da | 176 | jl [r9] |
547f1125 VG |
177 | |
178 | tracesys_exit: | |
c505b0da | 179 | st r0, [sp, PT_r0] |
547f1125 | 180 | |
c505b0da | 181 | ; POST syscall trace hook |
b1c6ecfd | 182 | mov r0, sp ; pt_regs needed |
547f1125 | 183 | bl @syscall_trace_exit |
c505b0da VG |
184 | |
185 | ; don't call ret_from_system_call as it saves r0, already done above | |
186 | b ret_from_exception | |
547f1125 | 187 | |
4bf4564b VG |
188 | ; --------------------------------------------- |
189 | ; Breakpoint TRAP | |
190 | ; --------------------------------------------- | |
9d42c84f | 191 | trap_with_param: |
00fdec98 | 192 | mov r0, r12 ; EFA in case ptracer/gdb wants stop_pc |
c505b0da | 193 | mov r1, sp ; pt_regs |
9d42c84f | 194 | |
c505b0da | 195 | ; save callee regs in case tracer/gdb wants to peek |
9d42c84f VG |
196 | SAVE_CALLEE_SAVED_USER |
197 | ||
c505b0da | 198 | ; safekeep ref to callee regs |
9d42c84f VG |
199 | GET_CURR_TASK_FIELD_PTR TASK_THREAD, r10 |
200 | st sp, [r10, THREAD_CALLEE_REG] | |
201 | ||
c505b0da | 202 | ; call the non syscall trap handler |
9d42c84f VG |
203 | bl do_non_swi_trap |
204 | ||
c505b0da | 205 | ; unwind stack to discard callee regs |
9d42c84f VG |
206 | DISCARD_CALLEE_SAVED_USER |
207 | ||
208 | b ret_from_exception | |
209 | ||
4bf4564b VG |
210 | ; --------------------------------------------- |
211 | ; syscall TRAP | |
ebfc2fd8 | 212 | ; ABI: (r0-r7) up to 8 args, (r8) syscall number |
4bf4564b | 213 | ; --------------------------------------------- |
9d42c84f | 214 | |
ec7ac6af | 215 | ENTRY(EV_Trap) |
9d42c84f | 216 | |
13347c10 | 217 | EXCEPTION_PROLOGUE_KEEP_AE |
9d42c84f | 218 | |
00fdec98 VG |
219 | lr r12, [efa] |
220 | ||
221 | FAKE_RET_FROM_EXCPN | |
222 | ||
c505b0da | 223 | ;============ TRAP N : breakpoints, kprobes etc |
68e5c6f0 | 224 | bmsk.f 0, r10, 7 |
9d42c84f VG |
225 | bnz trap_with_param |
226 | ||
c505b0da | 227 | ;============ TRAP 0 (no param): syscall |
9d42c84f | 228 | |
c505b0da | 229 | ; syscall tracing ongoing, invoke pre-post-hooks around syscall |
547f1125 | 230 | GET_CURR_THR_INFO_FLAGS r10 |
fb0b5490 SM |
231 | and.f 0, r10, _TIF_SYSCALL_WORK |
232 | bnz tracesys ; this never comes back | |
547f1125 | 233 | |
4bf4564b VG |
234 | ;============ Normal syscall case |
235 | ||
3433adc8 | 236 | cmp r8, NR_syscalls - 1 |
9d42c84f | 237 | mov.hi r0, -ENOSYS |
2dad1122 | 238 | bhi .Lret_from_system_call |
9d42c84f | 239 | |
9d42c84f | 240 | ld.as r9,[sys_call_table, r8] |
c505b0da | 241 | jl [r9] |
9d42c84f | 242 | |
2dad1122 | 243 | .Lret_from_system_call: |
9d42c84f VG |
244 | st r0, [sp, PT_r0] ; sys call return value in pt_regs |
245 | ||
2dad1122 VG |
246 | ; fall through to ret_from_exception |
247 | END(EV_Trap) | |
9d42c84f VG |
248 | |
249 | ;############# Return from Intr/Excp/Trap (Linux Specifics) ############## | |
250 | ; | |
251 | ; If ret to user mode do we need to handle signals, schedule() et al. | |
252 | ||
ec7ac6af | 253 | ENTRY(ret_from_exception) |
9d42c84f VG |
254 | |
255 | ; Pre-{IRQ,Trap,Exception} K/U mode from pt_regs->status32 | |
256 | ld r8, [sp, PT_status32] ; returning to User/Kernel Mode | |
257 | ||
9d42c84f | 258 | bbit0 r8, STATUS_U_BIT, resume_kernel_mode |
9d42c84f VG |
259 | |
260 | ; Before returning to User mode check-for-and-complete any pending work | |
261 | ; such as rescheduling/signal-delivery etc. | |
262 | resume_user_mode_begin: | |
263 | ||
264 | ; Disable IRQs to ensures that chk for pending work itself is atomic | |
265 | ; (and we don't end up missing a NEED_RESCHED/SIGPENDING due to an | |
266 | ; interim IRQ). | |
267 | IRQ_DISABLE r10 | |
268 | ||
269 | ; Fast Path return to user mode if no pending work | |
270 | GET_CURR_THR_INFO_FLAGS r9 | |
271 | and.f 0, r9, _TIF_WORK_MASK | |
c10d6969 | 272 | bz .Lrestore_regs |
9d42c84f VG |
273 | |
274 | ; --- (Slow Path #1) task preemption --- | |
275 | bbit0 r9, TIF_NEED_RESCHED, .Lchk_pend_signals | |
276 | mov blink, resume_user_mode_begin ; tail-call to U mode ret chks | |
6de6066c | 277 | j @schedule ; BTST+Bnz causes relo error in link |
9d42c84f VG |
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 do_signal()/do_notify_resume() | |
284 | ||
0dafafc3 | 285 | GET_CURR_THR_INFO_FLAGS r9 |
bb12433b | 286 | and.f 0, r9, _TIF_SIGPENDING|_TIF_NOTIFY_SIGNAL |
53855e12 | 287 | bz .Lchk_notify_resume |
9d42c84f | 288 | |
c3581039 VG |
289 | ; Normal Trap/IRQ entry only saves Scratch (caller-saved) regs |
290 | ; in pt_reg since the "C" ABI (kernel code) will automatically | |
291 | ; save/restore callee-saved regs. | |
292 | ; | |
293 | ; However, here we need to explicitly save callee regs because | |
9d42c84f VG |
294 | ; (i) If this signal causes coredump - full regfile needed |
295 | ; (ii) If signal is SIGTRAP/SIGSTOP, task is being traced thus | |
296 | ; tracer might call PEEKUSR(CALLEE reg) | |
297 | ; | |
298 | ; NOTE: SP will grow up by size of CALLEE Reg-File | |
cfca4b5a | 299 | SAVE_CALLEE_SAVED_USER |
9d42c84f VG |
300 | |
301 | ; save location of saved Callee Regs @ thread_struct->callee | |
302 | GET_CURR_TASK_FIELD_PTR TASK_THREAD, r10 | |
303 | st sp, [r10, THREAD_CALLEE_REG] | |
304 | ||
305 | bl @do_signal | |
306 | ||
c3581039 VG |
307 | ; Ideally we want to discard the Callee reg above, however if this was |
308 | ; a tracing signal, tracer could have done a POKEUSR(CALLEE reg) | |
309 | RESTORE_CALLEE_SAVED_USER | |
9d42c84f VG |
310 | |
311 | b resume_user_mode_begin ; loop back to start of U mode ret | |
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 ; unconditionally back to U mode ret chks | |
318 | ; for single exit point from this block | |
319 | ||
9d42c84f VG |
320 | resume_kernel_mode: |
321 | ||
8aa9e85a | 322 | ; Disable Interrupts from this point on |
91659172 TG |
323 | ; CONFIG_PREEMPTION: This is a must for preempt_schedule_irq() |
324 | ; !CONFIG_PREEMPTION: To ensure restore_regs is intr safe | |
fce16bc3 VG |
325 | IRQ_DISABLE r9 |
326 | ||
91659172 | 327 | #ifdef CONFIG_PREEMPTION |
8aa9e85a | 328 | |
9d42c84f VG |
329 | ; Can't preempt if preemption disabled |
330 | GET_CURR_THR_INFO_FROM_SP r10 | |
331 | ld r8, [r10, THREAD_INFO_PREEMPT_COUNT] | |
c10d6969 | 332 | brne r8, 0, .Lrestore_regs |
9d42c84f VG |
333 | |
334 | ; check if this task's NEED_RESCHED flag set | |
335 | ld r9, [r10, THREAD_INFO_FLAGS] | |
c10d6969 | 336 | bbit0 r9, TIF_NEED_RESCHED, .Lrestore_regs |
9d42c84f | 337 | |
9d42c84f | 338 | ; Invoke PREEMPTION |
6de6066c | 339 | jl preempt_schedule_irq |
9d42c84f VG |
340 | |
341 | ; preempt_schedule_irq() always returns with IRQ disabled | |
342 | #endif | |
343 | ||
6d1a20b1 | 344 | b .Lrestore_regs |
4adeefe1 | 345 | |
c7e6d792 | 346 | ##### DONT ADD CODE HERE - .Lrestore_regs actually follows in entry-<isa>.S |
6d1a20b1 | 347 |