arch: arm: Fix incorrect Cortex-R interrupt state control logic.
This commit fixes incorrect Cortex-R interrupt lock, unlock and state check function implementations. The issues can be summarised as follows: 1. The current implementation of 'z_arch_irq_lock' returns the value of CPSR as the IRQ key and, since CPSR contains many other state bits, this caused 'z_arch_irq_unlocked' to return false even when IRQ is unlocked. This problem is fixed by isolating only the I-bit of CPSR and returning this value as the IRQ key, such that it returns a non-zero value when interrupt is disabled. 2. The current implementation of 'z_arch_irq_unlock' directly updates the value of CPSR control field with the IRQ key and this can cause other state bits in CPSR to be corrupted. This problem is fixed by conditionally enabling interrupt using CPSIE instruction when the value of IRQ key is a zero. 3. The current implementation of 'z_arch_is_in_isr' checks the value of CPSR MODE field and returns true if its value is IRQ or FIQ. While this does not normally cause an issue, the function can return false when IRQ offloading is used because the offload function executes in SVC mode. This problem is fixed by adding check for SVC mode. Signed-off-by: Stephanos Ioannidis <root@stephanos.io>
This commit is contained in:
parent
aa544d678e
commit
bea3ee0ed0
2 changed files with 17 additions and 7 deletions
|
@ -42,7 +42,9 @@ static ALWAYS_INLINE bool arch_is_in_isr(void)
|
|||
: "=r" (status) : : "memory", "cc");
|
||||
status &= MODE_MASK;
|
||||
|
||||
return (status == MODE_FIQ) || (status == MODE_IRQ);
|
||||
return (status == MODE_FIQ) ||
|
||||
(status == MODE_IRQ) ||
|
||||
(status == MODE_SVC);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -22,6 +22,10 @@
|
|||
#include <arch/arm/aarch32/exc.h>
|
||||
#include <irq.h>
|
||||
|
||||
#if defined(CONFIG_CPU_CORTEX_R)
|
||||
#include <arch/arm/cortex_r/cpu.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -58,8 +62,10 @@ static ALWAYS_INLINE unsigned int arch_irq_lock(void)
|
|||
: "i"(_EXC_IRQ_DEFAULT_PRIO)
|
||||
: "memory");
|
||||
#elif defined(CONFIG_ARMV7_R)
|
||||
__asm__ volatile("mrs %0, cpsr;"
|
||||
"cpsid i"
|
||||
__asm__ volatile(
|
||||
"mrs %0, cpsr;"
|
||||
"and %0, #" TOSTR(I_BIT) ";"
|
||||
"cpsid i;"
|
||||
: "=r" (key)
|
||||
:
|
||||
: "memory", "cc");
|
||||
|
@ -91,10 +97,12 @@ static ALWAYS_INLINE void arch_irq_unlock(unsigned int key)
|
|||
"isb;"
|
||||
: : "r"(key) : "memory");
|
||||
#elif defined(CONFIG_ARMV7_R)
|
||||
__asm__ volatile("msr cpsr_c, %0"
|
||||
:
|
||||
: "r" (key)
|
||||
: "memory", "cc");
|
||||
if (key) {
|
||||
return;
|
||||
}
|
||||
__asm__ volatile(
|
||||
"cpsie i;"
|
||||
: : : "memory", "cc");
|
||||
#else
|
||||
#error Unknown ARM architecture
|
||||
#endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue