9bb6050d40
Since we can catch exceptions like data aborts on read/write, it takes very little to also catch exceptions in calls. When extending this with the catching of illegal instructions, the call instruction now becomes much more robust and also for address and instruction probing. Since we can catch several types of exception, rename set_data_abort_jmp to set_exception_jmp. At the same time, simplify the logic in read/write request handlers. Also fix a bug in ARM jump code: it was using stmia r1, {..., pc} as if pc would get current pc + 8 but this is actually implementation defined on older ARMs (typically pc + 12) and deprecated on newer ARMs, so rewrite the code avoid that. The set_exception_jmp() function now also reports the exception type. Change-Id: Icd0dd52d2456b361b27c4776be09c3d13528ed93
59 lines
2.5 KiB
ArmAsm
59 lines
2.5 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.
|
|
*
|
|
****************************************************************************/
|
|
#include "system.h"
|
|
|
|
/* Handling of data abort:
|
|
* the code can register a "longjmp" buffer to restore the context in case of
|
|
* fault */
|
|
.data
|
|
exception_jmp_ctx_ptr:
|
|
/* buffer contains in order: cpsr,r4-r11,sp,lr,pc */
|
|
.skip 48 /* = 4 * (cpsr + 11 registers) */
|
|
|
|
.text
|
|
/* Prototype: int set_exception_jmp()
|
|
* Return: !=0 in case of exception, 0 otherwise */
|
|
.global set_exception_jmp
|
|
set_exception_jmp:
|
|
mrs r2, cpsr
|
|
ldr r1, =exception_jmp_ctx_ptr
|
|
mov r0, #EXCEPTION_NONE /* nothing to report */
|
|
stmia r1!, {r2,r4-r11,sp,lr} /* see PC note below */
|
|
mov r3, pc /* see note below */
|
|
str r3, [r1] /* store PC */
|
|
bx lr /* <-- PC points here in mov */
|
|
|
|
.global data_abort_handler
|
|
data_abort_handler:
|
|
/* restore everything from context */
|
|
ldr r1, =exception_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
|
|
mov r0, #EXCEPTION_ADDR
|
|
ldmia r1, {r1,r4-r11,sp,lr,pc}^ /* reload some registers but we don't care */
|