Merge branch 'master' of git://git.denx.de/u-boot-spi
[oweals/u-boot.git] / arch / arm / lib / vectors.S
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 #ifdef CONFIG_ARCH_ROCKCHIP
71 #include <asm/arch-rockchip/boot0.h>
72 #else
73 #include <asm/arch/boot0.h>
74 #endif
75 #else
76
77 /*
78  *************************************************************************
79  *
80  * Exception vectors as described in ARM reference manuals
81  *
82  * Uses indirect branch to allow reaching handlers anywhere in memory.
83  *
84  *************************************************************************
85  */
86
87 _start:
88 #ifdef CONFIG_SYS_DV_NOR_BOOT_CFG
89         .word   CONFIG_SYS_DV_NOR_BOOT_CFG
90 #endif
91         ARM_VECTORS
92 #endif /* !defined(CONFIG_ENABLE_ARM_SOC_BOOT0_HOOK) */
93
94 /*
95  *************************************************************************
96  *
97  * Indirect vectors table
98  *
99  * Symbols referenced here must be defined somewhere else
100  *
101  *************************************************************************
102  */
103
104         .globl  _reset
105         .globl  _undefined_instruction
106         .globl  _software_interrupt
107         .globl  _prefetch_abort
108         .globl  _data_abort
109         .globl  _not_used
110         .globl  _irq
111         .globl  _fiq
112
113 #ifdef CONFIG_ARCH_K3
114 _reset:                 .word reset
115 #endif
116 _undefined_instruction: .word undefined_instruction
117 _software_interrupt:    .word software_interrupt
118 _prefetch_abort:        .word prefetch_abort
119 _data_abort:            .word data_abort
120 _not_used:              .word not_used
121 _irq:                   .word irq
122 _fiq:                   .word fiq
123
124         .balignl 16,0xdeadbeef
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         .align  5
139 undefined_instruction:
140 software_interrupt:
141 prefetch_abort:
142 data_abort:
143 not_used:
144 irq:
145 fiq:
146 1:
147         b       1b                      /* hang and never return */
148
149 #else   /* !CONFIG_SPL_BUILD */
150
151 /* IRQ stack memory (calculated at run-time) + 8 bytes */
152 .globl IRQ_STACK_START_IN
153 IRQ_STACK_START_IN:
154 #ifdef IRAM_BASE_ADDR
155         .word   IRAM_BASE_ADDR + 0x20
156 #else
157         .word   0x0badc0de
158 #endif
159
160 @
161 @ IRQ stack frame.
162 @
163 #define S_FRAME_SIZE    72
164
165 #define S_OLD_R0        68
166 #define S_PSR           64
167 #define S_PC            60
168 #define S_LR            56
169 #define S_SP            52
170
171 #define S_IP            48
172 #define S_FP            44
173 #define S_R10           40
174 #define S_R9            36
175 #define S_R8            32
176 #define S_R7            28
177 #define S_R6            24
178 #define S_R5            20
179 #define S_R4            16
180 #define S_R3            12
181 #define S_R2            8
182 #define S_R1            4
183 #define S_R0            0
184
185 #define MODE_SVC 0x13
186 #define I_BIT    0x80
187
188 /*
189  * use bad_save_user_regs for abort/prefetch/undef/swi ...
190  * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
191  */
192
193         .macro  bad_save_user_regs
194         @ carve out a frame on current user stack
195         sub     sp, sp, #S_FRAME_SIZE
196         stmia   sp, {r0 - r12}  @ Save user registers (now in svc mode) r0-r12
197         ldr     r2, IRQ_STACK_START_IN
198         @ get values for "aborted" pc and cpsr (into parm regs)
199         ldmia   r2, {r2 - r3}
200         add     r0, sp, #S_FRAME_SIZE           @ grab pointer to old stack
201         add     r5, sp, #S_SP
202         mov     r1, lr
203         stmia   r5, {r0 - r3}   @ save sp_SVC, lr_SVC, pc, cpsr
204         mov     r0, sp          @ save current stack into r0 (param register)
205         .endm
206
207         .macro  irq_save_user_regs
208         sub     sp, sp, #S_FRAME_SIZE
209         stmia   sp, {r0 - r12}                  @ Calling r0-r12
210         @ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.
211         add     r8, sp, #S_PC
212         stmdb   r8, {sp, lr}^           @ Calling SP, LR
213         str     lr, [r8, #0]            @ Save calling PC
214         mrs     r6, spsr
215         str     r6, [r8, #4]            @ Save CPSR
216         str     r0, [r8, #8]            @ Save OLD_R0
217         mov     r0, sp
218         .endm
219
220         .macro  irq_restore_user_regs
221         ldmia   sp, {r0 - lr}^                  @ Calling r0 - lr
222         mov     r0, r0
223         ldr     lr, [sp, #S_PC]                 @ Get PC
224         add     sp, sp, #S_FRAME_SIZE
225         subs    pc, lr, #4              @ return & move spsr_svc into cpsr
226         .endm
227
228         .macro get_bad_stack
229         ldr     r13, IRQ_STACK_START_IN         @ setup our mode stack
230
231         str     lr, [r13]       @ save caller lr in position 0 of saved stack
232         mrs     lr, spsr        @ get the spsr
233         str     lr, [r13, #4]   @ save spsr in position 1 of saved stack
234         mov     r13, #MODE_SVC  @ prepare SVC-Mode
235         @ msr   spsr_c, r13
236         msr     spsr, r13       @ switch modes, make sure moves will execute
237         mov     lr, pc          @ capture return pc
238         movs    pc, lr          @ jump to next instruction & switch modes.
239         .endm
240
241         .macro get_irq_stack                    @ setup IRQ stack
242         ldr     sp, IRQ_STACK_START
243         .endm
244
245         .macro get_fiq_stack                    @ setup FIQ stack
246         ldr     sp, FIQ_STACK_START
247         .endm
248
249 /*
250  * exception handlers
251  */
252
253         .align  5
254 undefined_instruction:
255         get_bad_stack
256         bad_save_user_regs
257         bl      do_undefined_instruction
258
259         .align  5
260 software_interrupt:
261         get_bad_stack
262         bad_save_user_regs
263         bl      do_software_interrupt
264
265         .align  5
266 prefetch_abort:
267         get_bad_stack
268         bad_save_user_regs
269         bl      do_prefetch_abort
270
271         .align  5
272 data_abort:
273         get_bad_stack
274         bad_save_user_regs
275         bl      do_data_abort
276
277         .align  5
278 not_used:
279         get_bad_stack
280         bad_save_user_regs
281         bl      do_not_used
282
283
284         .align  5
285 irq:
286         get_bad_stack
287         bad_save_user_regs
288         bl      do_irq
289
290         .align  5
291 fiq:
292         get_bad_stack
293         bad_save_user_regs
294         bl      do_fiq
295
296 #endif  /* CONFIG_SPL_BUILD */