1 /*=============================================================================
5 // SPARClite context switch code
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.
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.
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
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.
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.
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.
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####
43 // Author(s): nickg, gthomas, hmt
44 // Contributors: nickg, gthomas, hmt
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()
51 //####DESCRIPTIONEND####
53 //===========================================================================*/
55 #include <pkgconf/hal.h>
57 #include <cyg/hal/vectors.h>
59 #define DELAYS_AFTER_WRPSR_SAME_WINDOW
60 #define DELAYS_AFTER_WRWIM
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
70 .global hal_thread_switch_context
71 hal_thread_switch_context:
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
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]
88 std %i0, [%sp + 8 * 4]
89 std %i2, [%sp + 10 * 4]
90 std %i4, [%sp + 12 * 4]
91 std %i6, [%sp + 14 * 4]
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]
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
109 st %g7, [%sp + 16 * 4]
111 ! Now load the destination thread by dropping through
112 ! to hal_thread_load_context
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.
121 .global hal_thread_load_context
122 hal_thread_load_context:
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:
128 ld [ %o0 ], %g7 ! Get the next saved SP
130 ! DISABLE INTERRUPTS *ONLY* NOT TRAPS
132 or %g6, 0xfe0, %g5 ! PIL up to 15 leave traps enabled
135 ! force out all our callers register sets onto the stack
136 ! if necessary: the system will handily take care of this for
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
143 save %sp, -16 * 4, %sp
145 save %sp, -16 * 4, %sp
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.
154 ! now select the new window with traps disabled...
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
162 ! calculate a new WIM...
163 add %g4, 1, %g3 ! required invalid window number
165 and %g3, __WINBITS, %g3 ! modulo 8
166 #else // expect 5 or 6 or 7 windows
168 bge,a 567f ! taken: do delay slot, handle overflow
169 mov 0, %g3 ! only if .ge. above
173 sll %g2, %g3, %g2 ! converted to a mask for the WIM
175 ! DISABLE INTERRUPTS (TRAPS)
176 wr %g5, %psr ! set CWP to new window, disable traps
177 wr %g2, %wim ! and WIM to new value
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)
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
192 ldd [%sp + 8 * 4], %i0
193 ldd [%sp + 10 * 4], %i2
194 ldd [%sp + 12 * 4], %i4
195 ldd [%sp + 14 * 4], %i6
197 ! RESTORE INTERRUPTS to saved state
198 wr %g6, %psr ! set new CWP and old ET and PIL
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...
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
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
223 add %sp, SAVE_REGS_SIZE, %sp ! and set the stack back
224 ! to its entrant value
226 ! ------------------------------------------------------------------------------
227 ! HAL longjmp, setjmp implementations
229 !FUNC_START(hal_setjmp)
232 ! Treat this as a leaf routine, may as well.
233 ! %o0 is the address of the buffer.
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]
240 std %i0, [%o0 + 8 * 4]
241 std %i2, [%o0 + 10 * 4]
242 std %i4, [%o0 + 12 * 4]
243 std %i6, [%o0 + 14 * 4]
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]
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
259 ! and save the CWP in %g0 save place
261 st %g7, [%o0 + 16 * 4]
263 ! DISABLE INTERRUPTS *ONLY* NOT TRAPS
264 or %g7, 0xfe0, %g6 ! PIL up to 15 leave traps enabled
267 ! force out all our callers register sets onto the stack
268 ! if necessary: the system will handily take care of this for
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
275 save %sp, -16 * 4, %sp
277 save %sp, -16 * 4, %sp
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.
286 ! (after all, we are about to call deeper not shallower, otherwise
287 ! using setjmp is inappropriate)
290 wr %g7, %psr ! set CWP back to as-was
295 #ifndef CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM
296 ldd [%o0 + 22 * 4], %g6 ! preserve %g7 and %g6
299 retl ! ret and return zero to indicate
300 mov 0, %o0 ! not longjumped-to
302 ! hal_longjmp loads state from arg0 and returns arg1
303 !FUNC_START(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)
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...
314 ! preserve ET, clear CWP
315 andn %g6, __WINBITS_MAXIMAL, %g6
316 andn %g6, 0x20, %g5 ! clear ET also into %g5
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
322 ! calculate a new WIM...
323 add %g4, 1, %g3 ! required invalid window number
325 and %g3, __WINBITS, %g3 ! modulo 8
326 #else // expect 5 or 6 or 7 windows
328 bge,a 567f ! taken: do delay slot, handle overflow
329 mov 0, %g3 ! only if .ge. above
333 sll %g2, %g3, %g2 ! converted to a mask for the WIM
336 wr %g5, %g4, %psr ! set CWP to new window, disable traps
337 wr %g2, %wim ! and WIM to new value
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.
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
351 ldd [%g7 + 8 * 4], %i0
352 ldd [%g7 + 10 * 4], %i2
353 ldd [%g7 + 12 * 4], %i4
354 ldd [%g7 + 14 * 4], %i6
356 ld [%g7 + 30 * 4], %sp ! %o6 = %sp, set up now so as to conform
357 ! to PCS and so be interruptible
359 wr %g6, %g4, %psr ! set new CWP and old ET
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
373 #else // load a maximal context
374 mov %g7, %o0 ! original pointer was in %o0 anyway
376 ldd [%o0 + 18 * 4], %g2
377 ldd [%o0 + 20 * 4], %g4
378 ldd [%o0 + 22 * 4], %g6
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
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:
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
394 ld [%g1 + 17 * 4], %g1 ! and finally restore %g1
395 #endif // !CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM
397 ! ------------------------------------------------------------------------------