[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