Loading...
1/* SPDX-License-Identifier: GPL-2.0
2 *
3 * arch/sh/kernel/cpu/sh3/entry.S
4 *
5 * Copyright (C) 1999, 2000, 2002 Niibe Yutaka
6 * Copyright (C) 2003 - 2012 Paul Mundt
7 */
8#include <linux/sys.h>
9#include <linux/errno.h>
10#include <linux/linkage.h>
11#include <asm/asm-offsets.h>
12#include <asm/thread_info.h>
13#include <asm/unistd.h>
14#include <cpu/mmu_context.h>
15#include <asm/page.h>
16#include <asm/cache.h>
17
18! NOTE:
19! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address
20! to be jumped is too far, but it causes illegal slot exception.
21
22/*
23 * entry.S contains the system-call and fault low-level handling routines.
24 * This also contains the timer-interrupt handler, as well as all interrupts
25 * and faults that can result in a task-switch.
26 *
27 * NOTE: This code handles signal-recognition, which happens every time
28 * after a timer-interrupt and after each system call.
29 *
30 * NOTE: This code uses a convention that instructions in the delay slot
31 * of a transfer-control instruction are indented by an extra space, thus:
32 *
33 * jmp @k0 ! control-transfer instruction
34 * ldc k1, ssr ! delay slot
35 *
36 * Stack layout in 'ret_from_syscall':
37 * ptrace needs to have all regs on the stack.
38 * if the order here is changed, it needs to be
39 * updated in ptrace.c and ptrace.h
40 *
41 * r0
42 * ...
43 * r15 = stack pointer
44 * spc
45 * pr
46 * ssr
47 * gbr
48 * mach
49 * macl
50 * syscall #
51 *
52 */
53/* Offsets to the stack */
54OFF_R0 = 0 /* Return value. New ABI also arg4 */
55OFF_R1 = 4 /* New ABI: arg5 */
56OFF_R2 = 8 /* New ABI: arg6 */
57OFF_R3 = 12 /* New ABI: syscall_nr */
58OFF_R4 = 16 /* New ABI: arg0 */
59OFF_R5 = 20 /* New ABI: arg1 */
60OFF_R6 = 24 /* New ABI: arg2 */
61OFF_R7 = 28 /* New ABI: arg3 */
62OFF_SP = (15*4)
63OFF_PC = (16*4)
64OFF_SR = (16*4+8)
65OFF_TRA = (16*4+6*4)
66
67#define k0 r0
68#define k1 r1
69#define k2 r2
70#define k3 r3
71#define k4 r4
72
73#define g_imask r6 /* r6_bank1 */
74#define k_g_imask r6_bank /* r6_bank1 */
75#define current r7 /* r7_bank1 */
76
77#include <asm/entry-macros.S>
78
79/*
80 * Kernel mode register usage:
81 * k0 scratch
82 * k1 scratch
83 * k2 scratch (Exception code)
84 * k3 scratch (Return address)
85 * k4 scratch
86 * k5 reserved
87 * k6 Global Interrupt Mask (0--15 << 4)
88 * k7 CURRENT_THREAD_INFO (pointer to current thread info)
89 */
90
91!
92! TLB Miss / Initial Page write exception handling
93! _and_
94! TLB hits, but the access violate the protection.
95! It can be valid access, such as stack grow and/or C-O-W.
96!
97!
98! Find the pmd/pte entry and loadtlb
99! If it's not found, cause address error (SEGV)
100!
101! Although this could be written in assembly language (and it'd be faster),
102! this first version depends *much* on C implementation.
103!
104
105#if defined(CONFIG_MMU)
106 .align 2
107ENTRY(tlb_miss_load)
108 bra call_handle_tlbmiss
109 mov #0, r5
110
111 .align 2
112ENTRY(tlb_miss_store)
113 bra call_handle_tlbmiss
114 mov #FAULT_CODE_WRITE, r5
115
116 .align 2
117ENTRY(initial_page_write)
118 bra call_handle_tlbmiss
119 mov #FAULT_CODE_INITIAL, r5
120
121 .align 2
122ENTRY(tlb_protection_violation_load)
123 bra call_do_page_fault
124 mov #FAULT_CODE_PROT, r5
125
126 .align 2
127ENTRY(tlb_protection_violation_store)
128 bra call_do_page_fault
129 mov #(FAULT_CODE_PROT | FAULT_CODE_WRITE), r5
130
131call_handle_tlbmiss:
132 mov.l 1f, r0
133 mov r5, r8
134 mov.l @r0, r6
135 mov.l 2f, r0
136 sts pr, r10
137 jsr @r0
138 mov r15, r4
139 !
140 tst r0, r0
141 bf/s 0f
142 lds r10, pr
143 rts
144 nop
1450:
146 mov r8, r5
147call_do_page_fault:
148 mov.l 1f, r0
149 mov.l @r0, r6
150
151 mov.l 3f, r0
152 mov.l 4f, r1
153 mov r15, r4
154 jmp @r0
155 lds r1, pr
156
157 .align 2
1581: .long MMU_TEA
1592: .long handle_tlbmiss
1603: .long do_page_fault
1614: .long ret_from_exception
162
163 .align 2
164ENTRY(address_error_load)
165 bra call_dae
166 mov #0,r5 ! writeaccess = 0
167
168 .align 2
169ENTRY(address_error_store)
170 bra call_dae
171 mov #1,r5 ! writeaccess = 1
172
173 .align 2
174call_dae:
175 mov.l 1f, r0
176 mov.l @r0, r6 ! address
177 mov.l 2f, r0
178 jmp @r0
179 mov r15, r4 ! regs
180
181 .align 2
1821: .long MMU_TEA
1832: .long do_address_error
184#endif /* CONFIG_MMU */
185
186#if defined(CONFIG_SH_STANDARD_BIOS)
187 /* Unwind the stack and jmp to the debug entry */
188ENTRY(sh_bios_handler)
189 mov.l 1f, r8
190 bsr restore_regs
191 nop
192
193 lds k2, pr ! restore pr
194 mov k4, r15
195 !
196 mov.l 2f, k0
197 mov.l @k0, k0
198 jmp @k0
199 ldc k3, ssr
200 .align 2
2011: .long 0x300000f0
2022: .long gdb_vbr_vector
203#endif /* CONFIG_SH_STANDARD_BIOS */
204
205! restore_regs()
206! - restore r0, r1, r2, r3, r4, r5, r6, r7 from the stack
207! - switch bank
208! - restore r8, r9, r10, r11, r12, r13, r14, r15 from the stack
209! - restore spc, pr*, ssr, gbr, mach, macl, skip default tra
210! k2 returns original pr
211! k3 returns original sr
212! k4 returns original stack pointer
213! r8 passes SR bitmask, overwritten with restored data on return
214! r9 trashed
215! BL=0 on entry, on exit BL=1 (depending on r8).
216
217ENTRY(restore_regs)
218 mov.l @r15+, r0
219 mov.l @r15+, r1
220 mov.l @r15+, r2
221 mov.l @r15+, r3
222 mov.l @r15+, r4
223 mov.l @r15+, r5
224 mov.l @r15+, r6
225 mov.l @r15+, r7
226 !
227 stc sr, r9
228 or r8, r9
229 ldc r9, sr
230 !
231 mov.l @r15+, r8
232 mov.l @r15+, r9
233 mov.l @r15+, r10
234 mov.l @r15+, r11
235 mov.l @r15+, r12
236 mov.l @r15+, r13
237 mov.l @r15+, r14
238 mov.l @r15+, k4 ! original stack pointer
239 ldc.l @r15+, spc
240 mov.l @r15+, k2 ! original PR
241 mov.l @r15+, k3 ! original SR
242 ldc.l @r15+, gbr
243 lds.l @r15+, mach
244 lds.l @r15+, macl
245 rts
246 add #4, r15 ! Skip syscall number
247
248restore_all:
249 mov.l 7f, r8
250 bsr restore_regs
251 nop
252
253 lds k2, pr ! restore pr
254 !
255 ! Calculate new SR value
256 mov k3, k2 ! original SR value
257 mov #0xfffffff0, k1
258 extu.b k1, k1
259 not k1, k1
260 and k1, k2 ! Mask original SR value
261 !
262 mov k3, k0 ! Calculate IMASK-bits
263 shlr2 k0
264 and #0x3c, k0
265 cmp/eq #0x3c, k0
266 bt/s 6f
267 shll2 k0
268 mov g_imask, k0
269 !
2706: or k0, k2 ! Set the IMASK-bits
271 ldc k2, ssr
272 !
273 mov k4, r15
274 rte
275 nop
276
277 .align 2
2785: .long 0x00001000 ! DSP
2797: .long 0x30000000
280
281! common exception handler
282#include "../../entry-common.S"
283
284! Exception Vector Base
285!
286! Should be aligned page boundary.
287!
288 .balign 4096,0,4096
289ENTRY(vbr_base)
290 .long 0
291!
292! 0x100: General exception vector
293!
294 .balign 256,0,256
295general_exception:
296 bra handle_exception
297 sts pr, k3 ! save original pr value in k3
298
299! prepare_stack()
300! - roll back gRB
301! - switch to kernel stack
302! k0 returns original sp (after roll back)
303! k1 trashed
304! k2 trashed
305
306prepare_stack:
307#ifdef CONFIG_GUSA
308 ! Check for roll back gRB (User and Kernel)
309 mov r15, k0
310 shll k0
311 bf/s 1f
312 shll k0
313 bf/s 1f
314 stc spc, k1
315 stc r0_bank, k0
316 cmp/hs k0, k1 ! test k1 (saved PC) >= k0 (saved r0)
317 bt/s 2f
318 stc r1_bank, k1
319
320 add #-2, k0
321 add r15, k0
322 ldc k0, spc ! PC = saved r0 + r15 - 2
3232: mov k1, r15 ! SP = r1
3241:
325#endif
326 ! Switch to kernel stack if needed
327 stc ssr, k0 ! Is it from kernel space?
328 shll k0 ! Check MD bit (bit30) by shifting it into...
329 shll k0 ! ...the T bit
330 bt/s 1f ! It's a kernel to kernel transition.
331 mov r15, k0 ! save original stack to k0
332 /* User space to kernel */
333 mov #(THREAD_SIZE >> 10), k1
334 shll8 k1 ! k1 := THREAD_SIZE
335 shll2 k1
336 add current, k1
337 mov k1, r15 ! change to kernel stack
338 !
3391:
340 rts
341 nop
342
343!
344! 0x400: Instruction and Data TLB miss exception vector
345!
346 .balign 1024,0,1024
347tlb_miss:
348 sts pr, k3 ! save original pr value in k3
349
350handle_exception:
351 mova exception_data, k0
352
353 ! Setup stack and save DSP context (k0 contains original r15 on return)
354 bsr prepare_stack
355 PREF(k0)
356
357 ! Save registers / Switch to bank 0
358 mov.l 5f, k2 ! vector register address
359 mov.l 1f, k4 ! SR bits to clear in k4
360 bsr save_regs ! needs original pr value in k3
361 mov.l @k2, k2 ! read out vector and keep in k2
362
363handle_exception_special:
364 setup_frame_reg
365
366 ! Setup return address and jump to exception handler
367 mov.l 7f, r9 ! fetch return address
368 stc r2_bank, r0 ! k2 (vector)
369 mov.l 6f, r10
370 shlr2 r0
371 shlr r0
372 mov.l @(r0, r10), r10
373 jmp @r10
374 lds r9, pr ! put return address in pr
375
376 .align L1_CACHE_SHIFT
377
378! save_regs()
379! - save default tra, macl, mach, gbr, ssr, pr* and spc on the stack
380! - save r15*, r14, r13, r12, r11, r10, r9, r8 on the stack
381! - switch bank
382! - save r7, r6, r5, r4, r3, r2, r1, r0 on the stack
383! k0 contains original stack pointer*
384! k1 trashed
385! k3 passes original pr*
386! k4 passes SR bitmask
387! BL=1 on entry, on exit BL=0.
388
389ENTRY(save_regs)
390 mov #-1, r1
391 mov.l k1, @-r15 ! set TRA (default: -1)
392 sts.l macl, @-r15
393 sts.l mach, @-r15
394 stc.l gbr, @-r15
395 stc.l ssr, @-r15
396 mov.l k3, @-r15 ! original pr in k3
397 stc.l spc, @-r15
398
399 mov.l k0, @-r15 ! original stack pointer in k0
400 mov.l r14, @-r15
401 mov.l r13, @-r15
402 mov.l r12, @-r15
403 mov.l r11, @-r15
404 mov.l r10, @-r15
405 mov.l r9, @-r15
406 mov.l r8, @-r15
407
408 mov.l 0f, k3 ! SR bits to set in k3
409
410 ! fall-through
411
412! save_low_regs()
413! - modify SR for bank switch
414! - save r7, r6, r5, r4, r3, r2, r1, r0 on the stack
415! k3 passes bits to set in SR
416! k4 passes bits to clear in SR
417
418ENTRY(save_low_regs)
419 stc sr, r8
420 or k3, r8
421 and k4, r8
422 ldc r8, sr
423
424 mov.l r7, @-r15
425 mov.l r6, @-r15
426 mov.l r5, @-r15
427 mov.l r4, @-r15
428 mov.l r3, @-r15
429 mov.l r2, @-r15
430 mov.l r1, @-r15
431 rts
432 mov.l r0, @-r15
433
434!
435! 0x600: Interrupt / NMI vector
436!
437 .balign 512,0,512
438ENTRY(handle_interrupt)
439 sts pr, k3 ! save original pr value in k3
440 mova exception_data, k0
441
442 ! Setup stack and save DSP context (k0 contains original r15 on return)
443 bsr prepare_stack
444 PREF(k0)
445
446 ! Save registers / Switch to bank 0
447 mov.l 1f, k4 ! SR bits to clear in k4
448 bsr save_regs ! needs original pr value in k3
449 mov #-1, k2 ! default vector kept in k2
450
451 setup_frame_reg
452
453 stc sr, r0 ! get status register
454 shlr2 r0
455 and #0x3c, r0
456 cmp/eq #0x3c, r0
457 bf 9f
458 TRACE_IRQS_OFF
4599:
460
461 ! Setup return address and jump to do_IRQ
462 mov.l 4f, r9 ! fetch return address
463 lds r9, pr ! put return address in pr
464 mov.l 2f, r4
465 mov.l 3f, r9
466 mov.l @r4, r4 ! pass INTEVT vector as arg0
467
468 shlr2 r4
469 shlr r4
470 mov r4, r0 ! save vector->jmp table offset for later
471
472 shlr2 r4 ! vector to IRQ# conversion
473
474 mov #0x10, r5
475 cmp/hs r5, r4 ! is it a valid IRQ?
476 bt 10f
477
478 /*
479 * We got here as a result of taking the INTEVT path for something
480 * that isn't a valid hard IRQ, therefore we bypass the do_IRQ()
481 * path and special case the event dispatch instead. This is the
482 * expected path for the NMI (and any other brilliantly implemented
483 * exception), which effectively wants regular exception dispatch
484 * but is unfortunately reported through INTEVT rather than
485 * EXPEVT. Grr.
486 */
487 mov.l 6f, r9
488 mov.l @(r0, r9), r9
489 jmp @r9
490 mov r15, r8 ! trap handlers take saved regs in r8
491
49210:
493 jmp @r9 ! Off to do_IRQ() we go.
494 mov r15, r5 ! pass saved registers as arg1
495
496ENTRY(exception_none)
497 rts
498 nop
499
500 .align L1_CACHE_SHIFT
501exception_data:
5020: .long 0x000080f0 ! FD=1, IMASK=15
5031: .long 0xcfffffff ! RB=0, BL=0
5042: .long INTEVT
5053: .long do_IRQ
5064: .long ret_from_irq
5075: .long EXPEVT
5086: .long exception_handling_table
5097: .long ret_from_exception
1/*
2 * arch/sh/kernel/cpu/sh3/entry.S
3 *
4 * Copyright (C) 1999, 2000, 2002 Niibe Yutaka
5 * Copyright (C) 2003 - 2012 Paul Mundt
6 *
7 * This file is subject to the terms and conditions of the GNU General Public
8 * License. See the file "COPYING" in the main directory of this archive
9 * for more details.
10 */
11#include <linux/sys.h>
12#include <linux/errno.h>
13#include <linux/linkage.h>
14#include <asm/asm-offsets.h>
15#include <asm/thread_info.h>
16#include <asm/unistd.h>
17#include <cpu/mmu_context.h>
18#include <asm/page.h>
19#include <asm/cache.h>
20#include <asm/thread_info.h>
21
22! NOTE:
23! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address
24! to be jumped is too far, but it causes illegal slot exception.
25
26/*
27 * entry.S contains the system-call and fault low-level handling routines.
28 * This also contains the timer-interrupt handler, as well as all interrupts
29 * and faults that can result in a task-switch.
30 *
31 * NOTE: This code handles signal-recognition, which happens every time
32 * after a timer-interrupt and after each system call.
33 *
34 * NOTE: This code uses a convention that instructions in the delay slot
35 * of a transfer-control instruction are indented by an extra space, thus:
36 *
37 * jmp @k0 ! control-transfer instruction
38 * ldc k1, ssr ! delay slot
39 *
40 * Stack layout in 'ret_from_syscall':
41 * ptrace needs to have all regs on the stack.
42 * if the order here is changed, it needs to be
43 * updated in ptrace.c and ptrace.h
44 *
45 * r0
46 * ...
47 * r15 = stack pointer
48 * spc
49 * pr
50 * ssr
51 * gbr
52 * mach
53 * macl
54 * syscall #
55 *
56 */
57/* Offsets to the stack */
58OFF_R0 = 0 /* Return value. New ABI also arg4 */
59OFF_R1 = 4 /* New ABI: arg5 */
60OFF_R2 = 8 /* New ABI: arg6 */
61OFF_R3 = 12 /* New ABI: syscall_nr */
62OFF_R4 = 16 /* New ABI: arg0 */
63OFF_R5 = 20 /* New ABI: arg1 */
64OFF_R6 = 24 /* New ABI: arg2 */
65OFF_R7 = 28 /* New ABI: arg3 */
66OFF_SP = (15*4)
67OFF_PC = (16*4)
68OFF_SR = (16*4+8)
69OFF_TRA = (16*4+6*4)
70
71#define k0 r0
72#define k1 r1
73#define k2 r2
74#define k3 r3
75#define k4 r4
76
77#define g_imask r6 /* r6_bank1 */
78#define k_g_imask r6_bank /* r6_bank1 */
79#define current r7 /* r7_bank1 */
80
81#include <asm/entry-macros.S>
82
83/*
84 * Kernel mode register usage:
85 * k0 scratch
86 * k1 scratch
87 * k2 scratch (Exception code)
88 * k3 scratch (Return address)
89 * k4 scratch
90 * k5 reserved
91 * k6 Global Interrupt Mask (0--15 << 4)
92 * k7 CURRENT_THREAD_INFO (pointer to current thread info)
93 */
94
95!
96! TLB Miss / Initial Page write exception handling
97! _and_
98! TLB hits, but the access violate the protection.
99! It can be valid access, such as stack grow and/or C-O-W.
100!
101!
102! Find the pmd/pte entry and loadtlb
103! If it's not found, cause address error (SEGV)
104!
105! Although this could be written in assembly language (and it'd be faster),
106! this first version depends *much* on C implementation.
107!
108
109#if defined(CONFIG_MMU)
110 .align 2
111ENTRY(tlb_miss_load)
112 bra call_handle_tlbmiss
113 mov #0, r5
114
115 .align 2
116ENTRY(tlb_miss_store)
117 bra call_handle_tlbmiss
118 mov #FAULT_CODE_WRITE, r5
119
120 .align 2
121ENTRY(initial_page_write)
122 bra call_handle_tlbmiss
123 mov #FAULT_CODE_INITIAL, r5
124
125 .align 2
126ENTRY(tlb_protection_violation_load)
127 bra call_do_page_fault
128 mov #FAULT_CODE_PROT, r5
129
130 .align 2
131ENTRY(tlb_protection_violation_store)
132 bra call_do_page_fault
133 mov #(FAULT_CODE_PROT | FAULT_CODE_WRITE), r5
134
135call_handle_tlbmiss:
136 mov.l 1f, r0
137 mov r5, r8
138 mov.l @r0, r6
139 mov.l 2f, r0
140 sts pr, r10
141 jsr @r0
142 mov r15, r4
143 !
144 tst r0, r0
145 bf/s 0f
146 lds r10, pr
147 rts
148 nop
1490:
150 mov r8, r5
151call_do_page_fault:
152 mov.l 1f, r0
153 mov.l @r0, r6
154
155 mov.l 3f, r0
156 mov.l 4f, r1
157 mov r15, r4
158 jmp @r0
159 lds r1, pr
160
161 .align 2
1621: .long MMU_TEA
1632: .long handle_tlbmiss
1643: .long do_page_fault
1654: .long ret_from_exception
166
167 .align 2
168ENTRY(address_error_load)
169 bra call_dae
170 mov #0,r5 ! writeaccess = 0
171
172 .align 2
173ENTRY(address_error_store)
174 bra call_dae
175 mov #1,r5 ! writeaccess = 1
176
177 .align 2
178call_dae:
179 mov.l 1f, r0
180 mov.l @r0, r6 ! address
181 mov.l 2f, r0
182 jmp @r0
183 mov r15, r4 ! regs
184
185 .align 2
1861: .long MMU_TEA
1872: .long do_address_error
188#endif /* CONFIG_MMU */
189
190#if defined(CONFIG_SH_STANDARD_BIOS)
191 /* Unwind the stack and jmp to the debug entry */
192ENTRY(sh_bios_handler)
193 mov.l 1f, r8
194 bsr restore_regs
195 nop
196
197 lds k2, pr ! restore pr
198 mov k4, r15
199 !
200 mov.l 2f, k0
201 mov.l @k0, k0
202 jmp @k0
203 ldc k3, ssr
204 .align 2
2051: .long 0x300000f0
2062: .long gdb_vbr_vector
207#endif /* CONFIG_SH_STANDARD_BIOS */
208
209! restore_regs()
210! - restore r0, r1, r2, r3, r4, r5, r6, r7 from the stack
211! - switch bank
212! - restore r8, r9, r10, r11, r12, r13, r14, r15 from the stack
213! - restore spc, pr*, ssr, gbr, mach, macl, skip default tra
214! k2 returns original pr
215! k3 returns original sr
216! k4 returns original stack pointer
217! r8 passes SR bitmask, overwritten with restored data on return
218! r9 trashed
219! BL=0 on entry, on exit BL=1 (depending on r8).
220
221ENTRY(restore_regs)
222 mov.l @r15+, r0
223 mov.l @r15+, r1
224 mov.l @r15+, r2
225 mov.l @r15+, r3
226 mov.l @r15+, r4
227 mov.l @r15+, r5
228 mov.l @r15+, r6
229 mov.l @r15+, r7
230 !
231 stc sr, r9
232 or r8, r9
233 ldc r9, sr
234 !
235 mov.l @r15+, r8
236 mov.l @r15+, r9
237 mov.l @r15+, r10
238 mov.l @r15+, r11
239 mov.l @r15+, r12
240 mov.l @r15+, r13
241 mov.l @r15+, r14
242 mov.l @r15+, k4 ! original stack pointer
243 ldc.l @r15+, spc
244 mov.l @r15+, k2 ! original PR
245 mov.l @r15+, k3 ! original SR
246 ldc.l @r15+, gbr
247 lds.l @r15+, mach
248 lds.l @r15+, macl
249 rts
250 add #4, r15 ! Skip syscall number
251
252restore_all:
253 mov.l 7f, r8
254 bsr restore_regs
255 nop
256
257 lds k2, pr ! restore pr
258 !
259 ! Calculate new SR value
260 mov k3, k2 ! original SR value
261 mov #0xfffffff0, k1
262 extu.b k1, k1
263 not k1, k1
264 and k1, k2 ! Mask original SR value
265 !
266 mov k3, k0 ! Calculate IMASK-bits
267 shlr2 k0
268 and #0x3c, k0
269 cmp/eq #0x3c, k0
270 bt/s 6f
271 shll2 k0
272 mov g_imask, k0
273 !
2746: or k0, k2 ! Set the IMASK-bits
275 ldc k2, ssr
276 !
277 mov k4, r15
278 rte
279 nop
280
281 .align 2
2825: .long 0x00001000 ! DSP
2837: .long 0x30000000
284
285! common exception handler
286#include "../../entry-common.S"
287
288! Exception Vector Base
289!
290! Should be aligned page boundary.
291!
292 .balign 4096,0,4096
293ENTRY(vbr_base)
294 .long 0
295!
296! 0x100: General exception vector
297!
298 .balign 256,0,256
299general_exception:
300 bra handle_exception
301 sts pr, k3 ! save original pr value in k3
302
303! prepare_stack()
304! - roll back gRB
305! - switch to kernel stack
306! k0 returns original sp (after roll back)
307! k1 trashed
308! k2 trashed
309
310prepare_stack:
311#ifdef CONFIG_GUSA
312 ! Check for roll back gRB (User and Kernel)
313 mov r15, k0
314 shll k0
315 bf/s 1f
316 shll k0
317 bf/s 1f
318 stc spc, k1
319 stc r0_bank, k0
320 cmp/hs k0, k1 ! test k1 (saved PC) >= k0 (saved r0)
321 bt/s 2f
322 stc r1_bank, k1
323
324 add #-2, k0
325 add r15, k0
326 ldc k0, spc ! PC = saved r0 + r15 - 2
3272: mov k1, r15 ! SP = r1
3281:
329#endif
330 ! Switch to kernel stack if needed
331 stc ssr, k0 ! Is it from kernel space?
332 shll k0 ! Check MD bit (bit30) by shifting it into...
333 shll k0 ! ...the T bit
334 bt/s 1f ! It's a kernel to kernel transition.
335 mov r15, k0 ! save original stack to k0
336 /* User space to kernel */
337 mov #(THREAD_SIZE >> 10), k1
338 shll8 k1 ! k1 := THREAD_SIZE
339 shll2 k1
340 add current, k1
341 mov k1, r15 ! change to kernel stack
342 !
3431:
344 rts
345 nop
346
347!
348! 0x400: Instruction and Data TLB miss exception vector
349!
350 .balign 1024,0,1024
351tlb_miss:
352 sts pr, k3 ! save original pr value in k3
353
354handle_exception:
355 mova exception_data, k0
356
357 ! Setup stack and save DSP context (k0 contains original r15 on return)
358 bsr prepare_stack
359 PREF(k0)
360
361 ! Save registers / Switch to bank 0
362 mov.l 5f, k2 ! vector register address
363 mov.l 1f, k4 ! SR bits to clear in k4
364 bsr save_regs ! needs original pr value in k3
365 mov.l @k2, k2 ! read out vector and keep in k2
366
367handle_exception_special:
368 setup_frame_reg
369
370 ! Setup return address and jump to exception handler
371 mov.l 7f, r9 ! fetch return address
372 stc r2_bank, r0 ! k2 (vector)
373 mov.l 6f, r10
374 shlr2 r0
375 shlr r0
376 mov.l @(r0, r10), r10
377 jmp @r10
378 lds r9, pr ! put return address in pr
379
380 .align L1_CACHE_SHIFT
381
382! save_regs()
383! - save default tra, macl, mach, gbr, ssr, pr* and spc on the stack
384! - save r15*, r14, r13, r12, r11, r10, r9, r8 on the stack
385! - switch bank
386! - save r7, r6, r5, r4, r3, r2, r1, r0 on the stack
387! k0 contains original stack pointer*
388! k1 trashed
389! k3 passes original pr*
390! k4 passes SR bitmask
391! BL=1 on entry, on exit BL=0.
392
393ENTRY(save_regs)
394 mov #-1, r1
395 mov.l k1, @-r15 ! set TRA (default: -1)
396 sts.l macl, @-r15
397 sts.l mach, @-r15
398 stc.l gbr, @-r15
399 stc.l ssr, @-r15
400 mov.l k3, @-r15 ! original pr in k3
401 stc.l spc, @-r15
402
403 mov.l k0, @-r15 ! original stack pointer in k0
404 mov.l r14, @-r15
405 mov.l r13, @-r15
406 mov.l r12, @-r15
407 mov.l r11, @-r15
408 mov.l r10, @-r15
409 mov.l r9, @-r15
410 mov.l r8, @-r15
411
412 mov.l 0f, k3 ! SR bits to set in k3
413
414 ! fall-through
415
416! save_low_regs()
417! - modify SR for bank switch
418! - save r7, r6, r5, r4, r3, r2, r1, r0 on the stack
419! k3 passes bits to set in SR
420! k4 passes bits to clear in SR
421
422ENTRY(save_low_regs)
423 stc sr, r8
424 or k3, r8
425 and k4, r8
426 ldc r8, sr
427
428 mov.l r7, @-r15
429 mov.l r6, @-r15
430 mov.l r5, @-r15
431 mov.l r4, @-r15
432 mov.l r3, @-r15
433 mov.l r2, @-r15
434 mov.l r1, @-r15
435 rts
436 mov.l r0, @-r15
437
438!
439! 0x600: Interrupt / NMI vector
440!
441 .balign 512,0,512
442ENTRY(handle_interrupt)
443 sts pr, k3 ! save original pr value in k3
444 mova exception_data, k0
445
446 ! Setup stack and save DSP context (k0 contains original r15 on return)
447 bsr prepare_stack
448 PREF(k0)
449
450 ! Save registers / Switch to bank 0
451 mov.l 1f, k4 ! SR bits to clear in k4
452 bsr save_regs ! needs original pr value in k3
453 mov #-1, k2 ! default vector kept in k2
454
455 setup_frame_reg
456
457 stc sr, r0 ! get status register
458 shlr2 r0
459 and #0x3c, r0
460 cmp/eq #0x3c, r0
461 bf 9f
462 TRACE_IRQS_OFF
4639:
464
465 ! Setup return address and jump to do_IRQ
466 mov.l 4f, r9 ! fetch return address
467 lds r9, pr ! put return address in pr
468 mov.l 2f, r4
469 mov.l 3f, r9
470 mov.l @r4, r4 ! pass INTEVT vector as arg0
471
472 shlr2 r4
473 shlr r4
474 mov r4, r0 ! save vector->jmp table offset for later
475
476 shlr2 r4 ! vector to IRQ# conversion
477 add #-0x10, r4
478
479 cmp/pz r4 ! is it a valid IRQ?
480 bt 10f
481
482 /*
483 * We got here as a result of taking the INTEVT path for something
484 * that isn't a valid hard IRQ, therefore we bypass the do_IRQ()
485 * path and special case the event dispatch instead. This is the
486 * expected path for the NMI (and any other brilliantly implemented
487 * exception), which effectively wants regular exception dispatch
488 * but is unfortunately reported through INTEVT rather than
489 * EXPEVT. Grr.
490 */
491 mov.l 6f, r9
492 mov.l @(r0, r9), r9
493 jmp @r9
494 mov r15, r8 ! trap handlers take saved regs in r8
495
49610:
497 jmp @r9 ! Off to do_IRQ() we go.
498 mov r15, r5 ! pass saved registers as arg1
499
500ENTRY(exception_none)
501 rts
502 nop
503
504 .align L1_CACHE_SHIFT
505exception_data:
5060: .long 0x000080f0 ! FD=1, IMASK=15
5071: .long 0xcfffffff ! RB=0, BL=0
5082: .long INTEVT
5093: .long do_IRQ
5104: .long ret_from_irq
5115: .long EXPEVT
5126: .long exception_handling_table
5137: .long ret_from_exception