Commit | Line | Data |
---|---|---|
9d42c84f | 1 | /* |
6d1a20b1 VG |
2 | * Common Low Level Interrupts/Traps/Exceptions(non-TLB) Handling for ARC |
3 | * (included from entry-<isa>.S | |
9d42c84f | 4 | * |
6d1a20b1 | 5 | * Copyright (C) 2014-15 Synopsys, Inc. (www.synopsys.com) |
9d42c84f VG |
6 | * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License version 2 as | |
10 | * published by the Free Software Foundation. | |
9d42c84f VG |
11 | */ |
12 | ||
13 | /*------------------------------------------------------------------ | |
14 | * Function ABI | |
15 | *------------------------------------------------------------------ | |
16 | * | |
17 | * Arguments r0 - r7 | |
18 | * Caller Saved Registers r0 - r12 | |
19 | * Callee Saved Registers r13- r25 | |
20 | * Global Pointer (gp) r26 | |
21 | * Frame Pointer (fp) r27 | |
22 | * Stack Pointer (sp) r28 | |
9d42c84f VG |
23 | * Branch link register (blink) r31 |
24 | *------------------------------------------------------------------ | |
25 | */ | |
26 | ||
c7e6d792 VG |
27 | ;################### Special Sys Call Wrappers ########################## |
28 | ||
29 | ENTRY(sys_clone_wrapper) | |
30 | SAVE_CALLEE_SAVED_USER | |
31 | bl @sys_clone | |
32 | DISCARD_CALLEE_SAVED_USER | |
33 | ||
34 | GET_CURR_THR_INFO_FLAGS r10 | |
35 | btst r10, TIF_SYSCALL_TRACE | |
36 | bnz tracesys_exit | |
37 | ||
38 | b ret_from_system_call | |
39 | END(sys_clone_wrapper) | |
40 | ||
41 | ENTRY(ret_from_fork) | |
42 | ; when the forked child comes here from the __switch_to function | |
43 | ; r0 has the last task pointer. | |
44 | ; put last task in scheduler queue | |
6de6066c | 45 | jl @schedule_tail |
c7e6d792 VG |
46 | |
47 | ld r9, [sp, PT_status32] | |
48 | brne r9, 0, 1f | |
49 | ||
50 | jl.d [r14] ; kernel thread entry point | |
51 | mov r0, r13 ; (see PF_KTHREAD block in copy_thread) | |
52 | ||
53 | 1: | |
54 | ; Return to user space | |
55 | ; 1. Any forked task (Reach here via BRne above) | |
56 | ; 2. First ever init task (Reach here via return from JL above) | |
57 | ; This is the historic "kernel_execve" use-case, to return to init | |
58 | ; user mode, in a round about way since that is always done from | |
59 | ; a kernel thread which is executed via JL above but always returns | |
60 | ; out whenever kernel_execve (now inline do_fork()) is involved | |
61 | b ret_from_exception | |
62 | END(ret_from_fork) | |
63 | ||
64 | #ifdef CONFIG_ARC_DW2_UNWIND | |
65 | ; Workaround for bug 94179 (STAR ): | |
66 | ; Despite -fasynchronous-unwind-tables, linker is not making dwarf2 unwinder | |
67 | ; section (.debug_frame) as loadable. So we force it here. | |
68 | ; This also fixes STAR 9000487933 where the prev-workaround (objcopy --setflag) | |
69 | ; would not work after a clean build due to kernel build system dependencies. | |
70 | .section .debug_frame, "wa",@progbits | |
71 | ||
72 | ; Reset to .text as this file is included in entry-<isa>.S | |
73 | .section .text, "ax",@progbits | |
74 | #endif | |
75 | ||
9d42c84f VG |
76 | ;################### Non TLB Exception Handling ############################# |
77 | ||
78 | ; --------------------------------------------- | |
79 | ; Instruction Error Exception Handler | |
80 | ; --------------------------------------------- | |
81 | ||
ec7ac6af | 82 | ENTRY(instr_service) |
9d42c84f | 83 | |
37f3ac49 | 84 | EXCEPTION_PROLOGUE |
9d42c84f | 85 | |
38a9ff6d VG |
86 | lr r0, [efa] |
87 | mov r1, sp | |
9d42c84f | 88 | |
9b8c7d1e | 89 | FAKE_RET_FROM_EXCPN |
9d42c84f VG |
90 | |
91 | bl do_insterror_or_kprobe | |
92 | b ret_from_exception | |
ec7ac6af | 93 | END(instr_service) |
9d42c84f | 94 | |
9d42c84f VG |
95 | ; --------------------------------------------- |
96 | ; Machine Check Exception Handler | |
97 | ; --------------------------------------------- | |
98 | ||
ec7ac6af | 99 | ENTRY(EV_MachineCheck) |
9d42c84f | 100 | |
37f3ac49 | 101 | EXCEPTION_PROLOGUE |
9d42c84f | 102 | |
38a9ff6d VG |
103 | lr r2, [ecr] |
104 | lr r0, [efa] | |
105 | mov r1, sp | |
9d42c84f | 106 | |
38a9ff6d | 107 | lsr r3, r2, 8 |
1898a959 VG |
108 | bmsk r3, r3, 7 |
109 | brne r3, ECR_C_MCHK_DUP_TLB, 1f | |
110 | ||
9d42c84f VG |
111 | bl do_tlb_overlap_fault |
112 | b ret_from_exception | |
113 | ||
114 | 1: | |
115 | ; DEAD END: can't do much, display Regs and HALT | |
116 | SAVE_CALLEE_SAVED_USER | |
117 | ||
118 | GET_CURR_TASK_FIELD_PTR TASK_THREAD, r10 | |
119 | st sp, [r10, THREAD_CALLEE_REG] | |
120 | ||
121 | j do_machine_check_fault | |
122 | ||
ec7ac6af | 123 | END(EV_MachineCheck) |
9d42c84f | 124 | |
9d42c84f VG |
125 | ; --------------------------------------------- |
126 | ; Privilege Violation Exception Handler | |
127 | ; --------------------------------------------- | |
ec7ac6af | 128 | ENTRY(EV_PrivilegeV) |
9d42c84f | 129 | |
37f3ac49 | 130 | EXCEPTION_PROLOGUE |
9d42c84f | 131 | |
38a9ff6d VG |
132 | lr r0, [efa] |
133 | mov r1, sp | |
9d42c84f | 134 | |
9b8c7d1e | 135 | FAKE_RET_FROM_EXCPN |
9d42c84f VG |
136 | |
137 | bl do_privilege_fault | |
138 | b ret_from_exception | |
ec7ac6af | 139 | END(EV_PrivilegeV) |
9d42c84f VG |
140 | |
141 | ; --------------------------------------------- | |
142 | ; Extension Instruction Exception Handler | |
143 | ; --------------------------------------------- | |
ec7ac6af | 144 | ENTRY(EV_Extension) |
9d42c84f | 145 | |
37f3ac49 | 146 | EXCEPTION_PROLOGUE |
9d42c84f | 147 | |
38a9ff6d VG |
148 | lr r0, [efa] |
149 | mov r1, sp | |
37f3ac49 | 150 | |
9b8c7d1e | 151 | FAKE_RET_FROM_EXCPN |
37f3ac49 | 152 | |
9d42c84f VG |
153 | bl do_extension_fault |
154 | b ret_from_exception | |
ec7ac6af | 155 | END(EV_Extension) |
9d42c84f | 156 | |
4bf4564b | 157 | ;################ Trap Handling (Syscall, Breakpoint) ################## |
547f1125 | 158 | |
4bf4564b VG |
159 | ; --------------------------------------------- |
160 | ; syscall Tracing | |
161 | ; --------------------------------------------- | |
547f1125 VG |
162 | tracesys: |
163 | ; save EFA in case tracer wants the PC of traced task | |
164 | ; using ERET won't work since next-PC has already committed | |
165 | lr r12, [efa] | |
166 | GET_CURR_TASK_FIELD_PTR TASK_THREAD, r11 | |
367f3fcd | 167 | st r12, [r11, THREAD_FAULT_ADDR] ; thread.fault_address |
547f1125 VG |
168 | |
169 | ; PRE Sys Call Ptrace hook | |
170 | mov r0, sp ; pt_regs needed | |
171 | bl @syscall_trace_entry | |
172 | ||
173 | ; Tracing code now returns the syscall num (orig or modif) | |
174 | mov r8, r0 | |
175 | ||
176 | ; Do the Sys Call as we normally would. | |
177 | ; Validate the Sys Call number | |
178 | cmp r8, NR_syscalls | |
179 | mov.hi r0, -ENOSYS | |
180 | bhi tracesys_exit | |
181 | ||
182 | ; Restore the sys-call args. Mere invocation of the hook abv could have | |
183 | ; clobbered them (since they are in scratch regs). The tracer could also | |
184 | ; have deliberately changed the syscall args: r0-r7 | |
185 | ld r0, [sp, PT_r0] | |
186 | ld r1, [sp, PT_r1] | |
187 | ld r2, [sp, PT_r2] | |
188 | ld r3, [sp, PT_r3] | |
189 | ld r4, [sp, PT_r4] | |
190 | ld r5, [sp, PT_r5] | |
191 | ld r6, [sp, PT_r6] | |
192 | ld r7, [sp, PT_r7] | |
193 | ld.as r9, [sys_call_table, r8] | |
194 | jl [r9] ; Entry into Sys Call Handler | |
195 | ||
196 | tracesys_exit: | |
197 | st r0, [sp, PT_r0] ; sys call return value in pt_regs | |
198 | ||
199 | ;POST Sys Call Ptrace Hook | |
200 | bl @syscall_trace_exit | |
201 | b ret_from_exception ; NOT ret_from_system_call at is saves r0 which | |
202 | ; we'd done before calling post hook above | |
203 | ||
4bf4564b VG |
204 | ; --------------------------------------------- |
205 | ; Breakpoint TRAP | |
206 | ; --------------------------------------------- | |
9d42c84f VG |
207 | trap_with_param: |
208 | ||
5c39c0ab | 209 | ; stop_pc info by gdb needs this info |
38a9ff6d VG |
210 | lr r0, [efa] |
211 | mov r1, sp | |
9d42c84f | 212 | |
f63f98ea | 213 | ; Now that we have read EFA, it is safe to do "fake" rtie |
9d42c84f | 214 | ; and get out of CPU exception mode |
9b8c7d1e | 215 | FAKE_RET_FROM_EXCPN |
9d42c84f VG |
216 | |
217 | ; Save callee regs in case gdb wants to have a look | |
218 | ; SP will grow up by size of CALLEE Reg-File | |
219 | ; NOTE: clobbers r12 | |
220 | SAVE_CALLEE_SAVED_USER | |
221 | ||
222 | ; save location of saved Callee Regs @ thread_struct->pc | |
223 | GET_CURR_TASK_FIELD_PTR TASK_THREAD, r10 | |
224 | st sp, [r10, THREAD_CALLEE_REG] | |
225 | ||
226 | ; Call the trap handler | |
227 | bl do_non_swi_trap | |
228 | ||
229 | ; unwind stack to discard Callee saved Regs | |
230 | DISCARD_CALLEE_SAVED_USER | |
231 | ||
232 | b ret_from_exception | |
233 | ||
4bf4564b VG |
234 | ; --------------------------------------------- |
235 | ; syscall TRAP | |
236 | ; ABI: (r0-r7) upto 8 args, (r8) syscall number | |
237 | ; --------------------------------------------- | |
9d42c84f | 238 | |
ec7ac6af | 239 | ENTRY(EV_Trap) |
9d42c84f | 240 | |
37f3ac49 | 241 | EXCEPTION_PROLOGUE |
9d42c84f | 242 | |
4bf4564b | 243 | ;============ TRAP 1 :breakpoints |
62fb6403 VG |
244 | ; Check ECR for trap with arg (PROLOGUE ensures r9 has ECR) |
245 | bmsk.f 0, r9, 7 | |
9d42c84f VG |
246 | bnz trap_with_param |
247 | ||
4bf4564b | 248 | ;============ TRAP (no param): syscall top level |
9d42c84f | 249 | |
4bf4564b | 250 | ; First return from Exception to pure K mode (Exception/IRQs renabled) |
9b8c7d1e | 251 | FAKE_RET_FROM_EXCPN |
9d42c84f | 252 | |
4bf4564b | 253 | ; If syscall tracing ongoing, invoke pre-post-hooks |
547f1125 VG |
254 | GET_CURR_THR_INFO_FLAGS r10 |
255 | btst r10, TIF_SYSCALL_TRACE | |
256 | bnz tracesys ; this never comes back | |
257 | ||
4bf4564b VG |
258 | ;============ Normal syscall case |
259 | ||
260 | ; syscall num shd not exceed the total system calls avail | |
9d42c84f VG |
261 | cmp r8, NR_syscalls |
262 | mov.hi r0, -ENOSYS | |
263 | bhi ret_from_system_call | |
264 | ||
265 | ; Offset into the syscall_table and call handler | |
266 | ld.as r9,[sys_call_table, r8] | |
267 | jl [r9] ; Entry into Sys Call Handler | |
268 | ||
269 | ; fall through to ret_from_system_call | |
ec7ac6af | 270 | END(EV_Trap) |
9d42c84f | 271 | |
ec7ac6af | 272 | ENTRY(ret_from_system_call) |
9d42c84f VG |
273 | |
274 | st r0, [sp, PT_r0] ; sys call return value in pt_regs | |
275 | ||
276 | ; fall through yet again to ret_from_exception | |
277 | ||
278 | ;############# Return from Intr/Excp/Trap (Linux Specifics) ############## | |
279 | ; | |
280 | ; If ret to user mode do we need to handle signals, schedule() et al. | |
281 | ||
ec7ac6af | 282 | ENTRY(ret_from_exception) |
9d42c84f VG |
283 | |
284 | ; Pre-{IRQ,Trap,Exception} K/U mode from pt_regs->status32 | |
285 | ld r8, [sp, PT_status32] ; returning to User/Kernel Mode | |
286 | ||
9d42c84f | 287 | bbit0 r8, STATUS_U_BIT, resume_kernel_mode |
9d42c84f VG |
288 | |
289 | ; Before returning to User mode check-for-and-complete any pending work | |
290 | ; such as rescheduling/signal-delivery etc. | |
291 | resume_user_mode_begin: | |
292 | ||
293 | ; Disable IRQs to ensures that chk for pending work itself is atomic | |
294 | ; (and we don't end up missing a NEED_RESCHED/SIGPENDING due to an | |
295 | ; interim IRQ). | |
296 | IRQ_DISABLE r10 | |
297 | ||
298 | ; Fast Path return to user mode if no pending work | |
299 | GET_CURR_THR_INFO_FLAGS r9 | |
300 | and.f 0, r9, _TIF_WORK_MASK | |
c10d6969 | 301 | bz .Lrestore_regs |
9d42c84f VG |
302 | |
303 | ; --- (Slow Path #1) task preemption --- | |
304 | bbit0 r9, TIF_NEED_RESCHED, .Lchk_pend_signals | |
305 | mov blink, resume_user_mode_begin ; tail-call to U mode ret chks | |
6de6066c | 306 | j @schedule ; BTST+Bnz causes relo error in link |
9d42c84f VG |
307 | |
308 | .Lchk_pend_signals: | |
309 | IRQ_ENABLE r10 | |
310 | ||
311 | ; --- (Slow Path #2) pending signal --- | |
312 | mov r0, sp ; pt_regs for arg to do_signal()/do_notify_resume() | |
313 | ||
0dafafc3 | 314 | GET_CURR_THR_INFO_FLAGS r9 |
9d42c84f VG |
315 | bbit0 r9, TIF_SIGPENDING, .Lchk_notify_resume |
316 | ||
c3581039 VG |
317 | ; Normal Trap/IRQ entry only saves Scratch (caller-saved) regs |
318 | ; in pt_reg since the "C" ABI (kernel code) will automatically | |
319 | ; save/restore callee-saved regs. | |
320 | ; | |
321 | ; However, here we need to explicitly save callee regs because | |
9d42c84f VG |
322 | ; (i) If this signal causes coredump - full regfile needed |
323 | ; (ii) If signal is SIGTRAP/SIGSTOP, task is being traced thus | |
324 | ; tracer might call PEEKUSR(CALLEE reg) | |
325 | ; | |
326 | ; NOTE: SP will grow up by size of CALLEE Reg-File | |
327 | SAVE_CALLEE_SAVED_USER ; clobbers r12 | |
328 | ||
329 | ; save location of saved Callee Regs @ thread_struct->callee | |
330 | GET_CURR_TASK_FIELD_PTR TASK_THREAD, r10 | |
331 | st sp, [r10, THREAD_CALLEE_REG] | |
332 | ||
333 | bl @do_signal | |
334 | ||
c3581039 VG |
335 | ; Ideally we want to discard the Callee reg above, however if this was |
336 | ; a tracing signal, tracer could have done a POKEUSR(CALLEE reg) | |
337 | RESTORE_CALLEE_SAVED_USER | |
9d42c84f VG |
338 | |
339 | b resume_user_mode_begin ; loop back to start of U mode ret | |
340 | ||
341 | ; --- (Slow Path #3) notify_resume --- | |
342 | .Lchk_notify_resume: | |
343 | btst r9, TIF_NOTIFY_RESUME | |
344 | blnz @do_notify_resume | |
345 | b resume_user_mode_begin ; unconditionally back to U mode ret chks | |
346 | ; for single exit point from this block | |
347 | ||
9d42c84f VG |
348 | resume_kernel_mode: |
349 | ||
8aa9e85a VG |
350 | ; Disable Interrupts from this point on |
351 | ; CONFIG_PREEMPT: This is a must for preempt_schedule_irq() | |
352 | ; !CONFIG_PREEMPT: To ensure restore_regs is intr safe | |
fce16bc3 VG |
353 | IRQ_DISABLE r9 |
354 | ||
8aa9e85a VG |
355 | #ifdef CONFIG_PREEMPT |
356 | ||
9d42c84f VG |
357 | ; Can't preempt if preemption disabled |
358 | GET_CURR_THR_INFO_FROM_SP r10 | |
359 | ld r8, [r10, THREAD_INFO_PREEMPT_COUNT] | |
c10d6969 | 360 | brne r8, 0, .Lrestore_regs |
9d42c84f VG |
361 | |
362 | ; check if this task's NEED_RESCHED flag set | |
363 | ld r9, [r10, THREAD_INFO_FLAGS] | |
c10d6969 | 364 | bbit0 r9, TIF_NEED_RESCHED, .Lrestore_regs |
9d42c84f | 365 | |
9d42c84f | 366 | ; Invoke PREEMPTION |
6de6066c | 367 | jl preempt_schedule_irq |
9d42c84f VG |
368 | |
369 | ; preempt_schedule_irq() always returns with IRQ disabled | |
370 | #endif | |
371 | ||
6d1a20b1 | 372 | b .Lrestore_regs |
4adeefe1 | 373 | |
c7e6d792 | 374 | ##### DONT ADD CODE HERE - .Lrestore_regs actually follows in entry-<isa>.S |
6d1a20b1 | 375 |