source: rtems/c/src/lib/libcpu/sparc/syscall/syscall.S @ 3a3d85c

5
Last change on this file since 3a3d85c was 146adb1, checked in by Sebastian Huber <sebastian.huber@…>, on 07/17/17 at 05:30:46

sparc: Add lazy floating point switch

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 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 (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.

Update #3077.

  • Property mode set to 100644
File size: 7.2 KB
Line 
1/*
2 *  systrap.S
3 *
4 *  This file contains emulated system calls using software trap 0.
5 *  The following calls are supported:
6 *
7 *    + SYS_exit        (halt)
8 *    + SYS_irqdis      (disable interrupts)
9 *    + SYS_irqset      (set interrupt level)
10 *
11 *  COPYRIGHT:
12 *
13 *  COPYRIGHT (c) 1995. European Space Agency.
14 *  Copyright (c) 2016, 2017 embedded brains GmbH
15 *
16 *  This terms of the RTEMS license apply to this file.
17 *
18 */
19
20#include <rtems/asm.h>
21#include <rtems/score/cpuimpl.h>
22#include <rtems/score/percpu.h>
23#include "syscall.h"
24
25        .section    ".text"
26        /*
27         *  system call - halt
28         *
29         *  On entry:
30         *
31         *    l0 = psr (from trap table)
32         *    l1 = pc
33         *    l2 = npc
34         *    g1 = system call id (1)
35         *
36         *  System Call 1 (exit):
37         *    g2 = additional exit code 1
38         *    g3 = additional exit code 2
39         */
40
41        PUBLIC(syscall)
42
43SYM(syscall):
44        ta      0                       ! syscall 1, halt with %g1,%g2,%g3 info
45
46        PUBLIC(sparc_syscall_exit)
47
48SYM(sparc_syscall_exit):
49
50        mov     SYS_exit, %g1
51        mov     %o0, %g2        ! Additional exit code 1
52        mov     %o1, %g3        ! Additional exit code 2
53        ta      SPARC_SWTRAP_SYSCALL
54
55        /*
56         *  system call - Interrupt Disable
57         *
58         *  On entry:
59         *
60         *    l0 = psr (from trap table)
61         *    l1 = pc
62         *    l2 = npc
63         *    l3 = psr | SPARC_PSR_PIL_MASK
64         *
65         *  On exit:
66         *    g1 = old psr (to user)
67         */
68
69.align 32                               ! Align to 32-byte cache-line
70        PUBLIC(syscall_irqdis)
71
72SYM(syscall_irqdis):
73        mov     %l3, %psr                       ! Set PSR. Write delay 3 instr
74        or      %l0, SPARC_PSR_ET_MASK, %g1     ! return old PSR with ET=1
75        nop                                     ! PSR write delay
76        jmp     %l2                             ! Return to after TA 9.
77         rett   %l2 + 4
78
79        /*
80         *  system call - Interrupt Enable
81         *
82         *  On entry:
83         *
84         *    l0 = psr (from trap table)
85         *    l1 = pc
86         *    l2 = npc
87         *    l3 = psr & ~0x0f00
88         *    g1 = new PIL to write (from user)
89         */
90
91.align 32                               ! Align to 32-byte cache-line
92        PUBLIC(syscall_irqen)
93
94SYM(syscall_irqen):
95        and     %g1, SPARC_PSR_PIL_MASK, %l4    ! %l4 = (%g1 & 0xf00)
96        wr      %l3, %l4, %psr                  ! PSR = (PSR & ~0xf00) ^ %l4
97        nop; nop                                ! PSR write delay;
98        jmp     %l2                             ! Return to after TA 10.
99         rett   %l2 + 4
100
101#if defined(SPARC_USE_SYNCHRONOUS_FP_SWITCH)
102        /*
103         *  system call - Interrupt disable and set PSR[EF] according to caller
104         *                specified %g1
105         *
106         *  On entry:
107         *
108         *    g1 = the desired PSR[EF] value (from caller)
109         *    l0 = psr (from trap table)
110         *    l1 = pc
111         *    l2 = npc
112         *    l3 = psr | SPARC_PSR_PIL_MASK
113         *
114         *  On exit:
115         *    g1 = old psr (to user)
116         */
117
118.align 32                               ! Align to 32-byte cache-line
119        PUBLIC(syscall_irqdis_fp)
120
121SYM(syscall_irqdis_fp):
122        /*
123         * We cannot use an intermediate value for operations with the PSR[EF]
124         * bit since they use a 13-bit sign extension and PSR[EF] is bit 12.
125         */
126        sethi   %hi(SPARC_PSR_EF_MASK), %l4
127
128        andn    %l3, %l4, %l3                   ! Clear PSR[EF]
129        and     %g1, %l4, %g1                   ! Select PSR[EF] only from %g1
130        or      %l3, %g1, %l3                   ! Set PSR[EF] according to %g1
131        mov     %l3, %psr                       ! Set PSR. Write delay 3 instr
132        or      %l0, SPARC_PSR_ET_MASK, %g1     ! return old PSR with ET=1
133        nop                                     ! PSR write delay
134        jmp     %l2                             ! Return to after TA 9.
135         rett   %l2 + 4
136#endif
137
138#if defined(SPARC_USE_LAZY_FP_SWITCH)
139
140        /*
141         *  system call - Perform a lazy floating point switch
142         *
143         *  On entry:
144         *
145         *    l0 = psr (from trap table)
146         *    l1 = pc
147         *    l2 = npc
148         *    l3 = SPARC_PSR_EF_MASK
149         */
150
151.align 32                               ! Align to 32-byte cache-line
152        PUBLIC(syscall_lazy_fp_switch)
153
154SYM(syscall_lazy_fp_switch):
155        ld      [%g6 + PER_CPU_OFFSET_EXECUTING], %l4
156        ld      [%g6 + PER_CPU_ISR_NEST_LEVEL], %l5
157        ld      [%l4 + %lo(SPARC_THREAD_CONTROL_FP_CONTEXT_OFFSET)], %l6
158        ld      [%g6 + SPARC_PER_CPU_FP_OWNER_OFFSET], %l7
159
160        /* Ensure that we are not in interrupt context */
161        cmp     %l5, 0
162        bne     .Lillegal_use_of_floating_point_unit
163         or     %l0, %l3, %l0
164
165        /* Ensure that we are a proper floating point thread */
166        cmp     %l6, 0
167        be      .Lillegal_use_of_floating_point_unit
168         ld     [%l4 + %lo(SPARC_THREAD_CONTROL_REGISTERS_FP_CONTEXT_OFFSET)], %l6
169
170        /* Set PSR[EF] to 1, PSR write delay 3 instructions! */
171        mov     %l0, %psr
172
173        /*
174         * Check if there is a floating point owner.  We have to check this
175         * here, since the floating point owner may have been deleted in the
176         * meantime.  Save the floating point context if necessary.
177         */
178        cmp     %l7, 0
179        be      .Lfp_save_done
180         nop
181        ld      [%l7 + %lo(SPARC_THREAD_CONTROL_FP_CONTEXT_OFFSET)], %l5
182        std     %f0, [%l5 + SPARC_FP_CONTEXT_OFFSET_F0_F1]
183        SPARC_LEON3FT_B2BST_NOP
184        std     %f2, [%l5 + SPARC_FP_CONTEXT_OFFSET_F2_F3]
185        SPARC_LEON3FT_B2BST_NOP
186        std     %f4, [%l5 + SPARC_FP_CONTEXT_OFFSET_F4_F5]
187        SPARC_LEON3FT_B2BST_NOP
188        std     %f6, [%l5 + SPARC_FP_CONTEXT_OFFSET_F6_F7]
189        SPARC_LEON3FT_B2BST_NOP
190        std     %f8, [%l5 + SPARC_FP_CONTEXT_OFFSET_F8_F9]
191        SPARC_LEON3FT_B2BST_NOP
192        std     %f10, [%l5 + SPARC_FP_CONTEXT_OFFSET_F10_F11]
193        SPARC_LEON3FT_B2BST_NOP
194        std     %f12, [%l5 + SPARC_FP_CONTEXT_OFFSET_F12_F13]
195        SPARC_LEON3FT_B2BST_NOP
196        std     %f14, [%l5 + SPARC_FP_CONTEXT_OFFSET_F14_F15]
197        SPARC_LEON3FT_B2BST_NOP
198        std     %f16, [%l5 + SPARC_FP_CONTEXT_OFFSET_F16_F17]
199        SPARC_LEON3FT_B2BST_NOP
200        std     %f18, [%l5 + SPARC_FP_CONTEXT_OFFSET_F18_F19]
201        SPARC_LEON3FT_B2BST_NOP
202        std     %f20, [%l5 + SPARC_FP_CONTEXT_OFFSET_F20_F21]
203        SPARC_LEON3FT_B2BST_NOP
204        std     %f22, [%l5 + SPARC_FP_CONTEXT_OFFSET_F22_F23]
205        SPARC_LEON3FT_B2BST_NOP
206        std     %f24, [%l5 + SPARC_FP_CONTEXT_OFFSET_F24_F25]
207        SPARC_LEON3FT_B2BST_NOP
208        std     %f26, [%l5 + SPARC_FP_CONTEXT_OFFSET_F26_F27]
209        SPARC_LEON3FT_B2BST_NOP
210        std     %f28, [%l5 + SPARC_FP_CONTEXT_OFFSET_F28_F29]
211        SPARC_LEON3FT_B2BST_NOP
212        std     %f30, [%l5 + SPARC_FP_CONTEXT_OFFSET_F30_F31]
213        SPARC_LEON3FT_B2BST_NOP
214        st      %fsr, [%l5 + SPARC_FP_CONTEXT_OFFSET_FSR]
215        SPARC_LEON3FT_B2BST_NOP
216        st      %g0, [%g6 + SPARC_PER_CPU_FP_OWNER_OFFSET]
217        SPARC_LEON3FT_B2BST_NOP
218        st      %l5, [%l7 + %lo(SPARC_THREAD_CONTROL_REGISTERS_FP_CONTEXT_OFFSET)]
219
220.Lfp_save_done:
221
222        /* Restore the floating point context if necessary */
223        cmp     %l6, 0
224        be      .Lfp_restore_done
225         st     %g0, [%l4 + %lo(SPARC_THREAD_CONTROL_REGISTERS_FP_CONTEXT_OFFSET)]
226        ldd     [%l6 + SPARC_FP_CONTEXT_OFFSET_F0_F1], %f0
227        ldd     [%l6 + SPARC_FP_CONTEXT_OFFSET_F2_F3], %f2
228        ldd     [%l6 + SPARC_FP_CONTEXT_OFFSET_F4_F5], %f4
229        ldd     [%l6 + SPARC_FP_CONTEXT_OFFSET_F6_F7], %f6
230        ldd     [%l6 + SPARC_FP_CONTEXT_OFFSET_F8_F9], %f8
231        ldd     [%l6 + SPARC_FP_CONTEXT_OFFSET_F10_F11], %f10
232        ldd     [%l6 + SPARC_FP_CONTEXT_OFFSET_F12_F13], %f12
233        ldd     [%l6 + SPARC_FP_CONTEXT_OFFSET_F14_F15], %f14
234        ldd     [%l6 + SPARC_FP_CONTEXT_OFFSET_F16_F17], %f16
235        ldd     [%l6 + SPARC_FP_CONTEXT_OFFSET_F18_F19], %f18
236        ldd     [%l6 + SPARC_FP_CONTEXT_OFFSET_F20_F21], %f20
237        ldd     [%l6 + SPARC_FP_CONTEXT_OFFSET_F22_F23], %f22
238        ldd     [%l6 + SPARC_FP_CONTEXT_OFFSET_F24_F25], %f24
239        ldd     [%l6 + SPARC_FP_CONTEXT_OFFSET_F26_F27], %f26
240        ldd     [%l6 + SPARC_FP_CONTEXT_OFFSET_F28_F29], %f28
241        ldd     [%l6 + SPARC_FP_CONTEXT_OFFSET_F30_F31], %f30
242        ld      [%l6 + SPARC_FP_CONTEXT_OFFSET_FSR], %fsr
243
244.Lfp_restore_done:
245
246        /* Now, retry the floating point instruction with PSR[EF] == 1 */
247        jmp     %l1
248         rett   %l1 + 4
249
250.Lillegal_use_of_floating_point_unit:
251
252        sethi   %hi(_Internal_error), %l1
253        or      %l1, %lo(_Internal_error), %l1
254        mov     38, %i0
255        jmp     %l1
256         rett   %l1 + 4
257#endif
258
259#if defined(RTEMS_PARAVIRT)
260
261        PUBLIC(_SPARC_Get_PSR)
262
263SYM(_SPARC_Get_PSR):
264
265        retl
266         rd     %psr, %o0
267
268        PUBLIC(_SPARC_Set_PSR)
269
270SYM(_SPARC_Set_PSR):
271
272        mov     %o0, %psr
273        nop
274        nop
275        nop
276        retl
277         nop
278
279        PUBLIC(_SPARC_Get_TBR)
280
281SYM(_SPARC_Get_TBR):
282
283        retl
284         rd    %tbr, %o0
285
286        PUBLIC(_SPARC_Set_TBR)
287
288SYM(_SPARC_Set_TBR):
289
290        retl
291         wr    %o0, 0, %tbr
292
293#endif /* defined(RTEMS_PARAVIRT) */
294
295/* end of file */
Note: See TracBrowser for help on using the repository browser.