source: rtems/cpukit/score/cpu/sparc/syscall.S @ a3818705

Last change on this file since a3818705 was a3818705, checked in by Maksim E. Kozlov <maksim.e.kozlov@…>, on Jun 5, 2019 at 7:22:36 PM

sparc: Fix missed restoring of PSR in syscall_lazy_fp_switch

It is needed to restore PSR just before return because condition
codes are dirty after the CMP instructions and this may cause
undefined program behavior after returning from the switching
procedure (on following branch instruction, for example).

Close #3756.

  • Property mode set to 100644
File size: 7.4 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        st      %g0, [%g6 + SPARC_PER_CPU_FP_OWNER_OFFSET]
216        st      %l5, [%l7 + %lo(SPARC_THREAD_CONTROL_REGISTERS_FP_CONTEXT_OFFSET)]
217
218.Lfp_save_done:
219
220        /* Restore the floating point context if necessary */
221        cmp     %l6, 0
222        be      .Lfp_restore_done
223         st     %g0, [%l4 + %lo(SPARC_THREAD_CONTROL_REGISTERS_FP_CONTEXT_OFFSET)]
224        ldd     [%l6 + SPARC_FP_CONTEXT_OFFSET_F0_F1], %f0
225        ldd     [%l6 + SPARC_FP_CONTEXT_OFFSET_F2_F3], %f2
226        ldd     [%l6 + SPARC_FP_CONTEXT_OFFSET_F4_F5], %f4
227        ldd     [%l6 + SPARC_FP_CONTEXT_OFFSET_F6_F7], %f6
228        ldd     [%l6 + SPARC_FP_CONTEXT_OFFSET_F8_F9], %f8
229        ldd     [%l6 + SPARC_FP_CONTEXT_OFFSET_F10_F11], %f10
230        ldd     [%l6 + SPARC_FP_CONTEXT_OFFSET_F12_F13], %f12
231        ldd     [%l6 + SPARC_FP_CONTEXT_OFFSET_F14_F15], %f14
232        ldd     [%l6 + SPARC_FP_CONTEXT_OFFSET_F16_F17], %f16
233        ldd     [%l6 + SPARC_FP_CONTEXT_OFFSET_F18_F19], %f18
234        ldd     [%l6 + SPARC_FP_CONTEXT_OFFSET_F20_F21], %f20
235        ldd     [%l6 + SPARC_FP_CONTEXT_OFFSET_F22_F23], %f22
236        ldd     [%l6 + SPARC_FP_CONTEXT_OFFSET_F24_F25], %f24
237        ldd     [%l6 + SPARC_FP_CONTEXT_OFFSET_F26_F27], %f26
238        ldd     [%l6 + SPARC_FP_CONTEXT_OFFSET_F28_F29], %f28
239        ldd     [%l6 + SPARC_FP_CONTEXT_OFFSET_F30_F31], %f30
240        ld      [%l6 + SPARC_FP_CONTEXT_OFFSET_FSR], %fsr
241
242.Lfp_restore_done:
243
244        /*
245         * Restore condition codes.  PSR[EF] is 1 here.  Take PSR write delay
246         * into account (maximum is three instructions).
247         */
248        mov     %l0, %psr
249        nop
250
251        /* Now, retry the floating point instruction with PSR[EF] == 1 */
252        jmp     %l1
253         rett   %l2
254
255.Lillegal_use_of_floating_point_unit:
256
257        /*
258         * There is no need to restore the condition codes here, since
259         * _Internal_error() does not return.
260         */
261        sethi   %hi(_Internal_error), %l1
262        or      %l1, %lo(_Internal_error), %l1
263        mov     38, %i0
264        jmp     %l1
265         rett   %l1 + 4
266#endif
267
268#if defined(RTEMS_PARAVIRT)
269
270        PUBLIC(_SPARC_Get_PSR)
271
272SYM(_SPARC_Get_PSR):
273
274        retl
275         rd     %psr, %o0
276
277        PUBLIC(_SPARC_Set_PSR)
278
279SYM(_SPARC_Set_PSR):
280
281        mov     %o0, %psr
282        nop
283        nop
284        nop
285        retl
286         nop
287
288        PUBLIC(_SPARC_Get_TBR)
289
290SYM(_SPARC_Get_TBR):
291
292        retl
293         rd    %tbr, %o0
294
295        PUBLIC(_SPARC_Set_TBR)
296
297SYM(_SPARC_Set_TBR):
298
299        retl
300         wr    %o0, 0, %tbr
301
302#endif /* defined(RTEMS_PARAVIRT) */
303
304/* end of file */
Note: See TracBrowser for help on using the repository browser.