Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / third_party / pigweed / repo / pw_cpu_exception_cortex_m / cpu_state.cc
1 // Copyright 2019 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/cpu_state.h"
16
17 #include <cinttypes>
18 #include <cstdint>
19 #include <span>
20
21 #include "pw_cpu_exception/support.h"
22 #include "pw_cpu_exception_cortex_m_private/cortex_m_constants.h"
23 #include "pw_log/log.h"
24 #include "pw_string/string_builder.h"
25
26 // TODO(amontanez): Set up config when this module is moved to *_cortex_m.
27 #ifndef PW_CPU_EXCEPTION_EXTENDED_CFSR_DUMP
28 #define PW_CPU_EXCEPTION_EXTENDED_CFSR_DUMP 0
29 #endif  // PW_CPU_EXCEPTION_EXTENDED_CFSR_DUMP
30
31 namespace pw::cpu_exception {
32 namespace {
33
34 [[maybe_unused]] void AnalyzeCfsr(const uint32_t cfsr) {
35   if (cfsr == 0) {
36     return;
37   }
38
39   PW_LOG_INFO("Active CFSR fields:");
40
41   // Memory managment fault fields.
42   if (cfsr & kCfsrIaccviolMask) {
43     PW_LOG_ERROR("  IACCVIOL: MPU violation on instruction fetch");
44   }
45   if (cfsr & kCfsrDaccviolMask) {
46     PW_LOG_ERROR("  DACCVIOL: MPU violation on memory read/write");
47   }
48   if (cfsr & kCfsrMunstkerrMask) {
49     PW_LOG_ERROR("  MUNSTKERR: 'MPU violation on exception return");
50   }
51   if (cfsr & kCfsrMstkerrMask) {
52     PW_LOG_ERROR("  MSTKERR: MPU violation on exception entry");
53   }
54   if (cfsr & kCfsrMlsperrMask) {
55     PW_LOG_ERROR("  MLSPERR: MPU violation on lazy FPU state preservation");
56   }
57   if (cfsr & kCfsrMmarvalidMask) {
58     PW_LOG_ERROR("  MMARVALID: MMFAR register is valid");
59   }
60
61   // Bus fault fields.
62   if (cfsr & kCfsrIbuserrMask) {
63     PW_LOG_ERROR("  IBUSERR: Bus fault on instruction fetch");
64   }
65   if (cfsr & kCfsrPreciserrMask) {
66     PW_LOG_ERROR("  PRECISERR: Precise bus fault");
67   }
68   if (cfsr & kCfsrImpreciserrMask) {
69     PW_LOG_ERROR("  IMPRECISERR: Imprecise bus fault");
70   }
71   if (cfsr & kCfsrUnstkerrMask) {
72     PW_LOG_ERROR("  UNSTKERR: Derived bus fault on exception context save");
73   }
74   if (cfsr & kCfsrStkerrMask) {
75     PW_LOG_ERROR("  STKERR: Derived bus fault on exception context restore");
76   }
77   if (cfsr & kCfsrLsperrMask) {
78     PW_LOG_ERROR("  LSPERR: Derived bus fault on lazy FPU state preservation");
79   }
80   if (cfsr & kCfsrBfarvalidMask) {
81     PW_LOG_ERROR("  BFARVALID: BFAR register is valid");
82   }
83
84   // Usage fault fields.
85   if (cfsr & kCfsrUndefinstrMask) {
86     PW_LOG_ERROR("  UNDEFINSTR: Encountered invalid instruction");
87   }
88   if (cfsr & kCfsrInvstateMask) {
89     PW_LOG_ERROR(
90         "  INVSTATE: Attempted to execute an instruction with an invalid "
91         "Execution Program Status Register (EPSR) value");
92   }
93   if (cfsr & kCfsrInvpcMask) {
94     PW_LOG_ERROR("  INVPC: Program Counter (PC) is not legal");
95   }
96   if (cfsr & kCfsrNocpMask) {
97     PW_LOG_ERROR("  NOCP: Coprocessor disabled or not present");
98   }
99   if (cfsr & kCfsrUnalignedMask) {
100     PW_LOG_ERROR("  UNALIGNED: Unaligned memory access");
101   }
102   if (cfsr & kCfsrDivbyzeroMask) {
103     PW_LOG_ERROR("  DIVBYZERO: Division by zero");
104   }
105   // This flag is only present on ARMv8-M cores.
106   if (cfsr & kCfsrStkofMask) {
107     PW_LOG_ERROR("  STKOF: Stack overflowed");
108   }
109 }
110
111 void AnalyzeException(const pw_cpu_exception_State& cpu_state) {
112   // This provides a high-level assessment of the cause of the exception.
113   // These conditionals are ordered by priority to ensure the most critical
114   // issues are highlighted first. These are not mutually exclusive; a bus fault
115   // could occur during the handling of a MPU violation, causing a nested fault.
116   if (cpu_state.extended.hfsr & kHfsrForcedMask) {
117     PW_LOG_CRITICAL("Encountered a nested CPU fault (See active CFSR fields)");
118   }
119   // TODO(pwbug/296): #if this out on non-ARMv7-M builds.
120   if (cpu_state.extended.cfsr & kCfsrStkofMask) {
121     if (cpu_state.extended.exc_return & kExcReturnStackMask) {
122       PW_LOG_CRITICAL("Encountered stack overflow in thread mode");
123     } else {
124       PW_LOG_CRITICAL("Encountered main (interrupt handler) stack overflow");
125     }
126   }
127   if (cpu_state.extended.cfsr & kCfsrMemFaultMask) {
128     if (cpu_state.extended.cfsr & kCfsrMmarvalidMask) {
129       PW_LOG_CRITICAL(
130           "Encountered Memory Protection Unit (MPU) violation at 0x%08" PRIx32,
131           cpu_state.extended.mmfar);
132     } else {
133       PW_LOG_CRITICAL("Encountered Memory Protection Unit (MPU) violation");
134     }
135   }
136   if (cpu_state.extended.cfsr & kCfsrBusFaultMask) {
137     if (cpu_state.extended.cfsr & kCfsrBfarvalidMask) {
138       PW_LOG_CRITICAL("Encountered bus fault at 0x%08" PRIx32,
139                       cpu_state.extended.bfar);
140     } else {
141       PW_LOG_CRITICAL("Encountered bus fault");
142     }
143   }
144   if (cpu_state.extended.cfsr & kCfsrUsageFaultMask) {
145     PW_LOG_CRITICAL("Encountered usage fault (See active CFSR fields)");
146   }
147   if ((cpu_state.extended.icsr & kIcsrVectactiveMask) == kNmiIsrNum) {
148     PW_LOG_INFO("Encountered non-maskable interrupt (NMI)");
149   }
150 #if PW_CPU_EXCEPTION_EXTENDED_CFSR_DUMP
151   AnalyzeCfsr(cpu_state.extended.cfsr);
152 #endif  // PW_CPU_EXCEPTION_EXTENDED_CFSR_DUMP
153 }
154 }  // namespace
155
156 std::span<const uint8_t> RawFaultingCpuState(
157     const pw_cpu_exception_State& cpu_state) {
158   return std::span(reinterpret_cast<const uint8_t*>(&cpu_state),
159                    sizeof(cpu_state));
160 }
161
162 // Using this function adds approximately 100 bytes to binary size.
163 void ToString(const pw_cpu_exception_State& cpu_state,
164               const std::span<char>& dest) {
165   StringBuilder builder(dest);
166   const CortexMExceptionRegisters& base = cpu_state.base;
167   const CortexMExtraRegisters& extended = cpu_state.extended;
168
169 #define _PW_FORMAT_REGISTER(state_section, name) \
170   builder.Format("%s=0x%08" PRIx32 "\n", #name, state_section.name)
171
172   // Other registers.
173   _PW_FORMAT_REGISTER(base, pc);
174   _PW_FORMAT_REGISTER(base, lr);
175   _PW_FORMAT_REGISTER(base, psr);
176   _PW_FORMAT_REGISTER(extended, msp);
177   _PW_FORMAT_REGISTER(extended, psp);
178   _PW_FORMAT_REGISTER(extended, exc_return);
179   _PW_FORMAT_REGISTER(extended, cfsr);
180   _PW_FORMAT_REGISTER(extended, mmfar);
181   _PW_FORMAT_REGISTER(extended, bfar);
182   _PW_FORMAT_REGISTER(extended, icsr);
183   _PW_FORMAT_REGISTER(extended, hfsr);
184   _PW_FORMAT_REGISTER(extended, shcsr);
185   _PW_FORMAT_REGISTER(extended, control);
186
187   // General purpose registers.
188   _PW_FORMAT_REGISTER(base, r0);
189   _PW_FORMAT_REGISTER(base, r1);
190   _PW_FORMAT_REGISTER(base, r2);
191   _PW_FORMAT_REGISTER(base, r3);
192   _PW_FORMAT_REGISTER(extended, r4);
193   _PW_FORMAT_REGISTER(extended, r5);
194   _PW_FORMAT_REGISTER(extended, r6);
195   _PW_FORMAT_REGISTER(extended, r7);
196   _PW_FORMAT_REGISTER(extended, r8);
197   _PW_FORMAT_REGISTER(extended, r9);
198   _PW_FORMAT_REGISTER(extended, r10);
199   _PW_FORMAT_REGISTER(extended, r11);
200   _PW_FORMAT_REGISTER(base, r12);
201
202 #undef _PW_FORMAT_REGISTER
203 }
204
205 // Using this function adds approximately 100 bytes to binary size.
206 void LogCpuState(const pw_cpu_exception_State& cpu_state) {
207   const CortexMExceptionRegisters& base = cpu_state.base;
208   const CortexMExtraRegisters& extended = cpu_state.extended;
209
210   AnalyzeException(cpu_state);
211
212   PW_LOG_INFO("All captured CPU registers:");
213
214 #define _PW_LOG_REGISTER(state_section, name) \
215   PW_LOG_INFO("  %-10s 0x%08" PRIx32, #name, state_section.name)
216
217   // Other registers.
218   _PW_LOG_REGISTER(base, pc);
219   _PW_LOG_REGISTER(base, lr);
220   _PW_LOG_REGISTER(base, psr);
221   _PW_LOG_REGISTER(extended, msp);
222   _PW_LOG_REGISTER(extended, psp);
223   _PW_LOG_REGISTER(extended, exc_return);
224   _PW_LOG_REGISTER(extended, cfsr);
225   _PW_LOG_REGISTER(extended, mmfar);
226   _PW_LOG_REGISTER(extended, bfar);
227   _PW_LOG_REGISTER(extended, icsr);
228   _PW_LOG_REGISTER(extended, hfsr);
229   _PW_LOG_REGISTER(extended, shcsr);
230   _PW_LOG_REGISTER(extended, control);
231
232   // General purpose registers.
233   _PW_LOG_REGISTER(base, r0);
234   _PW_LOG_REGISTER(base, r1);
235   _PW_LOG_REGISTER(base, r2);
236   _PW_LOG_REGISTER(base, r3);
237   _PW_LOG_REGISTER(extended, r4);
238   _PW_LOG_REGISTER(extended, r5);
239   _PW_LOG_REGISTER(extended, r6);
240   _PW_LOG_REGISTER(extended, r7);
241   _PW_LOG_REGISTER(extended, r8);
242   _PW_LOG_REGISTER(extended, r9);
243   _PW_LOG_REGISTER(extended, r10);
244   _PW_LOG_REGISTER(extended, r11);
245   _PW_LOG_REGISTER(base, r12);
246
247 #undef _PW_LOG_REGISTER
248 }
249
250 }  // namespace pw::cpu_exception