1/*
2 * Copyright (c) 2013-2014 Wind River Systems, Inc.
3 * Copyright (c) 2017-2019 Nordic Semiconductor ASA.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8/**
9 * @file
10 * @brief Fault handlers for ARM Cortex-M
11 *
12 * Fault handlers for ARM Cortex-M processors.
13 */
14
15#include <zephyr/toolchain.h>
16#include <zephyr/linker/sections.h>
17
18_ASM_FILE_PROLOGUE
19
20GTEXT(z_arm_fault)
21
22GTEXT(z_arm_hard_fault)
23#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE)
24/* HardFault is used for all fault conditions on ARMv6-M. */
25#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE)
26GTEXT(z_arm_mpu_fault)
27GTEXT(z_arm_bus_fault)
28GTEXT(z_arm_usage_fault)
29#if defined(CONFIG_ARM_SECURE_FIRMWARE)
30GTEXT(z_arm_secure_fault)
31#endif /* CONFIG_ARM_SECURE_FIRMWARE*/
32WTEXT(z_arm_debug_monitor)
33#else
34#error Unknown ARM architecture
35#endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */
36GTEXT(z_arm_exc_spurious)
37
38/**
39 *
40 * @brief Fault handler installed in the fault vectors
41 *
42 * Entry point for the HardFault, MemManageFault, BusFault, UsageFault,
43 * SecureFault and Debug Monitor exceptions.
44 *
45 * The function supplies the values of
46 * - the MSP
47 * - the PSP
48 * - the EXC_RETURN value
49 * - callee saved register state (r4-r11, psp)
50 * as parameters to the z_arm_fault() C function that will perform the
51 * rest of the fault handling:
52 *    (i.e. z_arm_fault(MSP, PSP, EXC_RETURN, CALLEE_REGS)).
53 * Provides these symbols:
54 *
55 *   z_arm_hard_fault
56 *   z_arm_mpu_fault
57 *   z_arm_bus_fault
58 *   z_arm_usage_fault
59 *   z_arm_secure_fault
60 *   z_arm_debug_monitor
61 *   z_arm_exc_spurious
62 */
63
64SECTION_SUBSEC_FUNC(TEXT,__fault,z_arm_hard_fault)
65#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE)
66/* HardFault is used for all fault conditions on ARMv6-M. */
67#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE)
68SECTION_SUBSEC_FUNC(TEXT,__fault,z_arm_mpu_fault)
69SECTION_SUBSEC_FUNC(TEXT,__fault,z_arm_bus_fault)
70SECTION_SUBSEC_FUNC(TEXT,__fault,z_arm_usage_fault)
71#if defined(CONFIG_ARM_SECURE_FIRMWARE)
72SECTION_SUBSEC_FUNC(TEXT,__fault,z_arm_secure_fault)
73#endif /* CONFIG_ARM_SECURE_FIRMWARE */
74SECTION_SUBSEC_FUNC(TEXT,__fault,z_arm_debug_monitor)
75#else
76#error Unknown ARM architecture
77#endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */
78SECTION_SUBSEC_FUNC(TEXT,__fault,z_arm_exc_spurious)
79
80	mrs r0, MSP
81	mrs r1, PSP
82	push {r0, lr}
83#if defined(CONFIG_EXTRA_EXCEPTION_INFO)
84	/* Build _callee_saved_t. To match the struct
85	 * definition we push the psp & then r11-r4
86	 */
87	push { r1, r2 }
88#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE)
89	mov  r3, r11
90	mov  r2, r10
91	push {r2, r3}
92	mov  r3, r9
93	mov  r2, r8
94	push {r2, r3}
95	push {r4-r7}
96#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE)
97	push {r4-r11}
98#endif
99	mov  r3, sp /* pointer to _callee_saved_t */
100#endif /* CONFIG_EXTRA_EXCEPTION_INFO */
101	mov r2, lr /* EXC_RETURN */
102	bl z_arm_fault
103#if defined(CONFIG_EXTRA_EXCEPTION_INFO)
104	/* We do not need to restore any register state here
105	 * because we did not use any callee-saved registers
106	 * in this routine. Therefore, we can just reset
107	 * the MSP to its value prior to entering the function
108	 */
109	add sp, #40
110#endif
111	pop {r0, pc}
112
113	.end
114