diff options
Diffstat (limited to '')
-rw-r--r-- | c/src/lib/libbsp/sparc/shared/irq_asm.S | 85 | ||||
-rw-r--r-- | cpukit/score/cpu/sparc/cpu.c | 2 | ||||
-rw-r--r-- | cpukit/score/cpu/sparc/cpu_asm.S | 2 | ||||
-rw-r--r-- | cpukit/score/cpu/sparc/rtems/score/cpu.h | 29 |
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 |