diff options
Diffstat (limited to 'cpukit/score')
-rw-r--r-- | cpukit/score/cpu/sparc/Makefile.am | 2 | ||||
-rw-r--r-- | cpukit/score/cpu/sparc/cpu.c | 65 | ||||
-rw-r--r-- | cpukit/score/cpu/sparc/cpu_asm.S | 127 | ||||
-rw-r--r-- | cpukit/score/cpu/sparc/rtems/score/cpu.h | 115 | ||||
-rw-r--r-- | cpukit/score/cpu/sparc/rtems/score/cpuimpl.h | 33 | ||||
-rw-r--r-- | cpukit/score/cpu/sparc/sparc-context-validate.S | 13 |
6 files changed, 136 insertions, 219 deletions
diff --git a/cpukit/score/cpu/sparc/Makefile.am b/cpukit/score/cpu/sparc/Makefile.am index ec600b6cad..96d29e0e11 100644 --- a/cpukit/score/cpu/sparc/Makefile.am +++ b/cpukit/score/cpu/sparc/Makefile.am @@ -12,7 +12,7 @@ include_rtems_score_HEADERS += rtems/score/types.h include_rtems_score_HEADERS += rtems/score/cpuatomic.h noinst_LIBRARIES = libscorecpu.a -libscorecpu_a_SOURCES = cpu.c cpu_asm.S +libscorecpu_a_SOURCES = cpu.c libscorecpu_a_SOURCES += sparc-context-volatile-clobber.S libscorecpu_a_SOURCES += sparc-context-validate.S libscorecpu_a_SOURCES += sparc-counter.c diff --git a/cpukit/score/cpu/sparc/cpu.c b/cpukit/score/cpu/sparc/cpu.c index 5bea27fda5..8916a7d988 100644 --- a/cpukit/score/cpu/sparc/cpu.c +++ b/cpukit/score/cpu/sparc/cpu.c @@ -8,6 +8,8 @@ * COPYRIGHT (c) 1989-2007. * On-Line Applications Research Corporation (OAR). * + * Copyright (c) 2017 embedded brains GmbH + * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at * http://www.rtems.org/license/LICENSE. @@ -21,6 +23,7 @@ #include <rtems/score/isr.h> #include <rtems/score/percpu.h> #include <rtems/score/tls.h> +#include <rtems/score/thread.h> #include <rtems/rtems/cache.h> #if SPARC_HAS_FPU == 1 @@ -29,6 +32,14 @@ == SPARC_PER_CPU_FSR_OFFSET, SPARC_PER_CPU_FSR_OFFSET ); + + #if defined(SPARC_USE_LAZY_FP_SWITCH) + RTEMS_STATIC_ASSERT( + offsetof( Per_CPU_Control, cpu_per_cpu.fp_owner) + == SPARC_PER_CPU_FP_OWNER_OFFSET, + SPARC_PER_CPU_FP_OWNER_OFFSET + ); + #endif #endif #define SPARC_ASSERT_OFFSET(field, off) \ @@ -99,6 +110,30 @@ SPARC_ASSERT_ISF_OFFSET(i7, I7); SPARC_ASSERT_ISF_OFFSET(y, Y); SPARC_ASSERT_ISF_OFFSET(tpc, TPC); +#define SPARC_ASSERT_FP_OFFSET(field, off) \ + RTEMS_STATIC_ASSERT( \ + offsetof(Context_Control_fp, field) == SPARC_FP_CONTEXT_OFFSET_ ## off, \ + Context_Control_fp_offset_ ## field \ + ) + +SPARC_ASSERT_FP_OFFSET(f0_f1, F0_F1); +SPARC_ASSERT_FP_OFFSET(f2_f3, F2_F3); +SPARC_ASSERT_FP_OFFSET(f4_f5, F4_F5); +SPARC_ASSERT_FP_OFFSET(f6_f7, F6_F7); +SPARC_ASSERT_FP_OFFSET(f8_f9, F8_F9); +SPARC_ASSERT_FP_OFFSET(f10_f11, F10_F11); +SPARC_ASSERT_FP_OFFSET(f12_f13, F12_F13); +SPARC_ASSERT_FP_OFFSET(f14_f15, F14_F15); +SPARC_ASSERT_FP_OFFSET(f16_f17, F16_F17); +SPARC_ASSERT_FP_OFFSET(f18_f19, F18_F19); +SPARC_ASSERT_FP_OFFSET(f20_f21, F20_F21); +SPARC_ASSERT_FP_OFFSET(f22_f23, F22_F23); +SPARC_ASSERT_FP_OFFSET(f24_f25, F24_F25); +SPARC_ASSERT_FP_OFFSET(f26_f27, F26_F27); +SPARC_ASSERT_FP_OFFSET(f28_f29, F28_F29); +SPARC_ASSERT_FP_OFFSET(f30_f31, F30_F31); +SPARC_ASSERT_FP_OFFSET(fsr, FSR); + RTEMS_STATIC_ASSERT( sizeof(SPARC_Minimum_stack_frame) == SPARC_MINIMUM_STACK_FRAME_SIZE, SPARC_MINIMUM_STACK_FRAME_SIZE @@ -110,10 +145,6 @@ RTEMS_STATIC_ASSERT( CPU_Interrupt_frame_alignment ); -#if (SPARC_HAS_FPU == 1) && !defined(SPARC_USE_SYNCHRONOUS_FP_SWITCH) -Context_Control_fp _CPU_Null_fp_context; -#endif - /* * _CPU_Initialize * @@ -129,22 +160,16 @@ Context_Control_fp _CPU_Null_fp_context; void _CPU_Initialize(void) { -#if (SPARC_HAS_FPU == 1) && !defined(SPARC_USE_SYNCHRONOUS_FP_SWITCH) - Context_Control_fp *pointer; - uint32_t psr; - - sparc_get_psr( psr ); - psr |= SPARC_PSR_EF_MASK; - sparc_set_psr( psr ); - - /* - * This seems to be the most appropriate way to obtain an initial - * FP context on the SPARC. The NULL fp context is copied it to - * the task's FP context during Context_Initialize. - */ - - pointer = &_CPU_Null_fp_context; - _CPU_Context_save_fp( &pointer ); +#if defined(SPARC_USE_LAZY_FP_SWITCH) + __asm__ volatile ( + ".global SPARC_THREAD_CONTROL_REGISTERS_FP_CONTEXT_OFFSET\n" + ".set SPARC_THREAD_CONTROL_REGISTERS_FP_CONTEXT_OFFSET, %0\n" + ".global SPARC_THREAD_CONTROL_FP_CONTEXT_OFFSET\n" + ".set SPARC_THREAD_CONTROL_FP_CONTEXT_OFFSET, %1\n" + : + : "i" (offsetof(Thread_Control, Registers.fp_context)), + "i" (offsetof(Thread_Control, fp_context)) + ); #endif } diff --git a/cpukit/score/cpu/sparc/cpu_asm.S b/cpukit/score/cpu/sparc/cpu_asm.S deleted file mode 100644 index 66d36935a3..0000000000 --- a/cpukit/score/cpu/sparc/cpu_asm.S +++ /dev/null @@ -1,127 +0,0 @@ -/* cpu_asm.s - * - * This file contains the basic algorithms for all assembly code used - * in an specific CPU port of RTEMS. These algorithms must be implemented - * in assembly language. - * - * COPYRIGHT (c) 1989-2011. - * On-Line Applications Research Corporation (OAR). - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - * - * Ported to ERC32 implementation of the SPARC by On-Line Applications - * Research Corporation (OAR) under contract to the European Space - * Agency (ESA). - * - * ERC32 modifications of respective RTEMS file: COPYRIGHT (c) 1995. - * European Space Agency. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <rtems/asm.h> -#include <rtems/system.h> - -#if (SPARC_HAS_FPU == 1) && !defined(SPARC_USE_SYNCHRONOUS_FP_SWITCH) - -/* - * void _CPU_Context_save_fp( - * void **fp_context_ptr - * ) - * - * This routine is responsible for saving the FP context - * at *fp_context_ptr. If the point to load the FP context - * from is changed then the pointer is modified by this routine. - * - * NOTE: See the README in this directory for information on the - * management of the "EF" bit in the PSR. - */ - - .align 4 - PUBLIC(_CPU_Context_save_fp) -SYM(_CPU_Context_save_fp): - ld [%o0], %o1 - std %f0, [%o1 + FO_F1_OFFSET] - SPARC_LEON3FT_B2BST_NOP - std %f2, [%o1 + F2_F3_OFFSET] - SPARC_LEON3FT_B2BST_NOP - std %f4, [%o1 + F4_F5_OFFSET] - SPARC_LEON3FT_B2BST_NOP - std %f6, [%o1 + F6_F7_OFFSET] - SPARC_LEON3FT_B2BST_NOP - std %f8, [%o1 + F8_F9_OFFSET] - SPARC_LEON3FT_B2BST_NOP - std %f10, [%o1 + F1O_F11_OFFSET] - SPARC_LEON3FT_B2BST_NOP - std %f12, [%o1 + F12_F13_OFFSET] - SPARC_LEON3FT_B2BST_NOP - std %f14, [%o1 + F14_F15_OFFSET] - SPARC_LEON3FT_B2BST_NOP - std %f16, [%o1 + F16_F17_OFFSET] - SPARC_LEON3FT_B2BST_NOP - std %f18, [%o1 + F18_F19_OFFSET] - SPARC_LEON3FT_B2BST_NOP - std %f20, [%o1 + F2O_F21_OFFSET] - SPARC_LEON3FT_B2BST_NOP - std %f22, [%o1 + F22_F23_OFFSET] - SPARC_LEON3FT_B2BST_NOP - std %f24, [%o1 + F24_F25_OFFSET] - SPARC_LEON3FT_B2BST_NOP - std %f26, [%o1 + F26_F27_OFFSET] - SPARC_LEON3FT_B2BST_NOP - std %f28, [%o1 + F28_F29_OFFSET] - SPARC_LEON3FT_B2BST_NOP - std %f30, [%o1 + F3O_F31_OFFSET] - SPARC_LEON3FT_B2BST_NOP -#if defined(__FIX_LEON3FT_B2BST) - st %fsr, [%o1 + FSR_OFFSET] - jmp %o7 + 8 - nop -#else - jmp %o7 + 8 - st %fsr, [%o1 + FSR_OFFSET] -#endif - -/* - * void _CPU_Context_restore_fp( - * void **fp_context_ptr - * ) - * - * This routine is responsible for restoring the FP context - * at *fp_context_ptr. If the point to load the FP context - * from is changed then the pointer is modified by this routine. - * - * NOTE: See the README in this directory for information on the - * management of the "EF" bit in the PSR. - */ - - .align 4 - PUBLIC(_CPU_Context_restore_fp) -SYM(_CPU_Context_restore_fp): - ld [%o0], %o1 - ldd [%o1 + FO_F1_OFFSET], %f0 - ldd [%o1 + F2_F3_OFFSET], %f2 - ldd [%o1 + F4_F5_OFFSET], %f4 - ldd [%o1 + F6_F7_OFFSET], %f6 - ldd [%o1 + F8_F9_OFFSET], %f8 - ldd [%o1 + F1O_F11_OFFSET], %f10 - ldd [%o1 + F12_F13_OFFSET], %f12 - ldd [%o1 + F14_F15_OFFSET], %f14 - ldd [%o1 + F16_F17_OFFSET], %f16 - ldd [%o1 + F18_F19_OFFSET], %f18 - ldd [%o1 + F2O_F21_OFFSET], %f20 - ldd [%o1 + F22_F23_OFFSET], %f22 - ldd [%o1 + F24_F25_OFFSET], %f24 - ldd [%o1 + F26_F27_OFFSET], %f26 - ldd [%o1 + F28_F29_OFFSET], %f28 - ldd [%o1 + F3O_F31_OFFSET], %f30 - jmp %o7 + 8 - ld [%o1 + FSR_OFFSET], %fsr - -#endif /* SPARC_HAS_FPU */ - -/* end of file */ diff --git a/cpukit/score/cpu/sparc/rtems/score/cpu.h b/cpukit/score/cpu/sparc/rtems/score/cpu.h index 48db756ea6..2b50592e08 100644 --- a/cpukit/score/cpu/sparc/rtems/score/cpu.h +++ b/cpukit/score/cpu/sparc/rtems/score/cpu.h @@ -30,17 +30,28 @@ extern "C" { /* * 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 + * 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 + * interrupt processing. Historically, the deferred floating point switch was * 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. + * 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 (INTERNAL_ERROR_ILLEGAL_USE_OF_FLOATING_POINT_UNIT). + * + * In uniprocessor configurations, a lazy floating point context switch is + * used. In case an active floating point thread is interrupted (PSR[EF] == 1) + * and a thread dispatch is carried out, then this thread is registered as the + * floating point owner. When a floating point owner is present during a + * context switch, the floating point unit is disabled for the heir thread + * (PSR[EF] == 0). The floating point disabled trap checks that the use of the + * floating point unit is allowed and saves/restores the floating point context + * on demand. * * In SMP configurations, the deferred floating point switch is not supported * in principle. So, use here a synchronous floating point switching. @@ -52,6 +63,8 @@ extern "C" { #if SPARC_HAS_FPU == 1 #if defined(RTEMS_SMP) #define SPARC_USE_SYNCHRONOUS_FP_SWITCH + #else + #define SPARC_USE_LAZY_FP_SWITCH #endif #endif @@ -152,28 +165,7 @@ extern "C" { */ #define CPU_IDLE_TASK_IS_FP FALSE -/** - * Should the saving of the floating point registers be deferred - * until a context switch is made to another different floating point - * task? - * - * - If TRUE, then the floating point context will not be stored until - * necessary. It will remain in the floating point registers and not - * disturned until another floating point task is switched to. - * - * - If FALSE, then the floating point context is saved when a floating - * point task is switched out and restored when the next floating point - * task is restored. The state of the floating point registers between - * those two operations is not specified. - * - * On the SPARC, we can disable the FPU for integer only tasks so - * it is safe to defer floating point context switches. - */ -#if defined(SPARC_USE_SYNCHRONOUS_FP_SWITCH) - #define CPU_USE_DEFERRED_FP_SWITCH FALSE -#else - #define CPU_USE_DEFERRED_FP_SWITCH TRUE -#endif +#define CPU_USE_DEFERRED_FP_SWITCH FALSE #define CPU_ENABLE_ROBUST_THREAD_DISPATCH FALSE @@ -356,6 +348,7 @@ typedef struct { /**@{**/ #ifndef ASM +typedef struct Context_Control_fp Context_Control_fp; /** * @brief SPARC basic context. @@ -433,6 +426,10 @@ typedef struct { */ uint32_t isr_dispatch_disable; +#if defined(SPARC_USE_LAZY_FP_SWITCH) + Context_Control_fp *fp_context; +#endif + #if defined(RTEMS_SMP) volatile uint32_t is_executing; #endif @@ -528,7 +525,7 @@ typedef struct { * * This structure defines floating point context area. */ -typedef struct { +struct Context_Control_fp { /** 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. */ @@ -563,7 +560,7 @@ typedef struct { double f30_f31; /** This will contain the contents of the floating point status register. */ uint32_t fsr; -} Context_Control_fp; +}; #endif /* ASM */ @@ -670,13 +667,6 @@ typedef struct { #ifndef ASM /** - * This variable is contains the initialize context for the FP unit. - * It is filled in by _CPU_Initialize and copied into the task's FP - * context area during _CPU_Context_Initialize. - */ -extern Context_Control_fp _CPU_Null_fp_context; - -/** * The following type defines an entry in the SPARC's trap table. * * NOTE: The instructions chosen are RTEMS dependent although one is @@ -958,18 +948,22 @@ void _CPU_Context_Initialize( _CPU_Context_restore( (_the_context) ); /** - * This routine initializes the FP context area passed to it to. - * - * The SPARC allows us to use the simple initialization model - * in which an "initial" FP context was saved into _CPU_Null_fp_context - * at CPU initialization and it is simply copied into the destination - * context. + * @brief Nothing to do due to the synchronous or lazy floating point switch. */ #define _CPU_Context_Initialize_fp( _destination ) \ - do { \ - *(*(_destination)) = _CPU_Null_fp_context; \ - } while (0) + do { } while ( 0 ) +/** + * @brief Nothing to do due to the synchronous or lazy floating point switch. + */ +#define _CPU_Context_save_fp( _fp_context_ptr ) \ + do { } while ( 0 ) + +/** + * @brief Nothing to do due to the synchronous or lazy floating point switch. + */ +#define _CPU_Context_restore_fp( _fp_context_ptr ) \ + do { } while ( 0 ) /* end of Context handler macros */ /* Fatal Error manager macros */ @@ -1095,27 +1089,16 @@ void _CPU_Context_restore( } #endif -/** - * @brief SPARC specific save FPU method. - * - * This routine saves the floating point context passed to it. - * - * @param[in] fp_context_ptr is the area to save into - */ -void _CPU_Context_save_fp( - Context_Control_fp **fp_context_ptr -); - -/** - * @brief SPARC specific restore FPU method. - * - * This routine restores the floating point context passed to it. - * - * @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_LAZY_FP_SWITCH) +#define _CPU_Context_Destroy( _the_thread, _the_context ) \ + do { \ + Per_CPU_Control *cpu_self = _Per_CPU_Get(); \ + Thread_Control *_fp_owner = cpu_self->cpu_per_cpu.fp_owner; \ + if ( _fp_owner == _the_thread ) { \ + cpu_self->cpu_per_cpu.fp_owner = NULL; \ + } \ + } while ( 0 ) +#endif void _CPU_Context_volatile_clobber( uintptr_t pattern ); diff --git a/cpukit/score/cpu/sparc/rtems/score/cpuimpl.h b/cpukit/score/cpu/sparc/rtems/score/cpuimpl.h index 5563db8911..4f2311e755 100644 --- a/cpukit/score/cpu/sparc/rtems/score/cpuimpl.h +++ b/cpukit/score/cpu/sparc/rtems/score/cpuimpl.h @@ -67,6 +67,24 @@ /** This defines the size of the ISF area for use in assembly. */ #define CPU_INTERRUPT_FRAME_SIZE SPARC_MINIMUM_STACK_FRAME_SIZE + 0x50 +#define SPARC_FP_CONTEXT_OFFSET_F0_F1 0 +#define SPARC_FP_CONTEXT_OFFSET_F2_F3 8 +#define SPARC_FP_CONTEXT_OFFSET_F4_F5 16 +#define SPARC_FP_CONTEXT_OFFSET_F6_F7 24 +#define SPARC_FP_CONTEXT_OFFSET_F8_F9 32 +#define SPARC_FP_CONTEXT_OFFSET_F10_F11 40 +#define SPARC_FP_CONTEXT_OFFSET_F12_F13 48 +#define SPARC_FP_CONTEXT_OFFSET_F14_F15 56 +#define SPARC_FP_CONTEXT_OFFSET_F16_F17 64 +#define SPARC_FP_CONTEXT_OFFSET_F18_F19 72 +#define SPARC_FP_CONTEXT_OFFSET_F20_F21 80 +#define SPARC_FP_CONTEXT_OFFSET_F22_F23 88 +#define SPARC_FP_CONTEXT_OFFSET_F24_F25 96 +#define SPARC_FP_CONTEXT_OFFSET_F26_F27 104 +#define SPARC_FP_CONTEXT_OFFSET_F28_F29 112 +#define SPARC_FP_CONTEXT_OFFSET_F30_F31 120 +#define SPARC_FP_CONTEXT_OFFSET_FSR 128 + #if ( SPARC_HAS_FPU == 1 ) #define CPU_PER_CPU_CONTROL_SIZE 8 #else @@ -79,6 +97,14 @@ * Per_CPU_Control begin. */ #define SPARC_PER_CPU_FSR_OFFSET 0 + + #if defined(SPARC_USE_LAZY_FP_SWITCH) + /** + * @brief Offset of the CPU_Per_CPU_control::fp_owner field relative to the + * Per_CPU_Control begin. + */ + #define SPARC_PER_CPU_FP_OWNER_OFFSET 4 + #endif #endif #ifndef ASM @@ -98,9 +124,16 @@ typedef struct { */ uint32_t fsr; +#if defined(SPARC_USE_LAZY_FP_SWITCH) + /** + * @brief The current floating point owner. + */ + struct _Thread_Control *fp_owner; +#else /* See Per_CPU_Control::Interrupt_frame */ uint32_t reserved_for_alignment_of_interrupt_frame; #endif +#endif } CPU_Per_CPU_control; /** diff --git a/cpukit/score/cpu/sparc/sparc-context-validate.S b/cpukit/score/cpu/sparc/sparc-context-validate.S index 777f4dd8a6..83ecc54156 100644 --- a/cpukit/score/cpu/sparc/sparc-context-validate.S +++ b/cpukit/score/cpu/sparc/sparc-context-validate.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 embedded brains GmbH. All rights reserved. + * Copyright (c) 2015, 2017 embedded brains GmbH. All rights reserved. * * embedded brains GmbH * Dornierstr. 4 @@ -18,6 +18,7 @@ #include <rtems/asm.h> #include <rtems/score/cpuimpl.h> +#include <rtems/score/percpu.h> #define FRAME_OFFSET_BUFFER_0 (SPARC_MINIMUM_STACK_FRAME_SIZE) #define FRAME_OFFSET_BUFFER_1 (FRAME_OFFSET_BUFFER_0 + 0x04) @@ -73,13 +74,15 @@ PUBLIC(_CPU_Context_validate) SYM(_CPU_Context_validate): - /* - * g2 checks if the Floating Point Unit in the Processor Status - * Register (PSR) is set. - */ + /* g2 indicates if the FPU should be checked */ +#if defined(SPARC_USE_LAZY_FP_SWITCH) + ld [%g6 + PER_CPU_OFFSET_EXECUTING], %g2 + ld [%g2 + %lo(SPARC_THREAD_CONTROL_FP_CONTEXT_OFFSET)], %g2 +#else mov %psr, %g2 sethi %hi(SPARC_PSR_EF_MASK), %g3 and %g2, %g3, %g2 +#endif /* g1 is used to save the original pattern */ mov %o0, %g1 |