4 个 Fault Handler 迁入 USER CODE BEGIN 0(L3→L2):生成区恢复 CubeMX 原样,重生成零 diff
CI / L0 静态门禁 (pre-commit) (push) Has been cancelled
CI / L0.5 主机侧单测 (MSVC) (push) Has been cancelled

This commit is contained in:
2026-10-10 02:01:14 +08:00
parent e2e1d0fd42
commit 29df7bf8fb
6 changed files with 117 additions and 113 deletions
+81 -78
View File
@@ -165,7 +165,67 @@ void fault_entry_usage(uint32_t *frame)
hard_fault_report("USAGEFAULT", frame);
}
/* 为生成函数改名,避免与下方手工 `__asm` 实现符号冲突。
/* ==== 4 个异常入口:__asm 版 Handler(符号与向量表一致)====
* ⚠ **必须写在下面 4 个 `#define X X_Gen` 之前**——写在之后会被自己的宏改名。
* 2026-10-09 从生成区迁入本保护区:此前放在生成区内(L3),每次 CubeMX 重生成
* 都被抹掉、需 `git checkout HEAD -- Src/stm32f4xx_it.c` 复原;现在生成区保持
* CubeMX 原样,重生成零改动。
*
* 原理:EXC_RETURN bit2(`TST lr, #4`)判断异常帧在 MSP 还是 PSP,取帧指针后
* `B` 到上面的 per-fault C 入口。CubeMX 默认的空 `while(1)` 版会让死机在日志上
* **完全静默**(2026-09-20 实证)。
* ⚠ ARMCC 语法:内联汇编**只能**用整函数 `__asm void f(void) {...}` 形态。
* `__asm volatile("MRS %0, lr" : "=r"(x))`(GCC 语法)报 #18;
* `__asm { MRS x, lr }` 块内联会把寄存器名当 C 标识符报 #20(2026-09-29 实测)。
*/
__asm void HardFault_Handler(void)
{
extern fault_entry_hard
TST lr, #4
ITE EQ
MRSEQ r0, MSP
MRSNE r0, PSP
B fault_entry_hard
}
/* MEMFAULT:访问 MPU 禁止区 / 非法特权级访问。须 SHCSR 的 MEMFAULTENA(bit16) 使能。
* 命中时 CFSR 的 MMARVALID(bit7) 置 1,MMFAR 记录出错地址(报告函数按此判定)。 */
__asm void MemManage_Handler(void)
{
extern fault_entry_mem
TST lr, #4
ITE EQ
MRSEQ r0, MSP
MRSNE r0, PSP
B fault_entry_mem
}
/* BUSFAULT:非法总线访问 / 取指(外设时钟未开、错误指针、DMA 越界等)。
* 须 SHCSR 的 BUSFAULTENA(bit17) 使能。命中时 CFSR 的 BFARVALID(bit15) 置 1。 */
__asm void BusFault_Handler(void)
{
extern fault_entry_bus
TST lr, #4
ITE EQ
MRSEQ r0, MSP
MRSNE r0, PSP
B fault_entry_bus
}
/* USAGEFAULT:未定义指令 / 非对齐访问 / 除零(须 DIV_0_TRP)/ 非法状态。
* 须 SHCSR 的 USGFAULTENA(bit18) 使能。
* ⚠ 本项目**刻意不使用硬件除零陷入**(C 代码里除零应自己判,避免把普通 bug 升级为死机)。 */
__asm void UsageFault_Handler(void)
{
extern fault_entry_usage
TST lr, #4
ITE EQ
MRSEQ r0, MSP
MRSNE r0, PSP
B fault_entry_usage
}
/* 为生成函数改名,避免与上面手工 `__asm` 实现符号冲突。
* 生成实体改名为 <原名>_Gen(永不执行,仅为占名字不冲突,
* 保持生成区代码零删除;未被引用 → 链接器自动移除)。
*
@@ -216,36 +276,13 @@ void NMI_Handler(void)
}
/**
* @brief This function handles Hard fault interrupt.
*/
/* HARD-FAULT-ANCHOR — 本锚点与下方改动一体,重生成会一并消失,
* 供 scripts/check_cubemx_survival.py 检出(勿删):
*
* 崩溃现场采集(手工改写)。EXC_RETURN bit2 判断异常帧在 MSP 还是 PSP,
* 取帧指针交给 C 报告函数 hard_fault_report()(实现在文件头 USER CODE BEGIN 0
* 保护区内)。空 while(1) 版会让死机在日志上完全静默(2026-09-20 实证)。
*
* 命名:`#undef HardFault_Handler` 后重定义为 __asm 版本,与向量表符号一致;
* 为避免与下方生成实体"重复定义"(ARMCC 报 #247,其"已定义"检查
* 早于 C 作用域),已在文件头用 `#define HardFault_Handler
* HardFault_Handler_Gen` 把生成实体改名为不冲突的符号。
*
* ⚠ ARMCC 语法:内联汇编**只能**用整函数 `__asm void f(void) {...}` 形态。
* `__asm volatile("MRS %0, lr" : "=r"(x))`(GCC 语法)报 #18;
* `__asm { MRS x, lr }` 块内联会把寄存器名当 C 标识符报 #20(2026-09-29 实测)。 */
#undef HardFault_Handler
__asm void HardFault_Handler(void)
* @brief This function handles Hard fault interrupt.
*/
void HardFault_Handler(void)
{
extern fault_entry_hard
TST lr, #4
ITE EQ
MRSEQ r0, MSP
MRSNE r0, PSP
B fault_entry_hard
}
/* USER CODE BEGIN HardFault_IRQn 0 */
void HardFault_Handler_Gen(void)
{
/* USER CODE END HardFault_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_HardFault_IRQn 0 */
@@ -254,24 +291,13 @@ void HardFault_Handler_Gen(void)
}
/**
* @brief This function handles Memory management fault.
*/
/* MEMFAULT-ANCHOR — 见 HARD-FAULT-ANCHOR(同一套采集方案,勿删本锚点)
* 触发条件:访问 MPU 禁止区 / 非法特权级访问。须 SHCSR 的 MEMFAULTENA(bit16) 使能。
* 命中时 CFSR 的 MMARVALID(bit7) 置 1,MMFAR 记录出错地址(报告函数按此判定)。 */
#undef MemManage_Handler
__asm void MemManage_Handler(void)
* @brief This function handles Memory management fault.
*/
void MemManage_Handler(void)
{
extern fault_entry_mem
TST lr, #4
ITE EQ
MRSEQ r0, MSP
MRSNE r0, PSP
B fault_entry_mem
}
/* USER CODE BEGIN MemoryManagement_IRQn 0 */
void MemManage_Handler_Gen(void)
{
/* USER CODE END MemoryManagement_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */
@@ -280,24 +306,13 @@ void MemManage_Handler_Gen(void)
}
/**
* @brief This function handles Pre-fetch fault, memory access fault.
*/
/* BUSFAULT-ANCHOR — 见 HARD-FAULT-ANCHOR(同一套采集方案,勿删本锚点)
* 触发条件:非法总线访问 / 取指(外设时钟未开、错误指针、DMA 越界等)。
* 须 SHCSR 的 BUSFAULTENA(bit17) 使能。命中时 CFSR 的 BFARVALID(bit15) 置 1。 */
#undef BusFault_Handler
__asm void BusFault_Handler(void)
* @brief This function handles Pre-fetch fault, memory access fault.
*/
void BusFault_Handler(void)
{
extern fault_entry_bus
TST lr, #4
ITE EQ
MRSEQ r0, MSP
MRSNE r0, PSP
B fault_entry_bus
}
/* USER CODE BEGIN BusFault_IRQn 0 */
void BusFault_Handler_Gen(void)
{
/* USER CODE END BusFault_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_BusFault_IRQn 0 */
@@ -306,25 +321,13 @@ void BusFault_Handler_Gen(void)
}
/**
* @brief This function handles Undefined instruction or illegal state.
*/
/* USAGEFAULT-ANCHOR — 见 HARD-FAULT-ANCHOR(同一套采集方案,勿删本锚点)
* 触发条件:未定义指令 / 非对齐访问 / 除零(须 DIV_0_TRP)/ 非法状态。
* 须 SHCSR 的 USGFAULTENA(bit18) 使能。
* ⚠ 本项目**刻意不使用硬件除零陷入**(C 代码里除零应自己判,避免把普通 bug 升级为死机)。 */
#undef UsageFault_Handler
__asm void UsageFault_Handler(void)
* @brief This function handles Undefined instruction or illegal state.
*/
void UsageFault_Handler(void)
{
extern fault_entry_usage
TST lr, #4
ITE EQ
MRSEQ r0, MSP
MRSNE r0, PSP
B fault_entry_usage
}
/* USER CODE BEGIN UsageFault_IRQn 0 */
void UsageFault_Handler_Gen(void)
{
/* USER CODE END UsageFault_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_UsageFault_IRQn 0 */