| /* |
| * armboot - Startup Code for ARM926EJS CPU-core |
| * |
| * Copyright (c) 2003 Texas Instruments |
| * |
| * ----- Adapted for OMAP1610 OMAP730 from ARM925t code ------ |
| * |
| * Copyright (c) 2001 Marius Gröger <mag@sysgo.de> |
| * Copyright (c) 2002 Alex Züpke <azu@sysgo.de> |
| * Copyright (c) 2002 Gary Jennejohn <garyj@denx.de> |
| * Copyright (c) 2003 Richard Woodruff <r-woodruff2@ti.com> |
| * Copyright (c) 2003 Kshitij <kshitij@ti.com> |
| * |
| * SPDX-License-Identifier: GPL-2.0+ |
| */ |
| |
| #include <asm-offsets.h> |
| #include <config.h> |
| #include <version.h> |
| |
| /* |
| ************************************************************************* |
| * |
| * Jump vector table |
| * |
| ************************************************************************* |
| */ |
| |
| .globl _start |
| _start: |
| b reset |
| ldr pc, _undefined_instruction |
| ldr pc, _software_interrupt |
| ldr pc, _prefetch_abort |
| ldr pc, _data_abort |
| ldr pc, _not_used |
| ldr pc, _irq |
| ldr pc, _fiq |
| |
| _undefined_instruction: |
| .word undefined_instruction |
| _software_interrupt: |
| .word software_interrupt |
| _prefetch_abort: |
| .word prefetch_abort |
| _data_abort: |
| .word data_abort |
| _not_used: |
| .word not_used |
| _irq: |
| .word irq |
| _fiq: |
| .word fiq |
| |
| .balignl 16,0xdeadbeef |
| |
| /* |
| ************************************************************************* |
| * |
| * Startup Code (reset vector) |
| * |
| * do important init only if we don't start from memory! |
| * setup memory and board specific bits prior to relocation. |
| * relocate armboot to ram |
| * setup stack |
| * |
| ************************************************************************* |
| */ |
| |
| #ifdef CONFIG_USE_IRQ |
| /* IRQ stack memory (calculated at run-time) */ |
| .globl IRQ_STACK_START |
| IRQ_STACK_START: |
| .word 0x0badc0de |
| |
| /* IRQ stack memory (calculated at run-time) */ |
| .globl FIQ_STACK_START |
| FIQ_STACK_START: |
| .word 0x0badc0de |
| #endif |
| |
| /* IRQ stack memory (calculated at run-time) + 8 bytes */ |
| .globl IRQ_STACK_START_IN |
| IRQ_STACK_START_IN: |
| .word 0x0badc0de |
| |
| /* |
| * the actual reset code |
| */ |
| |
| reset: |
| /* |
| * set the cpu to SVC32 mode |
| */ |
| mrs r0,cpsr |
| bic r0,r0,#0x1f |
| orr r0,r0,#0xd3 |
| msr cpsr,r0 |
| |
| /* |
| * we do sys-critical inits only at reboot, |
| * not when booting from ram! |
| */ |
| #ifndef CONFIG_SKIP_LOWLEVEL_INIT |
| bl cpu_init_crit |
| #endif |
| |
| bl _main |
| |
| /*------------------------------------------------------------------------------*/ |
| |
| .globl c_runtime_cpu_setup |
| c_runtime_cpu_setup: |
| |
| mov pc, lr |
| |
| /* |
| ************************************************************************* |
| * |
| * CPU_init_critical registers |
| * |
| * setup important registers |
| * setup memory timing |
| * |
| ************************************************************************* |
| */ |
| |
| #ifndef CONFIG_SKIP_LOWLEVEL_INIT |
| cpu_init_crit: |
| /* arm_int_generic assumes the ARM boot monitor, or user software, |
| * has initialized the platform |
| */ |
| mov pc, lr /* back to my caller */ |
| #endif |
| /* |
| ************************************************************************* |
| * |
| * Interrupt handling |
| * |
| ************************************************************************* |
| */ |
| |
| @ |
| @ IRQ stack frame. |
| @ |
| #define S_FRAME_SIZE 72 |
| |
| #define S_OLD_R0 68 |
| #define S_PSR 64 |
| #define S_PC 60 |
| #define S_LR 56 |
| #define S_SP 52 |
| |
| #define S_IP 48 |
| #define S_FP 44 |
| #define S_R10 40 |
| #define S_R9 36 |
| #define S_R8 32 |
| #define S_R7 28 |
| #define S_R6 24 |
| #define S_R5 20 |
| #define S_R4 16 |
| #define S_R3 12 |
| #define S_R2 8 |
| #define S_R1 4 |
| #define S_R0 0 |
| |
| #define MODE_SVC 0x13 |
| #define I_BIT 0x80 |
| |
| /* |
| * use bad_save_user_regs for abort/prefetch/undef/swi ... |
| * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling |
| */ |
| |
| .macro bad_save_user_regs |
| @ carve out a frame on current user stack |
| sub sp, sp, #S_FRAME_SIZE |
| stmia sp, {r0 - r12} @ Save user registers (now in svc mode) r0-r12 |
| |
| ldr r2, IRQ_STACK_START_IN |
| @ get values for "aborted" pc and cpsr (into parm regs) |
| ldmia r2, {r2 - r3} |
| add r0, sp, #S_FRAME_SIZE @ grab pointer to old stack |
| add r5, sp, #S_SP |
| mov r1, lr |
| stmia r5, {r0 - r3} @ save sp_SVC, lr_SVC, pc, cpsr |
| mov r0, sp @ save current stack into r0 (param register) |
| .endm |
| |
| .macro irq_save_user_regs |
| sub sp, sp, #S_FRAME_SIZE |
| stmia sp, {r0 - r12} @ Calling r0-r12 |
| @ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good. |
| add r8, sp, #S_PC |
| stmdb r8, {sp, lr}^ @ Calling SP, LR |
| str lr, [r8, #0] @ Save calling PC |
| mrs r6, spsr |
| str r6, [r8, #4] @ Save CPSR |
| str r0, [r8, #8] @ Save OLD_R0 |
| mov r0, sp |
| .endm |
| |
| .macro irq_restore_user_regs |
| ldmia sp, {r0 - lr}^ @ Calling r0 - lr |
| mov r0, r0 |
| ldr lr, [sp, #S_PC] @ Get PC |
| add sp, sp, #S_FRAME_SIZE |
| subs pc, lr, #4 @ return & move spsr_svc into cpsr |
| .endm |
| |
| .macro get_bad_stack |
| ldr r13, IRQ_STACK_START_IN @ setup our mode stack |
| |
| str lr, [r13] @ save caller lr in position 0 of saved stack |
| mrs lr, spsr @ get the spsr |
| str lr, [r13, #4] @ save spsr in position 1 of saved stack |
| mov r13, #MODE_SVC @ prepare SVC-Mode |
| @ msr spsr_c, r13 |
| msr spsr, r13 @ switch modes, make sure moves will execute |
| mov lr, pc @ capture return pc |
| movs pc, lr @ jump to next instruction & switch modes. |
| .endm |
| |
| .macro get_irq_stack @ setup IRQ stack |
| ldr sp, IRQ_STACK_START |
| .endm |
| |
| .macro get_fiq_stack @ setup FIQ stack |
| ldr sp, FIQ_STACK_START |
| .endm |
| |
| /* |
| * exception handlers |
| */ |
| .align 5 |
| .globl undefined_instruction |
| undefined_instruction: |
| get_bad_stack |
| bad_save_user_regs |
| bl do_undefined_instruction |
| |
| .align 5 |
| .globl software_interrupt |
| software_interrupt: |
| get_bad_stack |
| bad_save_user_regs |
| bl do_software_interrupt |
| |
| .align 5 |
| .globl prefetch_abort |
| prefetch_abort: |
| get_bad_stack |
| bad_save_user_regs |
| bl do_prefetch_abort |
| |
| .align 5 |
| .globl data_abort |
| data_abort: |
| get_bad_stack |
| bad_save_user_regs |
| bl do_data_abort |
| |
| .align 5 |
| .globl not_used |
| not_used: |
| get_bad_stack |
| bad_save_user_regs |
| bl do_not_used |
| |
| #ifdef CONFIG_USE_IRQ |
| .align 5 |
| .globl irq |
| irq: |
| get_irq_stack |
| irq_save_user_regs |
| bl do_irq |
| irq_restore_user_regs |
| |
| .align 5 |
| .globl fiq |
| fiq: |
| get_fiq_stack |
| /* someone ought to write a more effiction fiq_save_user_regs */ |
| irq_save_user_regs |
| bl do_fiq |
| irq_restore_user_regs |
| |
| #else |
| |
| .align 5 |
| .globl irq |
| irq: |
| get_bad_stack |
| bad_save_user_regs |
| bl do_irq |
| |
| .align 5 |
| .globl fiq |
| fiq: |
| get_bad_stack |
| bad_save_user_regs |
| bl do_fiq |
| |
| #endif |