/* * Copyright (c) 2012-2013 Travis Geiselbrecht * * Use of this source code is governed by a MIT-style * license that can be found in the LICENSE file or at * https://opensource.org/licenses/MIT */ #include #include #include #include #include #include #include #include #pragma GCC diagnostic ignored "-Wmissing-declarations" static void dump_frame(const struct arm_cm_exception_frame *frame) { printf("exception frame at %p\n", frame); printf("\tr0 0x%08x r1 0x%08x r2 0x%08x r3 0x%08x r4 0x%08x\n", frame->r0, frame->r1, frame->r2, frame->r3, frame->r4); printf("\tr5 0x%08x r6 0x%08x r7 0x%08x r8 0x%08x r9 0x%08x\n", frame->r5, frame->r6, frame->r7, frame->r8, frame->r9); printf("\tr10 0x%08x r11 0x%08x r12 0x%08x\n", frame->r10, frame->r11, frame->r12); printf("\tlr 0x%08x pc 0x%08x psr 0x%08x\n", frame->lr, frame->pc, frame->psr); } void hardfault(struct arm_cm_exception_frame *frame) { printf("hardfault: "); dump_frame(frame); #if (__CORTEX_M >= 0X03) || (__CORTEX_SC >= 300) printf("HFSR 0x%x\n", SCB->HFSR); #endif platform_halt(HALT_ACTION_HALT, HALT_REASON_SW_PANIC); } void memmanage(struct arm_cm_exception_frame *frame) { printf("memmanage: "); dump_frame(frame); #if (__CORTEX_M >= 0X03) || (__CORTEX_SC >= 300) uint32_t mmfsr = SCB->CFSR & 0xff; if (mmfsr & (1<<0)) { // IACCVIOL printf("instruction fault\n"); } if (mmfsr & (1<<1)) { // DACCVIOL printf("data fault\n"); } if (mmfsr & (1<<3)) { // MUNSTKERR printf("fault on exception return\n"); } if (mmfsr & (1<<4)) { // MSTKERR printf("fault on exception entry\n"); } if (mmfsr & (1<<5)) { // MLSPERR printf("fault on lazy fpu preserve\n"); } if (mmfsr & (1<<7)) { // MMARVALID printf("fault address 0x%x\n", SCB->MMFAR); } #endif platform_halt(HALT_ACTION_HALT, HALT_REASON_SW_PANIC); } void usagefault(struct arm_cm_exception_frame *frame) { printf("usagefault: "); dump_frame(frame); #if (__CORTEX_M >= 0x03) uint32_t ufsr = BITS_SHIFT(SCB->CFSR, 31, 16); printf("UFSR 0x%x: ", ufsr); if (ufsr & (1<<0)) printf("undefined instruction\n"); if (ufsr & (1<<1)) printf("ESPR invalid\n"); if (ufsr & (1<<2)) printf("integrity check failed on EXC_RETURN\n"); if (ufsr & (1<<3)) printf("coprocessor access error\n"); if (ufsr & (1<<8)) printf("unaligned error\n"); if (ufsr & (1<<9)) printf("division by zero\n"); #endif platform_halt(HALT_ACTION_HALT, HALT_REASON_SW_PANIC); } void busfault(struct arm_cm_exception_frame *frame) { printf("busfault: "); dump_frame(frame); platform_halt(HALT_ACTION_HALT, HALT_REASON_SW_PANIC); } /* raw exception vectors */ void _nmi(void) { printf("nmi\n"); platform_halt(HALT_ACTION_HALT, HALT_REASON_SW_PANIC); } /* Declare two versions of the assembly to push the extra registers * not already saved by the exception delivery hardware. For armv6-m * based hardware we cannot directly push the higher registers so we * need to move them into lower registers before pushing. */ #if (__CORTEX_M >= 0X03) || (__CORTEX_SC >= 300) #define PUSH_REGS \ "push {r4-r11, lr};" /* 9 words on the stack */ #else #define PUSH_REGS \ "push {r4-r7, lr};" /* 5 words */ \ "mov r4, r8;" \ "mov r5, r9;" \ "mov r6, r10;" \ "mov r7, r11;" \ "push {r4-r7};" /* 4 more words */ #endif __NAKED void _hardfault(void) { __asm__ volatile( PUSH_REGS "mov r0, sp;" "sub sp, #4;" /* adjust the stack to be 8 byte aligned */ "b hardfault;" ); } __NAKED void _memmanage(void) { __asm__ volatile( PUSH_REGS "mov r0, sp;" "sub sp, #4;" /* adjust the stack to be 8 byte aligned */ "b memmanage;" ); } __NAKED void _busfault(void) { __asm__ volatile( PUSH_REGS "mov r0, sp;" "sub sp, #4;" /* adjust the stack to be 8 byte aligned */ "b busfault;" ); } __NAKED void _usagefault(void) { __asm__ volatile( PUSH_REGS "mov r0, sp;" "sub sp, #4;" /* adjust the stack to be 8 byte aligned */ "b usagefault;" ); } #undef PUSH_REGS /* declared weak so these can be overridden elsewhere */ /* systick handler */ void __WEAK _systick(void) { printf("systick\n"); platform_halt(HALT_ACTION_HALT, HALT_REASON_SW_PANIC); } void __WEAK _debugmonitor(void) { printf("debugmonitor\n"); platform_halt(HALT_ACTION_HALT, HALT_REASON_SW_PANIC); } void __WEAK _svc(void) { printf("svc\n"); platform_halt(HALT_ACTION_HALT, HALT_REASON_SW_PANIC); }