1#include <linux/config.h> /* for CONFIG_ARCH_xxxx */
2#include <linux/linkage.h>
3
4#include <asm/assembler.h>
5#include <asm/constants.h>
6#include <asm/errno.h>
7#include <asm/hardware.h>
8#include <asm/arch/irqs.h>
9#include <asm/proc-fns.h>
10
11#ifndef MODE_SVC
12#define MODE_SVC 0x13
13#endif
14
15		.macro	zero_fp
16#ifdef CONFIG_FRAME_POINTER
17		mov	fp, #0
18#endif
19		.endm
20
21		.text
22
23@ Bad Abort numbers
24@ -----------------
25@
26#define BAD_PREFETCH	0
27#define BAD_DATA	1
28#define BAD_ADDREXCPTN	2
29#define BAD_IRQ		3
30#define BAD_UNDEFINSTR	4
31
32#define PT_TRACESYS	0x00000002
33
34@ OS version number used in SWIs
35@  RISC OS is 0
36@  RISC iX is 8
37@
38#define OS_NUMBER	9
39#define ARMSWI_OFFSET	0x000f0000
40
41@
42@ Stack format (ensured by USER_* and SVC_*)
43@
44#ifdef CONFIG_CPU_32
45#define S_FRAME_SIZE	72
46#define S_OLD_R0	68
47#define S_PSR		64
48#else
49#define S_FRAME_SIZE	68
50#define S_OLD_R0	64
51#define S_PSR		60
52#endif
53
54#define S_PC		60
55#define S_LR		56
56#define S_SP		52
57#define S_IP		48
58#define S_FP		44
59#define S_R10		40
60#define S_R9		36
61#define S_R8		32
62#define S_R7		28
63#define S_R6		24
64#define S_R5		20
65#define S_R4		16
66#define S_R3		12
67#define S_R2		8
68#define S_R1		4
69#define S_R0		0
70#define S_OFF		8
71
72#ifdef CONFIG_CPU_32
73	.macro	set_cpsr_c, reg, mode
74#if 1
75	/* broken binutils */
76	mov	\reg, \mode
77	msr	cpsr_c, \reg
78#else
79	msr	cpsr_c, \mode
80#endif
81	.endm
82
83	.macro	disable_irq, temp
84	set_cpsr_c \temp, #I_BIT | MODE_SVC
85	.endm
86
87	.macro	enable_irq, temp
88	set_cpsr_c \temp, #MODE_SVC
89	.endm
90
91		.macro	save_user_regs
92		sub	sp, sp, #S_FRAME_SIZE
93		stmia	sp, {r0 - r12}			@ Calling r0 - r12
94		add	r8, sp, #S_PC
95		stmdb	r8, {sp, lr}^			@ Calling sp, lr
96		mrs	r8, spsr			@ called from non-FIQ mode, so ok.
97		str	lr, [sp, #S_PC]			@ Save calling PC
98		str	r8, [sp, #S_PSR]		@ Save CPSR
99		str	r0, [sp, #S_OLD_R0]		@ Save OLD_R0
100		.endm
101
102/*
103 * Must be called with IRQs already disabled.
104 */
105		.macro	restore_user_regs
106		ldr	r1, [sp, #S_PSR]		@ Get calling cpsr
107		ldr	lr, [sp, #S_PC]!		@ Get PC
108		msr	spsr, r1			@ save in spsr_svc
109		ldmdb	sp, {r0 - lr}^			@ Get calling r0 - lr
110		mov	r0, r0
111		add	sp, sp, #S_FRAME_SIZE - S_PC
112		movs	pc, lr				@ return & move spsr_svc into cpsr
113		.endm
114
115/*
116 * Must be called with IRQs already disabled.
117 */
118		.macro	fast_restore_user_regs
119		ldr	r1, [sp, #S_OFF + S_PSR]	@ get calling cpsr
120		ldr	lr, [sp, #S_OFF + S_PC]!	@ get pc
121 		msr	spsr, r1			@ save in spsr_svc
122		ldmdb	sp, {r1 - lr}^			@ get calling r1 - lr
123		mov	r0, r0
124		add	sp, sp, #S_FRAME_SIZE - S_PC
125		movs	pc, lr				@ return & move spsr_svc into cpsr
126		.endm
127
128		.macro	mask_pc, rd, rm
129		.endm
130
131		.macro	get_current_task, rd
132		mov	\rd, sp, lsr #13
133		mov	\rd, \rd, lsl #13
134		.endm
135
136		/*
137		 * Like adr, but force SVC mode (if required)
138		 */
139		.macro	adrsvc, cond, reg, label
140		adr\cond	\reg, \label
141		.endm
142
143		.macro	alignment_trap, rbase, rtemp, sym
144#ifdef CONFIG_ALIGNMENT_TRAP
145#define OFF_CR_ALIGNMENT(x)	cr_alignment - x
146
147		ldr	\rtemp, [\rbase, #OFF_CR_ALIGNMENT(\sym)]
148		mcr	p15, 0, \rtemp, c1, c0
149#endif
150		.endm
151
152#else
153		.macro	save_user_regs
154		sub	sp, sp, #S_FRAME_SIZE
155		str	r0, [sp, #S_OLD_R0]
156		str	lr, [sp, #S_PC]
157		stmia	sp, {r0 - lr}^
158		mov	r0, r0
159		.endm
160
161		.macro	restore_user_regs
162		ldmia	sp, {r0 - lr}^
163		mov	r0, r0
164		ldr	lr, [sp, #S_PC]
165		add	sp, sp, #S_FRAME_SIZE
166		movs	pc, lr
167		.endm
168
169		.macro	fast_restore_user_regs
170		add	sp, sp, #S_OFF + S_PC
171		ldmdb	sp, {r1 - lr}^
172		mov	r0, r0
173		ldr	lr, [sp], #S_FRAME_SIZE - S_PC
174		movs	pc, lr
175		.endm
176
177		.macro	mask_pc, rd, rm
178		bic	\rd, \rm, #PCMASK
179		.endm
180
181		.macro	disable_irq, temp
182		teqp	pc, #0x08000003
183		.endm
184
185		.macro	enable_irq, temp
186		teqp	pc, #0x00000003
187		.endm
188
189		.macro	initialise_traps_extra
190		.endm
191
192		.macro	get_current_task, rd
193		mov	\rd, sp, lsr #13
194		mov	\rd, \rd, lsl #13
195		.endm
196
197		/*
198		 * Like adr, but force SVC mode (if required)
199		 */
200		.macro	adrsvc, cond, reg, label
201		adr\cond	\reg, \label
202		orr\cond	\reg, \reg, #0x08000003
203		.endm
204
205#endif
206
207
208/*
209 * These are the registers used in the syscall handler, and allow us to
210 * have in theory up to 7 arguments to a function - r0 to r6.
211 *
212 * r7 is reserved for the system call number for thumb mode.
213 *
214 * Note that tbl == why is intentional.
215 *
216 * We must set at least "tsk" and "why" when calling ret_with_reschedule.
217 */
218scno	.req	r7				@ syscall number
219tbl	.req	r8				@ syscall table pointer
220why	.req	r8				@ Linux syscall (!= 0)
221tsk	.req	r9				@ current task
222
223/*
224 * Get the system call number.
225 */
226	.macro	get_scno
227#ifdef CONFIG_ARM_THUMB
228	tst	r8, #T_BIT		@ this is SPSR from save_user_regs
229	addne	scno, r7, #OS_NUMBER << 20 @ put OS number in
230	ldreq	scno, [lr, #-4]
231
232#else
233	mask_pc	lr, lr
234	ldr	scno, [lr, #-4]		@ get SWI instruction
235#endif
236	.endm
237
238