1/* SPDX-License-Identifier: GPL-2.0+ */
2/*
3 *  vectors - Generic ARM exception table code
4 *
5 *  Copyright (c) 1998	Dan Malek <dmalek@jlc.net>
6 *  Copyright (c) 1999	Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
7 *  Copyright (c) 2000	Wolfgang Denk <wd@denx.de>
8 *  Copyright (c) 2001	Alex Züpke <azu@sysgo.de>
9 *  Copyright (c) 2001	Marius Gröger <mag@sysgo.de>
10 *  Copyright (c) 2002	Alex Züpke <azu@sysgo.de>
11 *  Copyright (c) 2002	Gary Jennejohn <garyj@denx.de>
12 *  Copyright (c) 2002	Kyle Harris <kharris@nexus-tech.net>
13 */
14
15#include <config.h>
16
17/*
18 * A macro to allow insertion of an ARM exception vector either
19 * for the non-boot0 case or by a boot0-header.
20 */
21        .macro ARM_VECTORS
22#ifdef CONFIG_ARCH_K3
23	ldr     pc, _reset
24#else
25	b	reset
26#endif
27	ldr	pc, _undefined_instruction
28	ldr	pc, _software_interrupt
29	ldr	pc, _prefetch_abort
30	ldr	pc, _data_abort
31	ldr	pc, _not_used
32	ldr	pc, _irq
33	ldr	pc, _fiq
34	.endm
35
36
37/*
38 *************************************************************************
39 *
40 * Symbol _start is referenced elsewhere, so make it global
41 *
42 *************************************************************************
43 */
44
45.globl _start
46
47/*
48 *************************************************************************
49 *
50 * Vectors have their own section so linker script can map them easily
51 *
52 *************************************************************************
53 */
54
55	.section ".vectors", "ax"
56
57#if defined(CONFIG_ENABLE_ARM_SOC_BOOT0_HOOK)
58/*
59 * Various SoCs need something special and SoC-specific up front in
60 * order to boot, allow them to set that in their boot0.h file and then
61 * use it here.
62 *
63 * To allow a boot0 hook to insert a 'special' sequence after the vector
64 * table (e.g. for the socfpga), the presence of a boot0 hook supresses
65 * the below vector table and assumes that the vector table is filled in
66 * by the boot0 hook.  The requirements for a boot0 hook thus are:
67 *   (1) defines '_start:' as appropriate
68 *   (2) inserts the vector table using ARM_VECTORS as appropriate
69 */
70#include <asm/arch/boot0.h>
71#else
72
73/*
74 *************************************************************************
75 *
76 * Exception vectors as described in ARM reference manuals
77 *
78 * Uses indirect branch to allow reaching handlers anywhere in memory.
79 *
80 *************************************************************************
81 */
82
83_start:
84#ifdef CONFIG_SYS_DV_NOR_BOOT_CFG
85	.word	CONFIG_SYS_DV_NOR_BOOT_CFG
86#endif
87	ARM_VECTORS
88#endif /* !defined(CONFIG_ENABLE_ARM_SOC_BOOT0_HOOK) */
89
90/*
91 *************************************************************************
92 *
93 * Indirect vectors table
94 *
95 * Symbols referenced here must be defined somewhere else
96 *
97 *************************************************************************
98 */
99
100	.globl  _reset
101	.globl	_undefined_instruction
102	.globl	_software_interrupt
103	.globl	_prefetch_abort
104	.globl	_data_abort
105	.globl	_not_used
106	.globl	_irq
107	.globl	_fiq
108
109#ifdef CONFIG_ARCH_K3
110_reset:			.word reset
111#endif
112_undefined_instruction:	.word undefined_instruction
113_software_interrupt:	.word software_interrupt
114_prefetch_abort:	.word prefetch_abort
115_data_abort:		.word data_abort
116_not_used:		.word not_used
117_irq:			.word irq
118_fiq:			.word fiq
119
120	.balignl 16,0xdeadbeef
121
122/*
123 *************************************************************************
124 *
125 * Interrupt handling
126 *
127 *************************************************************************
128 */
129
130/* SPL interrupt handling: just hang */
131
132#ifdef CONFIG_SPL_BUILD
133
134	.align	5
135undefined_instruction:
136software_interrupt:
137prefetch_abort:
138data_abort:
139not_used:
140irq:
141fiq:
1421:
143	b	1b			/* hang and never return */
144
145#else	/* !CONFIG_SPL_BUILD */
146
147/* IRQ stack memory (calculated at run-time) + 8 bytes */
148.globl IRQ_STACK_START_IN
149IRQ_STACK_START_IN:
150#ifdef IRAM_BASE_ADDR
151	.word   IRAM_BASE_ADDR + 0x20
152#else
153	.word	0x0badc0de
154#endif
155
156@
157@ IRQ stack frame.
158@
159#define S_FRAME_SIZE	72
160
161#define S_OLD_R0	68
162#define S_PSR		64
163#define S_PC		60
164#define S_LR		56
165#define S_SP		52
166
167#define S_IP		48
168#define S_FP		44
169#define S_R10		40
170#define S_R9		36
171#define S_R8		32
172#define S_R7		28
173#define S_R6		24
174#define S_R5		20
175#define S_R4		16
176#define S_R3		12
177#define S_R2		8
178#define S_R1		4
179#define S_R0		0
180
181#define MODE_SVC 0x13
182#define I_BIT	 0x80
183
184/*
185 * use bad_save_user_regs for abort/prefetch/undef/swi ...
186 * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
187 */
188
189	.macro	bad_save_user_regs
190	@ carve out a frame on current user stack
191	sub	sp, sp, #S_FRAME_SIZE
192	stmia	sp, {r0 - r12}	@ Save user registers (now in svc mode) r0-r12
193	ldr	r2, IRQ_STACK_START_IN
194	@ get values for "aborted" pc and cpsr (into parm regs)
195	ldmia	r2, {r2 - r3}
196	add	r0, sp, #S_FRAME_SIZE		@ grab pointer to old stack
197	add	r5, sp, #S_SP
198	mov	r1, lr
199	stmia	r5, {r0 - r3}	@ save sp_SVC, lr_SVC, pc, cpsr
200	mov	r0, sp		@ save current stack into r0 (param register)
201	.endm
202
203	.macro	irq_save_user_regs
204	sub	sp, sp, #S_FRAME_SIZE
205	stmia	sp, {r0 - r12}			@ Calling r0-r12
206	@ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.
207	add	r8, sp, #S_PC
208	stmdb	r8, {sp, lr}^		@ Calling SP, LR
209	str	lr, [r8, #0]		@ Save calling PC
210	mrs	r6, spsr
211	str	r6, [r8, #4]		@ Save CPSR
212	str	r0, [r8, #8]		@ Save OLD_R0
213	mov	r0, sp
214	.endm
215
216	.macro	irq_restore_user_regs
217	ldmia	sp, {r0 - lr}^			@ Calling r0 - lr
218	mov	r0, r0
219	ldr	lr, [sp, #S_PC]			@ Get PC
220	add	sp, sp, #S_FRAME_SIZE
221	subs	pc, lr, #4		@ return & move spsr_svc into cpsr
222	.endm
223
224	.macro get_bad_stack
225	ldr	r13, IRQ_STACK_START_IN		@ setup our mode stack
226
227	str	lr, [r13]	@ save caller lr in position 0 of saved stack
228	mrs	lr, spsr	@ get the spsr
229	str	lr, [r13, #4]	@ save spsr in position 1 of saved stack
230	mov	r13, #MODE_SVC	@ prepare SVC-Mode
231	@ msr	spsr_c, r13
232	msr	spsr, r13	@ switch modes, make sure moves will execute
233	mov	lr, pc		@ capture return pc
234	movs	pc, lr		@ jump to next instruction & switch modes.
235	.endm
236
237	.macro get_irq_stack			@ setup IRQ stack
238	ldr	sp, IRQ_STACK_START
239	.endm
240
241	.macro get_fiq_stack			@ setup FIQ stack
242	ldr	sp, FIQ_STACK_START
243	.endm
244
245/*
246 * exception handlers
247 */
248
249	.align  5
250undefined_instruction:
251	get_bad_stack
252	bad_save_user_regs
253	bl	do_undefined_instruction
254
255	.align	5
256software_interrupt:
257	get_bad_stack
258	bad_save_user_regs
259	bl	do_software_interrupt
260
261	.align	5
262prefetch_abort:
263	get_bad_stack
264	bad_save_user_regs
265	bl	do_prefetch_abort
266
267	.align	5
268data_abort:
269	get_bad_stack
270	bad_save_user_regs
271	bl	do_data_abort
272
273	.align	5
274not_used:
275	get_bad_stack
276	bad_save_user_regs
277	bl	do_not_used
278
279
280	.align	5
281irq:
282	get_bad_stack
283	bad_save_user_regs
284	bl	do_irq
285
286	.align	5
287fiq:
288	get_bad_stack
289	bad_save_user_regs
290	bl	do_fiq
291
292#endif	/* CONFIG_SPL_BUILD */
293