source: rtems/c/src/lib/libcpu/sparc/reg_win/window.S @ 2f8704b6

5
Last change on this file since 2f8704b6 was 2f8704b6, checked in by Daniel Cederman <cederman@…>, on Jul 13, 2017 at 7:26:50 AM

sparc: Add assembly workaround for LEON3FT B2BST errata

This patch adds NOP instructions to prevent instruction sequences
that are sensitive to the LEON3FT B2BST errata. See GRLIB-TN-0009:
"LEON3FT Stale Cache Entry After Store with Data Tag Parity Error"
for more information.

The sequences are only modified if FIX_LEON3FT_B2BST is defined.

The patch works in conjunction with the -mfix-ut700, -mfix-gr712rc,
and -mfix-ut699 GCC flags that prevents the sensitive sequences from
being generated.

Update #3057.

  • Property mode set to 100644
File size: 8.4 KB
Line 
1/*
2 *  window.s
3 *
4 *  This file contains the register window management routines for the
5 *  SPARC architecture.  Trap handlers for the following capabilities
6 *  are included in this file:
7 *
8 *    + Window Overflow
9 *    + Window Underflow
10 *    + Flushing All Windows
11 *
12 *  COPYRIGHT:
13 *
14 *  This file includes the window overflow and underflow handlers from
15 *  the file srt0.s provided with the binary distribution of the SPARC
16 *  Instruction Simulator (SIS) found at
17 *  ftp://ftp.estec.esa.nl/pub/ws/wsd/erc32.
18 *
19 *  COPYRIGHT (c) 1995. European Space Agency.
20 *
21 *  This terms of the RTEMS license apply to this file.
22 */
23
24#include <rtems/asm.h>
25
26        .section    ".text"
27        /*
28         *  Window overflow trap handler.
29         *
30         *  On entry:
31         *
32         *    prev regwin l1 = pc
33         *    prev regwin l2 = npc
34         */
35
36        PUBLIC(window_overflow_trap_handler)
37
38SYM(window_overflow_trap_handler):
39
40        /*
41         *  Calculate new WIM by "rotating" the valid bits in the WIM right
42         *  by one position.  The following shows how the bits move for a SPARC
43         *  cpu implementation where SPARC_NUMBER_OF_REGISTER_WINDOWS is 8.
44         *
45         *    OLD WIM = 76543210
46         *    NEW WIM = 07654321
47         *
48         *  NOTE: New WIM must be stored in a global register since the
49         *        "save" instruction just prior to the load of the wim
50         *        register will result in the local register set changing.
51         */
52
53        std  %l0, [%sp + 0x00]           ! save local register set
54        SPARC_LEON3FT_B2BST_NOP
55        std  %l2, [%sp + 0x08]
56        mov  %wim, %l3
57        sll  %l3, SPARC_NUMBER_OF_REGISTER_WINDOWS-1 , %l2
58                                         ! l2  = WIM << (Number Windows - 1)
59        std  %l4, [%sp + 0x10]
60        SPARC_LEON3FT_B2BST_NOP
61        std  %l6, [%sp + 0x18]
62        srl  %l3, 1, %l3                 ! l3  = WIM >> 1
63        wr   %l3, %l2, %wim              ! WIM = (WIM >> 1) ^
64                                         !       (WIM << (Number Windows - 1))
65                                         ! 3 instruction delay not needed here
66        std  %i0, [%sp + 0x20]           ! save input register set
67        SPARC_LEON3FT_B2BST_NOP
68        std  %i2, [%sp + 0x28]
69        SPARC_LEON3FT_B2BST_NOP
70        std  %i4, [%sp + 0x30]
71        SPARC_LEON3FT_B2BST_NOP
72        std  %i6, [%sp + 0x38]
73        restore                          ! Go back to trap window.
74        jmp  %l1                         ! Re-execute save.
75         rett %l2
76
77        /*
78         *  Window underflow trap handler.
79         *
80         *  On entry:
81         *
82         *    l1 = pc
83         *    l2 = npc
84         *    l3 = wim (from trap vector)
85         *    l4 = wim << 1 (from trap vector)
86         */
87
88        PUBLIC(window_underflow_trap_handler)
89
90SYM(window_underflow_trap_handler):
91
92        /*
93         *  Calculate new WIM by "rotating" the valid bits in the WIM left
94         *  by one position.  The following shows how the bits move for a SPARC
95         *  cpu implementation where SPARC_NUMBER_OF_REGISTER_WINDOWS is 8.
96         *
97         *    OLD WIM = 76543210
98         *    NEW WIM = 07654321
99         *
100         *  NOTE: New WIM must be stored in a global register since the
101         *        "save" instruction just prior to the load of the wim
102         *        register will result in the local register set changing.
103         */
104
105        srl  %l3, SPARC_NUMBER_OF_REGISTER_WINDOWS-1, %l5
106        or   %l5, %l4, %l5              ! l5 = (WIM << 1) |
107                                        !      (WIM >> (Number Windows-1))
108        mov  %l5, %wim                  ! load the new WIM
109        nop; nop; nop                   ! 3 slot delay
110        restore                         ! Two restores to get into the
111        restore                         ! window to restore
112        ldd  [%sp + 0x00], %l0          ! First the local register set
113        ldd  [%sp + 0x08], %l2
114        ldd  [%sp + 0x10], %l4
115        ldd  [%sp + 0x18], %l6
116        ldd  [%sp + 0x20], %i0          ! Then the input registers
117        ldd  [%sp + 0x28], %i2
118        ldd  [%sp + 0x30], %i4
119        ldd  [%sp + 0x38], %i6
120        save                            ! Get back to the trap window.
121        save
122        jmp  %l1                        ! Re-execute restore.
123         rett  %l2
124
125        /*
126         *  Flush All Windows trap handler.
127         *
128         *  Flush all windows with valid contents except the current one
129         *  and the one we will be returning to.
130         *
131         *  In examining the set register windows, one may logically divide
132         *  the windows into sets (some of which may be empty) based on their
133         *  current status:
134         *
135         *    + current (i.e. in use),
136         *    + used (i.e. a restore would not trap)
137         *    + invalid (i.e. 1 in corresponding bit in WIM)
138         *    + unused
139         *
140         *  Either the used or unused set of windows may be empty.
141         *
142         *  NOTE: We assume only one bit is set in the WIM at a time.
143         *
144         *  Given a CWP of 5 and a WIM of 0x1, the registers are divided
145         *  into sets as follows:
146         *
147         *    + 0   - invalid
148         *    + 1-4 - unused
149         *    + 5   - current
150         *    + 6-7 - used
151         *
152         *  In this case, we only would save the used windows which we
153         *  will not be returning to -- 6.
154         *
155         *    Register Usage while saving the windows:
156         *      g1 = current PSR
157         *      g2 = current wim
158         *      g3 = CWP
159         *      g4 = wim scratch
160         *      g5 = scratch
161         *
162         *  On entry:
163         *
164         *    l0 = psr (from trap table)
165         *    l1 = pc
166         *    l2 = npc
167         */
168
169        PUBLIC(window_flush_trap_handler)
170
171SYM(window_flush_trap_handler):
172        /*
173         *  Save the global registers we will be using
174         */
175
176        mov     %g1, %l3
177        mov     %g2, %l4
178        mov     %g3, %l5
179        mov     %g4, %l6
180        mov     %g5, %l7
181
182        mov     %l0, %g1                      ! g1 = psr
183        mov     %wim, %g2                     ! g2 = wim
184        and     %l0, SPARC_PSR_CWP_MASK, %g3  ! g3 = CWP
185
186        add     %g3, 1, %g5                   ! g5 = CWP + 1
187        and     %g5, SPARC_NUMBER_OF_REGISTER_WINDOWS - 1, %g5
188
189        mov     1, %g4
190        sll     %g4, %g5, %g4                 ! g4 = WIM mask for CWP+1 invalid
191
192        restore                               ! go back one register window
193
194save_frame_loop:
195        sll     %g4, 1, %g5                   ! rotate the "wim" left 1
196        srl     %g4, SPARC_NUMBER_OF_REGISTER_WINDOWS - 1, %g4
197        or      %g4, %g5, %g4                 ! g4 = wim if we do one restore
198
199        /*
200         *  If a restore would not underflow, then continue.
201         */
202
203        andcc   %g4, %g2, %g0                 ! Any windows to flush?
204        bnz     done_flushing                 ! No, then continue
205        nop
206
207        restore                               ! back one window
208
209        /*
210         *  Now save the window just as if we overflowed to it.
211         */
212
213        std     %l0, [%sp + CPU_STACK_FRAME_L0_OFFSET]
214        SPARC_LEON3FT_B2BST_NOP
215        std     %l2, [%sp + CPU_STACK_FRAME_L2_OFFSET]
216        SPARC_LEON3FT_B2BST_NOP
217        std     %l4, [%sp + CPU_STACK_FRAME_L4_OFFSET]
218        SPARC_LEON3FT_B2BST_NOP
219        std     %l6, [%sp + CPU_STACK_FRAME_L6_OFFSET]
220        SPARC_LEON3FT_B2BST_NOP
221
222        std     %i0, [%sp + CPU_STACK_FRAME_I0_OFFSET]
223        SPARC_LEON3FT_B2BST_NOP
224        std     %i2, [%sp + CPU_STACK_FRAME_I2_OFFSET]
225        SPARC_LEON3FT_B2BST_NOP
226        std     %i4, [%sp + CPU_STACK_FRAME_I4_OFFSET]
227        SPARC_LEON3FT_B2BST_NOP
228        std     %i6, [%sp + CPU_STACK_FRAME_I6_FP_OFFSET]
229
230        ba      save_frame_loop
231        nop
232
233done_flushing:
234
235        add     %g3, 2, %g3                   ! calculate desired WIM
236        and     %g3, SPARC_NUMBER_OF_REGISTER_WINDOWS - 1, %g3
237        mov     1, %g4
238        sll     %g4, %g3, %g4                 ! g4 = new WIM
239        mov     %g4, %wim
240
241        mov     %g1, %psr                     ! restore PSR
242        nop
243        nop
244        nop
245
246        /*
247         *  Restore the global registers we used
248         */
249
250        mov     %l3, %g1
251        mov     %l4, %g2
252        mov     %l5, %g3
253        mov     %l6, %g4
254        mov     %l7, %g5
255
256        jmpl    %l2, %g0
257        rett    %l2 + 4
258
259/* end of file */
Note: See TracBrowser for help on using the repository browser.