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#if !CONFIG_IS_ENABLED(SYS_NO_VECTOR_TABLE)
28	ldr	pc, _undefined_instruction
29	ldr	pc, _software_interrupt
30	ldr	pc, _prefetch_abort
31	ldr	pc, _data_abort
32	ldr	pc, _not_used
33	ldr	pc, _irq
34	ldr	pc, _fiq
35#endif
36	.endm
37
38
39/*
40 *************************************************************************
41 *
42 * Symbol _start is referenced elsewhere, so make it global
43 *
44 *************************************************************************
45 */
46
47.globl _start
48
49/*
50 *************************************************************************
51 *
52 * Vectors have their own section so linker script can map them easily
53 *
54 *************************************************************************
55 */
56
57	.section ".vectors", "ax"
58
59#if defined(CONFIG_ENABLE_ARM_SOC_BOOT0_HOOK)
60/*
61 * Various SoCs need something special and SoC-specific up front in
62 * order to boot, allow them to set that in their boot0.h file and then
63 * use it here.
64 *
65 * To allow a boot0 hook to insert a 'special' sequence after the vector
66 * table (e.g. for the socfpga), the presence of a boot0 hook supresses
67 * the below vector table and assumes that the vector table is filled in
68 * by the boot0 hook.  The requirements for a boot0 hook thus are:
69 *   (1) defines '_start:' as appropriate
70 *   (2) inserts the vector table using ARM_VECTORS as appropriate
71 */
72#include <asm/arch/boot0.h>
73#else
74
75/*
76 *************************************************************************
77 *
78 * Exception vectors as described in ARM reference manuals
79 *
80 * Uses indirect branch to allow reaching handlers anywhere in memory.
81 *
82 *************************************************************************
83 */
84
85_start:
86#ifdef CFG_SYS_DV_NOR_BOOT_CFG
87	.word	CFG_SYS_DV_NOR_BOOT_CFG
88#endif
89	ARM_VECTORS
90#endif /* !defined(CONFIG_ENABLE_ARM_SOC_BOOT0_HOOK) */
91
92#if !CONFIG_IS_ENABLED(SYS_NO_VECTOR_TABLE)
93/*
94 *************************************************************************
95 *
96 * Indirect vectors table
97 *
98 * Symbols referenced here must be defined somewhere else
99 *
100 *************************************************************************
101 */
102
103	.globl  _reset
104	.globl	_undefined_instruction
105	.globl	_software_interrupt
106	.globl	_prefetch_abort
107	.globl	_data_abort
108	.globl	_not_used
109	.globl	_irq
110	.globl	_fiq
111
112#ifdef CONFIG_ARCH_K3
113_reset:			.word reset
114#endif
115_undefined_instruction:	.word undefined_instruction
116_software_interrupt:	.word software_interrupt
117_prefetch_abort:	.word prefetch_abort
118_data_abort:		.word data_abort
119_not_used:		.word not_used
120_irq:			.word irq
121_fiq:			.word fiq
122
123	.balignl 16,0xdeadbeef
124#endif
125
126/*
127 *************************************************************************
128 *
129 * Interrupt handling
130 *
131 *************************************************************************
132 */
133
134/* SPL interrupt handling: just hang */
135
136#ifdef CONFIG_SPL_BUILD
137
138#if !CONFIG_IS_ENABLED(SYS_NO_VECTOR_TABLE)
139	.align	5
140undefined_instruction:
141#if CONFIG_IS_ENABLED(USE_SEPARATE_FAULT_HANDLERS)
142	b	undefined_instruction
143#endif
144software_interrupt:
145#if CONFIG_IS_ENABLED(USE_SEPARATE_FAULT_HANDLERS)
146	b	software_interrupt
147#endif
148prefetch_abort:
149#if CONFIG_IS_ENABLED(USE_SEPARATE_FAULT_HANDLERS)
150	b	prefetch_abort
151#endif
152data_abort:
153#if CONFIG_IS_ENABLED(USE_SEPARATE_FAULT_HANDLERS)
154	b	data_abort
155#endif
156not_used:
157#if CONFIG_IS_ENABLED(USE_SEPARATE_FAULT_HANDLERS)
158	b	not_used
159#endif
160irq:
161#if CONFIG_IS_ENABLED(USE_SEPARATE_FAULT_HANDLERS)
162	b	irq
163#endif
164fiq:
1651:
166	b	1b			/* hang and never return */
167#endif
168
169#else	/* !CONFIG_SPL_BUILD */
170
171/* IRQ stack memory (calculated at run-time) + 8 bytes */
172.globl IRQ_STACK_START_IN
173IRQ_STACK_START_IN:
174#ifdef IRAM_BASE_ADDR
175	.word   IRAM_BASE_ADDR + 0x20
176#else
177	.word	0x0badc0de
178#endif
179
180@
181@ IRQ stack frame.
182@
183#define S_FRAME_SIZE	72
184
185#define S_OLD_R0	68
186#define S_PSR		64
187#define S_PC		60
188#define S_LR		56
189#define S_SP		52
190
191#define S_IP		48
192#define S_FP		44
193#define S_R10		40
194#define S_R9		36
195#define S_R8		32
196#define S_R7		28
197#define S_R6		24
198#define S_R5		20
199#define S_R4		16
200#define S_R3		12
201#define S_R2		8
202#define S_R1		4
203#define S_R0		0
204
205#define MODE_SVC 0x13
206#define I_BIT	 0x80
207
208/*
209 * use bad_save_user_regs for abort/prefetch/undef/swi ...
210 * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
211 */
212
213	.macro	bad_save_user_regs
214	@ carve out a frame on current user stack
215	sub	sp, sp, #S_FRAME_SIZE
216	stmia	sp, {r0 - r12}	@ Save user registers (now in svc mode) r0-r12
217	ldr	r2, IRQ_STACK_START_IN
218	@ get values for "aborted" pc and cpsr (into parm regs)
219	ldmia	r2, {r2 - r3}
220	add	r0, sp, #S_FRAME_SIZE		@ grab pointer to old stack
221	add	r5, sp, #S_SP
222	mov	r1, lr
223	stmia	r5, {r0 - r3}	@ save sp_SVC, lr_SVC, pc, cpsr
224	mov	r0, sp		@ save current stack into r0 (param register)
225	.endm
226
227	.macro	irq_save_user_regs
228	sub	sp, sp, #S_FRAME_SIZE
229	stmia	sp, {r0 - r12}			@ Calling r0-r12
230	@ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.
231	add	r8, sp, #S_PC
232	stmdb	r8, {sp, lr}^		@ Calling SP, LR
233	str	lr, [r8, #0]		@ Save calling PC
234	mrs	r6, spsr
235	str	r6, [r8, #4]		@ Save CPSR
236	str	r0, [r8, #8]		@ Save OLD_R0
237	mov	r0, sp
238	.endm
239
240	.macro	irq_restore_user_regs
241	ldmia	sp, {r0 - lr}^			@ Calling r0 - lr
242	mov	r0, r0
243	ldr	lr, [sp, #S_PC]			@ Get PC
244	add	sp, sp, #S_FRAME_SIZE
245	subs	pc, lr, #4		@ return & move spsr_svc into cpsr
246	.endm
247
248	.macro get_bad_stack
249	ldr	r13, IRQ_STACK_START_IN		@ setup our mode stack
250
251	str	lr, [r13]	@ save caller lr in position 0 of saved stack
252	mrs	lr, spsr	@ get the spsr
253	str	lr, [r13, #4]	@ save spsr in position 1 of saved stack
254	mov	r13, #MODE_SVC	@ prepare SVC-Mode
255	@ msr	spsr_c, r13
256	msr	spsr, r13	@ switch modes, make sure moves will execute
257	mov	lr, pc		@ capture return pc
258	movs	pc, lr		@ jump to next instruction & switch modes.
259	.endm
260
261	.macro get_bad_stack_swi
262	sub	r13, r13, #4	@ space on current stack for scratch reg.
263	str	r0, [r13]	@ save R0's value.
264	ldr	r0, IRQ_STACK_START_IN		@ get data regions start
265	str	lr, [r0]	@ save caller lr in position 0 of saved stack
266	mrs	lr, spsr	@ get the spsr
267	str	lr, [r0, #4]	@ save spsr in position 1 of saved stack
268	ldr	lr, [r0]	@ restore lr
269	ldr	r0, [r13]	@ restore r0
270	add	r13, r13, #4	@ pop stack entry
271	.endm
272
273	.macro get_irq_stack			@ setup IRQ stack
274	ldr	sp, IRQ_STACK_START
275	.endm
276
277	.macro get_fiq_stack			@ setup FIQ stack
278	ldr	sp, FIQ_STACK_START
279	.endm
280
281/*
282 * exception handlers
283 */
284
285	.align  5
286undefined_instruction:
287	get_bad_stack
288	bad_save_user_regs
289	bl	do_undefined_instruction
290
291	.align	5
292software_interrupt:
293	get_bad_stack_swi
294	bad_save_user_regs
295	bl	do_software_interrupt
296#if CONFIG_IS_ENABLED(SEMIHOSTING_FALLBACK)
297	ldmia	sp, {r0 - lr}^			@ Calling r0 - lr
298	mov	r0, r0
299	ldr	lr, [sp, #S_PC]			@ Get PC
300	add	sp, sp, #S_FRAME_SIZE
301	movs	pc, lr		@ return & move spsr_svc into cpsr
302#endif
303
304	.align	5
305prefetch_abort:
306	get_bad_stack
307	bad_save_user_regs
308	bl	do_prefetch_abort
309
310	.align	5
311data_abort:
312	get_bad_stack
313	bad_save_user_regs
314	bl	do_data_abort
315
316	.align	5
317not_used:
318	get_bad_stack
319	bad_save_user_regs
320	bl	do_not_used
321
322
323	.align	5
324irq:
325	get_bad_stack
326	bad_save_user_regs
327	bl	do_irq
328
329	.align	5
330fiq:
331	get_bad_stack
332	bad_save_user_regs
333	bl	do_fiq
334
335#endif	/* CONFIG_SPL_BUILD */
336