1 // Copyright 2022 The Pigweed Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 // use this file except in compliance with the License. You may obtain a copy of 5 // the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations under 13 // the License. 14 15 #include "pw_cpu_exception_cortex_m/util.h" 16 17 #include <cinttypes> 18 19 #include "pw_cpu_exception_cortex_m/cpu_state.h" 20 #include "pw_cpu_exception_cortex_m_private/config.h" 21 #include "pw_cpu_exception_cortex_m_private/cortex_m_constants.h" 22 #include "pw_log/log.h" 23 #include "pw_preprocessor/arch.h" 24 25 namespace pw::cpu_exception::cortex_m { 26 namespace { 27 LogCfsrAnalysis(const uint32_t cfsr)28[[maybe_unused]] void LogCfsrAnalysis(const uint32_t cfsr) { 29 if (cfsr == 0) { 30 return; 31 } 32 33 PW_LOG_INFO("Active CFSR fields:"); 34 35 // Memory managment fault fields. 36 if (cfsr & kCfsrIaccviolMask) { 37 PW_LOG_ERROR(" IACCVIOL: MPU violation on instruction fetch"); 38 } 39 if (cfsr & kCfsrDaccviolMask) { 40 PW_LOG_ERROR(" DACCVIOL: MPU violation on memory read/write"); 41 } 42 if (cfsr & kCfsrMunstkerrMask) { 43 PW_LOG_ERROR(" MUNSTKERR: 'MPU violation on exception return"); 44 } 45 if (cfsr & kCfsrMstkerrMask) { 46 PW_LOG_ERROR(" MSTKERR: MPU violation on exception entry"); 47 } 48 if (cfsr & kCfsrMlsperrMask) { 49 PW_LOG_ERROR(" MLSPERR: MPU violation on lazy FPU state preservation"); 50 } 51 if (cfsr & kCfsrMmarvalidMask) { 52 PW_LOG_ERROR(" MMARVALID: MMFAR register is valid"); 53 } 54 55 // Bus fault fields. 56 if (cfsr & kCfsrIbuserrMask) { 57 PW_LOG_ERROR(" IBUSERR: Bus fault on instruction fetch"); 58 } 59 if (cfsr & kCfsrPreciserrMask) { 60 PW_LOG_ERROR(" PRECISERR: Precise bus fault"); 61 } 62 if (cfsr & kCfsrImpreciserrMask) { 63 PW_LOG_ERROR(" IMPRECISERR: Imprecise bus fault"); 64 } 65 if (cfsr & kCfsrUnstkerrMask) { 66 PW_LOG_ERROR(" UNSTKERR: Derived bus fault on exception context save"); 67 } 68 if (cfsr & kCfsrStkerrMask) { 69 PW_LOG_ERROR(" STKERR: Derived bus fault on exception context restore"); 70 } 71 if (cfsr & kCfsrLsperrMask) { 72 PW_LOG_ERROR(" LSPERR: Derived bus fault on lazy FPU state preservation"); 73 } 74 if (cfsr & kCfsrBfarvalidMask) { 75 PW_LOG_ERROR(" BFARVALID: BFAR register is valid"); 76 } 77 78 // Usage fault fields. 79 if (cfsr & kCfsrUndefinstrMask) { 80 PW_LOG_ERROR(" UNDEFINSTR: Encountered invalid instruction"); 81 } 82 if (cfsr & kCfsrInvstateMask) { 83 PW_LOG_ERROR( 84 " INVSTATE: Attempted to execute an instruction with an invalid " 85 "Execution Program Status Register (EPSR) value"); 86 } 87 if (cfsr & kCfsrInvpcMask) { 88 PW_LOG_ERROR(" INVPC: Program Counter (PC) is not legal"); 89 } 90 if (cfsr & kCfsrNocpMask) { 91 PW_LOG_ERROR(" NOCP: Coprocessor disabled or not present"); 92 } 93 if (cfsr & kCfsrUnalignedMask) { 94 PW_LOG_ERROR(" UNALIGNED: Unaligned memory access"); 95 } 96 if (cfsr & kCfsrDivbyzeroMask) { 97 PW_LOG_ERROR(" DIVBYZERO: Division by zero"); 98 } 99 #if _PW_ARCH_ARM_V8M_MAINLINE || _PW_ARCH_ARM_V8_1M_MAINLINE 100 if (cfsr & kCfsrStkofMask) { 101 PW_LOG_ERROR(" STKOF: Stack overflowed"); 102 } 103 #endif // _PW_ARCH_ARM_V8M_MAINLINE || _PW_ARCH_ARM_V8_1M_MAINLINE 104 } 105 106 } // namespace 107 LogExceptionAnalysis(const pw_cpu_exception_State & cpu_state)108void LogExceptionAnalysis(const pw_cpu_exception_State& cpu_state) { 109 // This provides a high-level assessment of the cause of the exception. 110 // These conditionals are ordered by priority to ensure the most critical 111 // issues are highlighted first. These are not mutually exclusive; a bus fault 112 // could occur during the handling of a MPU violation, causing a nested fault. 113 #if !_PW_ARCH_ARM_V6M 114 if (cpu_state.extended.hfsr & kHfsrForcedMask) { 115 PW_LOG_CRITICAL("Encountered a nested CPU fault (See active CFSR fields)"); 116 } 117 #endif // !_PW_ARCH_ARM_V6M 118 #if _PW_ARCH_ARM_V8M_MAINLINE || _PW_ARCH_ARM_V8_1M_MAINLINE 119 if (cpu_state.extended.cfsr & kCfsrStkofMask) { 120 if (ProcessStackActive(cpu_state)) { 121 PW_LOG_CRITICAL("Encountered process stack overflow (psp)"); 122 } else { 123 PW_LOG_CRITICAL("Encountered main stack overflow (msp)"); 124 } 125 } 126 #endif // _PW_ARCH_ARM_V8M_MAINLINE || _PW_ARCH_ARM_V8_1M_MAINLINE 127 #if !_PW_ARCH_ARM_V6M 128 if (cpu_state.extended.cfsr & kCfsrMemFaultMask) { 129 if (cpu_state.extended.cfsr & kCfsrMmarvalidMask) { 130 PW_LOG_CRITICAL( 131 "Encountered Memory Protection Unit (MPU) violation at 0x%08" PRIx32, 132 cpu_state.extended.mmfar); 133 } else { 134 PW_LOG_CRITICAL("Encountered Memory Protection Unit (MPU) violation"); 135 } 136 } 137 if (cpu_state.extended.cfsr & kCfsrBusFaultMask) { 138 if (cpu_state.extended.cfsr & kCfsrBfarvalidMask) { 139 PW_LOG_CRITICAL("Encountered bus fault at 0x%08" PRIx32, 140 cpu_state.extended.bfar); 141 } else { 142 PW_LOG_CRITICAL("Encountered bus fault"); 143 } 144 } 145 if (cpu_state.extended.cfsr & kCfsrUsageFaultMask) { 146 PW_LOG_CRITICAL("Encountered usage fault (See active CFSR fields)"); 147 } 148 #endif // !_PW_ARCH_ARM_V6M 149 if ((cpu_state.extended.icsr & kIcsrVectactiveMask) == kNmiIsrNum) { 150 PW_LOG_INFO("Encountered non-maskable interrupt (NMI)"); 151 } 152 #if PW_CPU_EXCEPTION_CORTEX_M_EXTENDED_CFSR_DUMP 153 LogCfsrAnalysis(cpu_state.extended.cfsr); 154 #endif // PW_CPU_EXCEPTION_CORTEX_M_EXTENDED_CFSR_DUMP 155 } 156 ActiveProcessorMode(const pw_cpu_exception_State & cpu_state)157ProcessorMode ActiveProcessorMode(const pw_cpu_exception_State& cpu_state) { 158 // See ARMv6-M and ARMv7-M Architecture Reference Manual Section B1.5.8 for 159 // the exception return values, in particular bits 0:3. 160 // Bits 0:3 of EXC_RETURN: 161 // 0b0001 - 0x1 Handler mode Main 162 // 0b1001 - 0x9 Thread mode Main 163 // 0b1101 - 0xD Thread mode Process 164 // ^ 165 if (cpu_state.extended.exc_return & kExcReturnModeMask) { 166 return ProcessorMode::kThreadMode; 167 } 168 return ProcessorMode::kHandlerMode; 169 } 170 MainStackActive(const pw_cpu_exception_State & cpu_state)171bool MainStackActive(const pw_cpu_exception_State& cpu_state) { 172 // See ARMv6-M and ARMv7-M Architecture Reference Manual Section B1.5.8 for 173 // the exception return values, in particular bits 0:3. 174 // Bits 0:3 of EXC_RETURN: 175 // 0b0001 - 0x1 Handler mode Main 176 // 0b1001 - 0x9 Thread mode Main 177 // 0b1101 - 0xD Thread mode Process 178 // ^ 179 return (cpu_state.extended.exc_return & kExcReturnStackMask) == 0; 180 } 181 182 } // namespace pw::cpu_exception::cortex_m 183