diff options
Diffstat (limited to 'utils/hwstub/stub/asm/arm')
-rw-r--r-- | utils/hwstub/stub/asm/arm/system.S | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/utils/hwstub/stub/asm/arm/system.S b/utils/hwstub/stub/asm/arm/system.S new file mode 100644 index 0000000000..df6b5a2e81 --- /dev/null +++ b/utils/hwstub/stub/asm/arm/system.S @@ -0,0 +1,57 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2014 by Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +/* Handling of data abort: + * the code can register a "longjmp" buffer to restore the context in case of + * fault */ +.data +data_abort_jmp_ctx_ptr: +/* buffer contains in order: cpsr,r4-r11,sp,lr,pc */ +.skip 48 /* = 4 * (cpsr + 11 registers) */ + +.text +/* Prototype: int set_data_abort_jmp() + * Return: 1 in case of data abort, 0 otherwise */ +.global set_data_abort_jmp +set_data_abort_jmp: + mrs r2, cpsr + ldr r1, =data_abort_jmp_ctx_ptr + mov r0, #0 + stmia r1, {r2,r4-r11,sp,lr,pc} /* see PC note below */ + bx lr + mov r0, #1 /* <-- PC points here in stmia */ + bx lr + +.global data_abort_handler +data_abort_handler: + /* restore everything from context */ + ldr r1, =data_abort_jmp_ctx_ptr + /* NOTE: we need to restore sp_sys and lr_sys, for this we need the + * LDM Rn, {}^ + * variant, but we cannot restore PC from it because ^ has a different + * meaning and won't restore user/sys registers. On top of that, the + * non-PC ^ variant cannot do the register writeback, so on the PC restore, + * we reload all registers once again to avoid manually offseting the base + * register, it will trash sp_abt and lr_abr but those are unused anyway + * because we do not save the abort address and we don't use an abort stack */ + ldmia r1, {r0,r4-r11,sp,lr}^ /* this variant cannot have writeback (r1!) */ + msr spsr, r0 + ldmia r1, {r0,r4-r11,sp,lr,pc}^ /* reload some registers but we don't care */ |