summaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel/entry-common.S
blob: 42232633872faeb778c38ace002507b3a83f634f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
/*============================================================================
 * All exits to user mode from the kernel go through this code.
 */

#include <linux/config.h>

		.globl	ret_from_sys_call

		.globl	SYMBOL_NAME(fpreturn)
SYMBOL_NAME(fpreturn):
ret_from_exception:
		adr	r0, 1f
		ldmia	r0, {r0, r1}
		ldr	r0, [r0]
		ldr	r1, [r1]
		tst	r0, r1
		blne	SYMBOL_NAME(do_bottom_half)
ret_from_intr:	ldr	r0, [sp, #S_PSR]
		tst	r0, #3
		beq	ret_with_reschedule
		b	ret_from_all

ret_signal:	mov	r1, sp
		adrsvc	al, lr, ret_from_all
		b	SYMBOL_NAME(do_signal)

2:		bl	SYMBOL_NAME(schedule)

ret_from_sys_call:
		adr	r0, 1f
		ldmia	r0, {r0, r1}
		ldr	r0, [r0]
		ldr	r1, [r1]
		tst	r0, r1
		adrsvc	ne, lr, ret_from_intr
		bne	SYMBOL_NAME(do_bottom_half)

ret_with_reschedule:
		ldr	r0, 1f + 8
		ldr	r0, [r0]
		teq	r0, #0
		bne	2b

		get_current_task r1
		ldr	r1, [r1, #TSK_SIGPENDING]
		teq	r1, #0
		bne	ret_signal

ret_from_all:	restore_user_regs

1:		.word	SYMBOL_NAME(bh_mask)
		.word	SYMBOL_NAME(bh_active)
		.word	SYMBOL_NAME(need_resched)

/*=============================================================================
 * SWI handler
 *-----------------------------------------------------------------------------
 *
 * We now handle sys-call tracing, and the errno in the task structure.
 * Still have a problem with >4 arguments for functions.  Theres only
 * a couple of functions in the code that have 5 arguments, so Im not
 * too worried.
 */

#include "calls.S"

vector_swi:	save_user_regs
		mov	fp, #0
		mask_pc	lr, lr
		ldr	r6, [lr, #-4]!		@ get SWI instruction
		arm700_bug_check r6, r7
		enable_irqs r7
		
		bic	r6, r6, #0xff000000	@ mask off SWI op-code
		eor	r6, r6, #OS_NUMBER<<20	@ check OS number
		cmp	r6, #NR_syscalls	@ check upper syscall limit
		bcs	2f

		get_current_task r5
		ldr	ip, [r5, #TSK_FLAGS]	@ check for syscall tracing
		tst	ip, #PF_TRACESYS
		bne	1f

		adr	ip, SYMBOL_NAME(sys_call_table)
		str	r4, [sp, #-4]!		@ new style: (r0 = arg1, r5 = arg5)
		mov	lr, pc
		ldr	pc, [ip, r6, lsl #2]	@ call sys routine
		add	sp, sp, #4
		str	r0, [sp, #S_R0]		@ returned r0
		b	ret_from_sys_call

1:		ldr	r7, [sp, #S_IP]		@ save old IP
		mov	r0, #0
		str	r0, [sp, #S_IP]		@ trace entry [IP = 0]
		bl	SYMBOL_NAME(syscall_trace)
		str	r7, [sp, #S_IP]
		ldmia	sp, {r0 - r3}		@ have to reload r0 - r3
		adr	ip, SYMBOL_NAME(sys_call_table)
		str	r4, [sp, #-4]!		@ new style: (r0 = arg1, r5 = arg5)
		mov	lr, pc
		ldr	pc, [ip, r6, lsl #2]	@ call sys routine
		add	sp, sp, #4
		str	r0, [sp, #S_R0]		@ returned r0
		mov	r0, #1
		str	r0, [sp, #S_IP]		@ trace exit [IP = 1]
		bl	SYMBOL_NAME(syscall_trace)
		str	r7, [sp, #S_IP]
		b	ret_from_sys_call

2:		tst	r6, #0x00f00000		@ is it a Unix SWI?
		bne	3f
		cmp	r6, #(KSWI_SYS_BASE - KSWI_BASE)
		bcc	4f			@ not private func
		bic	r0, r6, #0x000f0000
		mov	r1, sp
		bl	SYMBOL_NAME(arm_syscall)
		b	ret_from_sys_call

3:		eor	r0, r6, #OS_NUMBER<<20	@ Put OS number back
		mov	r1, sp
		bl	SYMBOL_NAME(deferred)
		ldmfd	sp, {r0 - r3}
		b	ret_from_sys_call

4:		bl	SYMBOL_NAME(sys_ni_syscall)
		str	r0, [sp, #0]		@ returned r0
		b	ret_from_sys_call

@ r0 = syscall number
@ r1 = syscall r0
@ r5 = syscall r4
@ ip = syscall table
SYMBOL_NAME(sys_syscall):
		mov	r6, r0
		eor	r6, r6, #OS_NUMBER << 20
		cmp	r6, #NR_syscalls		@ check range
		movgt	r0, #-ENOSYS
		movgt	pc, lr
		add	sp, sp, #4			@ take of the save of our r4
		ldmib	sp, {r0 - r4}			@ get our args
		str	r4, [sp, #-4]!			@ Put our arg on the stack
		ldr	pc, [ip, r6, lsl #2]

ENTRY(sys_call_table)
#include "calls.S"

/*============================================================================
 * Special system call wrappers
 */
sys_fork_wrapper:
		add	r0, sp, #4
		b	SYMBOL_NAME(sys_fork)

sys_execve_wrapper:
		add	r3, sp, #4
		b	SYMBOL_NAME(sys_execve)

sys_mount_wrapper:
		mov	r6, lr
		add	r5, sp, #4
		str	r5, [sp]
		str	r4, [sp, #-4]!
		bl	SYMBOL_NAME(sys_compat_mount)
		add	sp, sp, #4
		RETINSTR(mov,pc,r6)

sys_clone_wapper:
		add	r2, sp, #4
		b	SYMBOL_NAME(sys_clone)

sys_llseek_wrapper:
		mov	r6, lr
		add	r5, sp, #4
		str	r5, [sp]
		str	r4, [sp, #-4]!
		bl	SYMBOL_NAME(sys_compat_llseek)
		add	sp, sp, #4
		RETINSTR(mov,pc,r6)

sys_sigsuspend_wrapper:
		add	r3, sp, #4
		b	SYMBOL_NAME(sys_sigsuspend)

sys_rt_sigsuspend_wrapper:
		add	r2, sp, #4
		b	SYMBOL_NAME(sys_rt_sigsuspend)

sys_sigreturn_wrapper:
		add	r0, sp, #4
		b	SYMBOL_NAME(sys_sigreturn)

sys_rt_sigreturn_wrapper:
		add	r0, sp, #4
		b	SYMBOL_NAME(sys_rt_sigreturn)

sys_sigaltstack_wrapper:
		ldr	r2, [sp, #4 + S_SP]
		b	do_sigaltstack

/*
 *=============================================================================
 *		Low-level interface code
 *-----------------------------------------------------------------------------
 *		Trap initialisation
 *-----------------------------------------------------------------------------
 *
 * Note - FIQ code has changed.  The default is a couple of words in 0x1c, 0x20
 * that call _unexp_fiq.  Nowever, we now copy the FIQ routine to 0x1c (removes
 * some excess cycles).
 *
 * What we need to put into 0-0x1c are ldrs to branch to 0xC0000000
 * (the kernel).
 * 0x1c onwards is reserved for FIQ, so I think that I will allocate 0xe0 onwards for
 * the actuall address to jump to.
 */
#if defined(CONFIG_CPU_32)
/*
 * these go into 0x00
 */
.Lbranches:	swi	SYS_ERROR0
		ldr	pc, .Lbranches + 0xe4
		ldr	pc, .Lbranches + 0xe8
		ldr	pc, .Lbranches + 0xec
		ldr	pc, .Lbranches + 0xf0
		ldr	pc, .Lbranches + 0xf4
		ldr	pc, .Lbranches + 0xf8
		ldr	pc, .Lbranches + 0xfc
/*
 * this is put into 0xe4 and above
 */
.Ljump_addresses:
		.word	vector_undefinstr	@ 0xe4
		.word	vector_swi		@ 0xe8
		.word	vector_prefetch		@ 0xec
		.word	vector_data		@ 0xf0
		.word	vector_addrexcptn	@ 0xf4
		.word	vector_IRQ		@ 0xf8
		.word	_unexp_fiq		@ 0xfc
/*
 * initialise the trap system
 */
ENTRY(trap_init)
		stmfd	sp!, {r4 - r7, lr}
		initialise_traps_extra
		mov	r0, #0xe4
		adr	r1, .Ljump_addresses
		ldmia	r1, {r1 - r7}
		stmia	r0, {r1 - r7}
		mov	r0, #0
		adr	r1, .Lbranches
		ldmia	r1, {r1 - r7}
		stmia	r0, {r1 - r7}
		LOADREGS(fd, sp!, {r4 - r7, pc})
#elif defined(CONFIG_CPU_26)
.Ljump_addresses:
		swi	SYS_ERROR0
		.word	vector_undefinstr	- 12
		.word	vector_swi		- 16
		.word	vector_prefetch		- 20
		.word	vector_data		- 24
		.word	vector_addrexcptn	- 28
		.word	vector_IRQ		- 32
		.word	_unexp_fiq		- 36
		b	. + 8
/*
 * initialise the trap system
 */
ENTRY(trap_init)
		stmfd	sp!, {r4 - r7, lr}
		adr	r1, .Ljump_addresses
		ldmia	r1, {r1 - r7, ip, lr}
		orr	r2, lr, r2, lsr #2
		orr	r3, lr, r3, lsr #2
		orr	r4, lr, r4, lsr #2
		orr	r5, lr, r5, lsr #2
		orr	r6, lr, r6, lsr #2
		orr	r7, lr, r7, lsr #2
		orr	ip, lr, ip, lsr #2
		mov	r0, #0
		stmia	r0, {r1 - r7, ip}
		ldmfd	sp!, {r4 - r7, pc}^
#endif

/*============================================================================
 * FP support
 */

1:		.word	SYMBOL_NAME(fp_save)
		.word	SYMBOL_NAME(fp_restore)

.Lfpnull:	mov	pc, lr


/*
 * Function to call when switching tasks to save FP state
 */
ENTRY(fpe_save)
		ldr	r1, 1b
		ldr	pc, [r1]

/*
 * Function to call when switching tasks to restore FP state
 */
ENTRY(fpe_restore)
		ldr	r1, 1b + 4
		ldr	pc, [r1]


		.data

ENTRY(fp_enter)
		.word	SYMBOL_NAME(fpundefinstr)
		.word	SYMBOL_NAME(fpundefinstrsvc)

ENTRY(fp_save)
		.word	.Lfpnull
ENTRY(fp_restore)
		.word	.Lfpnull