[rtems commit] arm: Fix ARMv7-M interrupt processing

Sebastian Huber sebh at rtems.org
Fri Jul 7 11:28:18 UTC 2017


Module:    rtems
Branch:    4.11
Commit:    7e91901303219f10cf865906931c07c31d2e37f4
Changeset: http://git.rtems.org/rtems/commit/?id=7e91901303219f10cf865906931c07c31d2e37f4

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Tue Jul  4 14:15:03 2017 +0200

arm: Fix ARMv7-M interrupt processing

Right after a "msr basepri_max, %[basepri]" instruction an interrupt
service may still take place (observed at least on Cortex-M7).  However,
pendable service calls that are activated during this interrupt service
may be delayed until interrupts are enable again.  The
_ARMV7M_Pendable_service_call() did not check that a thread dispatch is
allowed.  Move this test from _ARMV7M_Interrupt_service_leave() to
_ARMV7M_Pendable_service_call().

Close #3060.

---

 cpukit/score/cpu/arm/armv7m-isr-dispatch.c    | 50 +++++++++++++++++----------
 cpukit/score/cpu/arm/armv7m-isr-enter-leave.c | 28 +++++++++------
 2 files changed, 48 insertions(+), 30 deletions(-)

diff --git a/cpukit/score/cpu/arm/armv7m-isr-dispatch.c b/cpukit/score/cpu/arm/armv7m-isr-dispatch.c
index e460e9c..ffd1589 100644
--- a/cpukit/score/cpu/arm/armv7m-isr-dispatch.c
+++ b/cpukit/score/cpu/arm/armv7m-isr-dispatch.c
@@ -5,10 +5,10 @@
  */
 
 /*
- * Copyright (c) 2011-2014 Sebastian Huber.  All rights reserved.
+ * Copyright (c) 2011, 2017 Sebastian Huber.  All rights reserved.
  *
  *  embedded brains GmbH
- *  Obere Lagerstr. 30
+ *  Dornierstr. 4
  *  82178 Puchheim
  *  Germany
  *  <rtems at embedded-brains.de>
@@ -48,29 +48,42 @@ static void _ARMV7M_Trigger_lazy_floating_point_context_save( void )
 
 void _ARMV7M_Pendable_service_call( void )
 {
-  ARMV7M_Exception_frame *ef;
+  Per_CPU_Control *cpu_self = _Per_CPU_Get();
 
-  _ISR_Nest_level = 1;
+  /*
+   * We must check here if a thread dispatch is allowed.  Right after a
+   * "msr basepri_max, %[basepri]" instruction an interrupt service may still
+   * take place.  However, pendable service calls that are activated during
+   * this interrupt service may be delayed until interrupts are enable again.
+   */
+  if (
+    ( cpu_self->isr_nest_level | cpu_self->thread_dispatch_disable_level ) == 0
+  ) {
+    ARMV7M_Exception_frame *ef;
 
-  _ARMV7M_SCB->icsr = ARMV7M_SCB_ICSR_PENDSVCLR;
-  _ARMV7M_Trigger_lazy_floating_point_context_save();
+    cpu_self->isr_nest_level = 1;
 
-  ef = (ARMV7M_Exception_frame *) _ARMV7M_Get_PSP();
-  --ef;
-  _ARMV7M_Set_PSP( (uint32_t) ef );
+    _ARMV7M_SCB->icsr = ARMV7M_SCB_ICSR_PENDSVCLR;
+    _ARMV7M_Trigger_lazy_floating_point_context_save();
 
-  /*
-   * According to "ARMv7-M Architecture Reference Manual" section B1.5.6
-   * "Exception entry behavior" the return address is half-word aligned.
-   */
-  ef->register_pc = (void *)
-    ((uintptr_t) _ARMV7M_Thread_dispatch & ~((uintptr_t) 1));
+    ef = (ARMV7M_Exception_frame *) _ARMV7M_Get_PSP();
+    --ef;
+    _ARMV7M_Set_PSP( (uint32_t) ef );
 
-  ef->register_xpsr = 0x01000000U;
+    /*
+     * According to "ARMv7-M Architecture Reference Manual" section B1.5.6
+     * "Exception entry behavior" the return address is half-word aligned.
+     */
+    ef->register_pc = (void *)
+      ((uintptr_t) _ARMV7M_Thread_dispatch & ~((uintptr_t) 1));
+
+    ef->register_xpsr = 0x01000000U;
+  }
 }
 
 void _ARMV7M_Supervisor_call( void )
 {
+  Per_CPU_Control *cpu_self = _Per_CPU_Get();
   ARMV7M_Exception_frame *ef;
 
   _ARMV7M_Trigger_lazy_floating_point_context_save();
@@ -79,10 +92,9 @@ void _ARMV7M_Supervisor_call( void )
   ++ef;
   _ARMV7M_Set_PSP( (uint32_t) ef );
 
-  _ISR_Nest_level = 0;
-  RTEMS_COMPILER_MEMORY_BARRIER();
+  cpu_self->isr_nest_level = 0;
 
-  if ( _Thread_Dispatch_necessary ) {
+  if ( cpu_self->dispatch_necessary ) {
     _ARMV7M_Pendable_service_call();
   }
 }
diff --git a/cpukit/score/cpu/arm/armv7m-isr-enter-leave.c b/cpukit/score/cpu/arm/armv7m-isr-enter-leave.c
index 4ab800b..90e97fb 100644
--- a/cpukit/score/cpu/arm/armv7m-isr-enter-leave.c
+++ b/cpukit/score/cpu/arm/armv7m-isr-enter-leave.c
@@ -5,10 +5,10 @@
  */
 
 /*
- * Copyright (c) 2011 Sebastian Huber.  All rights reserved.
+ * Copyright (c) 2011, 2017 Sebastian Huber.  All rights reserved.
  *
  *  embedded brains GmbH
- *  Obere Lagerstr. 30
+ *  Dornierstr. 4
  *  82178 Puchheim
  *  Germany
  *  <rtems at embedded-brains.de>
@@ -30,19 +30,25 @@
 
 void _ARMV7M_Interrupt_service_enter( void )
 {
-  ++_Thread_Dispatch_disable_level;
-  ++_ISR_Nest_level;
+  Per_CPU_Control *cpu_self = _Per_CPU_Get();
+
+  ++cpu_self->thread_dispatch_disable_level;
+  ++cpu_self->isr_nest_level;
 }
 
 void _ARMV7M_Interrupt_service_leave( void )
 {
-  --_ISR_Nest_level;
-  --_Thread_Dispatch_disable_level;
-  if (
-    _ISR_Nest_level == 0
-      && _Thread_Dispatch_disable_level == 0
-      && _Thread_Dispatch_necessary
-  ) {
+  Per_CPU_Control *cpu_self = _Per_CPU_Get();
+
+  --cpu_self->thread_dispatch_disable_level;
+  --cpu_self->isr_nest_level;
+
+  /*
+   * Optimistically activate a pendable service call if a thread dispatch is
+   * necessary.  The _ARMV7M_Pendable_service_call() will check that a thread
+   * dispatch is allowed.
+   */
+  if ( cpu_self->dispatch_necessary ) {
     _ARMV7M_SCB->icsr = ARMV7M_SCB_ICSR_PENDSVSET;
   }
 }



More information about the vc mailing list