]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/hal/sparclite/arch/v2_0/src/context.S
Initial revision
[karo-tx-redboot.git] / packages / hal / sparclite / arch / v2_0 / src / context.S
1 /*=============================================================================
2 //
3 //      context.S
4 //
5 //      SPARClite context switch code
6 //
7 //=============================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //=============================================================================
41 //#####DESCRIPTIONBEGIN####
42 //
43 // Author(s):   nickg, gthomas, hmt
44 // Contributors:        nickg, gthomas, hmt
45 // Date:        1998-12-15
46 // Purpose:     SPARClite context switch code
47 // Description: This file contains implementations of the thread context 
48 //              switch routines. It also contains the longjmp() and setjmp()
49 //              routines.
50 //
51 //####DESCRIPTIONEND####
52 //
53 //===========================================================================*/
54
55 #include <pkgconf/hal.h>
56
57 #include <cyg/hal/vectors.h>
58         
59 #define DELAYS_AFTER_WRPSR_SAME_WINDOW
60 #define DELAYS_AFTER_WRWIM
61
62         .text
63
64 ! ------------------------------------------------------------------------------
65 !  hal_thread_switch_context
66 !  Switch thread contexts
67 !  %o0 = address of sp of next thread to execute
68 !  %o1 = address of sp save location of current thread
69
70         .global hal_thread_switch_context
71 hal_thread_switch_context:      
72
73         ! First take the stack down to make room for the saved register
74         ! state, including a window save area at the base.  Leave the
75         ! current window save area undisturbed.  It is unused within the
76         ! save but will become current again when we continue in this
77         ! context.  This lets us do this whole piece of work without
78         ! diabling interrupts for too long, since, for example, we can
79         ! lower the stack atomically with one instruction:
80         sub     %sp, SAVE_REGS_SIZE, %sp
81         st      %sp, [ %o1 ]            ! return SP for this thread
82                         
83         std     %l0, [%sp + 0 * 4]      ! save L & I registers
84         std     %l2, [%sp + 2 * 4]
85         std     %l4, [%sp + 4 * 4]
86         std     %l6, [%sp + 6 * 4]
87
88         std     %i0, [%sp + 8 * 4]
89         std     %i2, [%sp + 10 * 4]
90         std     %i4, [%sp + 12 * 4]
91         std     %i6, [%sp + 14 * 4]
92                 
93 #ifdef CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM
94         st      %o7, [%sp + 31 * 4]     ! save only the return address
95         ! and no need to preserve %o0 even though it is restored
96 #else // save a maximal context
97         st      %g1, [%sp + 17 * 4]     ! save G & O registers
98         std     %g2, [%sp + 18 * 4]
99         std     %g4, [%sp + 20 * 4]
100         std     %g6, [%sp + 22 * 4]
101
102         std     %o0, [%sp + 24 * 4]
103         std     %o2, [%sp + 26 * 4]
104         std     %o4, [%sp + 28 * 4]
105         std     %o6, [%sp + 30 * 4]
106 #endif // !CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM
107         ! and save the CWP in %g0 save place
108         rd      %psr, %g7
109         st      %g7, [%sp + 16 * 4]
110         
111         ! Now load the destination thread by dropping through
112         ! to hal_thread_load_context
113         
114 ! ------------------------------------------------------------------------------
115 !  hal_thread_load_context
116 !  Load thread context
117 !  %o0 = address of sp of next thread to execute
118 !  Note that this function is also the second half of hal_thread_switch_context
119 !  and is simply dropped into from it.
120
121         .global hal_thread_load_context
122 hal_thread_load_context:
123
124         ! Here, we are a leaf routine but with slightly odd properties.
125         ! The stack is still the callers at this point but the register
126         ! set is up for grabs.  So we can use globals:
127         
128         ld      [ %o0 ], %g7            ! Get the next saved SP
129         
130         ! DISABLE INTERRUPTS *ONLY* NOT TRAPS
131         rd      %psr, %g6
132         or      %g6, 0xfe0, %g5         ! PIL up to 15 leave traps enabled
133         wr      %g5, %psr
134         
135         ! force out all our callers register sets onto the stack
136         ! if necessary: the system will handily take care of this for
137         ! us as follows:
138         save    %sp, -16 * 4, %sp       ! need all these to preserve
139         save    %sp, -16 * 4, %sp       ! the linked list property...
140         save    %sp, -16 * 4, %sp
141         save    %sp, -16 * 4, %sp
142 #if 6 < __WINSIZE
143         save    %sp, -16 * 4, %sp
144 #if 7 < __WINSIZE
145         save    %sp, -16 * 4, %sp
146 #endif
147 #endif
148         ! Fewer saves if fewer register windows.  For 8 register windows,
149         ! six of these is correct; a seventh would force out the current
150         ! set that was already saved manually above.  Note that minimal
151         ! space is allowed on stack for locals and ins in case this
152         ! sequence itself gets interrupted and recurses too deep.
153         
154         ! now select the new window with traps disabled...
155
156         ! get the new PSR and CWP that we will ultimately restore
157         ! from the %g0 save place...
158         ld      [%g7 + 16 * 4], %g6     ! %g7 holds the new stack pointer
159         andn    %g6, 0x20, %g5          ! clear ET into %g5
160         and     %g6, __WINBITS, %g4     ! CWP bits only in %g4
161                 
162         ! calculate a new WIM...
163         add     %g4, 1, %g3             ! required invalid window number
164 #if 8 == __WINSIZE
165         and     %g3, __WINBITS, %g3     ! modulo 8
166 #else   // expect 5 or 6 or 7 windows
167         cmp     %g3, __WINSIZE
168         bge,a   567f                    ! taken: do delay slot, handle overflow
169          mov    0, %g3                  ! only if .ge. above
170 567:    
171 #endif
172         mov     1, %g2
173         sll     %g2, %g3, %g2           ! converted to a mask for the WIM
174
175         ! DISABLE INTERRUPTS (TRAPS)
176         wr      %g5, %psr               ! set CWP to new window, disable traps
177         wr      %g2, %wim               ! and WIM to new value
178         nop
179         nop
180         nop
181                 
182         ! Must do this atomically so that the registers match the stack.
183         ! After locals and ins are loaded, we are conformant to the PCS
184         ! so can re-enable interrupts.
185         mov     %g7, %sp                ! target sp in situ (%sp = %o6)
186
187         ldd     [%sp + 0 * 4], %l0      ! restore L & I registers
188         ldd     [%sp + 2 * 4], %l2
189         ldd     [%sp + 4 * 4], %l4
190         ldd     [%sp + 6 * 4], %l6
191
192         ldd     [%sp + 8 * 4], %i0
193         ldd     [%sp + 10 * 4], %i2
194         ldd     [%sp + 12 * 4], %i4
195         ldd     [%sp + 14 * 4], %i6
196
197         ! RESTORE INTERRUPTS to saved state
198         wr      %g6, %psr               ! set new CWP and old ET and PIL
199         nop
200         nop
201         nop
202         
203         ! now load the rest of the context; we can be interrupted here
204         ! (if the saved context was a voluntary yield or threadstart)
205         ! but that is OK, other state will be preserved in that case...
206
207 #ifdef CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM
208         ld      [%sp + 24 * 4], %o0     ! must load the initial argument
209 #else // restore a maximal context
210         ld      [%sp + 17 * 4], %g1
211         ldd     [%sp + 18 * 4], %g2
212         ldd     [%sp + 20 * 4], %g4
213         ldd     [%sp + 22 * 4], %g6
214
215         ldd     [%sp + 24 * 4], %o0
216         ldd     [%sp + 26 * 4], %o2
217         ldd     [%sp + 28 * 4], %o4
218 #endif // !CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM
219                                         ! %o6 = %sp, already set up
220         ld      [%sp + 31 * 4], %o7     ! "return" address
221
222         retl
223         add     %sp, SAVE_REGS_SIZE, %sp ! and set the stack back
224                                         ! to its entrant value
225
226 ! ------------------------------------------------------------------------------
227 !  HAL longjmp, setjmp implementations
228
229 !FUNC_START(hal_setjmp)
230         .global hal_setjmp
231 hal_setjmp:
232         ! Treat this as a leaf routine, may as well.
233         ! %o0 is the address of the buffer.
234
235         std     %l0, [%o0 + 0 * 4]      ! save L & I registers
236         std     %l2, [%o0 + 2 * 4]
237         std     %l4, [%o0 + 4 * 4]
238         std     %l6, [%o0 + 6 * 4]
239
240         std     %i0, [%o0 + 8 * 4]
241         std     %i2, [%o0 + 10 * 4]
242         std     %i4, [%o0 + 12 * 4]
243         std     %i6, [%o0 + 14 * 4]
244                 
245 #ifdef CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM
246         std     %o6, [%o0 + 30 * 4]     ! just save %sp and return address
247 #else // save a maximal context
248         st      %g1, [%o0 + 17 * 4]     ! save G & O registers
249         std     %g2, [%o0 + 18 * 4]
250         std     %g4, [%o0 + 20 * 4]
251         std     %g6, [%o0 + 22 * 4]
252
253         std     %o0, [%o0 + 24 * 4]
254         std     %o2, [%o0 + 26 * 4]
255         std     %o4, [%o0 + 28 * 4]
256         std     %o6, [%o0 + 30 * 4]
257 #endif // !CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM
258         
259         ! and save the CWP in %g0 save place
260         rd      %psr, %g7
261         st      %g7, [%o0 + 16 * 4]
262
263         ! DISABLE INTERRUPTS *ONLY* NOT TRAPS
264         or      %g7, 0xfe0, %g6         ! PIL up to 15 leave traps enabled
265         wr      %g6, %psr
266         
267         ! force out all our callers register sets onto the stack
268         ! if necessary: the system will handily take care of this for
269         ! us as follows:
270         save    %sp, -16 * 4, %sp       ! need all these to preserve
271         save    %sp, -16 * 4, %sp       ! the linked list property...
272         save    %sp, -16 * 4, %sp
273         save    %sp, -16 * 4, %sp
274 #if 6 < __WINSIZE
275         save    %sp, -16 * 4, %sp
276 #if 7 < __WINSIZE
277         save    %sp, -16 * 4, %sp
278 #endif
279 #endif
280         ! Fewer saves if fewer register windows.  For 8 register windows,
281         ! six of these is correct; a seventh would force out the current
282         ! set that was already saved manually above.  Note that minimal
283         ! space is allowed on stack for locals and ins in case this
284         ! sequence itself gets interrupted and recurses too deep.
285
286         ! (after all, we are about to call deeper not shallower, otherwise
287         !  using setjmp is inappropriate)
288
289         ! ENABLE INTERRUPTS
290         wr      %g7, %psr               ! set CWP back to as-was
291         nop
292         nop
293         nop
294         
295 #ifndef CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM
296         ldd     [%o0 + 22 * 4], %g6     ! preserve %g7 and %g6
297 #endif
298         
299         retl                            ! ret and return zero to indicate
300         mov     0, %o0                  ! not longjumped-to
301         
302 !  hal_longjmp loads state from arg0 and returns arg1
303 !FUNC_START(hal_longjmp)
304         .global hal_longjmp
305 hal_longjmp:
306         ! This is kind of a leaf routine, it returns elsewhere
307         ! %o0 is the address of the buffer.
308         ! %o1 is the value to return in %o0 (since we are a leaf)
309
310         mov     %o0, %g7                ! keep the pointer handy
311         mov     %o1, %g1                ! and the return value
312         ! now select the new window with traps disabled...
313         rd      %psr, %g6
314                                         ! preserve ET, clear CWP
315         andn    %g6, __WINBITS_MAXIMAL, %g6
316         andn    %g6, 0x20, %g5          ! clear ET also into %g5
317
318         ! get new CWP from %g0 save place...
319         ld      [%g7 + 16 * 4], %g4     ! %g7 holds the new stack pointer
320         and     %g4, __WINBITS, %g4     ! preserve CWP bits
321                 
322         ! calculate a new WIM...
323         add     %g4, 1, %g3             ! required invalid window number
324 #if 8 == __WINSIZE
325         and     %g3, __WINBITS, %g3     ! modulo 8
326 #else   // expect 5 or 6 or 7 windows
327         cmp     %g3, __WINSIZE
328         bge,a   567f                    ! taken: do delay slot, handle overflow
329          mov    0, %g3                  ! only if .ge. above
330 567:    
331 #endif
332         mov     1, %g2
333         sll     %g2, %g3, %g2           ! converted to a mask for the WIM
334
335         ! DISABLE INTERRUPTS
336         wr      %g5, %g4, %psr          ! set CWP to new window, disable traps
337         wr      %g2, %wim               ! and WIM to new value
338         nop
339         nop
340         nop
341                 
342         ! Must do this atomically so that the registers match the stack.
343         ! After locals and ins are loaded, we are conformant to the PCS
344         ! so can re-enable interrupts.
345
346         ldd     [%g7 + 0 * 4], %l0      ! restore L & I registers
347         ldd     [%g7 + 2 * 4], %l2
348         ldd     [%g7 + 4 * 4], %l4
349         ldd     [%g7 + 6 * 4], %l6
350
351         ldd     [%g7 + 8 * 4], %i0
352         ldd     [%g7 + 10 * 4], %i2
353         ldd     [%g7 + 12 * 4], %i4
354         ldd     [%g7 + 14 * 4], %i6
355
356         ld      [%g7 + 30 * 4], %sp     ! %o6 = %sp, set up now so as to conform
357                                         ! to PCS and so be interruptible
358         ! ENABLE INTERRUPTS
359         wr      %g6, %g4, %psr          ! set new CWP and old ET
360         nop
361         nop
362         nop
363         
364         ! now load the rest of the context; we can be interrupted here, but
365         ! that is OK, other state will be preserved in that case...
366 #ifdef CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM
367         ! we are not preserving globals...
368                                         ! %o6 = %sp, already set up
369         ld      [%g7 + 31 * 4], %o7     ! "return" address
370         retl                            ! %g1 still holds the return value
371         mov     %g1, %o0
372
373 #else // load a maximal context
374         mov     %g7, %o0                ! original pointer was in %o0 anyway
375
376         ldd     [%o0 + 18 * 4], %g2
377         ldd     [%o0 + 20 * 4], %g4
378         ldd     [%o0 + 22 * 4], %g6
379
380         ld      [%o0 + 25 * 4], %o1     ! %o0 = original pointer
381         ldd     [%o0 + 26 * 4], %o2
382         ldd     [%o0 + 28 * 4], %o4
383                                         ! %o6 = %sp, already set up
384         ld      [%o0 + 31 * 4], %o7     ! "return" address
385
386         ! %g1 still holds the return value; want to get this into %o0
387         ! and restore %g1 from the saved state;  %o0 is the state pointer:
388                                         ! g1 = R,   o0 = P
389         xor     %o0, %g1, %g1           ! g1 = R^P, o0 = P
390         xor     %o0, %g1, %o0           ! g1 = R^P, o0 = R
391         xor     %o0, %g1, %g1           ! g1 = P,   o0 = R all done
392                 
393         retl
394         ld      [%g1 + 17 * 4], %g1     ! and finally restore %g1
395 #endif // !CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM
396         
397 ! ------------------------------------------------------------------------------
398 ! end of context.S
399
400
401