1.. _module-pw_cpu_exception_cortex_m: 2 3------------------------- 4pw_cpu_exception_cortex_m 5------------------------- 6This backend provides an ARMv7-M implementation for the CPU exception module 7frontend. See the CPU exception frontend module description for more 8information. 9 10Setup 11===== 12There are a few ways to set up the ARMv7-M exception handler so the 13application's exception handler is properly called during an exception. 14 15**1. Use existing CMSIS functions** 16 Inside of CMSIS fault handler functions, branch to ``pw_cpu_exception_Entry``. 17 18 .. code-block:: cpp 19 20 __attribute__((naked)) void HardFault_Handler(void) { 21 asm volatile( 22 " ldr r0, =pw_cpu_exception_Entry \n" 23 " bx r0 \n"); 24 } 25 26**2. Modify a startup file** 27 Assembly startup files for some microcontrollers initialize the interrupt 28 vector table. The functions to call for fault handlers can be changed here. 29 For ARMv7-M, the fault handlers are indexes 3 to 6 of the interrupt vector 30 table. It's also may be helpful to redirect the NMI handler to the entry 31 function (if it's otherwise unused in your project). 32 33 Default: 34 35 .. code-block:: cpp 36 37 __isr_vector_table: 38 .word __stack_start 39 .word Reset_Handler 40 .word NMI_Handler 41 .word HardFault_Handler 42 .word MemManage_Handler 43 .word BusFault_Handler 44 .word UsageFault_Handler 45 46 Using CPU exception module: 47 48 .. code-block:: cpp 49 50 __isr_vector_table: 51 .word __stack_start 52 .word Reset_Handler 53 .word pw_cpu_exception_Entry 54 .word pw_cpu_exception_Entry 55 .word pw_cpu_exception_Entry 56 .word pw_cpu_exception_Entry 57 .word pw_cpu_exception_Entry 58 59 Note: ``__isr_vector_table`` and ``__stack_start`` are example names, and may 60 vary by platform. See your platform's assembly startup script. 61 62**3. Modify interrupt vector table at runtime** 63 Some applications may choose to modify their interrupt vector tables at 64 runtime. The ARMv7-M exception handler works with this use case (see the 65 exception_entry_test integration test), but keep in mind that your 66 application's exception handler will not be entered if an exception occurs 67 before the vector table entries are updated to point to 68 ``pw_cpu_exception_Entry``. 69 70Module Usage 71============ 72For lightweight exception handlers that don't need to access 73architecture-specific registers, using the generic exception handler functions 74is preferred. 75 76However, some projects may need to explicitly access architecture-specific 77registers to attempt to recover from a CPU exception. ``pw_cpu_exception_State`` 78provides access to the captured CPU state at the time of the fault. When the 79application-provided ``pw_cpu_exception_DefaultHandler()`` function returns, the 80CPU state is restored. This allows the exception handler to modify the captured 81state so that execution can safely continue. 82 83Expected Behavior 84----------------- 85In most cases, the CPU state captured by the exception handler will contain the 86ARMv7-M basic register frame in addition to an extended set of registers (see 87``cpu_state.h``). The exception to this is when the program stack pointer is in 88an MPU-protected or otherwise invalid memory region when the CPU attempts to 89push the exception register frame to it. In this situation, the PC, LR, and PSR 90registers will NOT be captured and will be marked with 0xFFFFFFFF to indicate 91they are invalid. This backend will still be able to capture all the other 92registers though. 93 94In the situation where the main stack pointer is in a memory protected or 95otherwise invalid region and fails to push CPU context, behavior is undefined. 96 97Nested Exceptions 98----------------- 99To enable nested fault handling: 100 1. Enable separate detection of usage/bus/memory faults via the SHCSR. 101 2. Decrease the priority of the memory, bus, and usage fault handlers. This 102 gives headroom for escalation. 103 104While this allows some faults to nest, it doesn't guarantee all will properly 105nest. 106 107Configuration Options 108===================== 109 110 - ``PW_CPU_EXCEPTION_EXTENDED_CFSR_DUMP``: Enable extended logging in 111 ``pw::cpu_exception::LogCpuState()`` that dumps the active CFSR fields with 112 help strings. This is disabled by default since it increases the binary size 113 by >1.5KB when using plain-text logs, or ~460 Bytes when using tokenized 114 logging. It's useful to enable this for device bringup until your application 115 has an end-to-end crash reporting solution. 116 117Exception Analysis 118================== 119This module provides Python tooling to analyze CPU state captured by a Cortex-M 120core during an exception. This can be useful as part of a crash report analyzer. 121 122CFSR decoder 123------------ 124The ARMv7-M and ARMv8-M architectures have a Configurable Fault Status Register 125(CFSR) that explains what illegal behavior caused a fault. This module provides 126a simple command-line tool to decode CFSR contents (e.g. 0x00010000) as 127human-readable information (e.g. "Encountered invalid instruction"). 128 129For example: 130 131 .. code-block:: 132 133 $ python -m pw_cpu_exception_cortex_m.cfsr_decoder 0x00010100 134 20210412 15:11:14 INF Exception caused by a usage fault, bus fault. 135 136 Active Crash Fault Status Register (CFSR) fields: 137 IBUSERR Bus fault on instruction fetch. 138 UNDEFINSTR Encountered invalid instruction. 139 140 All registers: 141 cfsr 0x00010100 142 143.. note:: 144 The CFSR is not supported on ARMv6-M CPUs (Cortex M0, M0+, M1). 145