Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/sh/kernel/cpu/sh3/entry.S
26495 views
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 */
54
OFF_R0 = 0 /* Return value. New ABI also arg4 */
55
OFF_R1 = 4 /* New ABI: arg5 */
56
OFF_R2 = 8 /* New ABI: arg6 */
57
OFF_R3 = 12 /* New ABI: syscall_nr */
58
OFF_R4 = 16 /* New ABI: arg0 */
59
OFF_R5 = 20 /* New ABI: arg1 */
60
OFF_R6 = 24 /* New ABI: arg2 */
61
OFF_R7 = 28 /* New ABI: arg3 */
62
OFF_SP = (15*4)
63
OFF_PC = (16*4)
64
OFF_SR = (16*4+8)
65
OFF_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
107
ENTRY(tlb_miss_load)
108
bra call_handle_tlbmiss
109
mov #0, r5
110
111
.align 2
112
ENTRY(tlb_miss_store)
113
bra call_handle_tlbmiss
114
mov #FAULT_CODE_WRITE, r5
115
116
.align 2
117
ENTRY(initial_page_write)
118
bra call_handle_tlbmiss
119
mov #FAULT_CODE_INITIAL, r5
120
121
.align 2
122
ENTRY(tlb_protection_violation_load)
123
bra call_do_page_fault
124
mov #FAULT_CODE_PROT, r5
125
126
.align 2
127
ENTRY(tlb_protection_violation_store)
128
bra call_do_page_fault
129
mov #(FAULT_CODE_PROT | FAULT_CODE_WRITE), r5
130
131
call_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
145
0:
146
mov r8, r5
147
call_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
158
1: .long MMU_TEA
159
2: .long handle_tlbmiss
160
3: .long do_page_fault
161
4: .long ret_from_exception
162
163
.align 2
164
ENTRY(address_error_load)
165
bra call_dae
166
mov #0,r5 ! writeaccess = 0
167
168
.align 2
169
ENTRY(address_error_store)
170
bra call_dae
171
mov #1,r5 ! writeaccess = 1
172
173
.align 2
174
call_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
182
1: .long MMU_TEA
183
2: .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 */
188
ENTRY(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
201
1: .long 0x300000f0
202
2: .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
217
ENTRY(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
248
restore_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
!
270
6: or k0, k2 ! Set the IMASK-bits
271
ldc k2, ssr
272
!
273
mov k4, r15
274
rte
275
nop
276
277
.align 2
278
5: .long 0x00001000 ! DSP
279
7: .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
289
ENTRY(vbr_base)
290
.long 0
291
!
292
! 0x100: General exception vector
293
!
294
.balign 256,0,256
295
general_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
306
prepare_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
323
2: mov k1, r15 ! SP = r1
324
1:
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
!
339
1:
340
rts
341
nop
342
343
!
344
! 0x400: Instruction and Data TLB miss exception vector
345
!
346
.balign 1024,0,1024
347
tlb_miss:
348
sts pr, k3 ! save original pr value in k3
349
350
handle_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
363
handle_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
389
ENTRY(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
418
ENTRY(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
438
ENTRY(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
459
9:
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
492
10:
493
jmp @r9 ! Off to do_IRQ() we go.
494
mov r15, r5 ! pass saved registers as arg1
495
496
ENTRY(exception_none)
497
rts
498
nop
499
500
.align L1_CACHE_SHIFT
501
exception_data:
502
0: .long 0x000080f0 ! FD=1, IMASK=15
503
1: .long 0xcfffffff ! RB=0, BL=0
504
2: .long INTEVT
505
3: .long do_IRQ
506
4: .long ret_from_irq
507
5: .long EXPEVT
508
6: .long exception_handling_table
509
7: .long ret_from_exception
510
511