Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/sh/kernel/entry-common.S
26424 views
1
/* SPDX-License-Identifier: GPL-2.0
2
*
3
* Copyright (C) 1999, 2000, 2002 Niibe Yutaka
4
* Copyright (C) 2003 - 2008 Paul Mundt
5
*/
6
7
! NOTE:
8
! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address
9
! to be jumped is too far, but it causes illegal slot exception.
10
11
/*
12
* entry.S contains the system-call and fault low-level handling routines.
13
* This also contains the timer-interrupt handler, as well as all interrupts
14
* and faults that can result in a task-switch.
15
*
16
* NOTE: This code handles signal-recognition, which happens every time
17
* after a timer-interrupt and after each system call.
18
*
19
* NOTE: This code uses a convention that instructions in the delay slot
20
* of a transfer-control instruction are indented by an extra space, thus:
21
*
22
* jmp @k0 ! control-transfer instruction
23
* ldc k1, ssr ! delay slot
24
*
25
* Stack layout in 'ret_from_syscall':
26
* ptrace needs to have all regs on the stack.
27
* if the order here is changed, it needs to be
28
* updated in ptrace.c and ptrace.h
29
*
30
* r0
31
* ...
32
* r15 = stack pointer
33
* spc
34
* pr
35
* ssr
36
* gbr
37
* mach
38
* macl
39
* syscall #
40
*
41
*/
42
#include <asm/dwarf.h>
43
44
#if defined(CONFIG_PREEMPTION)
45
# define preempt_stop() cli ; TRACE_IRQS_OFF
46
#else
47
# define preempt_stop()
48
# define resume_kernel __restore_all
49
#endif
50
51
52
.align 2
53
ENTRY(exception_error)
54
!
55
TRACE_IRQS_ON
56
sti
57
mov.l 1f, r0
58
jmp @r0
59
nop
60
61
.align 2
62
1: .long do_exception_error
63
64
.align 2
65
ret_from_exception:
66
CFI_STARTPROC simple
67
CFI_DEF_CFA r14, 0
68
CFI_REL_OFFSET 17, 64
69
CFI_REL_OFFSET 15, 60
70
CFI_REL_OFFSET 14, 56
71
CFI_REL_OFFSET 13, 52
72
CFI_REL_OFFSET 12, 48
73
CFI_REL_OFFSET 11, 44
74
CFI_REL_OFFSET 10, 40
75
CFI_REL_OFFSET 9, 36
76
CFI_REL_OFFSET 8, 32
77
preempt_stop()
78
ENTRY(ret_from_irq)
79
!
80
mov #OFF_SR, r0
81
mov.l @(r0,r15), r0 ! get status register
82
shll r0
83
shll r0 ! kernel space?
84
get_current_thread_info r8, r0
85
bt resume_kernel ! Yes, it's from kernel, go back soon
86
87
#ifdef CONFIG_PREEMPTION
88
bra resume_userspace
89
nop
90
ENTRY(resume_kernel)
91
cli
92
TRACE_IRQS_OFF
93
mov.l @(TI_PRE_COUNT,r8), r0 ! current_thread_info->preempt_count
94
tst r0, r0
95
bf noresched
96
need_resched:
97
mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags
98
tst #_TIF_NEED_RESCHED, r0 ! need_resched set?
99
bt noresched
100
101
mov #OFF_SR, r0
102
mov.l @(r0,r15), r0 ! get status register
103
shlr r0
104
and #(0xf0>>1), r0 ! interrupts off (exception path)?
105
cmp/eq #(0xf0>>1), r0
106
bt noresched
107
mov.l 1f, r0
108
jsr @r0 ! call preempt_schedule_irq
109
nop
110
bra need_resched
111
nop
112
113
noresched:
114
bra __restore_all
115
nop
116
117
.align 2
118
1: .long preempt_schedule_irq
119
#endif
120
121
ENTRY(resume_userspace)
122
! r8: current_thread_info
123
cli
124
TRACE_IRQS_OFF
125
mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags
126
tst #(_TIF_WORK_MASK & 0xff), r0
127
bt/s __restore_all
128
tst #_TIF_NEED_RESCHED, r0
129
130
.align 2
131
work_pending:
132
! r0: current_thread_info->flags
133
! r8: current_thread_info
134
! t: result of "tst #_TIF_NEED_RESCHED, r0"
135
bf/s work_resched
136
tst #(_TIF_SIGPENDING | _TIF_NOTIFY_RESUME), r0
137
work_notifysig:
138
bt/s __restore_all
139
mov r15, r4
140
mov r12, r5 ! set arg1(save_r0)
141
mov r0, r6
142
sti
143
mov.l 2f, r1
144
mov.l 3f, r0
145
jmp @r1
146
lds r0, pr
147
work_resched:
148
mov.l 1f, r1
149
jsr @r1 ! schedule
150
nop
151
cli
152
TRACE_IRQS_OFF
153
!
154
mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags
155
tst #(_TIF_WORK_MASK & 0xff), r0
156
bt __restore_all
157
bra work_pending
158
tst #_TIF_NEED_RESCHED, r0
159
160
.align 2
161
1: .long schedule
162
2: .long do_notify_resume
163
3: .long resume_userspace
164
165
.align 2
166
syscall_exit_work:
167
! r0: current_thread_info->flags
168
! r8: current_thread_info
169
tst #(_TIF_WORK_SYSCALL_MASK & 0xff), r0
170
bt/s work_pending
171
tst #_TIF_NEED_RESCHED, r0
172
TRACE_IRQS_ON
173
sti
174
mov r15, r4
175
mov.l 8f, r0 ! do_syscall_trace_leave
176
jsr @r0
177
nop
178
bra resume_userspace
179
nop
180
181
__restore_all:
182
mov #OFF_SR, r0
183
mov.l @(r0,r15), r0 ! get status register
184
185
shlr2 r0
186
and #0x3c, r0
187
cmp/eq #0x3c, r0
188
bt 1f
189
TRACE_IRQS_ON
190
bra 2f
191
nop
192
1:
193
TRACE_IRQS_OFF
194
2:
195
mov.l 3f, r0
196
jmp @r0
197
nop
198
199
.align 2
200
3: .long restore_all
201
202
.align 2
203
syscall_badsys: ! Bad syscall number
204
get_current_thread_info r8, r0
205
mov #-ENOSYS, r0
206
bra resume_userspace
207
mov.l r0, @(OFF_R0,r15) ! Return value
208
209
/*
210
* The main debug trap handler.
211
*
212
* r8=TRA (not the trap number!)
213
*
214
* Note: This assumes that the trapa value is left in its original
215
* form (without the shlr2 shift) so the calculation for the jump
216
* call table offset remains a simple in place mask.
217
*/
218
debug_trap:
219
mov r8, r0
220
and #(0xf << 2), r0
221
mov.l 1f, r8
222
add r0, r8
223
mov.l @r8, r8
224
jsr @r8
225
nop
226
bra ret_from_exception
227
nop
228
CFI_ENDPROC
229
230
.align 2
231
1: .long debug_trap_table
232
233
/*
234
* Syscall interface:
235
*
236
* Syscall #: R3
237
* Arguments #0 to #3: R4--R7
238
* Arguments #4 to #6: R0, R1, R2
239
* TRA: See following table.
240
*
241
* (TRA>>2) Purpose
242
* -------- -------
243
* 0x00-0x0f original SH-3/4 syscall ABI (not in general use).
244
* 0x10-0x1f general SH-3/4 syscall ABI.
245
* 0x1f unified SH-2/3/4 syscall ABI (preferred).
246
* 0x20-0x2f original SH-2 syscall ABI.
247
* 0x30-0x3f debug traps used by the kernel.
248
* 0x40-0xff Not supported by all parts, so left unhandled.
249
*
250
* For making system calls, any trap number in the range for the
251
* given cpu model may be used, but the unified trap number 0x1f is
252
* preferred for compatibility with all models.
253
*
254
* The low bits of the trap number were once documented as matching
255
* the number of arguments, but they were never actually used as such
256
* by the kernel. SH-2 originally used its own separate trap range
257
* because several hardware exceptions fell in the range used for the
258
* SH-3/4 syscall ABI.
259
*
260
* This code also handles delegating other traps to the BIOS/gdb stub.
261
*
262
* Note: When we're first called, the TRA value must be shifted
263
* right 2 bits in order to get the value that was used as the "trapa"
264
* argument.
265
*/
266
267
.align 2
268
.globl ret_from_fork
269
ret_from_fork:
270
mov.l 1f, r8
271
jsr @r8
272
mov r0, r4
273
bra syscall_exit
274
nop
275
276
.align 2
277
.globl ret_from_kernel_thread
278
ret_from_kernel_thread:
279
mov.l 1f, r8
280
jsr @r8
281
mov r0, r4
282
mov.l @(OFF_R5,r15), r5 ! fn
283
jsr @r5
284
mov.l @(OFF_R4,r15), r4 ! arg
285
bra syscall_exit
286
nop
287
288
.align 2
289
1: .long schedule_tail
290
291
/*
292
* The poorly named main trapa decode and dispatch routine, for
293
* system calls and debug traps through their respective jump tables.
294
*/
295
ENTRY(system_call)
296
setup_frame_reg
297
#if !defined(CONFIG_CPU_SH2)
298
mov.l 1f, r9
299
mov.l @r9, r8 ! Read from TRA (Trap Address) Register
300
#endif
301
302
mov #OFF_TRA, r10
303
add r15, r10
304
mov.l r8, @r10 ! set TRA value to tra
305
306
/*
307
* Check the trap type
308
*/
309
mov #((0x20 << 2) - 1), r9
310
cmp/hi r9, r8
311
bt/s debug_trap ! it's a debug trap..
312
nop
313
314
TRACE_IRQS_ON
315
sti
316
317
!
318
get_current_thread_info r8, r10
319
mov.l @(TI_FLAGS,r8), r8
320
mov #(_TIF_WORK_SYSCALL_MASK & 0xff), r10
321
mov #(_TIF_WORK_SYSCALL_MASK >> 8), r9
322
tst r10, r8
323
shll8 r9
324
bf syscall_trace_entry
325
tst r9, r8
326
bf syscall_trace_entry
327
!
328
mov.l 6f, r8 ! Number of syscalls
329
cmp/hs r8, r3
330
bt syscall_badsys
331
!
332
syscall_call:
333
shll2 r3 ! x4
334
mov.l 3f, r8 ! Load the address of sys_call_table
335
add r8, r3
336
mov.l @r3, r8
337
mov.l @(OFF_R2,r15), r2
338
mov.l @(OFF_R1,r15), r1
339
mov.l @(OFF_R0,r15), r0
340
mov.l r2, @-r15
341
mov.l r1, @-r15
342
mov.l r0, @-r15
343
jsr @r8 ! jump to specific syscall handler
344
nop
345
add #12, r15
346
mov.l @(OFF_R0,r15), r12 ! save r0
347
mov.l r0, @(OFF_R0,r15) ! save the return value
348
!
349
syscall_exit:
350
cli
351
TRACE_IRQS_OFF
352
!
353
get_current_thread_info r8, r0
354
mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags
355
tst #(_TIF_ALLWORK_MASK & 0xff), r0
356
mov #(_TIF_ALLWORK_MASK >> 8), r1
357
bf syscall_exit_work
358
shlr8 r0
359
tst r0, r1
360
bf syscall_exit_work
361
bra __restore_all
362
nop
363
364
.align 2
365
syscall_trace_entry:
366
! Yes it is traced.
367
mov r15, r4
368
mov.l 7f, r11 ! Call do_syscall_trace_enter which notifies
369
jsr @r11 ! superior (will chomp R[0-7])
370
nop
371
cmp/eq #-1, r0
372
bt syscall_exit
373
! Reload R0-R4 from kernel stack, where the
374
! parent may have modified them using
375
! ptrace(POKEUSR). (Note that R0-R2 are
376
! reloaded from the kernel stack by syscall_call
377
! below, so don't need to be reloaded here.)
378
! This allows the parent to rewrite system calls
379
! and args on the fly.
380
mov.l @(OFF_R4,r15), r4 ! arg0
381
mov.l @(OFF_R5,r15), r5
382
mov.l @(OFF_R6,r15), r6
383
mov.l @(OFF_R7,r15), r7 ! arg3
384
mov.l @(OFF_R3,r15), r3 ! syscall_nr
385
!
386
mov.l 6f, r10 ! Number of syscalls
387
cmp/hs r10, r3
388
bf syscall_call
389
mov #-ENOSYS, r0
390
bra syscall_exit
391
mov.l r0, @(OFF_R0,r15) ! Return value
392
393
.align 2
394
#if !defined(CONFIG_CPU_SH2)
395
1: .long TRA
396
#endif
397
6: .long NR_syscalls
398
3: .long sys_call_table
399
7: .long do_syscall_trace_enter
400
8: .long do_syscall_trace_leave
401
402