diff --git a/arch/arm/core/fault.c b/arch/arm/core/fault.c index 987d3b62837..6c9a1569f5c 100644 --- a/arch/arm/core/fault.c +++ b/arch/arm/core/fault.c @@ -21,8 +21,10 @@ #ifdef CONFIG_PRINTK #include #define PR_EXC(...) printk(__VA_ARGS__) +#define STORE_xFAR(reg_var, reg) u32_t reg_var = (u32_t)reg #else #define PR_EXC(...) +#define STORE_xFAR(reg_var, reg) #endif /* CONFIG_PRINTK */ #if (CONFIG_FAULT_DUMP > 0) @@ -73,15 +75,26 @@ void _FaultDump(const NANO_ESF *esf, int fault) PR_EXC("MMFSR: 0x%x, BFSR: 0x%x, UFSR: 0x%x\n", SCB_MMFSR, SCB_BFSR, SCB_MMFSR); + /* In a fault handler, to determine the true faulting address: + * 1. Read and save the MMFAR or BFAR value. + * 2. Read the MMARVALID bit in the MMFSR, or the BFARVALID bit in the + * BFSR. The MMFAR or BFAR address is valid only if this bit is 1. + * + * Software must follow this sequence because another higher priority + * exception might change the MMFAR or BFAR value. + */ + STORE_xFAR(mmfar, SCB->MMFAR); + STORE_xFAR(bfar, SCB->BFAR); + if (SCB->CFSR & CFSR_MMARVALID_Msk) { - PR_EXC("MMFAR: 0x%x\n", SCB->MMFAR); + PR_EXC("MMFAR: 0x%x\n", mmfar); if (escalation) { /* clear MMAR[VALID] to reset */ SCB->CFSR &= ~CFSR_MMARVALID_Msk; } } if (SCB->CFSR & CFSR_BFARVALID_Msk) { - PR_EXC("BFAR: 0x%x\n", SCB->BFAR); + PR_EXC("BFAR: 0x%x\n", bfar); if (escalation) { /* clear CFSR_BFAR[VALID] to reset */ SCB->CFSR &= ~CFSR_BFARVALID_Msk; @@ -136,8 +149,18 @@ static void _MpuFault(const NANO_ESF *esf, int fromHardFault) PR_EXC(" Unstacking error\n"); } else if (SCB->CFSR & CFSR_DACCVIOL_Msk) { PR_EXC(" Data Access Violation\n"); + /* In a fault handler, to determine the true faulting address: + * 1. Read and save the MMFAR value. + * 2. Read the MMARVALID bit in the MMFSR. + * The MMFAR address is valid only if this bit is 1. + * + * Software must follow this sequence because another higher + * priority exception might change the MMFAR value. + */ + STORE_xFAR(mmfar, SCB->MMFAR); + if (SCB->CFSR & CFSR_MMARVALID_Msk) { - PR_EXC(" Address: 0x%x\n", (u32_t)SCB->MMFAR); + PR_EXC(" Address: 0x%x\n", mmfar); if (fromHardFault) { /* clear MMAR[VALID] to reset */ SCB->CFSR &= ~CFSR_MMARVALID_Msk; @@ -168,8 +191,18 @@ static void _BusFault(const NANO_ESF *esf, int fromHardFault) PR_EXC(" Unstacking error\n"); } else if (SCB->CFSR & CFSR_PRECISERR_Msk) { PR_EXC(" Precise data bus error\n"); + /* In a fault handler, to determine the true faulting address: + * 1. Read and save the BFAR value. + * 2. Read the BFARVALID bit in the BFSR. + * The BFAR address is valid only if this bit is 1. + * + * Software must follow this sequence because another + * higher priority exception might change the BFAR value. + */ + STORE_xFAR(bfar, SCB->BFAR); + if (SCB->CFSR & CFSR_BFARVALID_Msk) { - PR_EXC(" Address: 0x%x\n", (u32_t)SCB->BFAR); + PR_EXC(" Address: 0x%x\n", bfar); if (fromHardFault) { /* clear CFSR_BFAR[VALID] to reset */ SCB->CFSR &= ~CFSR_BFARVALID_Msk;