Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* $Id: entry.S,v 1.37 2004/06/11 13:02:46 doyu Exp $ |
2 | * | |
3 | * linux/arch/sh/entry.S | |
4 | * | |
5 | * Copyright (C) 1999, 2000, 2002 Niibe Yutaka | |
6 | * Copyright (C) 2003 Paul Mundt | |
7 | * | |
8 | * This file is subject to the terms and conditions of the GNU General Public | |
9 | * License. See the file "COPYING" in the main directory of this archive | |
10 | * for more details. | |
11 | * | |
12 | */ | |
13 | ||
14 | #include <linux/sys.h> | |
15 | #include <linux/linkage.h> | |
16 | #include <linux/config.h> | |
17 | #include <asm/asm-offsets.h> | |
18 | #include <asm/thread_info.h> | |
19 | #include <asm/unistd.h> | |
20 | ||
21 | #if !defined(CONFIG_NFSD) && !defined(CONFIG_NFSD_MODULE) | |
22 | #define sys_nfsservctl sys_ni_syscall | |
23 | #endif | |
24 | ||
25 | #if !defined(CONFIG_MMU) | |
26 | #define sys_madvise sys_ni_syscall | |
27 | #define sys_readahead sys_ni_syscall | |
28 | #define sys_mprotect sys_ni_syscall | |
29 | #define sys_msync sys_ni_syscall | |
30 | #define sys_mlock sys_ni_syscall | |
31 | #define sys_munlock sys_ni_syscall | |
32 | #define sys_mlockall sys_ni_syscall | |
33 | #define sys_munlockall sys_ni_syscall | |
34 | #define sys_mremap sys_ni_syscall | |
35 | #define sys_mincore sys_ni_syscall | |
36 | #define sys_remap_file_pages sys_ni_syscall | |
37 | #endif | |
38 | ||
39 | ! NOTE: | |
40 | ! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address | |
41 | ! to be jumped is too far, but it causes illegal slot exception. | |
42 | ||
43 | /* | |
44 | * entry.S contains the system-call and fault low-level handling routines. | |
45 | * This also contains the timer-interrupt handler, as well as all interrupts | |
46 | * and faults that can result in a task-switch. | |
47 | * | |
48 | * NOTE: This code handles signal-recognition, which happens every time | |
49 | * after a timer-interrupt and after each system call. | |
50 | * | |
51 | * NOTE: This code uses a convention that instructions in the delay slot | |
52 | * of a transfer-control instruction are indented by an extra space, thus: | |
53 | * | |
54 | * jmp @k0 ! control-transfer instruction | |
55 | * ldc k1, ssr ! delay slot | |
56 | * | |
57 | * Stack layout in 'ret_from_syscall': | |
58 | * ptrace needs to have all regs on the stack. | |
59 | * if the order here is changed, it needs to be | |
60 | * updated in ptrace.c and ptrace.h | |
61 | * | |
62 | * r0 | |
63 | * ... | |
64 | * r15 = stack pointer | |
65 | * spc | |
66 | * pr | |
67 | * ssr | |
68 | * gbr | |
69 | * mach | |
70 | * macl | |
71 | * syscall # | |
72 | * | |
73 | */ | |
74 | ||
75 | ENOSYS = 38 | |
76 | EINVAL = 22 | |
77 | ||
78 | #if defined(CONFIG_CPU_SH3) | |
79 | TRA = 0xffffffd0 | |
80 | EXPEVT = 0xffffffd4 | |
81 | #if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \ | |
82 | defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705) | |
83 | INTEVT = 0xa4000000 ! INTEVTE2(0xa4000000) | |
84 | #else | |
85 | INTEVT = 0xffffffd8 | |
86 | #endif | |
87 | MMU_TEA = 0xfffffffc ! TLB Exception Address Register | |
88 | #elif defined(CONFIG_CPU_SH4) | |
89 | TRA = 0xff000020 | |
90 | EXPEVT = 0xff000024 | |
91 | INTEVT = 0xff000028 | |
92 | MMU_TEA = 0xff00000c ! TLB Exception Address Register | |
93 | #endif | |
94 | ||
95 | #if defined(CONFIG_KGDB_NMI) | |
96 | NMI_VEC = 0x1c0 ! Must catch early for debounce | |
97 | #endif | |
98 | ||
99 | /* Offsets to the stack */ | |
100 | OFF_R0 = 0 /* Return value. New ABI also arg4 */ | |
101 | OFF_R1 = 4 /* New ABI: arg5 */ | |
102 | OFF_R2 = 8 /* New ABI: arg6 */ | |
103 | OFF_R3 = 12 /* New ABI: syscall_nr */ | |
104 | OFF_R4 = 16 /* New ABI: arg0 */ | |
105 | OFF_R5 = 20 /* New ABI: arg1 */ | |
106 | OFF_R6 = 24 /* New ABI: arg2 */ | |
107 | OFF_R7 = 28 /* New ABI: arg3 */ | |
108 | OFF_SP = (15*4) | |
109 | OFF_PC = (16*4) | |
110 | OFF_SR = (16*4+8) | |
111 | OFF_TRA = (16*4+6*4) | |
112 | ||
113 | ||
114 | #define k0 r0 | |
115 | #define k1 r1 | |
116 | #define k2 r2 | |
117 | #define k3 r3 | |
118 | #define k4 r4 | |
119 | ||
120 | #define k_ex_code r2_bank /* r2_bank1 */ | |
121 | #define g_imask r6 /* r6_bank1 */ | |
122 | #define k_g_imask r6_bank /* r6_bank1 */ | |
123 | #define current r7 /* r7_bank1 */ | |
124 | ||
125 | /* | |
126 | * Kernel mode register usage: | |
127 | * k0 scratch | |
128 | * k1 scratch | |
129 | * k2 scratch (Exception code) | |
130 | * k3 scratch (Return address) | |
131 | * k4 scratch | |
132 | * k5 reserved | |
133 | * k6 Global Interrupt Mask (0--15 << 4) | |
134 | * k7 CURRENT_THREAD_INFO (pointer to current thread info) | |
135 | */ | |
136 | ||
137 | ! | |
138 | ! TLB Miss / Initial Page write exception handling | |
139 | ! _and_ | |
140 | ! TLB hits, but the access violate the protection. | |
141 | ! It can be valid access, such as stack grow and/or C-O-W. | |
142 | ! | |
143 | ! | |
144 | ! Find the pmd/pte entry and loadtlb | |
145 | ! If it's not found, cause address error (SEGV) | |
146 | ! | |
147 | ! Although this could be written in assembly language (and it'd be faster), | |
148 | ! this first version depends *much* on C implementation. | |
149 | ! | |
150 | ||
151 | #define CLI() \ | |
152 | stc sr, r0; \ | |
153 | or #0xf0, r0; \ | |
154 | ldc r0, sr | |
155 | ||
156 | #define STI() \ | |
157 | mov.l __INV_IMASK, r11; \ | |
158 | stc sr, r10; \ | |
159 | and r11, r10; \ | |
160 | stc k_g_imask, r11; \ | |
161 | or r11, r10; \ | |
162 | ldc r10, sr | |
163 | ||
164 | #if defined(CONFIG_PREEMPT) | |
165 | # define preempt_stop() CLI() | |
166 | #else | |
167 | # define preempt_stop() | |
168 | # define resume_kernel restore_all | |
169 | #endif | |
170 | ||
171 | #if defined(CONFIG_MMU) | |
172 | .align 2 | |
173 | ENTRY(tlb_miss_load) | |
174 | bra call_dpf | |
175 | mov #0, r5 | |
176 | ||
177 | .align 2 | |
178 | ENTRY(tlb_miss_store) | |
179 | bra call_dpf | |
180 | mov #1, r5 | |
181 | ||
182 | .align 2 | |
183 | ENTRY(initial_page_write) | |
184 | bra call_dpf | |
185 | mov #1, r5 | |
186 | ||
187 | .align 2 | |
188 | ENTRY(tlb_protection_violation_load) | |
189 | bra call_dpf | |
190 | mov #0, r5 | |
191 | ||
192 | .align 2 | |
193 | ENTRY(tlb_protection_violation_store) | |
194 | bra call_dpf | |
195 | mov #1, r5 | |
196 | ||
197 | call_dpf: | |
198 | mov.l 1f, r0 | |
199 | mov r5, r8 | |
200 | mov.l @r0, r6 | |
201 | mov r6, r9 | |
202 | mov.l 2f, r0 | |
203 | sts pr, r10 | |
204 | jsr @r0 | |
205 | mov r15, r4 | |
206 | ! | |
207 | tst r0, r0 | |
208 | bf/s 0f | |
209 | lds r10, pr | |
210 | rts | |
211 | nop | |
212 | 0: STI() | |
213 | mov.l 3f, r0 | |
214 | mov r9, r6 | |
215 | mov r8, r5 | |
216 | jmp @r0 | |
217 | mov r15, r4 | |
218 | ||
219 | .align 2 | |
220 | 1: .long MMU_TEA | |
221 | 2: .long __do_page_fault | |
222 | 3: .long do_page_fault | |
223 | ||
224 | .align 2 | |
225 | ENTRY(address_error_load) | |
226 | bra call_dae | |
227 | mov #0,r5 ! writeaccess = 0 | |
228 | ||
229 | .align 2 | |
230 | ENTRY(address_error_store) | |
231 | bra call_dae | |
232 | mov #1,r5 ! writeaccess = 1 | |
233 | ||
234 | .align 2 | |
235 | call_dae: | |
236 | mov.l 1f, r0 | |
237 | mov.l @r0, r6 ! address | |
238 | mov.l 2f, r0 | |
239 | jmp @r0 | |
240 | mov r15, r4 ! regs | |
241 | ||
242 | .align 2 | |
243 | 1: .long MMU_TEA | |
244 | 2: .long do_address_error | |
245 | #endif /* CONFIG_MMU */ | |
246 | ||
247 | #if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB) | |
248 | ! Handle kernel debug if either kgdb (SW) or gdb-stub (FW) is present. | |
249 | ! If both are configured, handle the debug traps (breakpoints) in SW, | |
250 | ! but still allow BIOS traps to FW. | |
251 | ||
252 | .align 2 | |
253 | debug_kernel: | |
254 | #if defined(CONFIG_SH_STANDARD_BIOS) && defined(CONFIG_SH_KGDB) | |
255 | /* Force BIOS call to FW (debug_trap put TRA in r8) */ | |
256 | mov r8,r0 | |
257 | shlr2 r0 | |
258 | cmp/eq #0x3f,r0 | |
259 | bt debug_kernel_fw | |
260 | #endif /* CONFIG_SH_STANDARD_BIOS && CONFIG_SH_KGDB */ | |
261 | ||
262 | debug_enter: | |
263 | #if defined(CONFIG_SH_KGDB) | |
264 | /* Jump to kgdb, pass stacked regs as arg */ | |
265 | debug_kernel_sw: | |
266 | mov.l 3f, r0 | |
267 | jmp @r0 | |
268 | mov r15, r4 | |
269 | .align 2 | |
270 | 3: .long kgdb_handle_exception | |
271 | #endif /* CONFIG_SH_KGDB */ | |
272 | ||
273 | #if defined(CONFIG_SH_STANDARD_BIOS) | |
274 | /* Unwind the stack and jmp to the debug entry */ | |
275 | debug_kernel_fw: | |
276 | mov.l @r15+, r0 | |
277 | mov.l @r15+, r1 | |
278 | mov.l @r15+, r2 | |
279 | mov.l @r15+, r3 | |
280 | mov.l @r15+, r4 | |
281 | mov.l @r15+, r5 | |
282 | mov.l @r15+, r6 | |
283 | mov.l @r15+, r7 | |
284 | stc sr, r8 | |
285 | mov.l 1f, r9 ! BL =1, RB=1, IMASK=0x0F | |
286 | or r9, r8 | |
287 | ldc r8, sr ! here, change the register bank | |
288 | mov.l @r15+, r8 | |
289 | mov.l @r15+, r9 | |
290 | mov.l @r15+, r10 | |
291 | mov.l @r15+, r11 | |
292 | mov.l @r15+, r12 | |
293 | mov.l @r15+, r13 | |
294 | mov.l @r15+, r14 | |
295 | mov.l @r15+, k0 | |
296 | ldc.l @r15+, spc | |
297 | lds.l @r15+, pr | |
298 | mov.l @r15+, k1 | |
299 | ldc.l @r15+, gbr | |
300 | lds.l @r15+, mach | |
301 | lds.l @r15+, macl | |
302 | mov k0, r15 | |
303 | ! | |
304 | mov.l 2f, k0 | |
305 | mov.l @k0, k0 | |
306 | jmp @k0 | |
307 | ldc k1, ssr | |
308 | .align 2 | |
309 | 1: .long 0x300000f0 | |
310 | 2: .long gdb_vbr_vector | |
311 | #endif /* CONFIG_SH_STANDARD_BIOS */ | |
312 | ||
313 | #endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */ | |
314 | ||
315 | ||
316 | .align 2 | |
317 | debug_trap: | |
318 | #if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB) | |
319 | mov #OFF_SR, r0 | |
320 | mov.l @(r0,r15), r0 ! get status register | |
321 | shll r0 | |
322 | shll r0 ! kernel space? | |
323 | bt/s debug_kernel | |
324 | #endif | |
325 | mov.l @r15, r0 ! Restore R0 value | |
326 | mov.l 1f, r8 | |
327 | jmp @r8 | |
328 | nop | |
329 | ||
330 | .align 2 | |
331 | ENTRY(exception_error) | |
332 | ! | |
333 | STI() | |
334 | mov.l 2f, r0 | |
335 | jmp @r0 | |
336 | nop | |
337 | ||
338 | ! | |
339 | .align 2 | |
340 | 1: .long break_point_trap_software | |
341 | 2: .long do_exception_error | |
342 | ||
343 | .align 2 | |
344 | ret_from_exception: | |
345 | preempt_stop() | |
346 | ret_from_irq: | |
347 | ! | |
348 | mov #OFF_SR, r0 | |
349 | mov.l @(r0,r15), r0 ! get status register | |
350 | shll r0 | |
351 | shll r0 ! kernel space? | |
352 | bt/s resume_kernel ! Yes, it's from kernel, go back soon | |
353 | GET_THREAD_INFO(r8) | |
354 | ||
355 | #ifdef CONFIG_PREEMPT | |
356 | bra resume_userspace | |
357 | nop | |
358 | ENTRY(resume_kernel) | |
359 | mov.l @(TI_PRE_COUNT,r8), r0 ! current_thread_info->preempt_count | |
360 | tst r0, r0 | |
361 | bf noresched | |
362 | need_resched: | |
363 | mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags | |
364 | tst #_TIF_NEED_RESCHED, r0 ! need_resched set? | |
365 | bt noresched | |
366 | ||
367 | mov #OFF_SR, r0 | |
368 | mov.l @(r0,r15), r0 ! get status register | |
369 | and #0xf0, r0 ! interrupts off (exception path)? | |
370 | cmp/eq #0xf0, r0 | |
371 | bt noresched | |
372 | ||
373 | mov.l 1f, r0 | |
374 | mov.l r0, @(TI_PRE_COUNT,r8) | |
375 | ||
376 | STI() | |
377 | mov.l 2f, r0 | |
378 | jsr @r0 | |
379 | nop | |
380 | mov #0, r0 | |
381 | mov.l r0, @(TI_PRE_COUNT,r8) | |
382 | CLI() | |
383 | ||
384 | bra need_resched | |
385 | nop | |
386 | noresched: | |
387 | bra restore_all | |
388 | nop | |
389 | ||
390 | .align 2 | |
391 | 1: .long PREEMPT_ACTIVE | |
392 | 2: .long schedule | |
393 | #endif | |
394 | ||
395 | ENTRY(resume_userspace) | |
396 | ! r8: current_thread_info | |
397 | CLI() | |
398 | mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags | |
399 | tst #_TIF_WORK_MASK, r0 | |
400 | bt/s restore_all | |
401 | tst #_TIF_NEED_RESCHED, r0 | |
402 | ||
403 | .align 2 | |
404 | work_pending: | |
405 | ! r0: current_thread_info->flags | |
406 | ! r8: current_thread_info | |
407 | ! t: result of "tst #_TIF_NEED_RESCHED, r0" | |
408 | bf/s work_resched | |
409 | tst #_TIF_SIGPENDING, r0 | |
410 | work_notifysig: | |
411 | bt/s restore_all | |
412 | mov r15, r4 | |
413 | mov #0, r5 | |
414 | mov.l 2f, r1 | |
415 | mova restore_all, r0 | |
416 | jmp @r1 | |
417 | lds r0, pr | |
418 | work_resched: | |
419 | #ifndef CONFIG_PREEMPT | |
420 | ! gUSA handling | |
421 | mov.l @(OFF_SP,r15), r0 ! get user space stack pointer | |
422 | mov r0, r1 | |
423 | shll r0 | |
424 | bf/s 1f | |
425 | shll r0 | |
426 | bf/s 1f | |
427 | mov #OFF_PC, r0 | |
428 | ! SP >= 0xc0000000 : gUSA mark | |
429 | mov.l @(r0,r15), r2 ! get user space PC (program counter) | |
430 | mov.l @(OFF_R0,r15), r3 ! end point | |
431 | cmp/hs r3, r2 ! r2 >= r3? | |
432 | bt 1f | |
433 | add r3, r1 ! rewind point #2 | |
434 | mov.l r1, @(r0,r15) ! reset PC to rewind point #2 | |
435 | ! | |
436 | 1: | |
437 | #endif | |
438 | mov.l 1f, r1 | |
439 | jsr @r1 ! schedule | |
440 | nop | |
441 | CLI() | |
442 | ! | |
443 | mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags | |
444 | tst #_TIF_WORK_MASK, r0 | |
445 | bt restore_all | |
446 | bra work_pending | |
447 | tst #_TIF_NEED_RESCHED, r0 | |
448 | ||
449 | .align 2 | |
450 | 1: .long schedule | |
451 | 2: .long do_signal | |
452 | ||
453 | .align 2 | |
454 | syscall_exit_work: | |
455 | ! r0: current_thread_info->flags | |
456 | ! r8: current_thread_info | |
457 | tst #_TIF_SYSCALL_TRACE, r0 | |
458 | bt/s work_pending | |
459 | tst #_TIF_NEED_RESCHED, r0 | |
460 | STI() | |
461 | ! XXX setup arguments... | |
462 | mov.l 4f, r0 ! do_syscall_trace | |
463 | jsr @r0 | |
464 | nop | |
465 | bra resume_userspace | |
466 | nop | |
467 | ||
468 | .align 2 | |
469 | syscall_trace_entry: | |
470 | ! Yes it is traced. | |
471 | ! XXX setup arguments... | |
472 | mov.l 4f, r11 ! Call do_syscall_trace which notifies | |
473 | jsr @r11 ! superior (will chomp R[0-7]) | |
474 | nop | |
475 | ! Reload R0-R4 from kernel stack, where the | |
476 | ! parent may have modified them using | |
477 | ! ptrace(POKEUSR). (Note that R0-R2 are | |
478 | ! used by the system call handler directly | |
479 | ! from the kernel stack anyway, so don't need | |
480 | ! to be reloaded here.) This allows the parent | |
481 | ! to rewrite system calls and args on the fly. | |
482 | mov.l @(OFF_R4,r15), r4 ! arg0 | |
483 | mov.l @(OFF_R5,r15), r5 | |
484 | mov.l @(OFF_R6,r15), r6 | |
485 | mov.l @(OFF_R7,r15), r7 ! arg3 | |
486 | mov.l @(OFF_R3,r15), r3 ! syscall_nr | |
487 | ! Arrange for do_syscall_trace to be called | |
488 | ! again as the system call returns. | |
489 | mov.l 2f, r10 ! Number of syscalls | |
490 | cmp/hs r10, r3 | |
491 | bf syscall_call | |
492 | mov #-ENOSYS, r0 | |
493 | bra syscall_exit | |
494 | mov.l r0, @(OFF_R0,r15) ! Return value | |
495 | ||
496 | /* | |
497 | * Syscall interface: | |
498 | * | |
499 | * Syscall #: R3 | |
500 | * Arguments #0 to #3: R4--R7 | |
501 | * Arguments #4 to #6: R0, R1, R2 | |
502 | * TRA: (number of arguments + 0x10) x 4 | |
503 | * | |
504 | * This code also handles delegating other traps to the BIOS/gdb stub | |
505 | * according to: | |
506 | * | |
507 | * Trap number | |
508 | * (TRA>>2) Purpose | |
509 | * -------- ------- | |
510 | * 0x0-0xf old syscall ABI | |
511 | * 0x10-0x1f new syscall ABI | |
512 | * 0x20-0xff delegated through debug_trap to BIOS/gdb stub. | |
513 | * | |
514 | * Note: When we're first called, the TRA value must be shifted | |
515 | * right 2 bits in order to get the value that was used as the "trapa" | |
516 | * argument. | |
517 | */ | |
518 | ||
519 | .align 2 | |
520 | .globl ret_from_fork | |
521 | ret_from_fork: | |
522 | mov.l 1f, r8 | |
523 | jsr @r8 | |
524 | mov r0, r4 | |
525 | bra syscall_exit | |
526 | nop | |
527 | .align 2 | |
528 | 1: .long schedule_tail | |
529 | ! | |
530 | ENTRY(system_call) | |
531 | mov.l 1f, r9 | |
532 | mov.l @r9, r8 ! Read from TRA (Trap Address) Register | |
533 | ! | |
534 | ! Is the trap argument >= 0x20? (TRA will be >= 0x80) | |
535 | mov #0x7f, r9 | |
536 | cmp/hi r9, r8 | |
537 | bt/s 0f | |
538 | mov #OFF_TRA, r9 | |
539 | add r15, r9 | |
540 | ! | |
541 | mov.l r8, @r9 ! set TRA value to tra | |
542 | STI() | |
543 | ! Call the system call handler through the table. | |
544 | ! First check for bad syscall number | |
545 | mov r3, r9 | |
546 | mov.l 2f, r8 ! Number of syscalls | |
547 | cmp/hs r8, r9 | |
548 | bf/s good_system_call | |
549 | GET_THREAD_INFO(r8) | |
550 | syscall_badsys: ! Bad syscall number | |
551 | mov #-ENOSYS, r0 | |
552 | bra resume_userspace | |
553 | mov.l r0, @(OFF_R0,r15) ! Return value | |
554 | ! | |
555 | 0: | |
556 | bra debug_trap | |
557 | nop | |
558 | ! | |
559 | good_system_call: ! Good syscall number | |
560 | mov.l @(TI_FLAGS,r8), r8 | |
561 | mov #_TIF_SYSCALL_TRACE, r10 | |
562 | tst r10, r8 | |
563 | bf syscall_trace_entry | |
564 | ! | |
565 | syscall_call: | |
566 | shll2 r9 ! x4 | |
567 | mov.l 3f, r8 ! Load the address of sys_call_table | |
568 | add r8, r9 | |
569 | mov.l @r9, r8 | |
570 | jsr @r8 ! jump to specific syscall handler | |
571 | nop | |
572 | mov.l r0, @(OFF_R0,r15) ! save the return value | |
573 | ! | |
574 | syscall_exit: | |
575 | CLI() | |
576 | ! | |
577 | GET_THREAD_INFO(r8) | |
578 | mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags | |
579 | tst #_TIF_ALLWORK_MASK, r0 | |
580 | bf syscall_exit_work | |
581 | restore_all: | |
582 | mov.l @r15+, r0 | |
583 | mov.l @r15+, r1 | |
584 | mov.l @r15+, r2 | |
585 | mov.l @r15+, r3 | |
586 | mov.l @r15+, r4 | |
587 | mov.l @r15+, r5 | |
588 | mov.l @r15+, r6 | |
589 | mov.l @r15+, r7 | |
590 | ! | |
591 | stc sr, r8 | |
592 | mov.l 7f, r9 | |
593 | or r9, r8 ! BL =1, RB=1 | |
594 | ldc r8, sr ! here, change the register bank | |
595 | ! | |
596 | mov.l @r15+, r8 | |
597 | mov.l @r15+, r9 | |
598 | mov.l @r15+, r10 | |
599 | mov.l @r15+, r11 | |
600 | mov.l @r15+, r12 | |
601 | mov.l @r15+, r13 | |
602 | mov.l @r15+, r14 | |
603 | mov.l @r15+, k4 ! original stack pointer | |
604 | ldc.l @r15+, spc | |
605 | lds.l @r15+, pr | |
606 | mov.l @r15+, k3 ! original SR | |
607 | ldc.l @r15+, gbr | |
608 | lds.l @r15+, mach | |
609 | lds.l @r15+, macl | |
610 | add #4, r15 ! Skip syscall number | |
611 | ! | |
612 | #ifdef CONFIG_SH_DSP | |
613 | mov.l @r15+, k0 ! DSP mode marker | |
614 | mov.l 5f, k1 | |
615 | cmp/eq k0, k1 ! Do we have a DSP stack frame? | |
616 | bf skip_restore | |
617 | ||
618 | stc sr, k0 ! Enable CPU DSP mode | |
619 | or k1, k0 ! (within kernel it may be disabled) | |
620 | ldc k0, sr | |
621 | mov r2, k0 ! Backup r2 | |
622 | ||
623 | ! Restore DSP registers from stack | |
624 | mov r15, r2 | |
625 | movs.l @r2+, a1 | |
626 | movs.l @r2+, a0g | |
627 | movs.l @r2+, a1g | |
628 | movs.l @r2+, m0 | |
629 | movs.l @r2+, m1 | |
630 | mov r2, r15 | |
631 | ||
632 | lds.l @r15+, a0 | |
633 | lds.l @r15+, x0 | |
634 | lds.l @r15+, x1 | |
635 | lds.l @r15+, y0 | |
636 | lds.l @r15+, y1 | |
637 | lds.l @r15+, dsr | |
638 | ldc.l @r15+, rs | |
639 | ldc.l @r15+, re | |
640 | ldc.l @r15+, mod | |
641 | ||
642 | mov k0, r2 ! Restore r2 | |
643 | skip_restore: | |
644 | #endif | |
645 | ! | |
646 | ! Calculate new SR value | |
647 | mov k3, k2 ! original SR value | |
648 | mov.l 9f, k1 | |
649 | and k1, k2 ! Mask orignal SR value | |
650 | ! | |
651 | mov k3, k0 ! Calculate IMASK-bits | |
652 | shlr2 k0 | |
653 | and #0x3c, k0 | |
654 | cmp/eq #0x3c, k0 | |
655 | bt/s 6f | |
656 | shll2 k0 | |
657 | mov g_imask, k0 | |
658 | ! | |
659 | 6: or k0, k2 ! Set the IMASK-bits | |
660 | ldc k2, ssr | |
661 | ! | |
662 | #if defined(CONFIG_KGDB_NMI) | |
663 | ! Clear in_nmi | |
664 | mov.l 4f, k0 | |
665 | mov #0, k1 | |
666 | mov.b k1, @k0 | |
667 | #endif | |
668 | mov.l @r15+, k2 ! restore EXPEVT | |
669 | mov k4, r15 | |
670 | rte | |
671 | nop | |
672 | ||
673 | .align 2 | |
674 | 1: .long TRA | |
675 | 2: .long NR_syscalls | |
676 | 3: .long sys_call_table | |
677 | 4: .long do_syscall_trace | |
678 | 5: .long 0x00001000 ! DSP | |
679 | 7: .long 0x30000000 | |
680 | 9: | |
681 | __INV_IMASK: | |
682 | .long 0xffffff0f ! ~(IMASK) | |
683 | ||
684 | ! Exception Vector Base | |
685 | ! | |
686 | ! Should be aligned page boundary. | |
687 | ! | |
688 | .balign 4096,0,4096 | |
689 | ENTRY(vbr_base) | |
690 | .long 0 | |
691 | ! | |
692 | .balign 256,0,256 | |
693 | general_exception: | |
694 | mov.l 1f, k2 | |
695 | mov.l 2f, k3 | |
696 | bra handle_exception | |
697 | mov.l @k2, k2 | |
698 | .align 2 | |
699 | 1: .long EXPEVT | |
700 | 2: .long ret_from_exception | |
701 | ! | |
702 | ! | |
703 | .balign 1024,0,1024 | |
704 | tlb_miss: | |
705 | mov.l 1f, k2 | |
706 | mov.l 4f, k3 | |
707 | bra handle_exception | |
708 | mov.l @k2, k2 | |
709 | ! | |
710 | .balign 512,0,512 | |
711 | interrupt: | |
712 | mov.l 2f, k2 | |
713 | mov.l 3f, k3 | |
714 | #if defined(CONFIG_KGDB_NMI) | |
715 | ! Debounce (filter nested NMI) | |
716 | mov.l @k2, k0 | |
717 | mov.l 5f, k1 | |
718 | cmp/eq k1, k0 | |
719 | bf 0f | |
720 | mov.l 6f, k1 | |
721 | tas.b @k1 | |
722 | bt 0f | |
723 | rte | |
724 | nop | |
725 | .align 2 | |
726 | 5: .long NMI_VEC | |
727 | 6: .long in_nmi | |
728 | 0: | |
729 | #endif /* defined(CONFIG_KGDB_NMI) */ | |
730 | bra handle_exception | |
731 | mov.l @k2, k2 | |
732 | ||
733 | .align 2 | |
734 | 1: .long EXPEVT | |
735 | 2: .long INTEVT | |
736 | 3: .long ret_from_irq | |
737 | 4: .long ret_from_exception | |
738 | ||
739 | ! | |
740 | ! | |
741 | .align 2 | |
742 | handle_exception: | |
743 | ! Using k0, k1 for scratch registers (r0_bank1, r1_bank), | |
744 | ! save all registers onto stack. | |
745 | ! | |
746 | stc ssr, k0 ! Is it from kernel space? | |
747 | shll k0 ! Check MD bit (bit30) by shifting it into... | |
748 | shll k0 ! ...the T bit | |
749 | bt/s 1f ! It's a kernel to kernel transition. | |
750 | mov r15, k0 ! save original stack to k0 | |
751 | /* User space to kernel */ | |
752 | mov #0x20, k1 | |
753 | shll8 k1 ! k1 := 8192 (== THREAD_SIZE) | |
754 | add current, k1 | |
755 | mov k1, r15 ! change to kernel stack | |
756 | ! | |
757 | 1: mov #-1, k4 | |
758 | mov.l 2f, k1 | |
759 | ! | |
760 | #ifdef CONFIG_SH_DSP | |
761 | mov.l r2, @-r15 ! Save r2, we need another reg | |
762 | stc sr, k4 | |
763 | mov.l 1f, r2 | |
764 | tst r2, k4 ! Check if in DSP mode | |
765 | mov.l @r15+, r2 ! Restore r2 now | |
766 | bt/s skip_save | |
767 | mov #0, k4 ! Set marker for no stack frame | |
768 | ||
769 | mov r2, k4 ! Backup r2 (in k4) for later | |
770 | ||
771 | ! Save DSP registers on stack | |
772 | stc.l mod, @-r15 | |
773 | stc.l re, @-r15 | |
774 | stc.l rs, @-r15 | |
775 | sts.l dsr, @-r15 | |
776 | sts.l y1, @-r15 | |
777 | sts.l y0, @-r15 | |
778 | sts.l x1, @-r15 | |
779 | sts.l x0, @-r15 | |
780 | sts.l a0, @-r15 | |
781 | ||
782 | ! GAS is broken, does not generate correct "movs.l Ds,@-As" instr. | |
783 | ||
784 | ! FIXME: Make sure that this is still the case with newer toolchains, | |
785 | ! as we're not at all interested in supporting ancient toolchains at | |
786 | ! this point. -- PFM. | |
787 | ||
788 | mov r15, r2 | |
789 | .word 0xf653 ! movs.l a1, @-r2 | |
790 | .word 0xf6f3 ! movs.l a0g, @-r2 | |
791 | .word 0xf6d3 ! movs.l a1g, @-r2 | |
792 | .word 0xf6c3 ! movs.l m0, @-r2 | |
793 | .word 0xf6e3 ! movs.l m1, @-r2 | |
794 | mov r2, r15 | |
795 | ||
796 | mov k4, r2 ! Restore r2 | |
797 | mov.l 1f, k4 ! Force DSP stack frame | |
798 | skip_save: | |
799 | mov.l k4, @-r15 ! Push DSP mode marker onto stack | |
800 | #endif | |
801 | ! Save the user registers on the stack. | |
802 | mov.l k2, @-r15 ! EXPEVT | |
803 | mov.l k4, @-r15 ! set TRA (default: -1) | |
804 | ! | |
805 | sts.l macl, @-r15 | |
806 | sts.l mach, @-r15 | |
807 | stc.l gbr, @-r15 | |
808 | stc.l ssr, @-r15 | |
809 | sts.l pr, @-r15 | |
810 | stc.l spc, @-r15 | |
811 | ! | |
812 | lds k3, pr ! Set the return address to pr | |
813 | ! | |
814 | mov.l k0, @-r15 ! save orignal stack | |
815 | mov.l r14, @-r15 | |
816 | mov.l r13, @-r15 | |
817 | mov.l r12, @-r15 | |
818 | mov.l r11, @-r15 | |
819 | mov.l r10, @-r15 | |
820 | mov.l r9, @-r15 | |
821 | mov.l r8, @-r15 | |
822 | ! | |
823 | stc sr, r8 ! Back to normal register bank, and | |
824 | or k1, r8 ! Block all interrupts | |
825 | mov.l 3f, k1 | |
826 | and k1, r8 ! ... | |
827 | ldc r8, sr ! ...changed here. | |
828 | ! | |
829 | mov.l r7, @-r15 | |
830 | mov.l r6, @-r15 | |
831 | mov.l r5, @-r15 | |
832 | mov.l r4, @-r15 | |
833 | mov.l r3, @-r15 | |
834 | mov.l r2, @-r15 | |
835 | mov.l r1, @-r15 | |
836 | mov.l r0, @-r15 | |
837 | ! Then, dispatch to the handler, according to the exception code. | |
838 | stc k_ex_code, r8 | |
839 | shlr2 r8 | |
840 | shlr r8 | |
841 | mov.l 4f, r9 | |
842 | add r8, r9 | |
843 | mov.l @r9, r9 | |
844 | jmp @r9 | |
845 | nop | |
846 | ||
847 | .align 2 | |
848 | 1: .long 0x00001000 ! DSP=1 | |
849 | 2: .long 0x000080f0 ! FD=1, IMASK=15 | |
850 | 3: .long 0xcfffffff ! RB=0, BL=0 | |
851 | 4: .long exception_handling_table | |
852 | ||
853 | .align 2 | |
854 | ENTRY(exception_none) | |
855 | rts | |
856 | nop | |
857 | ||
858 | .data | |
859 | ENTRY(sys_call_table) | |
860 | .long sys_ni_syscall /* 0 - old "setup()" system call*/ | |
861 | .long sys_exit | |
862 | .long sys_fork | |
863 | .long sys_read | |
864 | .long sys_write | |
865 | .long sys_open /* 5 */ | |
866 | .long sys_close | |
867 | .long sys_waitpid | |
868 | .long sys_creat | |
869 | .long sys_link | |
870 | .long sys_unlink /* 10 */ | |
871 | .long sys_execve | |
872 | .long sys_chdir | |
873 | .long sys_time | |
874 | .long sys_mknod | |
875 | .long sys_chmod /* 15 */ | |
876 | .long sys_lchown16 | |
877 | .long sys_ni_syscall /* old break syscall holder */ | |
878 | .long sys_stat | |
879 | .long sys_lseek | |
880 | .long sys_getpid /* 20 */ | |
881 | .long sys_mount | |
882 | .long sys_oldumount | |
883 | .long sys_setuid16 | |
884 | .long sys_getuid16 | |
885 | .long sys_stime /* 25 */ | |
886 | .long sys_ptrace | |
887 | .long sys_alarm | |
888 | .long sys_fstat | |
889 | .long sys_pause | |
890 | .long sys_utime /* 30 */ | |
891 | .long sys_ni_syscall /* old stty syscall holder */ | |
892 | .long sys_ni_syscall /* old gtty syscall holder */ | |
893 | .long sys_access | |
894 | .long sys_nice | |
895 | .long sys_ni_syscall /* 35 */ /* old ftime syscall holder */ | |
896 | .long sys_sync | |
897 | .long sys_kill | |
898 | .long sys_rename | |
899 | .long sys_mkdir | |
900 | .long sys_rmdir /* 40 */ | |
901 | .long sys_dup | |
902 | .long sys_pipe | |
903 | .long sys_times | |
904 | .long sys_ni_syscall /* old prof syscall holder */ | |
905 | .long sys_brk /* 45 */ | |
906 | .long sys_setgid16 | |
907 | .long sys_getgid16 | |
908 | .long sys_signal | |
909 | .long sys_geteuid16 | |
910 | .long sys_getegid16 /* 50 */ | |
911 | .long sys_acct | |
912 | .long sys_umount /* recycled never used phys() */ | |
913 | .long sys_ni_syscall /* old lock syscall holder */ | |
914 | .long sys_ioctl | |
915 | .long sys_fcntl /* 55 */ | |
916 | .long sys_ni_syscall /* old mpx syscall holder */ | |
917 | .long sys_setpgid | |
918 | .long sys_ni_syscall /* old ulimit syscall holder */ | |
919 | .long sys_ni_syscall /* sys_olduname */ | |
920 | .long sys_umask /* 60 */ | |
921 | .long sys_chroot | |
922 | .long sys_ustat | |
923 | .long sys_dup2 | |
924 | .long sys_getppid | |
925 | .long sys_getpgrp /* 65 */ | |
926 | .long sys_setsid | |
927 | .long sys_sigaction | |
928 | .long sys_sgetmask | |
929 | .long sys_ssetmask | |
930 | .long sys_setreuid16 /* 70 */ | |
931 | .long sys_setregid16 | |
932 | .long sys_sigsuspend | |
933 | .long sys_sigpending | |
934 | .long sys_sethostname | |
935 | .long sys_setrlimit /* 75 */ | |
936 | .long sys_old_getrlimit | |
937 | .long sys_getrusage | |
938 | .long sys_gettimeofday | |
939 | .long sys_settimeofday | |
940 | .long sys_getgroups16 /* 80 */ | |
941 | .long sys_setgroups16 | |
942 | .long sys_ni_syscall /* sys_oldselect */ | |
943 | .long sys_symlink | |
944 | .long sys_lstat | |
945 | .long sys_readlink /* 85 */ | |
946 | .long sys_uselib | |
947 | .long sys_swapon | |
948 | .long sys_reboot | |
949 | .long old_readdir | |
950 | .long old_mmap /* 90 */ | |
951 | .long sys_munmap | |
952 | .long sys_truncate | |
953 | .long sys_ftruncate | |
954 | .long sys_fchmod | |
955 | .long sys_fchown16 /* 95 */ | |
956 | .long sys_getpriority | |
957 | .long sys_setpriority | |
958 | .long sys_ni_syscall /* old profil syscall holder */ | |
959 | .long sys_statfs | |
960 | .long sys_fstatfs /* 100 */ | |
961 | .long sys_ni_syscall /* ioperm */ | |
962 | .long sys_socketcall | |
963 | .long sys_syslog | |
964 | .long sys_setitimer | |
965 | .long sys_getitimer /* 105 */ | |
966 | .long sys_newstat | |
967 | .long sys_newlstat | |
968 | .long sys_newfstat | |
969 | .long sys_uname | |
970 | .long sys_ni_syscall /* 110 */ /* iopl */ | |
971 | .long sys_vhangup | |
972 | .long sys_ni_syscall /* idle */ | |
973 | .long sys_ni_syscall /* vm86old */ | |
974 | .long sys_wait4 | |
975 | .long sys_swapoff /* 115 */ | |
976 | .long sys_sysinfo | |
977 | .long sys_ipc | |
978 | .long sys_fsync | |
979 | .long sys_sigreturn | |
980 | .long sys_clone /* 120 */ | |
981 | .long sys_setdomainname | |
982 | .long sys_newuname | |
983 | .long sys_ni_syscall /* sys_modify_ldt */ | |
984 | .long sys_adjtimex | |
985 | .long sys_mprotect /* 125 */ | |
986 | .long sys_sigprocmask | |
987 | .long sys_ni_syscall /* old "create_module" */ | |
988 | .long sys_init_module | |
989 | .long sys_delete_module | |
990 | .long sys_ni_syscall /* 130: old "get_kernel_syms" */ | |
991 | .long sys_quotactl | |
992 | .long sys_getpgid | |
993 | .long sys_fchdir | |
994 | .long sys_bdflush | |
995 | .long sys_sysfs /* 135 */ | |
996 | .long sys_personality | |
997 | .long sys_ni_syscall /* for afs_syscall */ | |
998 | .long sys_setfsuid16 | |
999 | .long sys_setfsgid16 | |
1000 | .long sys_llseek /* 140 */ | |
1001 | .long sys_getdents | |
1002 | .long sys_select | |
1003 | .long sys_flock | |
1004 | .long sys_msync | |
1005 | .long sys_readv /* 145 */ | |
1006 | .long sys_writev | |
1007 | .long sys_getsid | |
1008 | .long sys_fdatasync | |
1009 | .long sys_sysctl | |
1010 | .long sys_mlock /* 150 */ | |
1011 | .long sys_munlock | |
1012 | .long sys_mlockall | |
1013 | .long sys_munlockall | |
1014 | .long sys_sched_setparam | |
1015 | .long sys_sched_getparam /* 155 */ | |
1016 | .long sys_sched_setscheduler | |
1017 | .long sys_sched_getscheduler | |
1018 | .long sys_sched_yield | |
1019 | .long sys_sched_get_priority_max | |
1020 | .long sys_sched_get_priority_min /* 160 */ | |
1021 | .long sys_sched_rr_get_interval | |
1022 | .long sys_nanosleep | |
1023 | .long sys_mremap | |
1024 | .long sys_setresuid16 | |
1025 | .long sys_getresuid16 /* 165 */ | |
1026 | .long sys_ni_syscall /* vm86 */ | |
1027 | .long sys_ni_syscall /* old "query_module" */ | |
1028 | .long sys_poll | |
1029 | .long sys_nfsservctl | |
1030 | .long sys_setresgid16 /* 170 */ | |
1031 | .long sys_getresgid16 | |
1032 | .long sys_prctl | |
1033 | .long sys_rt_sigreturn | |
1034 | .long sys_rt_sigaction | |
1035 | .long sys_rt_sigprocmask /* 175 */ | |
1036 | .long sys_rt_sigpending | |
1037 | .long sys_rt_sigtimedwait | |
1038 | .long sys_rt_sigqueueinfo | |
1039 | .long sys_rt_sigsuspend | |
1040 | .long sys_pread_wrapper /* 180 */ | |
1041 | .long sys_pwrite_wrapper | |
1042 | .long sys_chown16 | |
1043 | .long sys_getcwd | |
1044 | .long sys_capget | |
1045 | .long sys_capset /* 185 */ | |
1046 | .long sys_sigaltstack | |
1047 | .long sys_sendfile | |
1048 | .long sys_ni_syscall /* streams1 */ | |
1049 | .long sys_ni_syscall /* streams2 */ | |
1050 | .long sys_vfork /* 190 */ | |
1051 | .long sys_getrlimit | |
1052 | .long sys_mmap2 | |
1053 | .long sys_truncate64 | |
1054 | .long sys_ftruncate64 | |
1055 | .long sys_stat64 /* 195 */ | |
1056 | .long sys_lstat64 | |
1057 | .long sys_fstat64 | |
1058 | .long sys_lchown | |
1059 | .long sys_getuid | |
1060 | .long sys_getgid /* 200 */ | |
1061 | .long sys_geteuid | |
1062 | .long sys_getegid | |
1063 | .long sys_setreuid | |
1064 | .long sys_setregid | |
1065 | .long sys_getgroups /* 205 */ | |
1066 | .long sys_setgroups | |
1067 | .long sys_fchown | |
1068 | .long sys_setresuid | |
1069 | .long sys_getresuid | |
1070 | .long sys_setresgid /* 210 */ | |
1071 | .long sys_getresgid | |
1072 | .long sys_chown | |
1073 | .long sys_setuid | |
1074 | .long sys_setgid | |
1075 | .long sys_setfsuid /* 215 */ | |
1076 | .long sys_setfsgid | |
1077 | .long sys_pivot_root | |
1078 | .long sys_mincore | |
1079 | .long sys_madvise | |
1080 | .long sys_getdents64 /* 220 */ | |
1081 | .long sys_fcntl64 | |
1082 | .long sys_ni_syscall /* reserved for TUX */ | |
1083 | .long sys_ni_syscall /* Reserved for Security */ | |
1084 | .long sys_gettid | |
1085 | .long sys_readahead /* 225 */ | |
1086 | .long sys_setxattr | |
1087 | .long sys_lsetxattr | |
1088 | .long sys_fsetxattr | |
1089 | .long sys_getxattr | |
1090 | .long sys_lgetxattr /* 230 */ | |
1091 | .long sys_fgetxattr | |
1092 | .long sys_listxattr | |
1093 | .long sys_llistxattr | |
1094 | .long sys_flistxattr | |
1095 | .long sys_removexattr /* 235 */ | |
1096 | .long sys_lremovexattr | |
1097 | .long sys_fremovexattr | |
1098 | .long sys_tkill | |
1099 | .long sys_sendfile64 | |
1100 | .long sys_futex /* 240 */ | |
1101 | .long sys_sched_setaffinity | |
1102 | .long sys_sched_getaffinity | |
1103 | .long sys_ni_syscall | |
1104 | .long sys_ni_syscall | |
1105 | .long sys_io_setup /* 245 */ | |
1106 | .long sys_io_destroy | |
1107 | .long sys_io_getevents | |
1108 | .long sys_io_submit | |
1109 | .long sys_io_cancel | |
1110 | .long sys_fadvise64 /* 250 */ | |
1111 | .long sys_ni_syscall | |
1112 | .long sys_exit_group | |
1113 | .long sys_lookup_dcookie | |
1114 | .long sys_epoll_create | |
1115 | .long sys_epoll_ctl /* 255 */ | |
1116 | .long sys_epoll_wait | |
1117 | .long sys_remap_file_pages | |
1118 | .long sys_set_tid_address | |
1119 | .long sys_timer_create | |
1120 | .long sys_timer_settime /* 260 */ | |
1121 | .long sys_timer_gettime | |
1122 | .long sys_timer_getoverrun | |
1123 | .long sys_timer_delete | |
1124 | .long sys_clock_settime | |
1125 | .long sys_clock_gettime /* 265 */ | |
1126 | .long sys_clock_getres | |
1127 | .long sys_clock_nanosleep | |
1128 | .long sys_statfs64 | |
1129 | .long sys_fstatfs64 | |
1130 | .long sys_tgkill /* 270 */ | |
1131 | .long sys_utimes | |
1132 | .long sys_fadvise64_64_wrapper | |
1133 | .long sys_ni_syscall /* Reserved for vserver */ | |
1134 | .long sys_ni_syscall /* Reserved for mbind */ | |
1135 | .long sys_ni_syscall /* 275 - get_mempolicy */ | |
1136 | .long sys_ni_syscall /* set_mempolicy */ | |
1137 | .long sys_mq_open | |
1138 | .long sys_mq_unlink | |
1139 | .long sys_mq_timedsend | |
1140 | .long sys_mq_timedreceive /* 280 */ | |
1141 | .long sys_mq_notify | |
1142 | .long sys_mq_getsetattr | |
1143 | .long sys_ni_syscall /* Reserved for kexec */ | |
1144 | .long sys_waitid | |
1145 | .long sys_add_key /* 285 */ | |
1146 | .long sys_request_key | |
1147 | .long sys_keyctl | |
1148 | ||
1149 | /* End of entry.S */ |