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:
Stephanos Ioannidis 2019-10-15 12:45:51 +09:00 committed by Andrew Boie
commit bea3ee0ed0
2 changed files with 17 additions and 7 deletions

View file

@ -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);
}
/**

View file

@ -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 */