| .. _chapter-cpu-exception-armv7m: |
| |
| .. default-domain:: cpp |
| |
| .. highlight:: sh |
| |
| ----------------------- |
| pw_cpu_exception_armv7m |
| ----------------------- |
| This backend provides an ARMv7-M implementation for the CPU exception module |
| frontend. See the CPU exception frontend module description for more |
| information. |
| |
| Setup |
| ===== |
| There are a few ways to set up the ARMv7-M exception handler so the |
| application's exception handler is properly called during an exception. |
| |
| **1. Use existing CMSIS functions** |
| Inside of CMSIS fault handler functions, branch to ``pw_CpuExceptionEntry``. |
| |
| .. code-block:: cpp |
| |
| __attribute__((naked)) void HardFault_Handler(void) { |
| asm volatile( |
| " ldr r0, =pw_CpuExceptionEntry \n" |
| " bx r0 \n"); |
| } |
| |
| **2. Modify a startup file** |
| Assembly startup files for some microcontrollers initialize the interrupt |
| vector table. The functions to call for fault handlers can be changed here. |
| For ARMv7-M, the fault handlers are indexes 3 to 6 of the interrupt vector |
| table. It's also may be helpful to redirect the NMI handler to the entry |
| function (if it's otherwise unused in your project). |
| |
| Default: |
| |
| .. code-block:: cpp |
| |
| __isr_vector_table: |
| .word __stack_start |
| .word Reset_Handler |
| .word NMI_Handler |
| .word HardFault_Handler |
| .word MemManage_Handler |
| .word BusFault_Handler |
| .word UsageFault_Handler |
| |
| Using CPU exception module: |
| |
| .. code-block:: cpp |
| |
| __isr_vector_table: |
| .word __stack_start |
| .word Reset_Handler |
| .word pw_CpuExceptionEntry |
| .word pw_CpuExceptionEntry |
| .word pw_CpuExceptionEntry |
| .word pw_CpuExceptionEntry |
| .word pw_CpuExceptionEntry |
| |
| Note: ``__isr_vector_table`` and ``__stack_start`` are example names, and may |
| vary by platform. See your platform's assembly startup script. |
| |
| **3. Modify interrupt vector table at runtime** |
| Some applications may choose to modify their interrupt vector tables at |
| runtime. The ARMv7-M exception handler works with this use case (see the |
| exception_entry_test integration test), but keep in mind that your |
| application's exception handler will not be entered if an exception occurs |
| before the vector table entries are updated to point to |
| ``pw_CpuExceptionEntry``. |
| |
| Module Usage |
| ============ |
| For lightweight exception handlers that don't need to access |
| architecture-specific registers, using the generic exception handler functions |
| is preferred. |
| |
| However, some projects may need to explicitly access architecture-specific |
| registers to attempt to recover from a CPU exception. ``CpuState`` provides |
| access to the captured CPU state at the time of the fault. When the |
| application-provided ``HandleCpuException()`` function returns, the CPU state is |
| restored. This allows the exception handler to modify the captured state so that |
| execution can safely continue. |
| |
| Expected Behavior |
| ----------------- |
| In most cases, the CPU state captured by the exception handler will contain the |
| ARMv7-M basic register frame in addition to an extended set of registers (see |
| ``cpu_state.h``). The exception to this is when the program stack pointer is in |
| an MPU-protected or otherwise invalid memory region when the CPU attempts to |
| push the exception register frame to it. In this situation, the PC, LR, and PSR |
| registers will NOT be captured and will be marked with 0xFFFFFFFF to indicate |
| they are invalid. This backend will still be able to capture all the other |
| registers though. |
| |
| In the situation where the main stack pointer is in a memory protected or |
| otherwise invalid region and fails to push CPU context, behavior is undefined. |
| |
| Nested Exceptions |
| ----------------- |
| To enable nested fault handling: |
| 1. Enable separate detection of usage/bus/memory faults via the SHCSR. |
| 2. Decrease the priority of the memory, bus, and usage fault handlers. This |
| gives headroom for escalation. |
| |
| While this allows some faults to nest, it doesn't guarantee all will properly |
| nest. |