rockbox/utils/hwstub/stub/asm/arm/system.S
Amaury Pouly 2cdfc43f10 hwstub: implement read/write data abort recovery
Change-Id: I1625873b6864584c40984723d82548ad242ee08e
2015-01-13 23:35:33 +01:00

57 lines
2.4 KiB
ArmAsm

/***************************************************************************
* __________ __ ___.
* 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 */