From 7d70ae2da93e8fe92e0eb471ed4278a59cab0cf8 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Sat, 9 Jul 2011 07:43:30 +0800 Subject: preliminary abort exception handler --- Debugger/abort_handler.S | 106 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 Debugger/abort_handler.S diff --git a/Debugger/abort_handler.S b/Debugger/abort_handler.S new file mode 100644 index 0000000..a968374 --- /dev/null +++ b/Debugger/abort_handler.S @@ -0,0 +1,106 @@ + +/* Copyright (C) 2007-2011 the NxOS developers + * + * Module Developed by: TC Wan + * + * See AUTHORS for a full list of the developers. + * + * Redistribution of this file is permitted under + * the terms of the GNU Public License (GPL) version 2. + */ +#define __ASSEMBLY__ +#include "debug_stub.h" +#include "debug_internals.h" + +#define PREFETCH_OFFSET 4 +#define DATA_OFFSET 8 + +/* Trap Abort Exceptions. + * On triggering, lr (R14) contains the previous mode's pc (R15). + * Based on example in Hohl, "ARM Assembly Language: Fundamentals and Techniques" + * Chapter 11, Example 11.1. + */ +/* + * NOTE: This routine closely mirrors the undef_handler routine, since we will store + * the ABORT stack frame in the UNDEF stack. + * In addition, since ARMDEBUG uses Abort mode, if the ABORT occurs while the + * debugger is running, the value of SP_abort is not valid. This should not happen + * in any case (it is a BUG if ARMDEBUG triggers an ABORT). + * + * We assume that the DEBUG stack holds only one stack frame and we will overwrite it. + * On entry, LR_undef contains the PC+4 for Prefetch Abort, and PC+8 for Data Abort. + * + * For the purpose of Debugging, the stack frame should present the PC (R15) as the address + * of the instruction that triggered the Abort. Hence we need to adjust R15 + * to point to the address of the ABORTed instruction. + * + * We will also store ABORT LR (next instruction pointer) and ABORT SPSR to the stack. + * + * For the handler, once the user registers have been stored in the DEBUG stack, the + * registers will be used as follows: + * + * R0: ABORT LR, then ABORT instruction address + * R1: SPSR + * R2: PC Offset, then Mode + * R3: DEBUG Stack Pointer (for Banked R13-R14 update) + * R4: Abort Type Enum + */ + +.text +.code 32 +.align 0 + + .extern dbg__display_abort_info + .extern dbg__bkpt_waitCMD + .extern default_prefetch_abort_handler + .extern default_data_abort_handler + + .global prefetch_abort_handler + .global data_abort_handler + +prefetch_abort_handler: + ldr sp, =__debugger_stack__ + stmfd sp, {r0-r15}^ /* Save workspace, previous mode's pc via 'S' flag, R13-R15: placeholders */ + mov r2, #PREFETCH_OFFSET + mov r4, #ABORT_PREFETCH + b _common_abort_handler + +data_abort_handler: + ldr sp, =__debugger_stack__ + stmfd sp, {r0-r15}^ /* Save workspace, previous mode's pc via 'S' flag, R13-R15: placeholders */ + mov r2, #DATA_OFFSET + mov r4, #ABORT_DATA + +_common_abort_handler: + sub r0, lr, r2 /* R0: Adjust PC to ABORTed instruction address */ + str r0, [sp, #-4] /* Save PC to stack (R15 slot) */ + + mov r3, sp /* Use R3 to write Banked R13-R14 of ABORT instruction */ + + mrs r1, spsr /* Copy SPSR to r1 */ + tst r1, #CPSR_THUMB /* Check for Thumb Mode */ + addne r0, r0, #2 /* Is Thumb instruction, adjust PC for ABORT next instruction address */ + addeq r0, r0, #4 /* Is ARM instruction, adjust PC for ABORT next instruction address */ + sub sp, sp, #(4*16) /* Need to manually update SP(abort) */ + stmfd sp!, {r0,r1} /* Save ABORTed Next Instr Pointer (in R0) and previous mode's CPSR to stack */ + + and r2, r1, #CPSR_MODE /* Get previous mode */ + teq r2, #MODE_USR + beq _exit_abort_handler /* Can't switch back if we're in User mode! */ + +_store_prev_mode_banked_regs: + /* FIXME: We don't handle FIQ properly! */ + + orr r2, #(CPSR_FIQ | CPSR_IRQ) /* Disable Interrupts */ + msr cpsr_c, r2 /* Switch to previous mode */ + stmfd r3!, {sp, lr} /* Store Previous Mode's LR (R14), SP (R13) via R3 */ + msr cpsr_c, #(MODE_ABT | CPSR_FIQ | CPSR_IRQ) /* Revert to ABORT Mode */ + +_exit_abort_handler: + ldr sp, =__abort_stack__ /* Reinitialize stack pointer each time an Abort happens */ + bic sp, sp, #7 + mov r0, r4 /* Copy Abort Type Enum to R0 */ + bl dbg__display_abort_info /* Display Abort Type to LCD */ + b dbg__bkpt_waitCMD /* Invoke Debugger */ + + -- cgit v1.2.3