|
|
|
@ -36,22 +36,56 @@ extern uint32_t irq_stats[IRQ_STATS_MAX];
|
|
|
|
|
#define IRQ_EXIT(irq)
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
typedef uint32_t irq_key_t;
|
|
|
|
|
|
|
|
|
|
// Checks if interrupts are enabled
|
|
|
|
|
#define IS_IRQ_ENABLED(state) (((state) & 1) == 0)
|
|
|
|
|
#define IS_IRQ_ENABLED(key) (((key) & 1) == 0)
|
|
|
|
|
|
|
|
|
|
// Get the current value of the CPU's exception mask register.
|
|
|
|
|
// The least significant bit indicates if interrupts are enabled or disabled.
|
|
|
|
|
static inline uint32_t query_irq(void) { return __get_PRIMASK(); }
|
|
|
|
|
static inline irq_key_t query_irq(void) { return __get_PRIMASK(); }
|
|
|
|
|
|
|
|
|
|
// Restore the CPU's exception mask register to a previous state
|
|
|
|
|
static inline void enable_irq(uint32_t state) { __set_PRIMASK(state); }
|
|
|
|
|
// Disables interrupts and returns the previous interrupt state.
|
|
|
|
|
//
|
|
|
|
|
// This function is used to create critical sections by disabling interrupts
|
|
|
|
|
// on a Cortex-M platform. It returns the current state of the PRIMASK register,
|
|
|
|
|
// which controls the global interrupt enable/disable state.
|
|
|
|
|
//
|
|
|
|
|
// Important:
|
|
|
|
|
// - The `"memory"` clobber is included to prevent the compiler from reordering
|
|
|
|
|
// memory operations across this function, ensuring that all memory accesses
|
|
|
|
|
// efore `irq_lock()` are completed before interrupts are disabled.
|
|
|
|
|
// - The order of operations on non-volatile variables relative to this
|
|
|
|
|
// function is not guaranteed without memory barriers or other
|
|
|
|
|
// synchronization mechanisms.
|
|
|
|
|
// - When using Link-Time Optimization (LTO), ensure that the behavior of these
|
|
|
|
|
// functions is thoroughly tested, as LTO can lead to more aggressive
|
|
|
|
|
// optimizations. While GCC typically respects the order of `volatile`
|
|
|
|
|
// operations, this is not guaranteed by the C standard.
|
|
|
|
|
static inline irq_key_t irq_lock(void) {
|
|
|
|
|
uint32_t key;
|
|
|
|
|
__asm volatile(
|
|
|
|
|
"MRS %0, PRIMASK\n"
|
|
|
|
|
"CPSID i"
|
|
|
|
|
: "=r"(key)
|
|
|
|
|
:
|
|
|
|
|
: "memory" // Clobber memory to ensure correct memory operations
|
|
|
|
|
);
|
|
|
|
|
return key;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Disable all interrupts and return the current state of the
|
|
|
|
|
// CPU's exception mask register
|
|
|
|
|
static inline uint32_t disable_irq(void) {
|
|
|
|
|
uint32_t state = __get_PRIMASK();
|
|
|
|
|
__disable_irq();
|
|
|
|
|
return state;
|
|
|
|
|
// Restores the interrupt state to what it was before `irq_lock`.
|
|
|
|
|
//
|
|
|
|
|
// This function re-enables interrupts based on the PRIMASK state passed to it.
|
|
|
|
|
// It should be used in conjunction with `irq_lock` to restore the previous
|
|
|
|
|
// interrupt state after a critical section.
|
|
|
|
|
static inline void irq_unlock(irq_key_t key) {
|
|
|
|
|
__asm volatile(
|
|
|
|
|
"MSR PRIMASK, %0\n"
|
|
|
|
|
:
|
|
|
|
|
: "r"(key)
|
|
|
|
|
: "memory" // Clobber memory to ensure correct memory operations
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// IRQ priority levels used throughout the system
|
|
|
|
|