diff options
author | Diego Ismirlian <dismirlian@gmail.com> | 2019-10-02 15:14:28 -0300 |
---|---|---|
committer | Diego Ismirlian <dismirlian@gmail.com> | 2019-10-02 15:14:28 -0300 |
commit | 41f2f8462a2dc71c8194703fb879e6a667fb723b (patch) | |
tree | 307d1ab1be365128869d6ff025bd4355c4fc0c21 /os/common/ports/ARMCMx/compilers/GCC/utils/fault_handlers_v7m.c | |
parent | 2cd41f99df0fc857afaef091ca3b984a728d0e3c (diff) | |
download | ChibiOS-Contrib-41f2f8462a2dc71c8194703fb879e6a667fb723b.tar.gz ChibiOS-Contrib-41f2f8462a2dc71c8194703fb879e6a667fb723b.tar.bz2 ChibiOS-Contrib-41f2f8462a2dc71c8194703fb879e6a667fb723b.zip |
Add fault handlers to ease ARM-v7m (Cortex M3/M4(F)/M7 debugging
Diffstat (limited to 'os/common/ports/ARMCMx/compilers/GCC/utils/fault_handlers_v7m.c')
-rw-r--r-- | os/common/ports/ARMCMx/compilers/GCC/utils/fault_handlers_v7m.c | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/os/common/ports/ARMCMx/compilers/GCC/utils/fault_handlers_v7m.c b/os/common/ports/ARMCMx/compilers/GCC/utils/fault_handlers_v7m.c new file mode 100644 index 0000000..37b7fc7 --- /dev/null +++ b/os/common/ports/ARMCMx/compilers/GCC/utils/fault_handlers_v7m.c @@ -0,0 +1,215 @@ +/* + ChibiOS - Copyright (C) 2019 Diego Ismirlian (dismirlian(at)google's mail) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include "fault_handlers.h" +#include <hal.h> +#include <string.h> + +#ifndef FAULT_NO_PRINT +#include <chprintf.h> +#include <memstreams.h> + +#define fault_printf(f, ...) \ + chprintf((BaseSequentialStream *)(&ms), \ + f "\n", ##__VA_ARGS__) + +static MemoryStream ms; +#else +#define fault_printf(f, ...) do {} while(0) +#endif + +static struct fault_info fault_info; + +static void _mem_fault(void) { + fault_printf("== Mem faults follow =="); + + if (SCB->CFSR & SCB_CFSR_MSTKERR_Msk) { + fault_printf("Stacking error"); + fault_info.decoded_fault_registers.memfault.stacking_error = true; + } + if (SCB->CFSR & SCB_CFSR_MUNSTKERR_Msk) { + fault_printf("Unstacking error"); + fault_info.decoded_fault_registers.memfault.unstacking_error = true; + } + if (SCB->CFSR & SCB_CFSR_DACCVIOL_Msk) { + fault_printf("Data Access Violation"); + fault_info.decoded_fault_registers.memfault.data_access_violation = true; + } + if (SCB->CFSR & SCB_CFSR_MMARVALID_Msk) { + fault_printf("Address: 0x%08x", (uint32_t)SCB->MMFAR); + fault_info.decoded_fault_registers.memfault.data_access_violation_address = (uint32_t)SCB->MMFAR; + } else { + fault_printf("Address: unknown"); + fault_info.decoded_fault_registers.memfault.data_access_violation_address = 0xffffffff; + } + if (SCB->CFSR & SCB_CFSR_IACCVIOL_Msk) { + fault_printf("Instruction Access Violation"); + fault_info.decoded_fault_registers.memfault.instruction_access_violation = true; + } +} + +static void _bus_fault(void) { + fault_printf("== Bus faults follow =="); + + if (SCB->CFSR & SCB_CFSR_STKERR_Msk) { + fault_printf("Stacking error"); + fault_info.decoded_fault_registers.busfault.stacking_error = true; + } + if (SCB->CFSR & SCB_CFSR_UNSTKERR_Msk) { + fault_printf("Unstacking error"); + fault_info.decoded_fault_registers.busfault.unstacking_error = true; + } + if (SCB->CFSR & SCB_CFSR_PRECISERR_Msk) { + fault_printf("Precise data bus error"); + fault_info.decoded_fault_registers.busfault.precise_data_bus_error = true; + } + if (SCB->CFSR & SCB_CFSR_BFARVALID_Msk) { + fault_printf("Address: 0x%08x", (uint32_t)SCB->BFAR); + fault_info.decoded_fault_registers.busfault.precise_data_bus_error_address = (uint32_t)SCB->BFAR; + } else { + fault_printf("Address: unknown"); + fault_info.decoded_fault_registers.busfault.precise_data_bus_error_address = 0xffffffff; + } + if (SCB->CFSR & SCB_CFSR_IMPRECISERR_Msk) { + fault_printf("Imprecise data bus error"); + fault_info.decoded_fault_registers.busfault.imprecise_data_bus_error = true; + } + if (SCB->CFSR & SCB_CFSR_IBUSERR_Msk) { + fault_printf("Instruction bus error"); + fault_info.decoded_fault_registers.busfault.instruction_bus_error = true; + } +} + +static void _usage_fault(void) { + fault_printf("== Usage faults follow =="); + + if (SCB->CFSR & SCB_CFSR_DIVBYZERO_Msk) { + fault_printf("Division by zero"); + fault_info.decoded_fault_registers.usagefault.division_by_zero = true; + } + if (SCB->CFSR & SCB_CFSR_UNALIGNED_Msk) { + fault_printf("Unaligned memory access"); + fault_info.decoded_fault_registers.usagefault.unaligned_memory_access = true; + } + if (SCB->CFSR & SCB_CFSR_NOCP_Msk) { + fault_printf("No coprocessor instructions"); + fault_info.decoded_fault_registers.usagefault.no_coprocessor_instructions = true; + } + if (SCB->CFSR & SCB_CFSR_INVPC_Msk) { + fault_printf("Invalid load of PC"); + fault_info.decoded_fault_registers.usagefault.invalid_load_of_pc = true; + } + if (SCB->CFSR & SCB_CFSR_INVSTATE_Msk) { + fault_printf("Invalid state"); + fault_info.decoded_fault_registers.usagefault.invalid_state = true; + } + if (SCB->CFSR & SCB_CFSR_UNDEFINSTR_Msk) { + fault_printf("Undefined instruction"); + fault_info.decoded_fault_registers.usagefault.undefined_instruction = true; + } +} + +static void _init_fault_info(void) { +#ifndef FAULT_NO_PRINT + msObjectInit(&ms, + (uint8_t *)fault_info.decoded_info_string, + sizeof(fault_info.decoded_info_string) - 1, 0); +#endif +} + +static void _save_fault_info(void) { + memset(&fault_info.decoded_fault_registers, 0, sizeof(fault_info.decoded_fault_registers)); +#ifndef FAULT_NO_PRINT + memset(&fault_info.decoded_info_string, 0, sizeof(fault_info.decoded_info_string)); +#endif + + if (ch.rlist.current) { + fault_printf("Thread: 0x%08x, %s", + ch.rlist.current, ch.rlist.current->name); + + fault_info.decoded_fault_registers.general.current_thread_address = (uint32_t)ch.rlist.current; + fault_info.decoded_fault_registers.general.current_thread_name = ch.rlist.current->name; + } else { + fault_printf("Thread: unknown"); + } + + if (SCB->HFSR & SCB_HFSR_VECTTBL_Msk) { + fault_printf("Bus fault on vector table read"); + fault_info.decoded_fault_registers.general.bus_fault_on_ivt_read = true; + } + + if (SCB->HFSR & SCB_HFSR_FORCED_Msk) { + fault_info.decoded_fault_registers.general.escalation = true; + _mem_fault(); + _bus_fault(); + _usage_fault(); + } + if (!(SCB->HFSR & + (SCB_HFSR_VECTTBL_Msk | SCB_HFSR_FORCED_Msk))) { + fault_printf("No fault info"); + } +} + +#if defined(FAULT_INFO_HOOK) +void FAULT_INFO_HOOK(const struct fault_info *info); +#endif + +void _hardfault_info(void) { + _init_fault_info(); + fault_printf("HardFault Handler"); + _save_fault_info(); + +#if defined(FAULT_INFO_HOOK) + FAULT_INFO_HOOK(&fault_info); +#endif +} + +void _hardfault_epilogue(void) __attribute__((used, naked)); +void _hardfault_epilogue(void) { + + /* This is part of the HardFault handler + * + * You may inspect fault_info.decoded_fault_registers and + * fault_info.decoded_info_string to get a description of the fault that + * occurred. + * + * Also, the debugger should show an artificial call stack that led to the + * fault. This stack is reconstructed in assembly code, until GDB includes + * a way of automatically unwind an exception stack. + * + */ + __asm volatile( + "bkpt #0 \n" + "b _hardfault_exit \n" + ); +} + +void _unhandled_exception(void) { + /* This is an unhandled exception + * + * Once the breakpoint is hit, the debugger should show the ISR number + * in the vector_number variable. Don't trust the debugger's stack unwind; + * the _unhandled_exception ISR is shared among all undefined vectors. + */ + + volatile uint32_t vector_number = SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk; + (void)vector_number; + + __asm volatile("bkpt #0"); + + /* we are here if there is no debugger attached */ + chSysHalt("unhandled exception"); +} |