[PATCH] sparc: Add SPARC_USE_SAFE_FP_SUPPORT

Gedare Bloom gedare at gwu.edu
Mon Jun 1 14:29:29 UTC 2015


On Sat, May 30, 2015 at 11:59 AM, Sebastian Huber
<sebastian.huber at 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 at rtems.org
> http://lists.rtems.org/mailman/listinfo/devel


More information about the devel mailing list