[PATCH 1/4] sparc: Disable FPU in interrupt context

Sebastian Huber sebastian.huber at embedded-brains.de
Fri May 29 13:54:27 UTC 2015


From: Alexander Krutwig <alexander.krutwig at embedded-brains.de>

Update #2270.
---
 c/src/lib/libbsp/sparc/shared/irq_asm.S  | 30 ++++++++++++++++++++++++++++++
 cpukit/score/cpu/sparc/cpu.c             |  8 ++++++++
 cpukit/score/cpu/sparc/rtems/score/cpu.h | 25 ++++++++++++++++++++++++-
 3 files changed, 62 insertions(+), 1 deletion(-)

diff --git a/c/src/lib/libbsp/sparc/shared/irq_asm.S b/c/src/lib/libbsp/sparc/shared/irq_asm.S
index eef144f..8e1dc1f 100644
--- a/c/src/lib/libbsp/sparc/shared/irq_asm.S
+++ b/c/src/lib/libbsp/sparc/shared/irq_asm.S
@@ -423,6 +423,14 @@ dont_do_the_window:
         add      %l6, 1, %l6
         st       %l6, [%g6 + PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL]
 
+#if SPARC_HAS_FPU == 1
+        /*
+         * We cannot use an intermediate value for operations with the PSR[EF]
+         * bit since they use a 13-bit sign extension and PSR[EF] is bit 12.
+         */
+        sethi    %hi(SPARC_PSR_EF_MASK), %l5
+#endif
+
         /*
          *  If ISR nest level was zero (now 1), then switch stack.
          */
@@ -441,6 +449,19 @@ dont_do_the_window:
 
         ld       [%g6 + PER_CPU_INTERRUPT_STACK_HIGH], %sp
 
+#if SPARC_HAS_FPU == 1
+        /*
+         * Test if the interrupted thread uses the floating point unit
+         * (PSR[EF] == 1).  In case it uses the floating point unit, then store
+         * the floating point status register.  This has the side-effect that
+         * all pending floating point operations complete before the store
+         * completes.
+         */
+        andcc    %l0, %l5, %g0
+        bne,a    dont_switch_stacks
+         st      %fsr, [%g6 + SPARC_PER_CPU_FSR_OFFSET]
+#endif
+
 dont_switch_stacks:
         /*
          *  Make sure we have a place on the stack for the window overflow
@@ -471,6 +492,15 @@ dont_switch_stacks:
 dont_fix_pil:
         or       %g5, SPARC_PSR_PIL_MASK, %g5
 pil_fixed:
+
+#if SPARC_HAS_FPU == 1
+        /*
+         * Clear the PSR[EF] bit of the interrupted context to ensure that
+         * interrupt service routines cannot corrupt the floating point context.
+         */
+        andn     %g5, %l5, %g5
+#endif
+
         wr       %g5, SPARC_PSR_ET_MASK, %psr ! **** ENABLE TRAPS ****
 
         /*
diff --git a/cpukit/score/cpu/sparc/cpu.c b/cpukit/score/cpu/sparc/cpu.c
index f96d1ea..ee64b1e 100644
--- a/cpukit/score/cpu/sparc/cpu.c
+++ b/cpukit/score/cpu/sparc/cpu.c
@@ -29,6 +29,14 @@ RTEMS_STATIC_ASSERT(
   SPARC_PER_CPU_ISR_DISPATCH_DISABLE
 );
 
+#if SPARC_HAS_FPU == 1
+  RTEMS_STATIC_ASSERT(
+    offsetof( Per_CPU_Control, cpu_per_cpu.fsr)
+      == SPARC_PER_CPU_FSR_OFFSET,
+    SPARC_PER_CPU_FSR_OFFSET
+  );
+#endif
+
 #define SPARC_ASSERT_OFFSET(field, off) \
   RTEMS_STATIC_ASSERT( \
     offsetof(Context_Control, field) == off ## _OFFSET, \
diff --git a/cpukit/score/cpu/sparc/rtems/score/cpu.h b/cpukit/score/cpu/sparc/rtems/score/cpu.h
index 5d5f1e4..02891b0 100644
--- a/cpukit/score/cpu/sparc/rtems/score/cpu.h
+++ b/cpukit/score/cpu/sparc/rtems/score/cpu.h
@@ -341,7 +341,11 @@ typedef struct {
 /** This defines the size of the minimum stack frame. */
 #define CPU_MINIMUM_STACK_FRAME_SIZE          0x60
 
-#define CPU_PER_CPU_CONTROL_SIZE 4
+#if ( SPARC_HAS_FPU == 1 )
+  #define CPU_PER_CPU_CONTROL_SIZE 8
+#else
+  #define CPU_PER_CPU_CONTROL_SIZE 4
+#endif
 
 /**
  * @brief Offset of the CPU_Per_CPU_control::isr_dispatch_disable field
@@ -349,6 +353,14 @@ typedef struct {
  */
 #define SPARC_PER_CPU_ISR_DISPATCH_DISABLE 0
 
+#if ( SPARC_HAS_FPU == 1 )
+  /**
+   * @brief Offset of the CPU_Per_CPU_control::fsr field relative to the
+   * Per_CPU_Control begin.
+   */
+  #define SPARC_PER_CPU_FSR_OFFSET 4
+#endif
+
 /**
  * @defgroup Contexts SPARC Context Structures
  *
@@ -380,6 +392,17 @@ typedef struct {
    * attempts on a previously interrupted thread's stack.
    */
   uint32_t isr_dispatch_disable;
+
+#if ( SPARC_HAS_FPU == 1 )
+  /**
+   * @brief Memory location to store the FSR register during interrupt
+   * processing.
+   *
+   * This is a write-only field.  The FSR is written to force a completion of
+   * floating point operations in progress.
+   */
+  uint32_t fsr;
+#endif
 } CPU_Per_CPU_control;
 
 /**
-- 
1.8.4.5



More information about the devel mailing list