summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--c/src/lib/libbsp/sparc/shared/irq_asm.S85
-rw-r--r--cpukit/score/cpu/sparc/cpu.c2
-rw-r--r--cpukit/score/cpu/sparc/cpu_asm.S2
-rw-r--r--cpukit/score/cpu/sparc/rtems/score/cpu.h29
4 files changed, 114 insertions, 4 deletions
diff --git a/c/src/lib/libbsp/sparc/shared/irq_asm.S b/c/src/lib/libbsp/sparc/shared/irq_asm.S
index 53b24f72bb..f7222e7623 100644
--- a/c/src/lib/libbsp/sparc/shared/irq_asm.S
+++ b/c/src/lib/libbsp/sparc/shared/irq_asm.S
@@ -25,6 +25,27 @@
#include <rtems/score/percpu.h>
#include <bspopts.h>
+#if SPARC_HAS_FPU == 1 && defined(SPARC_USE_SAFE_FP_SUPPORT)
+ #define FP_FRAME_OFFSET_FO_F1 (CPU_MINIMUM_STACK_FRAME_SIZE + 0)
+ #define FP_FRAME_OFFSET_F2_F3 (FP_FRAME_OFFSET_FO_F1 + 8)
+ #define FP_FRAME_OFFSET_F4_F5 (FP_FRAME_OFFSET_F2_F3 + 8)
+ #define FP_FRAME_OFFSET_F6_F7 (FP_FRAME_OFFSET_F4_F5 + 8)
+ #define FP_FRAME_OFFSET_F8_F9 (FP_FRAME_OFFSET_F6_F7 + 8)
+ #define FP_FRAME_OFFSET_F1O_F11 (FP_FRAME_OFFSET_F8_F9 + 8)
+ #define FP_FRAME_OFFSET_F12_F13 (FP_FRAME_OFFSET_F1O_F11 + 8)
+ #define FP_FRAME_OFFSET_F14_F15 (FP_FRAME_OFFSET_F12_F13 + 8)
+ #define FP_FRAME_OFFSET_F16_F17 (FP_FRAME_OFFSET_F14_F15 + 8)
+ #define FP_FRAME_OFFSET_F18_F19 (FP_FRAME_OFFSET_F16_F17 + 8)
+ #define FP_FRAME_OFFSET_F2O_F21 (FP_FRAME_OFFSET_F18_F19 + 8)
+ #define FP_FRAME_OFFSET_F22_F23 (FP_FRAME_OFFSET_F2O_F21 + 8)
+ #define FP_FRAME_OFFSET_F24_F25 (FP_FRAME_OFFSET_F22_F23 + 8)
+ #define FP_FRAME_OFFSET_F26_F27 (FP_FRAME_OFFSET_F24_F25 + 8)
+ #define FP_FRAME_OFFSET_F28_F29 (FP_FRAME_OFFSET_F26_F27 + 8)
+ #define FP_FRAME_OFFSET_F3O_F31 (FP_FRAME_OFFSET_F28_F29 + 8)
+ #define FP_FRAME_OFFSET_FSR (FP_FRAME_OFFSET_F3O_F31 + 8)
+ #define FP_FRAME_SIZE (FP_FRAME_OFFSET_FSR + 8)
+#endif
+
/*
* void _CPU_Context_switch(
* Context_Control *run,
@@ -613,9 +634,73 @@ profiling_not_outer_most_exit:
nop
nop
isr_dispatch:
+
+#if SPARC_HAS_FPU == 1 && defined(SPARC_USE_SAFE_FP_SUPPORT)
+ /* Test if we interrupted a floating point thread (PSR[EF] == 1) */
+ andcc %l0, %l5, %g0
+ be non_fp_thread_dispatch
+ nop
+
+ /*
+ * Yes, this is a floating point thread, then save the floating point
+ * context to a new stack frame. Then do the thread dispatch.
+ * Post-switch actions (e.g. signal handlers) and context switch
+ * extensions may safely use the floating point unit.
+ */
+ sub %sp, FP_FRAME_SIZE, %sp
+ std %f0, [%sp + FP_FRAME_OFFSET_FO_F1]
+ std %f2, [%sp + FP_FRAME_OFFSET_F2_F3]
+ std %f4, [%sp + FP_FRAME_OFFSET_F4_F5]
+ std %f6, [%sp + FP_FRAME_OFFSET_F6_F7]
+ std %f8, [%sp + FP_FRAME_OFFSET_F8_F9]
+ std %f10, [%sp + FP_FRAME_OFFSET_F1O_F11]
+ std %f12, [%sp + FP_FRAME_OFFSET_F12_F13]
+ std %f14, [%sp + FP_FRAME_OFFSET_F14_F15]
+ std %f16, [%sp + FP_FRAME_OFFSET_F16_F17]
+ std %f18, [%sp + FP_FRAME_OFFSET_F18_F19]
+ std %f20, [%sp + FP_FRAME_OFFSET_F2O_F21]
+ std %f22, [%sp + FP_FRAME_OFFSET_F22_F23]
+ std %f24, [%sp + FP_FRAME_OFFSET_F24_F25]
+ std %f26, [%sp + FP_FRAME_OFFSET_F26_F27]
+ std %f28, [%sp + FP_FRAME_OFFSET_F28_F29]
+ std %f30, [%sp + FP_FRAME_OFFSET_F3O_F31]
+ call SYM(_Thread_Dispatch), 0
+ st %fsr, [%sp + FP_FRAME_OFFSET_FSR]
+
+ /*
+ * Restore the floating point context from stack frame and release the
+ * stack frame.
+ */
+ ldd [%sp + FP_FRAME_OFFSET_FO_F1], %f0
+ ldd [%sp + FP_FRAME_OFFSET_F2_F3], %f2
+ ldd [%sp + FP_FRAME_OFFSET_F4_F5], %f4
+ ldd [%sp + FP_FRAME_OFFSET_F6_F7], %f6
+ ldd [%sp + FP_FRAME_OFFSET_F8_F9], %f8
+ ldd [%sp + FP_FRAME_OFFSET_F1O_F11], %f10
+ ldd [%sp + FP_FRAME_OFFSET_F12_F13], %f12
+ ldd [%sp + FP_FRAME_OFFSET_F14_F15], %f14
+ ldd [%sp + FP_FRAME_OFFSET_F16_F17], %f16
+ ldd [%sp + FP_FRAME_OFFSET_F18_F19], %f18
+ ldd [%sp + FP_FRAME_OFFSET_F2O_F21], %f20
+ ldd [%sp + FP_FRAME_OFFSET_F22_F23], %f22
+ ldd [%sp + FP_FRAME_OFFSET_F24_F25], %f24
+ ldd [%sp + FP_FRAME_OFFSET_F26_F27], %f26
+ ldd [%sp + FP_FRAME_OFFSET_F28_F29], %f28
+ ldd [%sp + FP_FRAME_OFFSET_F3O_F31], %f30
+ ld [%sp + FP_FRAME_OFFSET_FSR], %fsr
+ ba thread_dispatch_done
+ add %sp, FP_FRAME_SIZE, %sp
+
+non_fp_thread_dispatch:
+#endif
+
call SYM(_Thread_Dispatch), 0
nop
+#if SPARC_HAS_FPU == 1 && defined(SPARC_USE_SAFE_FP_SUPPORT)
+thread_dispatch_done:
+#endif
+
/*
* We invoked _Thread_Dispatch in a state similar to the interrupted
* task. In order to safely be able to tinker with the register
diff --git a/cpukit/score/cpu/sparc/cpu.c b/cpukit/score/cpu/sparc/cpu.c
index bab0040058..569b6f8ec8 100644
--- a/cpukit/score/cpu/sparc/cpu.c
+++ b/cpukit/score/cpu/sparc/cpu.c
@@ -131,7 +131,7 @@ RTEMS_STATIC_ASSERT(
void _CPU_Initialize(void)
{
-#if (SPARC_HAS_FPU == 1)
+#if (SPARC_HAS_FPU == 1) && !defined(SPARC_USE_SAFE_FP_SUPPORT)
Context_Control_fp *pointer;
uint32_t psr;
diff --git a/cpukit/score/cpu/sparc/cpu_asm.S b/cpukit/score/cpu/sparc/cpu_asm.S
index 3fa0532c86..4e683dae0d 100644
--- a/cpukit/score/cpu/sparc/cpu_asm.S
+++ b/cpukit/score/cpu/sparc/cpu_asm.S
@@ -26,7 +26,7 @@
#include <rtems/asm.h>
#include <rtems/system.h>
-#if (SPARC_HAS_FPU == 1)
+#if (SPARC_HAS_FPU == 1) && !defined(SPARC_USE_SAFE_FP_SUPPORT)
/*
* void _CPU_Context_save_fp(
diff --git a/cpukit/score/cpu/sparc/rtems/score/cpu.h b/cpukit/score/cpu/sparc/rtems/score/cpu.h
index 02891b0438..d35846521e 100644
--- a/cpukit/score/cpu/sparc/rtems/score/cpu.h
+++ b/cpukit/score/cpu/sparc/rtems/score/cpu.h
@@ -28,6 +28,31 @@ extern "C" {
/* conditional compilation parameters */
+#if defined(RTEMS_SMP)
+ /*
+ * The SPARC ABI is a bit special with respect to the floating point context.
+ * The complete floating point context is volatile. Thus from an ABI point
+ * of view nothing needs to be saved and restored during a context switch.
+ * Instead the floating point context must be saved and restored during
+ * interrupt processing. Historically the deferred floating point switch is
+ * used for SPARC and the complete floating point context is saved and
+ * restored during a context switch to the new floating point unit owner.
+ * This is a bit dangerous since post-switch actions (e.g. signal handlers)
+ * and context switch extensions may silently corrupt the floating point
+ * context. The floating point unit is disabled for interrupt handlers.
+ * Thus in case an interrupt handler uses the floating point unit then this
+ * will result in a trap.
+ *
+ * On SMP configurations the deferred floating point switch is not
+ * supported in principle. So use here a safe floating point support. Safe
+ * means that the volatile floating point context is saved and restored
+ * around a thread dispatch issued during interrupt processing. Thus
+ * post-switch actions and context switch extensions may safely use the
+ * floating point unit.
+ */
+ #define SPARC_USE_SAFE_FP_SUPPORT
+#endif
+
/**
* Should the calls to _Thread_Enable_dispatch be inlined?
*
@@ -102,7 +127,7 @@ extern "C" {
*
* This is set based upon the multilib settings.
*/
-#if ( SPARC_HAS_FPU == 1 )
+#if ( SPARC_HAS_FPU == 1 ) && !defined(SPARC_USE_SAFE_FP_SUPPORT)
#define CPU_HARDWARE_FP TRUE
#else
#define CPU_HARDWARE_FP FALSE
@@ -152,7 +177,7 @@ extern "C" {
* On the SPARC, we can disable the FPU for integer only tasks so
* it is safe to defer floating point context switches.
*/
-#if defined(RTEMS_SMP)
+#if defined(SPARC_USE_SAFE_FP_SUPPORT)
#define CPU_USE_DEFERRED_FP_SWITCH FALSE
#else
#define CPU_USE_DEFERRED_FP_SWITCH TRUE