xref: /haiku/src/system/kernel/arch/arm/arch_exceptions.S (revision 52f7c9389475e19fc21487b38064b4390eeb6fea)
1/*
2 * Copyright 2012-2022, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Ithamar R. Adema <ithamar@upgrade-android.com>
7 *
8 */
9
10#include <asm_defs.h>
11
12#define CPSR_MODE_MASK	0x1f
13#define CPSR_MODE_USR	0x10
14#define CPSR_MODE_FIQ	0x11
15#define CPSR_MODE_IRQ	0x12
16#define CPSR_MODE_SVC	0x13
17#define CPSR_MODE_ABT	0x17
18#define CPSR_MODE_UND	0x1b
19
20/* The following two macros are taken from FreeBSD... */
21
22.macro PUSHFRAMEINSVC
23	stmdb	sp, {r0-r3}					/* Save 4 registers */
24	mov		r0, lr						/* Save xxx32 r14 */
25	mov		r1, sp						/* Save xxx32 sp */
26	mrs		r3, spsr					/* Save xxx32 spsr */
27	mrs		r2, cpsr					/* Get the CPSR */
28	bic		r2, r2, #(CPSR_MODE_MASK)	/* Fix for SVC mode */
29	orr		r2, r2, #(CPSR_MODE_SVC)
30	msr		cpsr_c, r2					/* Punch into SVC mode */
31	mov		r2, sp						/* Save SVC sp */
32	str		r0, [sp, #-4]!				/* Push return address */
33	str		lr, [sp, #-4]!				/* Push SVC lr */
34	str		r2, [sp, #-4]!				/* Push SVC sp */
35	msr		spsr, r3					/* Restore correct spsr */
36	ldmdb	r1, {r0-r3}					/* Restore 4 regs from xxx mode */
37	sub		sp, sp, #(4*15)				/* Adjust the stack pointer */
38	stmia	sp, {r0-r12}				/* Push the user mode registers */
39	add		r0, sp, #(4*13)				/* Adjust the stack pointer */
40	stmia	r0, {r13-r14}^				/* Push the user mode registers */
41	mov		r0, r0						/* NOP for previous instruction */
42	mrs		r0, spsr
43	str		r0, [sp, #-4]!				/* Save spsr */
44.endm
45
46.macro PULLFRAMEFROMSVCANDEXIT
47	ldr		r0, [sp], #0x0004			/* Get the SPSR from stack */
48	msr		spsr, r0					/* restore SPSR */
49	ldmia	sp, {r0-r14}^				/* Restore registers (usr mode) */
50	mov		r0, r0						/* NOP for previous instruction */
51	add		sp, sp, #(4*15)				/* Adjust the stack pointer */
52	ldmia	sp, {sp, lr, pc}^			/* Restore lr and exit */
53.endm
54
55/* The following two macros are adapted from the two macros above, taken from FreeBSD. */
56
57.macro	PUSHFRAMEINSWI
58	str		lr, [sp, #-4]!				/* Push the return address */
59	sub		sp, sp, #(4*17)				/* Adjust the stack pointer */
60	stmia	sp, {r0-r12}				/* Store the general purpose registers */
61	add		r0, sp, #(4*13)				/* Adjust the stack pointer */
62	stmia	r0, {r13-r14}^				/* Store the user mode sp and lr registers */
63	mrs		r0, spsr					/* Store the SPSR */
64	str		r0, [sp, #-4]!
65	mov		r0, #0						/* Fill in svc mode sp and lr with zeroes */
66	str		r0, [sp, #(4*16)]
67	str		r0, [sp, #(4*17)]
68.endm
69
70.macro	PULLFRAMEINSWIANDEXIT
71	ldr		r0, [sp], #4				/* Get SPSR from stack */
72	msr		spsr, r0
73	ldmia	sp, {r0-r14}^				/* Restore user mode registers */
74	add		sp, sp, #(4*17)				/* Adjust the stack pointer */
75	ldr		lr, [sp], #4				/* Pull the return address */
76	movs	pc, lr						/* Return to user mode */
77.endm
78
79.text
80
81.globl _vectors_start
82_vectors_start:
83	ldr		pc, _arm_reset
84	ldr		pc, _arm_undefined
85	ldr		pc, _arm_syscall
86	ldr		pc, _arm_prefetch_abort
87	ldr		pc, _arm_data_abort
88	ldr		pc, _arm_reserved
89	ldr		pc, _arm_irq
90	ldr		pc, _arm_fiq
91
92
93_arm_reset:
94	.word	arm_reserved // actually reset, but not used when mapped
95
96_arm_undefined:
97	.word	arm_undefined
98
99_arm_syscall:
100	.word	arm_syscall
101
102_arm_prefetch_abort:
103	.word	arm_prefetch_abort
104
105_arm_data_abort:
106	.word	arm_data_abort
107
108_arm_reserved:
109	.word	arm_reserved
110
111_arm_irq:
112	.word	arm_irq
113
114_arm_fiq:
115	.word	arm_fiq
116
117
118.globl _vectors_end
119_vectors_end:
120	.rept	64
121	.word	0xdeadbeef
122	.endr
123
124abort_stack:
125	.word	. - 4
126	.word	0xdeadbeef
127
128	.rept	64
129	.word	0xcafebabe
130	.endr
131
132irq_stack:
133	.word	. - 4
134	.word	0xcafebabe
135
136	.rept	64
137	.word	0xaaaabbbb
138	.endr
139
140fiq_stack:
141	.word	. - 4
142	.word	0xaaaabbbb
143
144	.rept	64
145	.word	0xccccdddd
146	.endr
147
148und_stack:
149	.word	. - 4
150	.word	0xccccdddd
151
152
153FUNCTION(arm_undefined):
154	PUSHFRAMEINSVC
155
156	mov	r0, sp
157	bl	arch_arm_undefined
158
159	PULLFRAMEFROMSVCANDEXIT
160FUNCTION_END(arm_undefined)
161
162
163FUNCTION(arm_syscall):
164	PUSHFRAMEINSWI
165
166	mov	r0, sp
167	bl	arch_arm_syscall
168
169	PULLFRAMEINSWIANDEXIT
170FUNCTION_END(arm_syscall)
171
172
173FUNCTION(arm_prefetch_abort):
174#ifdef __XSCALE__
175	nop					/* Make absolutely sure any pending */
176	nop					/* imprecise aborts have occurred. */
177#endif
178	sub	lr, lr, #4
179	PUSHFRAMEINSVC
180
181	mov	r0, sp
182	bl	arch_arm_prefetch_abort
183
184	PULLFRAMEFROMSVCANDEXIT
185FUNCTION_END(arm_prefetch_abort)
186
187
188FUNCTION(arm_data_abort):
189#ifdef __XSCALE__
190	nop					/* Make absolutely sure any pending */
191	nop					/* imprecise aborts have occurred. */
192#endif
193	sub	lr, lr, #8		/* Adjust the lr */
194	PUSHFRAMEINSVC
195
196	mov	r0, sp
197	bl	arch_arm_data_abort
198
199	PULLFRAMEFROMSVCANDEXIT
200FUNCTION_END(arm_data_abort)
201
202
203FUNCTION(arm_reserved):
204	b	.
205FUNCTION_END(arm_reserved)
206
207
208FUNCTION(arm_irq):
209	sub	lr, lr, #4
210	PUSHFRAMEINSVC
211
212	mov	r0, sp			/* iframe */
213	bl	arch_arm_irq
214
215	PULLFRAMEFROMSVCANDEXIT
216FUNCTION_END(arm_irq)
217
218
219FUNCTION(arm_fiq):
220	sub	lr, lr, #4
221	PUSHFRAMEINSVC
222
223	mov	r0, sp			/* iframe */
224	bl	arch_arm_fiq
225
226	PULLFRAMEFROMSVCANDEXIT
227FUNCTION_END(arm_fiq)
228
229
230
231FUNCTION(arm_vector_init):
232	mrs	r1, cpsr
233	bic	r1, r1, #CPSR_MODE_MASK
234
235	/* move into modes and set initial sp */
236	mov	r0, r1
237	orr	r0, r0, #CPSR_MODE_FIQ
238	msr	cpsr_c, r0
239	ldr	sp, fiq_stack
240
241	mov	r0, r1
242	orr	r0, r0, #CPSR_MODE_IRQ
243	msr	cpsr_c, r0
244	ldr	sp, irq_stack
245
246	mov	r0, r1
247	orr	r0, r0, #CPSR_MODE_ABT
248	msr	cpsr_c, r0
249	ldr	sp, abort_stack
250
251	mov	r0, r1
252	orr	r0, r0, #CPSR_MODE_UND
253	msr	cpsr_c, r0
254	ldr	sp, und_stack
255
256	/* ... and return back to supervisor mode */
257	mov	r0, r1
258	orr	r0, r0, #CPSR_MODE_SVC
259	msr	cpsr_c, r0
260
261	bx	lr
262FUNCTION_END(arm_vector_init)
263