xref: /aosp_15_r20/external/pigweed/pw_cpu_exception_cortex_m/docs.rst (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1.. _module-pw_cpu_exception_cortex_m:
2
3=========================
4pw_cpu_exception_cortex_m
5=========================
6This module provides backend implementations for the CPU exception module frontend
7for the following Cortex-M architectures:
8
9* ARMv6-M - Cortex M0, M0+
10* ARMv7-M - Cortex M3
11* ARMv7-EM - Cortex M4, M7
12* ARMv8-M Mainline - Cortex M33, M33P
13
14It also includes a crash facade for a more detailed analysis of the CPU state.
15
16Backend Setup
17=============
18There are a few ways to set up the Cortex M exception handler so the
19application's exception handler is properly called during an exception.
20
211. Use existing CMSIS functions
22-------------------------------
23Inside of CMSIS fault handler functions, branch to ``pw_cpu_exception_Entry``.
24
25.. code-block:: cpp
26
27   __attribute__((naked)) void HardFault_Handler(void) {
28   asm volatile(
29       " ldr r0, =pw_cpu_exception_Entry  \n"
30       " bx r0                            \n");
31   }
32
332. Modify a startup file
34------------------------
35Assembly startup files for some microcontrollers initialize the interrupt
36vector table. The functions to call for fault handlers can be changed here.
37For ARMv7-M and ARMv8-M, the fault handlers are indexes 3 to 6 of the
38interrupt vector table. It's also may be helpful to redirect the NMI handler
39to the entry function (if it's otherwise unused in your project).
40
41Default:
42
43.. code-block:: cpp
44
45   __isr_vector_table:
46     .word  __stack_start
47     .word  Reset_Handler
48     .word  NMI_Handler
49     .word  HardFault_Handler
50     .word  MemManage_Handler
51     .word  BusFault_Handler
52     .word  UsageFault_Handler
53
54Using CPU exception module:
55
56.. code-block:: cpp
57
58   __isr_vector_table:
59     .word  __stack_start
60     .word  Reset_Handler
61     .word  pw_cpu_exception_Entry
62     .word  pw_cpu_exception_Entry
63     .word  pw_cpu_exception_Entry
64     .word  pw_cpu_exception_Entry
65     .word  pw_cpu_exception_Entry
66
67Note: ``__isr_vector_table`` and ``__stack_start`` are example names, and may
68vary by platform. See your platform's assembly startup script.
69
703. Modify interrupt vector table at runtime
71-------------------------------------------
72Some applications may choose to modify their interrupt vector tables at
73runtime. The exception handler works with this use case (see the
74exception_entry_test integration test), but keep in mind that your
75application's exception handler will not be entered if an exception occurs
76before the vector table entries are updated to point to
77``pw_cpu_exception_Entry``.
78
79.. _module-pw_cpu_exception_cortex_m-crash-facade-setup:
80
81Crash Facade Setup
82==================
83The function ``AnalyzeCpuStateAndCrash()`` creates a condensed analysis of the
84CPU state at crash time. It passes the given state along with a format string
85and its arguments to ``PW_CPU_EXCEPTION_CORTEX_M_CRASH()``. The user must
86implement the ``PW_CPU_EXCEPTION_CORTEX_M_HANDLE_CRASH()`` macro and the
87``GetCrashThreadName()`` function, which must returna a null-terminated string
88with the thread name at the time of the crash. The user can choose what to do
89with the format string and arguments in their implementation of
90``PW_CPU_EXCEPTION_CORTEX_M_HANDLE_CRASH()``. For example, the format string and
91arguments can be tokenized to reduce the size of data collected at crash time or
92a string can be composed and reported instead.
93
94The function ``AnalyzeCpuStateAndCrash()`` can be called in the
95``pw_cpu_exception_DefaultHandler()`` directly to delegate the crash handling
96to the user-provided ``PW_CPU_EXCEPTION_CORTEX_M_HANDLE_CRASH()``
97implementation.
98
99Configuration Options
100---------------------
101- ``PW_CPU_EXCEPTION_CORTEX_M_CRASH_EXTENDED_CPU_ANALYSIS``: Enable extended
102  analysis in ``AnalyzeCpuStateAndCrash()`` that collects important register
103  values depending on the fault type.
104
105- ``PW_CPU_EXCEPTION_CORTEX_M_CRASH_ANALYSIS_INCLUDE_PC_LR``: Enable including
106  the PC and LR register values in the ``AnalyzeCpuStateAndCrash()`` analysis.
107
108Module Usage
109============
110For lightweight exception handlers that don't need to access
111architecture-specific registers, using the generic exception handler functions
112is preferred.
113
114However, some projects may need to explicitly access architecture-specific
115registers to attempt to recover from a CPU exception. ``pw_cpu_exception_State``
116provides access to the captured CPU state at the time of the fault. When the
117application-provided ``pw_cpu_exception_DefaultHandler()`` function returns, the
118CPU state is restored. This allows the exception handler to modify the captured
119state so that execution can safely continue.
120
121Expected Behavior
122-----------------
123In most cases, the CPU state captured by the exception handler will contain the
124basic register frame in addition to an extended set of registers
125(see ``cpu_state.h``).
126
127The exception to this is when the program stack pointer is in an MPU-protected
128or otherwise invalid memory region when the CPU attempts to push the exception
129register frame to it. In this situation, the PC, LR, and PSR registers will NOT
130be captured and will be marked with ``0xFFFFFFFF`` to indicate they are invalid.
131This backend will still be able to capture all the other registers though.
132
133``0xFFFFFFFF`` is an illegal LR value, which is why it was selected for this
134purpose. PC and PSR values of 0xFFFFFFFF are dubious too, so this constant is
135clear enough at suggesting that the registers weren't properly captured.
136
137In the situation where the main stack pointer is in a memory protected or
138otherwise invalid region and fails to push CPU context, behavior is undefined.
139
140Nested Exceptions
141-----------------
142To enable nested fault handling:
143
1441. Enable separate detection of usage/bus/memory faults via the SHCSR.
1452. Decrease the priority of the memory, bus, and usage fault handlers. This
146   gives headroom for escalation.
147
148While this allows some faults to nest, it doesn't guarantee all will properly
149nest.
150
151Configuration Options
152=====================
153- ``PW_CPU_EXCEPTION_CORTEX_M_EXTENDED_CFSR_DUMP``: Enable extended logging in
154  ``pw::cpu_exception::LogCpuState()`` that dumps the active CFSR fields with
155  help strings. This is disabled by default since it increases the binary size
156  by >1.5KB when using plain-text logs, or ~460 Bytes when using tokenized
157  logging. It's useful to enable this for device bringup until your application
158  has an end-to-end crash reporting solution.
159- ``PW_CPU_EXCEPTION_CORTEX_M_LOG_LEVEL``: The log level to use for this module.
160  Logs below this level are omitted.
161
162Exception Analysis
163==================
164This module provides Python tooling to analyze CPU state captured by a Cortex-M
165core during an exception. This can be useful as part of a crash report analyzer.
166
167CFSR decoder
168------------
169The ARMv7-M and ARMv8-M architectures have a Configurable Fault Status Register
170(CFSR) that explains what illegal behavior caused a fault. This module provides
171a simple command-line tool to decode CFSR contents (e.g. 0x00010000) as
172human-readable information (e.g. "Encountered invalid instruction").
173
174For example:
175
176.. code-block::
177
178   $ python -m pw_cpu_exception_cortex_m.cfsr_decoder 0x00010100
179   20210412 15:11:14 INF Exception caused by a usage fault, bus fault.
180
181   Active Crash Fault Status Register (CFSR) fields:
182   IBUSERR     Instruction bus error.
183       The processor attempted to issue an invalid instruction. It
184       detects the instruction bus error on prefecting, but this
185       flag is only set to 1 if it attempts to issue the faulting
186       instruction. When this bit is set, the processor has not
187       written a fault address to the BFAR.
188   UNDEFINSTR  Encountered invalid instruction.
189       The processor has attempted to execute an undefined
190       instruction. When this bit is set to 1, the PC value stacked
191       for the exception return points to the undefined instruction.
192       An undefined instruction is an instruction that the processor
193       cannot decode.
194
195   All registers:
196   cfsr       0x00010100
197
198.. note::
199   The CFSR is not supported on ARMv6-M CPUs (Cortex M0, M0+, M1).
200
201--------------------
202Snapshot integration
203--------------------
204This ``pw_cpu_exception`` backend provides helper functions that capture CPU
205exception state to snapshot protos.
206
207SnapshotCpuState()
208==================
209``SnapshotCpuState()`` captures the ``pw_cpu_exception_State`` to a
210``pw.cpu_exception.cortex_m.ArmV7mCpuState`` protobuf encoder.
211
212
213SnapshotMainStackThread()
214=========================
215``SnapshotMainStackThread()`` captures the main stack's execution thread state
216if active either from a given ``pw_cpu_exception_State`` or from the current
217running context. It captures the thread name depending on the processor mode,
218either ``Main Stack (Handler Mode)`` or ``Main Stack (Thread Mode)``. The stack
219limits must be provided along with a stack processing callback. All of this
220information is captured by a ``pw::Thread`` protobuf encoder.
221
222.. note::
223   To minimize how much of the snapshot handling callstack is captured in the
224   stack trace, provide the ``pw_cpu_exception_State`` collected by the
225   exception entry (For example, as provided by
226   ``pw_cpu_exception_DefaultHandler()``)
227   instead of capturing the stack pointer just before calling into this
228   function.
229
230Python processor
231================
232This module's included Python exception analyzer tooling provides snapshot
233integration via a ``process_snapshot()`` function that produces a multi-line
234dump from a serialized snapshot proto, for example:
235
236.. code-block::
237
238   Exception caused by a usage fault.
239
240   Active Crash Fault Status Register (CFSR) fields:
241   UNDEFINSTR  Undefined Instruction UsageFault.
242       The processor has attempted to execute an undefined
243       instruction. When this bit is set to 1, the PC value stacked
244       for the exception return points to the undefined instruction.
245       An undefined instruction is an instruction that the processor
246       cannot decode.
247
248   All registers:
249   pc         0x0800e1c4 example::Service::Crash(_example_service_CrashRequest const&, _pw_protobuf_Empty&) (src/example_service/service.cc:131)
250   lr         0x0800e141 example::Service::Crash(_example_service_CrashRequest const&, _pw_protobuf_Empty&) (src/example_service/service.cc:128)
251   psr        0x81000000
252   msp        0x20040fd8
253   psp        0x20001488
254   exc_return 0xffffffed
255   cfsr       0x00010000
256   mmfar      0xe000ed34
257   bfar       0xe000ed38
258   icsr       0x00000803
259   hfsr       0x40000000
260   shcsr      0x00000000
261   control    0x00000000
262   r0         0xe03f7847
263   r1         0x714083dc
264   r2         0x0b36dc49
265   r3         0x7fbfbe1a
266   r4         0xc36e8efb
267   r5         0x69a14b13
268   r6         0x0ec35eaa
269   r7         0xa5df5543
270   r8         0xc892b931
271   r9         0xa2372c94
272   r10        0xbd15c968
273   r11        0x759b95ab
274   r12        0x00000000
275
276Module Configuration Options
277============================
278The following configurations can be adjusted via compile-time configuration of
279this module, see the
280:ref:`module documentation <module-structure-compile-time-configuration>` for
281more details.
282
283.. c:macro:: PW_CPU_EXCEPTION_CORTEX_M_LOG_LEVEL
284
285   The log level to use for this module. Logs below this level are omitted.
286
287   This defaults to ``PW_LOG_LEVEL_DEBUG``.
288
289.. c:macro:: PW_CPU_EXCEPTION_CORTEX_M_EXTENDED_CFSR_DUMP
290
291   Enables extended logging in pw::cpu_exception::LogCpuState() and
292   pw::cpu_exception::cortex_m::LogExceptionAnalysis() that dumps the active
293   CFSR fields with help strings. This is disabled by default since it
294   increases the binary size by >1.5KB when using plain-text logs, or ~460
295   Bytes when using tokenized logging. It's useful to enable this for device
296   bringup until your application has an end-to-end crash reporting solution.
297
298   This is disabled by default.
299