[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