diff --git a/arch/posix/include/posix_soc_if.h b/arch/posix/include/posix_soc_if.h index cddd6c74f77..13db3815a80 100644 --- a/arch/posix/include/posix_soc_if.h +++ b/arch/posix/include/posix_soc_if.h @@ -37,6 +37,15 @@ void posix_irq_full_unlock(void); int posix_get_current_irq(void); /* irq_offload() from irq_offload.h must also be defined by the SOC or board */ +/** + * Returns true if interrupts were unlocked prior to the + * z_arch_irq_lock() call that produced the key argument. + */ +static inline bool z_arch_irq_unlocked(unsigned int key) +{ + return key == false; +} + #ifdef __cplusplus } #endif diff --git a/arch/x86_64/include/kernel_arch_func.h b/arch/x86_64/include/kernel_arch_func.h index 8c3800025aa..6ec89055c3a 100644 --- a/arch/x86_64/include/kernel_arch_func.h +++ b/arch/x86_64/include/kernel_arch_func.h @@ -42,6 +42,15 @@ static inline void z_arch_irq_unlock(unsigned int key) } } +/** + * Returns true if interrupts were unlocked prior to the + * z_arch_irq_lock() call that produced the key argument. + */ +static inline bool z_arch_irq_unlocked(unsigned int key) +{ + return (key & 0x200) != 0; +} + static inline void arch_nop(void) { __asm__ volatile("nop"); diff --git a/include/arch/arc/v2/irq.h b/include/arch/arc/v2/irq.h index 61a4d118c7d..b462f3f8a6c 100644 --- a/include/arch/arc/v2/irq.h +++ b/include/arch/arc/v2/irq.h @@ -127,6 +127,19 @@ static ALWAYS_INLINE void z_arch_irq_unlock(unsigned int key) __asm__ volatile("seti %0" : : "ir"(key) : "memory"); } +/** + * Returns true if interrupts were unlocked prior to the + * z_arch_irq_lock() call that produced the key argument. + */ +static ALWAYS_INLINE bool z_arch_irq_unlocked(unsigned int key) +{ + /* ARC irq lock uses instruction "clri r0", + * r0 == {26’d0, 1’b1, STATUS32.IE, STATUS32.E[3:0] } + * bit4 is used to record IE (Interrupt Enable) bit + */ + return (key & 0x10) == 0x10; +} + #endif /* _ASMLANGUAGE */ #ifdef __cplusplus diff --git a/include/arch/arm/cortex_m/asm_inline_gcc.h b/include/arch/arm/cortex_m/asm_inline_gcc.h index a4a79bb3fef..dac869d7e37 100644 --- a/include/arch/arm/cortex_m/asm_inline_gcc.h +++ b/include/arch/arm/cortex_m/asm_inline_gcc.h @@ -184,6 +184,15 @@ static ALWAYS_INLINE void z_arch_irq_unlock(unsigned int key) #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ } +/** + * Returns true if interrupts were unlocked prior to the + * z_arch_irq_lock() call that produced the key argument. + */ +static ALWAYS_INLINE bool z_arch_irq_unlocked(unsigned int key) +{ + /* This convention works for both PRIMASK and BASEPRI */ + return key == 0; +} #endif /* _ASMLANGUAGE */ diff --git a/include/arch/nios2/arch.h b/include/arch/nios2/arch.h index 3f9f3be8233..756784dc4a1 100644 --- a/include/arch/nios2/arch.h +++ b/include/arch/nios2/arch.h @@ -124,6 +124,15 @@ static ALWAYS_INLINE void z_arch_irq_unlock(unsigned int key) #endif } +/** + * Returns true if interrupts were unlocked prior to the + * z_arch_irq_lock() call that produced the key argument. + */ +static ALWAYS_INLINE bool z_arch_irq_unlocked(unsigned int key) +{ + return key & 1; +} + void z_arch_irq_enable(unsigned int irq); void z_arch_irq_disable(unsigned int irq); diff --git a/include/arch/riscv32/arch.h b/include/arch/riscv32/arch.h index fb9f5010c77..66c7810f594 100644 --- a/include/arch/riscv32/arch.h +++ b/include/arch/riscv32/arch.h @@ -115,6 +115,22 @@ static ALWAYS_INLINE void z_arch_irq_unlock(unsigned int key) : "memory"); } +/** + * Returns true if interrupts were unlocked prior to the + * z_arch_irq_lock() call that produced the key argument. + */ +static ALWAYS_INLINE bool z_arch_irq_unlocked(unsigned int key) +{ + /* FIXME: looking at z_arch_irq_lock, this should be reducable + * to just testing that key is nonzero (because it should only + * have the single bit set). But there is a mask applied to + * the argument in z_arch_irq_unlock() that has me worried + * that something elseswhere might try to set a bit? Do it + * the safe way for now. + */ + return (key & SOC_MSTATUS_IEN) == SOC_MSTATUS_IEN; +} + /** * @brief Explicitly nop operation. */ diff --git a/include/arch/x86/arch.h b/include/arch/x86/arch.h index acd3b622d65..39867f04a91 100644 --- a/include/arch/x86/arch.h +++ b/include/arch/x86/arch.h @@ -441,6 +441,15 @@ static ALWAYS_INLINE void z_arch_irq_unlock(unsigned int key) z_do_irq_unlock(); } +/** + * Returns true if interrupts were unlocked prior to the + * z_arch_irq_lock() call that produced the key argument. + */ +static ALWAYS_INLINE bool z_arch_irq_unlocked(unsigned int key) +{ + return (key & 0x200) != 0; +} + /** * @brief Explicitly nop operation. */ diff --git a/include/arch/xtensa/xtensa_irq.h b/include/arch/xtensa/xtensa_irq.h index b49c61b966f..edb87a1bbc8 100644 --- a/include/arch/xtensa/xtensa_irq.h +++ b/include/arch/xtensa/xtensa_irq.h @@ -73,6 +73,15 @@ static ALWAYS_INLINE void z_arch_irq_unlock(unsigned int key) XTOS_RESTORE_INTLEVEL(key); } +/** + * Returns true if interrupts were unlocked prior to the + * z_arch_irq_lock() call that produced the key argument. + */ +static ALWAYS_INLINE bool z_arch_irq_unlocked(unsigned int key) +{ + return (key & 0xf) == 0; /* INTLEVEL field */ +} + #include #endif /* ZEPHYR_INCLUDE_ARCH_XTENSA_XTENSA_IRQ_H_ */ diff --git a/tests/kernel/common/src/irq_offload.c b/tests/kernel/common/src/irq_offload.c index 52648b95faa..196bff0cf5e 100644 --- a/tests/kernel/common/src/irq_offload.c +++ b/tests/kernel/common/src/irq_offload.c @@ -40,6 +40,20 @@ static void offload_function(void *param) */ void test_irq_offload(void) { + /* Simple validation of nested locking. */ + unsigned int key1, key2; + + key1 = z_arch_irq_lock(); + zassert_true(z_arch_irq_unlocked(key1), + "IRQs should have been unlocked, but key is 0x%x\n", + key1); + key2 = z_arch_irq_lock(); + zassert_false(z_arch_irq_unlocked(key2), + "IRQs should have been locked, but key is 0x%x\n", + key2); + z_arch_irq_unlock(key2); + z_arch_irq_unlock(key1); + /**TESTPOINT: Offload to IRQ context*/ irq_offload(offload_function, (void *)SENTINEL_VALUE);