/* * Copyright (c) 2013-2014 Wind River Systems, Inc. * * SPDX-License-Identifier: Apache-2.0 */ /** * @file * @brief Exception/interrupt context helpers for Cortex-M CPUs * * Exception/interrupt context helpers. */ #ifndef ZEPHYR_ARCH_ARM_INCLUDE_CORTEX_M_EXC_H_ #define ZEPHYR_ARCH_ARM_INCLUDE_CORTEX_M_EXC_H_ #include #ifdef _ASMLANGUAGE /* nothing */ #else #include #include #include #ifdef __cplusplus extern "C" { #endif #ifdef CONFIG_IRQ_OFFLOAD extern volatile irq_offload_routine_t offload_routine; #endif /* Writes to the AIRCR must be accompanied by a write of the value 0x05FA * to the Vector Key field, otherwise the writes are ignored. */ #define AIRCR_VECT_KEY_PERMIT_WRITE 0x05FAUL /* * The current executing vector is found in the IPSR register. All * IRQs and system exceptions are considered as interrupt context. */ static ALWAYS_INLINE bool z_arch_is_in_isr(void) { return (__get_IPSR()) ? (true) : (false); } /** * @brief Find out if we were in ISR context * before the current exception occurred. * * A function that determines, based on inspecting the current * ESF, whether the processor was in handler mode before entering * the current exception state (i.e. nested exception) or not. * * Notes: * - The function shall only be called from ISR context. * - We do not use ARM processor state flags to determine * whether we are in a nested exception; we rely on the * RETPSR value stacked on the ESF. Hence, the function * assumes that the ESF stack frame has a valid RETPSR * value. * * @param esf the exception stack frame (cannot be NULL) * @return true if execution state was in handler mode, before * the current exception occurred, otherwise false. */ static ALWAYS_INLINE bool z_arch_is_in_nested_exception( const z_arch_esf_t *esf) { return (esf->basic.xpsr & IPSR_ISR_Msk) ? (true) : (false); } /** * @brief Setup system exceptions * * Set exception priorities to conform with the BASEPRI locking mechanism. * Set PendSV priority to lowest possible. * * Enable fault exceptions. * * @return N/A */ static ALWAYS_INLINE void z_arm_exc_setup(void) { NVIC_SetPriority(PendSV_IRQn, 0xff); #ifdef CONFIG_CPU_CORTEX_M_HAS_BASEPRI NVIC_SetPriority(SVCall_IRQn, _EXC_SVC_PRIO); #endif #ifdef CONFIG_CPU_CORTEX_M_HAS_PROGRAMMABLE_FAULT_PRIOS NVIC_SetPriority(MemoryManagement_IRQn, _EXC_FAULT_PRIO); NVIC_SetPriority(BusFault_IRQn, _EXC_FAULT_PRIO); NVIC_SetPriority(UsageFault_IRQn, _EXC_FAULT_PRIO); #if defined(CONFIG_ARM_SECURE_FIRMWARE) NVIC_SetPriority(SecureFault_IRQn, _EXC_FAULT_PRIO); #endif /* CONFIG_ARM_SECURE_FIRMWARE */ /* Enable Usage, Mem, & Bus Faults */ SCB->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk | SCB_SHCSR_MEMFAULTENA_Msk | SCB_SHCSR_BUSFAULTENA_Msk; #if defined(CONFIG_ARM_SECURE_FIRMWARE) /* Enable Secure Fault */ SCB->SHCSR |= SCB_SHCSR_SECUREFAULTENA_Msk; /* Clear BFAR before setting BusFaults to target Non-Secure state. */ SCB->BFAR = 0; #endif /* CONFIG_ARM_SECURE_FIRMWARE */ #endif /* CONFIG_CPU_CORTEX_M_HAS_PROGRAMMABLE_FAULT_PRIOS */ #if defined(CONFIG_ARM_SECURE_FIRMWARE) && \ !defined(CONFIG_ARM_SECURE_BUSFAULT_HARDFAULT_NMI) /* Set NMI, Hard, and Bus Faults as Non-Secure. * NMI and Bus Faults targeting the Secure state will * escalate to a SecureFault or SecureHardFault. */ SCB->AIRCR = (SCB->AIRCR & (~(SCB_AIRCR_VECTKEY_Msk))) | SCB_AIRCR_BFHFNMINS_Msk | ((AIRCR_VECT_KEY_PERMIT_WRITE << SCB_AIRCR_VECTKEY_Pos) & SCB_AIRCR_VECTKEY_Msk); /* Note: Fault conditions that would generate a SecureFault * in a PE with the Main Extension instead generate a * SecureHardFault in a PE without the Main Extension. */ #endif /* ARM_SECURE_FIRMWARE && !ARM_SECURE_BUSFAULT_HARDFAULT_NMI */ } /** * @brief Clear Fault exceptions * * Clear out exceptions for Mem, Bus, Usage and Hard Faults * * @return N/A */ static ALWAYS_INLINE void z_arm_clear_faults(void) { #if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) /* Reset all faults */ SCB->CFSR = SCB_CFSR_USGFAULTSR_Msk | SCB_CFSR_MEMFAULTSR_Msk | SCB_CFSR_BUSFAULTSR_Msk; /* Clear all Hard Faults - HFSR is write-one-to-clear */ SCB->HFSR = 0xffffffff; #else #error Unknown ARM architecture #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ } #ifdef __cplusplus } #endif #endif /* _ASMLANGUAGE */ #endif /* ZEPHYR_ARCH_ARM_INCLUDE_CORTEX_M_EXC_H_ */