summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libcpu/sparc/syscall/syscall.S
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/lib/libcpu/sparc/syscall/syscall.S')
-rw-r--r--c/src/lib/libcpu/sparc/syscall/syscall.S126
1 files changed, 125 insertions, 1 deletions
diff --git a/c/src/lib/libcpu/sparc/syscall/syscall.S b/c/src/lib/libcpu/sparc/syscall/syscall.S
index d5e1f43403..da0ee43889 100644
--- a/c/src/lib/libcpu/sparc/syscall/syscall.S
+++ b/c/src/lib/libcpu/sparc/syscall/syscall.S
@@ -11,12 +11,15 @@
* COPYRIGHT:
*
* COPYRIGHT (c) 1995. European Space Agency.
+ * Copyright (c) 2016, 2017 embedded brains GmbH
*
* This terms of the RTEMS license apply to this file.
*
*/
#include <rtems/asm.h>
+#include <rtems/score/cpuimpl.h>
+#include <rtems/score/percpu.h>
#include "syscall.h"
.section ".text"
@@ -95,7 +98,7 @@ SYM(syscall_irqen):
jmp %l2 ! Return to after TA 10.
rett %l2 + 4
-#if SPARC_HAS_FPU == 1
+#if defined(SPARC_USE_SYNCHRONOUS_FP_SWITCH)
/*
* system call - Interrupt disable and set PSR[EF] according to caller
* specified %g1
@@ -132,6 +135,127 @@ SYM(syscall_irqdis_fp):
rett %l2 + 4
#endif
+#if defined(SPARC_USE_LAZY_FP_SWITCH)
+
+ /*
+ * system call - Perform a lazy floating point switch
+ *
+ * On entry:
+ *
+ * l0 = psr (from trap table)
+ * l1 = pc
+ * l2 = npc
+ * l3 = SPARC_PSR_EF_MASK
+ */
+
+.align 32 ! Align to 32-byte cache-line
+ PUBLIC(syscall_lazy_fp_switch)
+
+SYM(syscall_lazy_fp_switch):
+ ld [%g6 + PER_CPU_OFFSET_EXECUTING], %l4
+ ld [%g6 + PER_CPU_ISR_NEST_LEVEL], %l5
+ ld [%l4 + %lo(SPARC_THREAD_CONTROL_FP_CONTEXT_OFFSET)], %l6
+ ld [%g6 + SPARC_PER_CPU_FP_OWNER_OFFSET], %l7
+
+ /* Ensure that we are not in interrupt context */
+ cmp %l5, 0
+ bne .Lillegal_use_of_floating_point_unit
+ or %l0, %l3, %l0
+
+ /* Ensure that we are a proper floating point thread */
+ cmp %l6, 0
+ be .Lillegal_use_of_floating_point_unit
+ ld [%l4 + %lo(SPARC_THREAD_CONTROL_REGISTERS_FP_CONTEXT_OFFSET)], %l6
+
+ /* Set PSR[EF] to 1, PSR write delay 3 instructions! */
+ mov %l0, %psr
+
+ /*
+ * Check if there is a floating point owner. We have to check this
+ * here, since the floating point owner may have been deleted in the
+ * meantime. Save the floating point context if necessary.
+ */
+ cmp %l7, 0
+ be .Lfp_save_done
+ nop
+ ld [%l7 + %lo(SPARC_THREAD_CONTROL_FP_CONTEXT_OFFSET)], %l5
+ std %f0, [%l5 + SPARC_FP_CONTEXT_OFFSET_F0_F1]
+ SPARC_LEON3FT_B2BST_NOP
+ std %f2, [%l5 + SPARC_FP_CONTEXT_OFFSET_F2_F3]
+ SPARC_LEON3FT_B2BST_NOP
+ std %f4, [%l5 + SPARC_FP_CONTEXT_OFFSET_F4_F5]
+ SPARC_LEON3FT_B2BST_NOP
+ std %f6, [%l5 + SPARC_FP_CONTEXT_OFFSET_F6_F7]
+ SPARC_LEON3FT_B2BST_NOP
+ std %f8, [%l5 + SPARC_FP_CONTEXT_OFFSET_F8_F9]
+ SPARC_LEON3FT_B2BST_NOP
+ std %f10, [%l5 + SPARC_FP_CONTEXT_OFFSET_F10_F11]
+ SPARC_LEON3FT_B2BST_NOP
+ std %f12, [%l5 + SPARC_FP_CONTEXT_OFFSET_F12_F13]
+ SPARC_LEON3FT_B2BST_NOP
+ std %f14, [%l5 + SPARC_FP_CONTEXT_OFFSET_F14_F15]
+ SPARC_LEON3FT_B2BST_NOP
+ std %f16, [%l5 + SPARC_FP_CONTEXT_OFFSET_F16_F17]
+ SPARC_LEON3FT_B2BST_NOP
+ std %f18, [%l5 + SPARC_FP_CONTEXT_OFFSET_F18_F19]
+ SPARC_LEON3FT_B2BST_NOP
+ std %f20, [%l5 + SPARC_FP_CONTEXT_OFFSET_F20_F21]
+ SPARC_LEON3FT_B2BST_NOP
+ std %f22, [%l5 + SPARC_FP_CONTEXT_OFFSET_F22_F23]
+ SPARC_LEON3FT_B2BST_NOP
+ std %f24, [%l5 + SPARC_FP_CONTEXT_OFFSET_F24_F25]
+ SPARC_LEON3FT_B2BST_NOP
+ std %f26, [%l5 + SPARC_FP_CONTEXT_OFFSET_F26_F27]
+ SPARC_LEON3FT_B2BST_NOP
+ std %f28, [%l5 + SPARC_FP_CONTEXT_OFFSET_F28_F29]
+ SPARC_LEON3FT_B2BST_NOP
+ std %f30, [%l5 + SPARC_FP_CONTEXT_OFFSET_F30_F31]
+ SPARC_LEON3FT_B2BST_NOP
+ st %fsr, [%l5 + SPARC_FP_CONTEXT_OFFSET_FSR]
+ SPARC_LEON3FT_B2BST_NOP
+ st %g0, [%g6 + SPARC_PER_CPU_FP_OWNER_OFFSET]
+ SPARC_LEON3FT_B2BST_NOP
+ st %l5, [%l7 + %lo(SPARC_THREAD_CONTROL_REGISTERS_FP_CONTEXT_OFFSET)]
+
+.Lfp_save_done:
+
+ /* Restore the floating point context if necessary */
+ cmp %l6, 0
+ be .Lfp_restore_done
+ st %g0, [%l4 + %lo(SPARC_THREAD_CONTROL_REGISTERS_FP_CONTEXT_OFFSET)]
+ ldd [%l6 + SPARC_FP_CONTEXT_OFFSET_F0_F1], %f0
+ ldd [%l6 + SPARC_FP_CONTEXT_OFFSET_F2_F3], %f2
+ ldd [%l6 + SPARC_FP_CONTEXT_OFFSET_F4_F5], %f4
+ ldd [%l6 + SPARC_FP_CONTEXT_OFFSET_F6_F7], %f6
+ ldd [%l6 + SPARC_FP_CONTEXT_OFFSET_F8_F9], %f8
+ ldd [%l6 + SPARC_FP_CONTEXT_OFFSET_F10_F11], %f10
+ ldd [%l6 + SPARC_FP_CONTEXT_OFFSET_F12_F13], %f12
+ ldd [%l6 + SPARC_FP_CONTEXT_OFFSET_F14_F15], %f14
+ ldd [%l6 + SPARC_FP_CONTEXT_OFFSET_F16_F17], %f16
+ ldd [%l6 + SPARC_FP_CONTEXT_OFFSET_F18_F19], %f18
+ ldd [%l6 + SPARC_FP_CONTEXT_OFFSET_F20_F21], %f20
+ ldd [%l6 + SPARC_FP_CONTEXT_OFFSET_F22_F23], %f22
+ ldd [%l6 + SPARC_FP_CONTEXT_OFFSET_F24_F25], %f24
+ ldd [%l6 + SPARC_FP_CONTEXT_OFFSET_F26_F27], %f26
+ ldd [%l6 + SPARC_FP_CONTEXT_OFFSET_F28_F29], %f28
+ ldd [%l6 + SPARC_FP_CONTEXT_OFFSET_F30_F31], %f30
+ ld [%l6 + SPARC_FP_CONTEXT_OFFSET_FSR], %fsr
+
+.Lfp_restore_done:
+
+ /* Now, retry the floating point instruction with PSR[EF] == 1 */
+ jmp %l1
+ rett %l1 + 4
+
+.Lillegal_use_of_floating_point_unit:
+
+ sethi %hi(_Internal_error), %l1
+ or %l1, %lo(_Internal_error), %l1
+ mov 38, %i0
+ jmp %l1
+ rett %l1 + 4
+#endif
+
#if defined(RTEMS_PARAVIRT)
PUBLIC(_SPARC_Get_PSR)