1 /*
2 * Copyright (c) 2013-2014 Wind River Systems, Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /**
8 * @file
9 * @brief Exception/interrupt context helpers for Cortex-M CPUs
10 *
11 * Exception/interrupt context helpers.
12 */
13
14 #ifndef ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_M_EXC_H_
15 #define ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_M_EXC_H_
16
17 #include <zephyr/arch/cpu.h>
18
19 #ifdef _ASMLANGUAGE
20
21 /* nothing */
22
23 #else
24
25 #include <zephyr/arch/arm/aarch32/cortex_m/cmsis.h>
26 #include <zephyr/arch/arm/aarch32/exc.h>
27 #include <zephyr/irq_offload.h>
28
29 #ifdef __cplusplus
30 extern "C" {
31 #endif
32
33 #ifdef CONFIG_IRQ_OFFLOAD
34 extern volatile irq_offload_routine_t offload_routine;
35 #endif
36
37 /* Writes to the AIRCR must be accompanied by a write of the value 0x05FA
38 * to the Vector Key field, otherwise the writes are ignored.
39 */
40 #define AIRCR_VECT_KEY_PERMIT_WRITE 0x05FAUL
41
42 /*
43 * The current executing vector is found in the IPSR register. All
44 * IRQs and system exceptions are considered as interrupt context.
45 */
arch_is_in_isr(void)46 static ALWAYS_INLINE bool arch_is_in_isr(void)
47 {
48 return (__get_IPSR()) ? (true) : (false);
49 }
50
51 /**
52 * @brief Find out if we were in ISR context
53 * before the current exception occurred.
54 *
55 * A function that determines, based on inspecting the current
56 * ESF, whether the processor was in handler mode before entering
57 * the current exception state (i.e. nested exception) or not.
58 *
59 * Notes:
60 * - The function shall only be called from ISR context.
61 * - We do not use ARM processor state flags to determine
62 * whether we are in a nested exception; we rely on the
63 * RETPSR value stacked on the ESF. Hence, the function
64 * assumes that the ESF stack frame has a valid RETPSR
65 * value.
66 *
67 * @param esf the exception stack frame (cannot be NULL)
68 * @return true if execution state was in handler mode, before
69 * the current exception occurred, otherwise false.
70 */
arch_is_in_nested_exception(const z_arch_esf_t * esf)71 static ALWAYS_INLINE bool arch_is_in_nested_exception(const z_arch_esf_t *esf)
72 {
73 return (esf->basic.xpsr & IPSR_ISR_Msk) ? (true) : (false);
74 }
75
76 #if defined(CONFIG_USERSPACE)
77 /**
78 * @brief Is the thread in unprivileged mode
79 *
80 * @param esf the exception stack frame (unused)
81 * @return true if the current thread was in unprivileged mode
82 */
z_arm_preempted_thread_in_user_mode(const z_arch_esf_t * esf)83 static ALWAYS_INLINE bool z_arm_preempted_thread_in_user_mode(const z_arch_esf_t *esf)
84 {
85 return z_arm_thread_is_in_user_mode();
86 }
87 #endif
88
89 /**
90 * @brief Setup system exceptions
91 *
92 * Set exception priorities to conform with the BASEPRI locking mechanism.
93 * Set PendSV priority to lowest possible.
94 *
95 * Enable fault exceptions.
96 */
z_arm_exc_setup(void)97 static ALWAYS_INLINE void z_arm_exc_setup(void)
98 {
99 /* PendSV is set to lowest priority, regardless of it being used.
100 * This is done as the IRQ is always enabled.
101 */
102 NVIC_SetPriority(PendSV_IRQn, _EXC_PENDSV_PRIO);
103
104 #ifdef CONFIG_CPU_CORTEX_M_HAS_BASEPRI
105 /* Note: SVCall IRQ priority level is left to default (0)
106 * for Cortex-M variants without BASEPRI (e.g. ARMv6-M).
107 */
108 NVIC_SetPriority(SVCall_IRQn, _EXC_SVC_PRIO);
109 #endif
110
111 #ifdef CONFIG_CPU_CORTEX_M_HAS_PROGRAMMABLE_FAULT_PRIOS
112 NVIC_SetPriority(MemoryManagement_IRQn, _EXC_FAULT_PRIO);
113 NVIC_SetPriority(BusFault_IRQn, _EXC_FAULT_PRIO);
114 NVIC_SetPriority(UsageFault_IRQn, _EXC_FAULT_PRIO);
115 #if defined(CONFIG_CORTEX_M_DEBUG_MONITOR_HOOK)
116 NVIC_SetPriority(DebugMonitor_IRQn, IRQ_PRIO_LOWEST);
117 #elif defined(CONFIG_CPU_CORTEX_M_HAS_DWT)
118 NVIC_SetPriority(DebugMonitor_IRQn, _EXC_FAULT_PRIO);
119 #endif
120 #if defined(CONFIG_ARM_SECURE_FIRMWARE)
121 NVIC_SetPriority(SecureFault_IRQn, _EXC_FAULT_PRIO);
122 #endif /* CONFIG_ARM_SECURE_FIRMWARE */
123
124 /* Enable Usage, Mem, & Bus Faults */
125 SCB->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk | SCB_SHCSR_MEMFAULTENA_Msk |
126 SCB_SHCSR_BUSFAULTENA_Msk;
127 #if defined(CONFIG_ARM_SECURE_FIRMWARE)
128 /* Enable Secure Fault */
129 SCB->SHCSR |= SCB_SHCSR_SECUREFAULTENA_Msk;
130 /* Clear BFAR before setting BusFaults to target Non-Secure state. */
131 SCB->BFAR = 0;
132 #endif /* CONFIG_ARM_SECURE_FIRMWARE */
133 #endif /* CONFIG_CPU_CORTEX_M_HAS_PROGRAMMABLE_FAULT_PRIOS */
134
135 #if defined(CONFIG_ARM_SECURE_FIRMWARE) && \
136 !defined(CONFIG_ARM_SECURE_BUSFAULT_HARDFAULT_NMI)
137 /* Set NMI, Hard, and Bus Faults as Non-Secure.
138 * NMI and Bus Faults targeting the Secure state will
139 * escalate to a SecureFault or SecureHardFault.
140 */
141 SCB->AIRCR =
142 (SCB->AIRCR & (~(SCB_AIRCR_VECTKEY_Msk)))
143 | SCB_AIRCR_BFHFNMINS_Msk
144 | ((AIRCR_VECT_KEY_PERMIT_WRITE << SCB_AIRCR_VECTKEY_Pos) &
145 SCB_AIRCR_VECTKEY_Msk);
146 /* Note: Fault conditions that would generate a SecureFault
147 * in a PE with the Main Extension instead generate a
148 * SecureHardFault in a PE without the Main Extension.
149 */
150 #endif /* ARM_SECURE_FIRMWARE && !ARM_SECURE_BUSFAULT_HARDFAULT_NMI */
151
152 #if defined(CONFIG_CPU_CORTEX_M_HAS_SYSTICK) && \
153 !defined(CONFIG_CORTEX_M_SYSTICK)
154 /* SoC implements SysTick, but the system does not use it
155 * as driver for system timing. However, the SysTick IRQ is
156 * always enabled, so we must ensure the interrupt priority
157 * is set to a level lower than the kernel interrupts (for
158 * the assert mechanism to work properly) in case the SysTick
159 * interrupt is accidentally raised.
160 */
161 NVIC_SetPriority(SysTick_IRQn, _EXC_IRQ_DEFAULT_PRIO);
162 #endif /* CPU_CORTEX_M_HAS_SYSTICK && ! CORTEX_M_SYSTICK */
163
164 }
165
166 /**
167 * @brief Clear Fault exceptions
168 *
169 * Clear out exceptions for Mem, Bus, Usage and Hard Faults
170 */
z_arm_clear_faults(void)171 static ALWAYS_INLINE void z_arm_clear_faults(void)
172 {
173 #if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE)
174 #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE)
175 /* Reset all faults */
176 SCB->CFSR = SCB_CFSR_USGFAULTSR_Msk |
177 SCB_CFSR_MEMFAULTSR_Msk |
178 SCB_CFSR_BUSFAULTSR_Msk;
179
180 /* Clear all Hard Faults - HFSR is write-one-to-clear */
181 SCB->HFSR = 0xffffffff;
182 #else
183 #error Unknown ARM architecture
184 #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */
185 }
186
187 /**
188 * @brief Assess whether a debug monitor event should be treated as an error
189 *
190 * This routine checks the status of a debug_monitor() exception, and
191 * evaluates whether this needs to be considered as a processor error.
192 *
193 * @return true if the DM exception is a processor error, otherwise false
194 */
195 bool z_arm_debug_monitor_event_error_check(void);
196
197 #ifdef __cplusplus
198 }
199 #endif
200
201 #endif /* _ASMLANGUAGE */
202
203 #endif /* ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_M_EXC_H_ */
204