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