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