On Sat, May 30, 2015 at 11:59 AM, Sebastian Huber <sebastian.hu...@embedded-brains.de> wrote: > 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. > > Update #2270. > --- > c/src/lib/libbsp/sparc/shared/irq_asm.S | 85 > ++++++++++++++++++++++++++++++++ > cpukit/score/cpu/sparc/cpu.c | 2 +- > cpukit/score/cpu/sparc/cpu_asm.S | 2 +- > cpukit/score/cpu/sparc/rtems/score/cpu.h | 70 +++++++++++++++++++++----- > 4 files changed, 146 insertions(+), 13 deletions(-) > > diff --git a/c/src/lib/libbsp/sparc/shared/irq_asm.S > b/c/src/lib/libbsp/sparc/shared/irq_asm.S > index 53b24f7..f7222e7 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 bab0040..569b6f8 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 3fa0532..4e683da 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 02891b0..3335c0d 100644 > --- a/cpukit/score/cpu/sparc/rtems/score/cpu.h > +++ b/cpukit/score/cpu/sparc/rtems/score/cpu.h > @@ -135,6 +135,31 @@ extern "C" { > */ > #define CPU_IDLE_TASK_IS_FP FALSE > > +#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 saving of the floating point registers be deferred > * until a context switch is made to another different floating point > @@ -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 > @@ -577,6 +602,9 @@ typedef struct { > * This structure defines floating point context area. > */ > typedef struct { > +#if defined(SPARC_USE_SAFE_FP_SUPPORT) > + char dummy_to_make_the_workspace_estimate_happy; What's this?
> +#else > /** This will contain the contents of the f0 and f1 register. */ > double f0_f1; > /** This will contain the contents of the f2 and f3 register. */ > @@ -611,10 +639,13 @@ typedef struct { > double f30_f31; > /** This will contain the contents of the floating point status register. > */ > uint32_t fsr; > +#endif > } Context_Control_fp; > > #endif /* ASM */ > > +#if !defined(SPARC_USE_SAFE_FP_SUPPORT) > + > /* > * Offsets of fields with Context_Control_fp for assembly routines. > */ > @@ -657,6 +688,8 @@ typedef struct { > /** This defines the size of the FPU context area for use in assembly. */ > #define CONTEXT_CONTROL_FP_SIZE 0x84 > > +#endif /* !defined(SPARC_USE_SAFE_FP_SUPPORT) */ > + > #ifndef ASM > > /** @} */ > @@ -1068,10 +1101,15 @@ void _CPU_Context_Initialize( > * at CPU initialization and it is simply copied into the destination > * context. > */ > -#define _CPU_Context_Initialize_fp( _destination ) \ > - do { \ > - *(*(_destination)) = _CPU_Null_fp_context; \ > - } while (0) > +#if defined(SPARC_USE_SAFE_FP_SUPPORT) > + #define _CPU_Context_Initialize_fp( _destination ) \ > + do { } while ( 0 ) > +#else > + #define _CPU_Context_Initialize_fp( _destination ) \ > + do { \ > + *(*(_destination)) = _CPU_Null_fp_context; \ > + } while (0) > +#endif > > /* end of Context handler macros */ > > @@ -1219,9 +1257,14 @@ register struct Per_CPU_Control > *_SPARC_Per_CPU_current __asm__( "g6" ); > * > * @param[in] fp_context_ptr is the area to save into > */ > -void _CPU_Context_save_fp( > - Context_Control_fp **fp_context_ptr > -); > +#if defined(SPARC_USE_SAFE_FP_SUPPORT) > + #define _CPU_Context_save_fp( fp_context_ptr ) \ > + do { } while ( 0 ) > +#else > + void _CPU_Context_save_fp( > + Context_Control_fp **fp_context_ptr > + ); > +#endif > > /** > * @brief SPARC specific restore FPU method. > @@ -1230,9 +1273,14 @@ void _CPU_Context_save_fp( > * > * @param[in] fp_context_ptr is the area to restore from > */ > -void _CPU_Context_restore_fp( > - Context_Control_fp **fp_context_ptr > -); > +#if defined(SPARC_USE_SAFE_FP_SUPPORT) > + #define _CPU_Context_restore_fp( fp_context_ptr ) \ > + do { } while ( 0 ) > +#else > + void _CPU_Context_restore_fp( > + Context_Control_fp **fp_context_ptr > + ); > +#endif > > void _CPU_Context_volatile_clobber( uintptr_t pattern ); > > -- > 2.1.4 > > _______________________________________________ > devel mailing list > devel@rtems.org > http://lists.rtems.org/mailman/listinfo/devel _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel