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 100 if (cfsr & kCfsrStkofMask) { 101 PW_LOG_ERROR(" STKOF: Stack overflowed"); 102 } 103 #endif // _PW_ARCH_ARM_V8M_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 (cpu_state.extended.hfsr & kHfsrForcedMask) { 114 PW_LOG_CRITICAL("Encountered a nested CPU fault (See active CFSR fields)"); 115 } 116 #if _PW_ARCH_ARM_V8M_MAINLINE 117 if (cpu_state.extended.cfsr & kCfsrStkofMask) { 118 if (ProcessStackActive(cpu_state)) { 119 PW_LOG_CRITICAL("Encountered process stack overflow (psp)"); 120 } else { 121 PW_LOG_CRITICAL("Encountered main stack overflow (msp)"); 122 } 123 } 124 #endif // _PW_ARCH_ARM_V8M_MAINLINE 125 if (cpu_state.extended.cfsr & kCfsrMemFaultMask) { 126 if (cpu_state.extended.cfsr & kCfsrMmarvalidMask) { 127 PW_LOG_CRITICAL( 128 "Encountered Memory Protection Unit (MPU) violation at 0x%08" PRIx32, 129 cpu_state.extended.mmfar); 130 } else { 131 PW_LOG_CRITICAL("Encountered Memory Protection Unit (MPU) violation"); 132 } 133 } 134 if (cpu_state.extended.cfsr & kCfsrBusFaultMask) { 135 if (cpu_state.extended.cfsr & kCfsrBfarvalidMask) { 136 PW_LOG_CRITICAL("Encountered bus fault at 0x%08" PRIx32, 137 cpu_state.extended.bfar); 138 } else { 139 PW_LOG_CRITICAL("Encountered bus fault"); 140 } 141 } 142 if (cpu_state.extended.cfsr & kCfsrUsageFaultMask) { 143 PW_LOG_CRITICAL("Encountered usage fault (See active CFSR fields)"); 144 } 145 if ((cpu_state.extended.icsr & kIcsrVectactiveMask) == kNmiIsrNum) { 146 PW_LOG_INFO("Encountered non-maskable interrupt (NMI)"); 147 } 148 #if PW_CPU_EXCEPTION_CORTEX_M_EXTENDED_CFSR_DUMP 149 LogCfsrAnalysis(cpu_state.extended.cfsr); 150 #endif // PW_CPU_EXCEPTION_CORTEX_M_EXTENDED_CFSR_DUMP 151 } 152 ActiveProcessorMode(const pw_cpu_exception_State & cpu_state)153ProcessorMode ActiveProcessorMode(const pw_cpu_exception_State& cpu_state) { 154 // See ARMv7-M Architecture Reference Manual Section B1.5.8 for the exception 155 // return values, in particular bits 0:3. 156 // Bits 0:3 of EXC_RETURN: 157 // 0b0001 - 0x1 Handler mode Main 158 // 0b1001 - 0x9 Thread mode Main 159 // 0b1101 - 0xD Thread mode Process 160 // ^ 161 if (cpu_state.extended.exc_return & kExcReturnModeMask) { 162 return ProcessorMode::kThreadMode; 163 } 164 return ProcessorMode::kHandlerMode; 165 } 166 MainStackActive(const pw_cpu_exception_State & cpu_state)167bool MainStackActive(const pw_cpu_exception_State& cpu_state) { 168 // See ARMv7-M Architecture Reference Manual Section B1.5.8 for the exception 169 // return values, in particular bits 0:3. 170 // Bits 0:3 of EXC_RETURN: 171 // 0b0001 - 0x1 Handler mode Main 172 // 0b1001 - 0x9 Thread mode Main 173 // 0b1101 - 0xD Thread mode Process 174 // ^ 175 return (cpu_state.extended.exc_return & kExcReturnStackMask) == 0; 176 } 177 178 } // namespace pw::cpu_exception::cortex_m 179