source: rtems/cpukit/score/cpu/sparc/sparc-context-validate.S @ 146adb1

Last change on this file since 146adb1 was 146adb1, checked in by Sebastian Huber <sebastian.huber@…>, on Jul 17, 2017 at 5:30:46 AM

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: 8.7 KB
Line 
1/*
2 * Copyright (c) 2015, 2017 embedded brains GmbH.  All rights reserved.
3 *
4 *  embedded brains GmbH
5 *  Dornierstr. 4
6 *  82178 Puchheim
7 *  Germany
8 *  <rtems@embedded-brains.de>
9 *
10 * The license and distribution terms for this file may be
11 * found in the file LICENSE in this distribution or at
12 * http://www.rtems.org/license/LICENSE.
13 */
14
15#ifdef HAVE_CONFIG_H
16  #include "config.h"
17#endif
18
19#include <rtems/asm.h>
20#include <rtems/score/cpuimpl.h>
21#include <rtems/score/percpu.h>
22
23#define FRAME_OFFSET_BUFFER_0 (SPARC_MINIMUM_STACK_FRAME_SIZE)
24#define FRAME_OFFSET_BUFFER_1 (FRAME_OFFSET_BUFFER_0 + 0x04)
25#define FRAME_OFFSET_BUFFER_2 (FRAME_OFFSET_BUFFER_1 + 0x04)
26#define FRAME_OFFSET_L0 (FRAME_OFFSET_BUFFER_2 + 0x04)
27#define FRAME_OFFSET_L1 (FRAME_OFFSET_L0 + 0x04)
28#define FRAME_OFFSET_L2 (FRAME_OFFSET_L1 + 0x04)
29#define FRAME_OFFSET_L3 (FRAME_OFFSET_L2 + 0x04)
30#define FRAME_OFFSET_L4 (FRAME_OFFSET_L3 + 0x04)
31#define FRAME_OFFSET_L5 (FRAME_OFFSET_L4 + 0x04)
32#define FRAME_OFFSET_L6 (FRAME_OFFSET_L5 + 0x04)
33#define FRAME_OFFSET_L7 (FRAME_OFFSET_L6 + 0x04)
34#define FRAME_OFFSET_I0 (FRAME_OFFSET_L7 + 0x04)
35#define FRAME_OFFSET_I1 (FRAME_OFFSET_I0 + 0x04)
36#define FRAME_OFFSET_I2 (FRAME_OFFSET_I1 + 0x04)
37#define FRAME_OFFSET_I3 (FRAME_OFFSET_I2 + 0x04)
38#define FRAME_OFFSET_I4 (FRAME_OFFSET_I3 + 0x04)
39#define FRAME_OFFSET_I5 (FRAME_OFFSET_I4 + 0x04)
40#define FRAME_OFFSET_I6 (FRAME_OFFSET_I5 + 0x04)
41#define FRAME_OFFSET_I7 (FRAME_OFFSET_I6 + 0x04)
42#define FRAME_END (FRAME_OFFSET_I7 + 0x04)
43#define FRAME_SIZE \
44  ((FRAME_END + CPU_STACK_ALIGNMENT - 1) & ~(CPU_STACK_ALIGNMENT - 1))
45
46.macro check_register reg
47        sub     %g1, 1, %g1
48        cmp     %g1, \reg
49        bne     restore_registers
50         nop
51.endm
52
53.macro check_float_register reg
54        sub     %g1, 1, %g1
55        st      \reg, [%sp + FRAME_OFFSET_BUFFER_0]
56        ld      [%sp + FRAME_OFFSET_BUFFER_0], %o1
57        cmp     %g1, %o1
58        bne     restore_registers
59         nop
60.endm
61
62.macro write_register reg
63        add     %g1, 1, %g1
64        mov     %g1, \reg
65.endm
66
67.macro write_float_register reg
68        add     %g1, 1, %g1
69        st      %g1, [%sp + FRAME_OFFSET_BUFFER_0]
70        ld      [%sp + FRAME_OFFSET_BUFFER_0], \reg
71.endm
72
73        .align 4
74        PUBLIC(_CPU_Context_validate)
75SYM(_CPU_Context_validate):
76
77        /* g2 indicates if the FPU should be checked */
78#if defined(SPARC_USE_LAZY_FP_SWITCH)
79        ld      [%g6 + PER_CPU_OFFSET_EXECUTING], %g2
80        ld      [%g2 + %lo(SPARC_THREAD_CONTROL_FP_CONTEXT_OFFSET)], %g2
81#else
82        mov     %psr, %g2
83        sethi   %hi(SPARC_PSR_EF_MASK), %g3
84        and     %g2, %g3, %g2
85#endif
86
87        /* g1 is used to save the original pattern */
88        mov     %o0, %g1
89
90        /* g4 establishes window counter */
91        clr     %g4
92
93        add     %sp, -FRAME_SIZE, %sp
94
95        st      %l0, [%sp + FRAME_OFFSET_L0]
96        st      %l1, [%sp + FRAME_OFFSET_L1]
97        st      %l2, [%sp + FRAME_OFFSET_L2]
98        st      %l3, [%sp + FRAME_OFFSET_L3]
99        st      %l4, [%sp + FRAME_OFFSET_L4]
100        st      %l5, [%sp + FRAME_OFFSET_L5]
101        st      %l6, [%sp + FRAME_OFFSET_L6]
102        st      %l7, [%sp + FRAME_OFFSET_L7]
103        st      %i0, [%sp + FRAME_OFFSET_I0]
104        st      %i1, [%sp + FRAME_OFFSET_I1]
105        st      %i2, [%sp + FRAME_OFFSET_I2]
106        st      %i3, [%sp + FRAME_OFFSET_I3]
107        st      %i4, [%sp + FRAME_OFFSET_I4]
108        st      %i5, [%sp + FRAME_OFFSET_I5]
109        st      %i6, [%sp + FRAME_OFFSET_I6]
110        st      %i7, [%sp + FRAME_OFFSET_I7]
111
112        cmp     %g4, 0
113        bne     write_locals_and_outputs
114         nop
115        be      check_for_fp
116         nop
117
118new_check_cycle:
119        clr     %g4
120        add     %g4, 1, %g4
121        ld      [%sp + FRAME_OFFSET_BUFFER_1], %g1
122        b       switch_to_next_window
123         nop
124        /* Write pattern values into registers */
125
126check_for_fp:
127        cmp     %g2, 0
128        be      write_y
129         nop
130
131        /*
132         * Write pattern to FSR.  FSR is masked with undefined, reserved or
133         * system-specific values (e.g. FPU architecture version, FP queue).
134         */
135        st      %fsr, [%sp + FRAME_OFFSET_BUFFER_0]
136        ld      [%sp + FRAME_OFFSET_BUFFER_0], %o1
137        add     %g1, 1, %g1
138        sethi   %hi(0xCF800000), %g3
139        or      %g3, %lo(0x0FFF), %g3
140        and     %g1, %g3, %g3
141        or      %o1, %g3, %g3
142        st      %g3, [%sp + FRAME_OFFSET_BUFFER_0]
143        ld      [%sp + FRAME_OFFSET_BUFFER_0], %fsr
144
145        write_float_register    %f0
146        write_float_register    %f1
147        write_float_register    %f2
148        write_float_register    %f3
149        write_float_register    %f4
150        write_float_register    %f5
151        write_float_register    %f6
152        write_float_register    %f7
153        write_float_register    %f8
154        write_float_register    %f9
155        write_float_register    %f10
156        write_float_register    %f11
157        write_float_register    %f12
158        write_float_register    %f13
159        write_float_register    %f14
160        write_float_register    %f15
161        write_float_register    %f16
162        write_float_register    %f17
163        write_float_register    %f18
164        write_float_register    %f19
165        write_float_register    %f20
166        write_float_register    %f21
167        write_float_register    %f22
168        write_float_register    %f23
169        write_float_register    %f24
170        write_float_register    %f25
171        write_float_register    %f26
172        write_float_register    %f27
173        write_float_register    %f28
174        write_float_register    %f29
175        write_float_register    %f30
176        write_float_register    %f31
177
178write_y:
179        write_register  %y
180
181        write_register  %i0
182        write_register  %i1
183        write_register  %i2
184        write_register  %i3
185        write_register  %i4
186        write_register  %i5
187        /* Don't write register $i6 => frame pointer */
188        /* Don't write register $i7 => return address */
189        b       write_locals_and_outputs
190         nop
191
192switch_to_next_window:
193        save    %sp, -FRAME_SIZE, %sp
194
195write_locals_and_outputs:
196        /* l0 is used as a scratch register */
197        write_register  %l1
198        write_register  %l2
199        write_register  %l3
200        write_register  %l4
201        write_register  %l5
202        write_register  %l6
203        write_register  %l7
204        write_register  %o1
205        write_register  %o2
206        write_register  %o3
207        write_register  %o4
208        write_register  %o5
209        /* Don't write register $o6 => stack pointer */
210        /* Don't write register $o7 => return address */
211
212        add     %g4, 1, %g4
213        cmp     %g4, 1
214        bne     no_store
215         nop
216        st      %g1, [%sp + FRAME_OFFSET_BUFFER_1]
217
218no_store:
219        cmp     %g4, SPARC_NUMBER_OF_REGISTER_WINDOWS
220        bne     switch_to_next_window
221         nop
222
223        /* Dummy increment to set up reverse mechanism for checking process */
224        add     %g1, 1, %g1
225        clr     %g4
226
227        /* Checking begins here */
228window_checking:
229        cmp     %g4, SPARC_NUMBER_OF_REGISTER_WINDOWS
230        be      y_checking
231         nop
232
233further_checking:
234        cmp     %g4, 0
235        bne     goto_local_registers
236         nop
237
238        /* Check normal registers */
239        check_register  %o5
240        check_register  %o4
241        check_register  %o3
242        check_register  %o2
243        check_register  %o1
244
245goto_local_registers:
246        check_register  %l7
247        check_register  %l6
248        check_register  %l5
249        check_register  %l4
250        check_register  %l3
251        check_register  %l2
252        check_register  %l1
253
254        check_register  %i5
255        check_register  %i4
256        check_register  %i3
257        check_register  %i2
258        check_register  %i1
259        /*
260        For the last window i0 also needs to be checked as this variable
261        is not overwritten by the outputs of another window.
262        */
263        add     %g4, 1, %g4
264        cmp     %g4, SPARC_NUMBER_OF_REGISTER_WINDOWS
265        bne     dont_check_i0
266         nop
267        check_register  %i0
268        b       y_checking
269         nop
270
271dont_check_i0:
272        restore
273
274        ba      window_checking
275         nop
276
277        /* Check Y register */
278y_checking:
279        st      %o1, [%sp + FRAME_OFFSET_BUFFER_2]
280        mov     %y, %o1
281        check_register  %o1
282        ld      [%sp + FRAME_OFFSET_BUFFER_2], %o1
283        cmp     %g2, 0
284        be      new_check_cycle
285         nop
286
287        st      %o1, [%sp + FRAME_OFFSET_BUFFER_2]
288        SPARC_LEON3FT_B2BST_NOP
289        /* Check floating point registers */
290        check_float_register    %f31
291        check_float_register    %f30
292        check_float_register    %f29
293        check_float_register    %f28
294        check_float_register    %f27
295        check_float_register    %f26
296        check_float_register    %f25
297        check_float_register    %f24
298        check_float_register    %f23
299        check_float_register    %f22
300        check_float_register    %f21
301        check_float_register    %f20
302        check_float_register    %f19
303        check_float_register    %f18
304        check_float_register    %f17
305        check_float_register    %f16
306        check_float_register    %f15
307        check_float_register    %f14
308        check_float_register    %f13
309        check_float_register    %f12
310        check_float_register    %f11
311        check_float_register    %f10
312        check_float_register    %f9
313        check_float_register    %f8
314        check_float_register    %f7
315        check_float_register    %f6
316        check_float_register    %f5
317        check_float_register    %f4
318        check_float_register    %f3
319        check_float_register    %f2
320        check_float_register    %f1
321        check_float_register    %f0
322
323        st      %fsr, [%sp + FRAME_OFFSET_BUFFER_0]
324        ld      [%sp + FRAME_OFFSET_BUFFER_0], %o1
325        sub     %g1, 1, %g1
326        clr     %g3
327        sethi   %hi(0xCF800000), %g3
328        or      %g3, %lo(0x0FFF), %g3
329        and     %g1, %g3, %g3
330        and     %o1, %g3, %o1
331        cmp     %o1, %g3
332        bne     restore_registers
333         ld     [%sp + FRAME_OFFSET_BUFFER_2], %o1
334
335        b       new_check_cycle
336         nop
337
338        /****** RESTORE STARTS HERE *******/
339
340        /* Restore non-volatile registers */
341
342restore_registers:
343        and     %g4, (SPARC_NUMBER_OF_REGISTER_WINDOWS - 1), %g4
344        cmp     %g4, 0
345        be      real_restore
346         nop
347        restore
348        sub     %g4, 1, %g4
349        bne     restore_registers
350         nop
351
352real_restore:
353        ld      [%sp + FRAME_OFFSET_L0], %l0
354        ld      [%sp + FRAME_OFFSET_L1], %l1
355        ld      [%sp + FRAME_OFFSET_L2], %l2
356        ld      [%sp + FRAME_OFFSET_L3], %l3
357        ld      [%sp + FRAME_OFFSET_L4], %l4
358        ld      [%sp + FRAME_OFFSET_L5], %l5
359        ld      [%sp + FRAME_OFFSET_L6], %l6
360        ld      [%sp + FRAME_OFFSET_L7], %l7
361        ld      [%sp + FRAME_OFFSET_I0], %i0
362        ld      [%sp + FRAME_OFFSET_I1], %i1
363        ld      [%sp + FRAME_OFFSET_I2], %i2
364        ld      [%sp + FRAME_OFFSET_I3], %i3
365        ld      [%sp + FRAME_OFFSET_I4], %i4
366        ld      [%sp + FRAME_OFFSET_I5], %i5
367        ld      [%sp + FRAME_OFFSET_I6], %i6
368        ld      [%sp + FRAME_OFFSET_I7], %i7
369
370        sub     %sp, -FRAME_SIZE, %sp
371
372return_value:
373        /* Load callback address and jump back */
374        jmp     %o7 + 8
375         add    %sp, FRAME_SIZE, %sp
Note: See TracBrowser for help on using the repository browser.