Sometimes it's useful to test if a memory operation works or aborts. This adds data_abort_mask() to ignore data aborts and data_abort_unmask() to enable them again. This is used in the next step for the 'md' command so that illegal addresses just show 'xxxxxxxx' instead of crashing the system. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
229 lines
4.8 KiB
ArmAsm
229 lines
4.8 KiB
ArmAsm
#include <config.h>
|
|
#include <linux/linkage.h>
|
|
#include <asm-generic/memory_layout.h>
|
|
|
|
/*
|
|
*************************************************************************
|
|
*
|
|
* 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
|
|
|
|
/*
|
|
* 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
|
|
sub sp, sp, #S_FRAME_SIZE
|
|
stmia sp, {r0 - r12} @ Calling r0-r12
|
|
ldr r2, =abort_stack
|
|
ldmia r2, {r2 - r3} @ get pc, cpsr
|
|
add r0, sp, #S_FRAME_SIZE @ restore sp_SVC
|
|
|
|
add r5, sp, #S_SP
|
|
mov r1, lr
|
|
stmia r5, {r0 - r3} @ save sp_SVC, lr_SVC, pc, cpsr
|
|
mov r0, sp
|
|
.endm
|
|
|
|
.macro irq_save_user_regs
|
|
sub sp, sp, #S_FRAME_SIZE
|
|
stmia sp, {r0 - r12} @ Calling r0-r12
|
|
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, =abort_stack
|
|
str lr, [r13] @ save caller lr / spsr
|
|
mrs lr, spsr
|
|
str lr, [r13, #4]
|
|
|
|
mov r13, #MODE_SVC @ prepare SVC-Mode
|
|
@ msr spsr_c, r13
|
|
msr spsr, r13
|
|
mov lr, pc
|
|
movs pc, lr
|
|
.endm
|
|
|
|
.macro try_data_abort
|
|
ldr r13, =arm_ignore_data_abort @ check try mode
|
|
ldr r13, [r13]
|
|
cmp r13, #0
|
|
beq do_abort_\@
|
|
ldr r13, =arm_data_abort_occurred
|
|
str r13, [r13]
|
|
mrs r13, spsr @ read saved CPSR
|
|
tst r13, #1<<5 @ check Thumb mode
|
|
subeq lr, #4 @ next ARM instr
|
|
subne lr, #6 @ next Thumb instr
|
|
movs pc, lr
|
|
do_abort_\@:
|
|
.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
|
|
*/
|
|
.section ".text","ax"
|
|
.arm
|
|
|
|
.align 5
|
|
undefined_instruction:
|
|
get_bad_stack
|
|
bad_save_user_regs
|
|
bl do_undefined_instruction
|
|
|
|
.align 5
|
|
software_interrupt:
|
|
get_bad_stack
|
|
bad_save_user_regs
|
|
bl do_software_interrupt
|
|
|
|
.align 5
|
|
prefetch_abort:
|
|
get_bad_stack
|
|
bad_save_user_regs
|
|
bl do_prefetch_abort
|
|
|
|
.align 5
|
|
data_abort:
|
|
try_data_abort
|
|
get_bad_stack
|
|
bad_save_user_regs
|
|
bl do_data_abort
|
|
|
|
.align 5
|
|
irq:
|
|
get_bad_stack
|
|
bad_save_user_regs
|
|
bl do_irq
|
|
|
|
.align 5
|
|
fiq:
|
|
get_bad_stack
|
|
bad_save_user_regs
|
|
bl do_fiq
|
|
|
|
#if defined(CONFIG_RELOCATABLE) && defined(CONFIG_ARM_EXCEPTIONS)
|
|
/*
|
|
* With relocatable binary support the runtime exception vectors do not match
|
|
* the addresses in the binary. We have to fix them up during runtime
|
|
*/
|
|
ENTRY(arm_fixup_vectors)
|
|
ldr r0, =undefined_instruction
|
|
ldr r1, =_undefined_instruction
|
|
str r0, [r1]
|
|
ldr r0, =software_interrupt
|
|
ldr r1, =_software_interrupt
|
|
str r0, [r1]
|
|
ldr r0, =prefetch_abort
|
|
ldr r1, =_prefetch_abort
|
|
str r0, [r1]
|
|
ldr r0, =data_abort
|
|
ldr r1, =_data_abort
|
|
str r0, [r1]
|
|
ldr r0, =irq
|
|
ldr r1, =_irq
|
|
str r0, [r1]
|
|
ldr r0, =fiq
|
|
ldr r1, =_fiq
|
|
str r0, [r1]
|
|
bx lr
|
|
ENDPROC(arm_fixup_vectors)
|
|
#endif
|
|
|
|
.section .text_exceptions
|
|
.globl extable
|
|
extable:
|
|
1: b 1b /* barebox_arm_reset_vector */
|
|
#ifdef CONFIG_ARM_EXCEPTIONS
|
|
ldr pc, _undefined_instruction /* undefined instruction */
|
|
ldr pc, _software_interrupt /* software interrupt (SWI) */
|
|
ldr pc, _prefetch_abort /* prefetch abort */
|
|
ldr pc, _data_abort /* data abort */
|
|
1: b 1b /* (reserved) */
|
|
ldr pc, _irq /* irq (interrupt) */
|
|
ldr pc, _fiq /* fiq (fast interrupt) */
|
|
.globl _undefined_instruction
|
|
_undefined_instruction: .word undefined_instruction
|
|
.globl _software_interrupt
|
|
_software_interrupt: .word software_interrupt
|
|
.globl _prefetch_abort
|
|
_prefetch_abort: .word prefetch_abort
|
|
.globl _data_abort
|
|
_data_abort: .word data_abort
|
|
.globl _irq
|
|
_irq: .word irq
|
|
.globl _fiq
|
|
_fiq: .word fiq
|
|
#else
|
|
1: b 1b /* undefined instruction */
|
|
1: b 1b /* software interrupt (SWI) */
|
|
1: b 1b /* prefetch abort */
|
|
1: b 1b /* data abort */
|
|
1: b 1b /* (reserved) */
|
|
1: b 1b /* irq (interrupt) */
|
|
1: b 1b /* fiq (fast interrupt) */
|
|
#endif
|
|
|
|
.section .data
|
|
.align 4
|
|
.global arm_ignore_data_abort
|
|
arm_ignore_data_abort:
|
|
.word arm_ignore_data_abort /* When != 0 data aborts are ignored */
|
|
.global arm_data_abort_occurred
|
|
arm_data_abort_occurred:
|
|
.word arm_data_abort_occurred /* set != 0 by the data abort handler */
|
|
abort_stack:
|
|
.space 8
|