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