Branch data Line data Source code
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 <arch/cpu.h> 18 : : 19 : : #ifdef _ASMLANGUAGE 20 : : 21 : : /* nothing */ 22 : : 23 : : #else 24 : : 25 : : #include <arch/arm/aarch32/cortex_m/cmsis.h> 26 : : #include <arch/arm/aarch32/exc.h> 27 : : #include <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 : : */ 46 : 44336 : static ALWAYS_INLINE bool arch_is_in_isr(void) 47 : : { 48 : 44336 : 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 : : */ 71 : 0 : static ALWAYS_INLINE bool arch_is_in_nested_exception(const z_arch_esf_t *esf) 72 : : { 73 : 0 : 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 : : */ 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 : : */ 97 : 1 : 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 : 1 : 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 : 1 : NVIC_SetPriority(SVCall_IRQn, _EXC_SVC_PRIO); 109 : : #endif 110 : : 111 : : #ifdef CONFIG_CPU_CORTEX_M_HAS_PROGRAMMABLE_FAULT_PRIOS 112 : 1 : NVIC_SetPriority(MemoryManagement_IRQn, _EXC_FAULT_PRIO); 113 : 1 : NVIC_SetPriority(BusFault_IRQn, _EXC_FAULT_PRIO); 114 : 1 : NVIC_SetPriority(UsageFault_IRQn, _EXC_FAULT_PRIO); 115 : : #if defined(CONFIG_CPU_CORTEX_M_HAS_DWT) 116 : 1 : NVIC_SetPriority(DebugMonitor_IRQn, _EXC_FAULT_PRIO); 117 : : #endif 118 : : #if defined(CONFIG_ARM_SECURE_FIRMWARE) 119 : : NVIC_SetPriority(SecureFault_IRQn, _EXC_FAULT_PRIO); 120 : : #endif /* CONFIG_ARM_SECURE_FIRMWARE */ 121 : : 122 : : /* Enable Usage, Mem, & Bus Faults */ 123 : 1 : SCB->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk | SCB_SHCSR_MEMFAULTENA_Msk | 124 : : SCB_SHCSR_BUSFAULTENA_Msk; 125 : : #if defined(CONFIG_ARM_SECURE_FIRMWARE) 126 : : /* Enable Secure Fault */ 127 : : SCB->SHCSR |= SCB_SHCSR_SECUREFAULTENA_Msk; 128 : : /* Clear BFAR before setting BusFaults to target Non-Secure state. */ 129 : : SCB->BFAR = 0; 130 : : #endif /* CONFIG_ARM_SECURE_FIRMWARE */ 131 : : #endif /* CONFIG_CPU_CORTEX_M_HAS_PROGRAMMABLE_FAULT_PRIOS */ 132 : : 133 : : #if defined(CONFIG_ARM_SECURE_FIRMWARE) && \ 134 : : !defined(CONFIG_ARM_SECURE_BUSFAULT_HARDFAULT_NMI) 135 : : /* Set NMI, Hard, and Bus Faults as Non-Secure. 136 : : * NMI and Bus Faults targeting the Secure state will 137 : : * escalate to a SecureFault or SecureHardFault. 138 : : */ 139 : : SCB->AIRCR = 140 : : (SCB->AIRCR & (~(SCB_AIRCR_VECTKEY_Msk))) 141 : : | SCB_AIRCR_BFHFNMINS_Msk 142 : : | ((AIRCR_VECT_KEY_PERMIT_WRITE << SCB_AIRCR_VECTKEY_Pos) & 143 : : SCB_AIRCR_VECTKEY_Msk); 144 : : /* Note: Fault conditions that would generate a SecureFault 145 : : * in a PE with the Main Extension instead generate a 146 : : * SecureHardFault in a PE without the Main Extension. 147 : : */ 148 : : #endif /* ARM_SECURE_FIRMWARE && !ARM_SECURE_BUSFAULT_HARDFAULT_NMI */ 149 : : 150 : : #if defined(CONFIG_CPU_CORTEX_M_HAS_SYSTICK) && \ 151 : : !defined(CONFIG_CORTEX_M_SYSTICK) 152 : : /* SoC implements SysTick, but the system does not use it 153 : : * as driver for system timing. However, the SysTick IRQ is 154 : : * always enabled, so we must ensure the interrupt priority 155 : : * is set to a level lower than the kernel interrupts (for 156 : : * the assert mechanism to work properly) in case the SysTick 157 : : * interrupt is accidentally raised. 158 : : */ 159 : 1 : NVIC_SetPriority(SysTick_IRQn, _EXC_IRQ_DEFAULT_PRIO); 160 : : #endif /* CPU_CORTEX_M_HAS_SYSTICK && ! CORTEX_M_SYSTICK */ 161 : : 162 : 1 : } 163 : : 164 : : /** 165 : : * @brief Clear Fault exceptions 166 : : * 167 : : * Clear out exceptions for Mem, Bus, Usage and Hard Faults 168 : : */ 169 : 1 : static ALWAYS_INLINE void z_arm_clear_faults(void) 170 : : { 171 : : #if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) 172 : : #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) 173 : : /* Reset all faults */ 174 : 1 : SCB->CFSR = SCB_CFSR_USGFAULTSR_Msk | 175 : : SCB_CFSR_MEMFAULTSR_Msk | 176 : : SCB_CFSR_BUSFAULTSR_Msk; 177 : : 178 : : /* Clear all Hard Faults - HFSR is write-one-to-clear */ 179 : 1 : SCB->HFSR = 0xffffffff; 180 : : #else 181 : : #error Unknown ARM architecture 182 : : #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ 183 : 1 : } 184 : : 185 : : /** 186 : : * @brief Assess whether a debug monitor event should be treated as an error 187 : : * 188 : : * This routine checks the status of a debug_monitor() exception, and 189 : : * evaluates whether this needs to be considered as a processor error. 190 : : * 191 : : * @return true if the DM exception is a processor error, otherwise false 192 : : */ 193 : : bool z_arm_debug_monitor_event_error_check(void); 194 : : 195 : : #ifdef __cplusplus 196 : : } 197 : : #endif 198 : : 199 : : #endif /* _ASMLANGUAGE */ 200 : : 201 : : #endif /* ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_M_EXC_H_ */