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