static void _FaultShow(const NANO_ESF *esf, int fault) { PR_EXC("Fault! EXC #%d\n", fault); #if defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) PR_EXC("MMFSR: 0x%x, BFSR: 0x%x, UFSR: 0x%x\n", SCB_MMFSR, SCB_BFSR, SCB_UFSR); #if defined(CONFIG_ARM_SECURE_FIRMWARE) PR_EXC("SFSR: 0x%x\n", SAU->SFSR); #endif /* CONFIG_ARM_SECURE_FIRMWARE */ #endif /* CONFIG_ARMV7_M_ARMV8_M_MAINLINE */ }
/** * * @brief Dump bus fault information * * See _FaultDump() for example. * * @return N/A */ static void _BusFault(const NANO_ESF *esf, int fromHardFault) { PR_EXC("***** BUS FAULT *****\n"); _FaultThreadShow(esf); if (_ScbBusFaultIsStacking()) { PR_EXC(" Stacking error\n"); } else if (_ScbBusFaultIsUnstacking()) { PR_EXC(" Unstacking error\n"); } else if (_ScbBusFaultIsPrecise()) { PR_EXC(" Precise data bus error\n"); if (_ScbBusFaultIsBfarValid()) { PR_EXC(" Address: 0x%x\n", _ScbBusFaultAddrGet()); if (fromHardFault) { _ScbBusFaultBfarReset(); } } /* it's possible to have both a precise and imprecise fault */ if (_ScbBusFaultIsImprecise()) { PR_EXC(" Imprecise data bus error\n"); } } else if (_ScbBusFaultIsImprecise()) { PR_EXC(" Imprecise data bus error\n"); } else if (_ScbBusFaultIsInstrBusErr()) { PR_EXC(" Instruction bus error\n"); } }
/** * * @brief Dump hard fault information * * See _FaultDump() for example. * * @return N/A */ static void _HardFault(const NANO_ESF *esf) { PR_EXC("***** HARD FAULT *****\n"); if (_ScbHardFaultIsBusErrOnVectorRead()) { PR_EXC(" Bus fault on vector table read\n"); } else if (_ScbHardFaultIsForced()) { PR_EXC(" Fault escalation (see below)\n"); if (_ScbIsMemFault()) { _MpuFault(esf, 1); } else if (_ScbIsBusFault()) { _BusFault(esf, 1); } else if (_ScbIsUsageFault()) { _UsageFault(esf); } } }
/** * * @brief Dump thread information * * See _FaultDump() for example. * * @return N/A */ static void _FaultThreadShow(const NANO_ESF *esf) { PR_EXC(" Executing thread ID (thread): 0x%x\n" " Faulting instruction address: 0x%x\n", sys_thread_self_get(), esf->pc); }
/** * * @brief Dump usage fault information * * See _FaultDump() for example. * * @return N/A */ static void _UsageFault(const NANO_ESF *esf) { PR_EXC("***** USAGE FAULT *****\n"); _FaultThreadShow(esf); /* bits are sticky: they stack and must be reset */ if (_ScbUsageFaultIsDivByZero()) { PR_EXC(" Division by zero\n"); } if (_ScbUsageFaultIsUnaligned()) { PR_EXC(" Unaligned memory access\n"); } if (_ScbUsageFaultIsNoCp()) { PR_EXC(" No coprocessor instructions\n"); } if (_ScbUsageFaultIsInvalidPcLoad()) { PR_EXC(" Illegal load of EXC_RETURN into PC\n"); } if (_ScbUsageFaultIsInvalidState()) { PR_EXC(" Illegal use of the EPSR\n"); } if (_ScbUsageFaultIsUndefinedInstr()) { PR_EXC(" Attempt to execute undefined instruction\n"); } _ScbUsageFaultAllFaultsReset(); }
/** * * @brief Dump information regarding fault (FAULT_DUMP == 1) * * Dump information regarding the fault when CONFIG_FAULT_DUMP is set to 1 * (short form). * * eg. (precise bus error escalated to hard fault): * * Fault! EXC #3, Thread: 0x200000dc, instr: 0x000011d3 * HARD FAULT: Escalation (see below)! * MMFSR: 0x00000000, BFSR: 0x00000082, UFSR: 0x00000000 * BFAR: 0xff001234 * * @return N/A */ void _FaultDump(const NANO_ESF *esf, int fault) { int escalation = 0; PR_EXC("Fault! EXC #%d, Thread: %x, instr @ %x\n", fault, sys_thread_self_get(), esf->pc); if (3 == fault) { /* hard fault */ escalation = _ScbHardFaultIsForced(); PR_EXC("HARD FAULT: %s\n", escalation ? "Escalation (see below)!" : "Bus fault on vector table read\n"); } PR_EXC("MMFSR: %x, BFSR: %x, UFSR: %x\n", __scs.scb.cfsr.byte.mmfsr.val, __scs.scb.cfsr.byte.bfsr.val, __scs.scb.cfsr.byte.ufsr.val); if (_ScbMemFaultIsMmfarValid()) { PR_EXC("MMFAR: %x\n", _ScbMemFaultAddrGet()); if (escalation) { _ScbMemFaultMmfarReset(); } } if (_ScbBusFaultIsBfarValid()) { PR_EXC("BFAR: %x\n", _ScbBusFaultAddrGet()); if (escalation) { _ScbBusFaultBfarReset(); } } /* clear USFR sticky bits */ _ScbUsageFaultAllFaultsReset(); }
/** * * @brief Dump bus fault information * * See _FaultDump() for example. * * @return N/A */ static int _BusFault(NANO_ESF *esf, int fromHardFault) { PR_FAULT_INFO("***** BUS FAULT *****\n"); if (SCB->CFSR & SCB_CFSR_STKERR_Msk) { PR_FAULT_INFO(" Stacking error\n"); } else if (SCB->CFSR & SCB_CFSR_UNSTKERR_Msk) { PR_FAULT_INFO(" Unstacking error\n"); } else if (SCB->CFSR & SCB_CFSR_PRECISERR_Msk) { PR_FAULT_INFO(" 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 & SCB_CFSR_BFARVALID_Msk) { PR_EXC(" BFAR Address: 0x%x\n", bfar); if (fromHardFault) { /* clear SCB_CFSR_BFAR[VALID] to reset */ SCB->CFSR &= ~SCB_CFSR_BFARVALID_Msk; } } /* it's possible to have both a precise and imprecise fault */ if (SCB->CFSR & SCB_CFSR_IMPRECISERR_Msk) { PR_FAULT_INFO(" Imprecise data bus error\n"); } } else if (SCB->CFSR & SCB_CFSR_IMPRECISERR_Msk) { PR_FAULT_INFO(" Imprecise data bus error\n"); } else if (SCB->CFSR & SCB_CFSR_IBUSERR_Msk) { PR_FAULT_INFO(" Instruction bus error\n"); #if !defined(CONFIG_ARMV7_M_ARMV8_M_FP) } #else } else if (SCB->CFSR & SCB_CFSR_LSPERR_Msk) {
/** * * @brief Dump MPU fault information * * See _FaultDump() for example. * * @return N/A */ static void _MpuFault(const NANO_ESF *esf, int fromHardFault) { PR_EXC("***** MPU FAULT *****\n"); _FaultThreadShow(esf); if (_ScbMemFaultIsStacking()) { PR_EXC(" Stacking error\n"); } else if (_ScbMemFaultIsUnstacking()) { PR_EXC(" Unstacking error\n"); } else if (_ScbMemFaultIsDataAccessViolation()) { PR_EXC(" Data Access Violation\n"); if (_ScbMemFaultIsMmfarValid()) { PR_EXC(" Address: 0x%x\n", _ScbMemFaultAddrGet()); if (fromHardFault) { _ScbMemFaultMmfarReset(); } } } else if (_ScbMemFaultIsInstrAccessViolation()) { PR_EXC(" Instruction Access Violation\n"); } }
/** * * @brief Dump MPU fault information * * See _FaultDump() for example. * * @return error code to identify the fatal error reason */ static u32_t _MpuFault(NANO_ESF *esf, int fromHardFault) { u32_t reason = _NANO_ERR_HW_EXCEPTION; PR_FAULT_INFO("***** MPU FAULT *****\n"); if (SCB->CFSR & SCB_CFSR_MSTKERR_Msk) { PR_FAULT_INFO(" Stacking error\n"); } if (SCB->CFSR & SCB_CFSR_MUNSTKERR_Msk) { PR_FAULT_INFO(" Unstacking error\n"); } if (SCB->CFSR & SCB_CFSR_DACCVIOL_Msk) { PR_FAULT_INFO(" 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. */ u32_t mmfar = SCB->MMFAR; if (SCB->CFSR & SCB_CFSR_MMARVALID_Msk) { PR_EXC(" MMFAR Address: 0x%x\n", mmfar); if (fromHardFault) { /* clear SCB_MMAR[VALID] to reset */ SCB->CFSR &= ~SCB_CFSR_MMARVALID_Msk; } #if defined(CONFIG_HW_STACK_PROTECTION) /* When stack protection is enabled, we need to see * if the memory violation error is a stack corruption. * For that we investigate the address fail. */ struct k_thread *thread = _current; u32_t guard_start; if (thread != NULL) { #if defined(CONFIG_USERSPACE) guard_start = thread->arch.priv_stack_start ? (u32_t)thread->arch.priv_stack_start : (u32_t)thread->stack_obj; #else guard_start = thread->stack_info.start; #endif if (mmfar >= guard_start && mmfar < guard_start + MPU_GUARD_ALIGN_AND_SIZE) { /* Thread stack corruption */ reason = _NANO_ERR_STACK_CHK_FAIL; } } #else (void)mmfar; #endif /* CONFIG_HW_STACK_PROTECTION */ } } if (SCB->CFSR & SCB_CFSR_IACCVIOL_Msk) { PR_FAULT_INFO(" Instruction Access Violation\n"); } #if defined(CONFIG_ARMV7_M_ARMV8_M_FP) if (SCB->CFSR & SCB_CFSR_MLSPERR_Msk) { PR_FAULT_INFO( " Floating-point lazy state preservation error\n"); } #endif /* !defined(CONFIG_ARMV7_M_ARMV8_M_FP) */ /* Assess whether system shall ignore/recover from this MPU fault. */ if (_MemoryFaultIsRecoverable(esf)) { reason = _NANO_ERR_RECOVERABLE; } return reason; }
/** * * @brief Dump reserved exception information * * See _FaultDump() for example. * * @return N/A */ static void _ReservedException(const NANO_ESF *esf, int fault) { PR_EXC("***** %s %d) *****\n", fault < 16 ? "Reserved Exception (" : "Spurious interrupt (IRQ ", fault - 16); }
/** * * @brief Dump debug monitor exception information * * See _FaultDump() for example. * * @return N/A */ static void _DebugMonitor(const NANO_ESF *esf) { PR_EXC("***** Debug monitor exception (not implemented) *****\n"); }