From abe5b0c5b9db7ebb0a4018a874ede1c15955f784 Mon Sep 17 00:00:00 2001 From: Chen Peng Date: Thu, 16 Jul 2026 01:02:09 +0800 Subject: [PATCH] HardFault_Handler --- os_port.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++ os_port_armcc.S | 10 +++++ os_port_gnu.S | 13 +++++++ 3 files changed, 122 insertions(+) diff --git a/os_port.c b/os_port.c index 14b5c15..e4c9f62 100644 --- a/os_port.c +++ b/os_port.c @@ -145,3 +145,102 @@ void SVC_Handler_C(os_uintptr_t* svc_args){ } } +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +// https://interrupt.memfault.com/blog/cortex-m-hardfault-debug +// Logic for dealing with the exception. Typically: +// - log the fault which occurred for postmortem analysis +// - If the fault is recoverable, +// - clear errors and return back to Thread Mode +// - else +// - reboot system + + +#define AUTO_REBOOT_ENABLE /* 允许自动重启 */ +#define OUTPUT_FAULT_TO_CONSOLE_ENABLE /* 在调试终端输出运行时信息 */ +#define RECOVER_FROM_FAULT_ENABLE /* 尝试从错误中继续运行 */ + +#if defined(RECOVER_FROM_FAULT_ENABLE) +static void recover_from_task_fault(void){ + while(1){ + os_task_yield(); + } +} +#endif + +typedef OS_PACKED_STRUCT(ContextStateFrame) { + uint32_t r0; + uint32_t r1; + uint32_t r2; + uint32_t r3; + uint32_t r12; + uint32_t lr; + uint32_t return_address; + uint32_t xpsr; +} ContextStateFrame_t; + +void HardFault_Handler_C(ContextStateFrame_t* frame, uint32_t lr_value){ + uint32_t bus_fault_address = SCB->BFAR; + uint32_t mem_manage_fault_address = SCB->MMFAR; + uint32_t cfsr = SCB->CFSR; + +#if defined(AUTO_REBOOT_ENABLE) + const uint32_t usage_fault_mask = 0xffff0000; + const bool non_usage_fault_occurred = + (cfsr & ~usage_fault_mask) != 0; + // the bottom 8 bits of the xpsr hold the exception number of the + // executing exception or 0 if the processor is in Thread mode + const bool faulted_from_exception = ((frame->xpsr & 0xFF) != 0); + + if (faulted_from_exception || non_usage_fault_occurred) { + // For any fault within an ISR or non-usage faults + // let's reboot the system + volatile uint32_t *aircr = (volatile uint32_t *)0xE000ED0C; + *aircr = (0x05FA << 16) | 0x1 << 2; + while (1) { } // should be unreachable + } +#endif + +#if defined(OUTPUT_FAULT_TO_CONSOLE_ENABLE) + printf("[HardFault]\n"); + printf("- Stack frame:\n"); + printf(" R0 = %08"OS_PRIx"\n", frame->r0); + printf(" R1 = %08"OS_PRIx"\n", frame->r1); + printf(" R2 = %08"OS_PRIx"\n", frame->r2); + printf(" R3 = %08"OS_PRIx"\n", frame->r3); + printf(" R12 = %08"OS_PRIx"\n", frame->r12); + printf(" LR = %08"OS_PRIx"\n", frame->lr); + printf(" PC = %08"OS_PRIx"\n", frame->return_address); + printf(" PSR = %08"OS_PRIx"\n", frame->xpsr); + printf("- FSR/FAR:\n"); + printf(" CFSR = %08"OS_PRIx"\n", cfsr); + printf(" HFSR = %08"OS_PRIx"\n", SCB->HFSR); + printf(" DFSR = %08"OS_PRIx"\n", SCB->DFSR); + printf(" AFSR = %08"OS_PRIx"\n", SCB->AFSR); + if(cfsr & 0x0080){ + printf(" MMFAR = %08"OS_PRIx"\n", mem_manage_fault_address); + } + if(cfsr & 0x8000){ + printf(" BFAR = %08"OS_PRIx"\n", bus_fault_address); + } + printf("- Misc:\n"); + printf(" LR/EXC_RETURN = %08"OS_PRIx"\n", lr_value); +#endif + +#if defined(RECOVER_FROM_FAULT_ENABLE) + // Clear any logged faults from the CFSR + SCB->CFSR |= SCB->CFSR; + // the instruction we will return to when we exit from the exception + frame->return_address = (uint32_t)recover_from_task_fault; + // the function we are returning to should never branch + // so set lr to a pattern that would fault if it did + frame->lr = 0xdeadbeef; + // reset the psr state and only leave the + // "thumb instruction interworking" bit set + frame->xpsr = (1 << 24); +#else + while(1); +#endif +} + diff --git a/os_port_armcc.S b/os_port_armcc.S index 4af1b4b..f159f77 100644 --- a/os_port_armcc.S +++ b/os_port_armcc.S @@ -67,5 +67,15 @@ __PendSV_SwitchTo ENDP +HardFault_Handler PROC + EXPORT HardFault_Handler + tst lr, #4 // 检查 EXC_RETURN (LR) 的位 2 + ite eq + mrseq r0, msp // 如果位 2 是 0,栈帧在 MSP + mrsne r0, psp // 如果位 2 是 1,栈帧在 PSP + mov r1, lr + b HardFault_Handler_C // 跳转到 C 实现,r0 作为第一个参数传入 + ENDP + END diff --git a/os_port_gnu.S b/os_port_gnu.S index cdecec6..0f1fc63 100644 --- a/os_port_gnu.S +++ b/os_port_gnu.S @@ -76,5 +76,18 @@ cpu_clz: CLZ R0, R0 BX LR + .section .text.HardFault_Handler,"ax",%progbits + .global HardFault_Handler + .thumb_func +HardFault_Handler: + tst lr, #4 + ite eq + mrseq r0, msp + mrsne r0, psp + mov r1, lr + b HardFault_Handler_C + + + .align 4 .end \ No newline at end of file