|
2
|
1 /*============================================================================= |
|
|
2 // |
|
|
3 // context.S |
|
|
4 // |
|
|
5 // SPARClite context switch code |
|
|
6 // |
|
|
7 //============================================================================= |
|
|
8 //####COPYRIGHTBEGIN#### |
|
|
9 // |
|
|
10 // ------------------------------------------- |
|
|
11 // The contents of this file are subject to the Cygnus eCos Public License |
|
|
12 // Version 1.0 (the "License"); you may not use this file except in |
|
|
13 // compliance with the License. You may obtain a copy of the License at |
|
|
14 // http://sourceware.cygnus.com/ecos |
|
|
15 // |
|
|
16 // Software distributed under the License is distributed on an "AS IS" |
|
|
17 // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the |
|
|
18 // License for the specific language governing rights and limitations under |
|
|
19 // the License. |
|
|
20 // |
|
|
21 // The Original Code is eCos - Embedded Cygnus Operating System, released |
|
|
22 // September 30, 1998. |
|
|
23 // |
|
|
24 // The Initial Developer of the Original Code is Cygnus. Portions created |
|
|
25 // by Cygnus are Copyright (C) 1998,1999 Cygnus Solutions. All Rights Reserved. |
|
|
26 // ------------------------------------------- |
|
|
27 // |
|
|
28 //###COPYRIGHTEND#### |
|
|
29 //============================================================================= |
|
|
30 //#####DESCRIPTIONBEGIN#### |
|
|
31 // |
|
|
32 // Author(s): nickg, gthomas, hmt |
|
|
33 // Contributors: nickg, gthomas, hmt |
|
|
34 // Date: 1998-12-15 |
|
|
35 // Purpose: SPARClite context switch code |
|
|
36 // Description: This file contains implementations of the thread context |
|
|
37 // switch routines. It also contains the longjmp() and setjmp() |
|
|
38 // routines. |
|
|
39 // |
|
|
40 //####DESCRIPTIONEND#### |
|
|
41 // |
|
|
42 //===========================================================================*/ |
|
|
43 |
|
|
44 #include <pkgconf/hal.h> |
|
|
45 |
|
|
46 #include <cyg/hal/vectors.h> |
|
|
47 |
|
|
48 #define DELAYS_AFTER_WRPSR_SAME_WINDOW |
|
|
49 #define DELAYS_AFTER_WRWIM |
|
|
50 |
|
|
51 .text |
|
|
52 |
|
|
53 ! ------------------------------------------------------------------------------ |
|
|
54 ! hal_thread_switch_context |
|
|
55 ! Switch thread contexts |
|
|
56 ! %o0 = address of sp of next thread to execute |
|
|
57 ! %o1 = address of sp save location of current thread |
|
|
58 |
|
|
59 .global hal_thread_switch_context |
|
|
60 hal_thread_switch_context: |
|
|
61 |
|
|
62 ! First take the stack down to make room for the saved register |
|
|
63 ! state, including a window save area at the base. Leave the |
|
|
64 ! current window save area undisturbed. It is unused within the |
|
|
65 ! save but will become current again when we continue in this |
|
|
66 ! context. This lets us do this whole piece of work without |
|
|
67 ! diabling interrupts for too long, since, for example, we can |
|
|
68 ! lower the stack atomically with one instruction: |
|
|
69 sub %sp, SAVE_REGS_SIZE, %sp |
|
|
70 st %sp, [ %o1 ] ! return SP for this thread |
|
|
71 |
|
|
72 std %l0, [%sp + 0 * 4] ! save L & I registers |
|
|
73 std %l2, [%sp + 2 * 4] |
|
|
74 std %l4, [%sp + 4 * 4] |
|
|
75 std %l6, [%sp + 6 * 4] |
|
|
76 |
|
|
77 std %i0, [%sp + 8 * 4] |
|
|
78 std %i2, [%sp + 10 * 4] |
|
|
79 std %i4, [%sp + 12 * 4] |
|
|
80 std %i6, [%sp + 14 * 4] |
|
|
81 |
|
|
82 #ifdef CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM |
|
|
83 st %o7, [%sp + 31 * 4] ! save only the return address |
|
|
84 ! and no need to preserve %o0 even though it is restored |
|
|
85 #else // save a maximal context |
|
|
86 st %g1, [%sp + 17 * 4] ! save G & O registers |
|
|
87 std %g2, [%sp + 18 * 4] |
|
|
88 std %g4, [%sp + 20 * 4] |
|
|
89 std %g6, [%sp + 22 * 4] |
|
|
90 |
|
|
91 std %o0, [%sp + 24 * 4] |
|
|
92 std %o2, [%sp + 26 * 4] |
|
|
93 std %o4, [%sp + 28 * 4] |
|
|
94 std %o6, [%sp + 30 * 4] |
|
|
95 #endif // !CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM |
|
|
96 ! and save the CWP in %g0 save place |
|
|
97 rd %psr, %g7 |
|
|
98 st %g7, [%sp + 16 * 4] |
|
|
99 |
|
|
100 ! Now load the destination thread by dropping through |
|
|
101 ! to hal_thread_load_context |
|
|
102 |
|
|
103 ! ------------------------------------------------------------------------------ |
|
|
104 ! hal_thread_load_context |
|
|
105 ! Load thread context |
|
|
106 ! %o0 = address of sp of next thread to execute |
|
|
107 ! Note that this function is also the second half of hal_thread_switch_context |
|
|
108 ! and is simply dropped into from it. |
|
|
109 |
|
|
110 .global hal_thread_load_context |
|
|
111 hal_thread_load_context: |
|
|
112 |
|
|
113 ! Here, we are a leaf routine but with slightly odd properties. |
|
|
114 ! The stack is still the callers at this point but the register |
|
|
115 ! set is up for grabs. So we can use globals: |
|
|
116 |
|
|
117 ld [ %o0 ], %g7 ! Get the next saved SP |
|
|
118 |
|
|
119 ! DISABLE INTERRUPTS *ONLY* NOT TRAPS |
|
|
120 rd %psr, %g6 |
|
|
121 or %g6, 0xfe0, %g5 ! PIL up to 15 leave traps enabled |
|
|
122 wr %g5, %psr |
|
|
123 |
|
|
124 ! force out all our callers register sets onto the stack |
|
|
125 ! if necessary: the system will handily take care of this for |
|
|
126 ! us as follows: |
|
|
127 save %sp, -16 * 4, %sp ! need all these to preserve |
|
|
128 save %sp, -16 * 4, %sp ! the linked list property... |
|
|
129 save %sp, -16 * 4, %sp |
|
|
130 save %sp, -16 * 4, %sp |
|
|
131 save %sp, -16 * 4, %sp |
|
|
132 save %sp, -16 * 4, %sp |
|
|
133 ! six of these is correct; a seventh would force out the current |
|
|
134 ! set that was already saved manually above. Note that minimal |
|
|
135 ! space is allowed on stack for locals and ins in case this |
|
|
136 ! sequence itself gets interrupted and recurses too deep. |
|
|
137 |
|
|
138 ! now select the new window with traps disabled... |
|
|
139 ! preserve ET, clear CWP |
|
|
140 andn %g6, __WINBITS_MAXIMAL, %g6 |
|
|
141 andn %g6, 0x20, %g5 ! clear ET also into %g5 |
|
|
142 |
|
|
143 ! get new CWP from %g0 save place... |
|
|
144 ld [%g7 + 16 * 4], %g4 ! %g7 holds the new stack pointer |
|
|
145 and %g4, __WINBITS, %g4 ! preserve CWP bits |
|
|
146 |
|
|
147 ! calculate a new WIM... |
|
|
148 add %g4, 1, %g3 ! required invalid window number |
|
|
149 and %g3, __WINBITS, %g3 ! modulo 8 |
|
|
150 mov 1, %g2 |
|
|
151 sll %g2, %g3, %g2 ! converted to a mask for the WIM |
|
|
152 |
|
|
153 ! DISABLE INTERRUPTS |
|
|
154 wr %g5, %g4, %psr ! set CWP to new window, disable traps |
|
|
155 wr %g2, %wim ! and WIM to new value |
|
|
156 nop |
|
|
157 nop |
|
|
158 nop |
|
|
159 |
|
|
160 ! Must do this atomically so that the registers match the stack. |
|
|
161 ! After locals and ins are loaded, we are conformant to the PCS |
|
|
162 ! so can re-enable interrupts. |
|
|
163 mov %g7, %sp ! target sp in situ (%sp = %o6) |
|
|
164 |
|
|
165 ldd [%sp + 0 * 4], %l0 ! restore L & I registers |
|
|
166 ldd [%sp + 2 * 4], %l2 |
|
|
167 ldd [%sp + 4 * 4], %l4 |
|
|
168 ldd [%sp + 6 * 4], %l6 |
|
|
169 |
|
|
170 ldd [%sp + 8 * 4], %i0 |
|
|
171 ldd [%sp + 10 * 4], %i2 |
|
|
172 ldd [%sp + 12 * 4], %i4 |
|
|
173 ldd [%sp + 14 * 4], %i6 |
|
|
174 |
|
|
175 ! ENABLE INTERRUPTS |
|
|
176 wr %g6, %g4, %psr ! set new CWP and old ET |
|
|
177 nop |
|
|
178 nop |
|
|
179 nop |
|
|
180 |
|
|
181 ! now load the rest of the context; we can be interrupted here, but |
|
|
182 ! that is OK, other state will be preserved in that case... |
|
|
183 |
|
|
184 #ifdef CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM |
|
|
185 ld [%sp + 24 * 4], %o0 ! must load the initial argument |
|
|
186 #else // restore a maximal context |
|
|
187 ld [%sp + 17 * 4], %g1 |
|
|
188 ldd [%sp + 18 * 4], %g2 |
|
|
189 ldd [%sp + 20 * 4], %g4 |
|
|
190 ldd [%sp + 22 * 4], %g6 |
|
|
191 |
|
|
192 ldd [%sp + 24 * 4], %o0 |
|
|
193 ldd [%sp + 26 * 4], %o2 |
|
|
194 ldd [%sp + 28 * 4], %o4 |
|
|
195 #endif // !CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM |
|
|
196 ! %o6 = %sp, already set up |
|
|
197 ld [%sp + 31 * 4], %o7 ! "return" address |
|
|
198 |
|
|
199 retl |
|
|
200 add %sp, SAVE_REGS_SIZE, %sp ! and set the stack back |
|
|
201 ! to its entrant value |
|
|
202 |
|
|
203 ! ------------------------------------------------------------------------------ |
|
|
204 ! HAL longjmp, setjmp implementations |
|
|
205 |
|
|
206 !FUNC_START(hal_setjmp) |
|
|
207 .global hal_setjmp |
|
|
208 hal_setjmp: |
|
|
209 ! Treat this as a leaf routine, may as well. |
|
|
210 ! %o0 is the address of the buffer. |
|
|
211 |
|
|
212 std %l0, [%o0 + 0 * 4] ! save L & I registers |
|
|
213 std %l2, [%o0 + 2 * 4] |
|
|
214 std %l4, [%o0 + 4 * 4] |
|
|
215 std %l6, [%o0 + 6 * 4] |
|
|
216 |
|
|
217 std %i0, [%o0 + 8 * 4] |
|
|
218 std %i2, [%o0 + 10 * 4] |
|
|
219 std %i4, [%o0 + 12 * 4] |
|
|
220 std %i6, [%o0 + 14 * 4] |
|
|
221 |
|
|
222 #ifdef CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM |
|
|
223 std %o6, [%o0 + 30 * 4] ! just save %sp and return address |
|
|
224 #else // save a maximal context |
|
|
225 st %g1, [%o0 + 17 * 4] ! save G & O registers |
|
|
226 std %g2, [%o0 + 18 * 4] |
|
|
227 std %g4, [%o0 + 20 * 4] |
|
|
228 std %g6, [%o0 + 22 * 4] |
|
|
229 |
|
|
230 std %o0, [%o0 + 24 * 4] |
|
|
231 std %o2, [%o0 + 26 * 4] |
|
|
232 std %o4, [%o0 + 28 * 4] |
|
|
233 std %o6, [%o0 + 30 * 4] |
|
|
234 #endif // !CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM |
|
|
235 |
|
|
236 ! and save the CWP in %g0 save place |
|
|
237 rd %psr, %g7 |
|
|
238 st %g7, [%o0 + 16 * 4] |
|
|
239 |
|
|
240 ! DISABLE INTERRUPTS *ONLY* NOT TRAPS |
|
|
241 or %g7, 0xfe0, %g6 ! PIL up to 15 leave traps enabled |
|
|
242 wr %g6, %psr |
|
|
243 |
|
|
244 ! force out all our callers register sets onto the stack |
|
|
245 ! if necessary: the system will handily take care of this for |
|
|
246 ! us as follows: |
|
|
247 save %sp, -16 * 4, %sp ! need all these to preserve |
|
|
248 save %sp, -16 * 4, %sp ! the linked list property... |
|
|
249 save %sp, -16 * 4, %sp |
|
|
250 save %sp, -16 * 4, %sp |
|
|
251 save %sp, -16 * 4, %sp |
|
|
252 save %sp, -16 * 4, %sp |
|
|
253 ! six of these is correct; a seventh would force out the current |
|
|
254 ! set that was already saved manually above. Note that minimal |
|
|
255 ! space is allowed on stack for locals and ins in case this |
|
|
256 ! sequence itself gets interrupted and recurses too deep. |
|
|
257 |
|
|
258 ! (after all, we are about to call deeper not shallower, otherwise |
|
|
259 ! using setjmp is inappropriate) |
|
|
260 |
|
|
261 ! ENABLE INTERRUPTS |
|
|
262 wr %g7, %psr ! set CWP back to as-was |
|
|
263 nop |
|
|
264 nop |
|
|
265 nop |
|
|
266 |
|
|
267 #ifndef CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM |
|
|
268 ldd [%o0 + 22 * 4], %g6 ! preserve %g7 and %g6 |
|
|
269 #endif |
|
|
270 |
|
|
271 retl ! ret and return zero to indicate |
|
|
272 mov 0, %o0 ! not longjumped-to |
|
|
273 |
|
|
274 ! hal_longjmp loads state from arg0 and returns arg1 |
|
|
275 !FUNC_START(hal_longjmp) |
|
|
276 .global hal_longjmp |
|
|
277 hal_longjmp: |
|
|
278 ! This is kind of a leaf routine, it returns elsewhere |
|
|
279 ! %o0 is the address of the buffer. |
|
|
280 ! %o1 is the value to return in %o0 (since we are a leaf) |
|
|
281 |
|
|
282 mov %o0, %g7 ! keep the pointer handy |
|
|
283 mov %o1, %g1 ! and the return value |
|
|
284 ! now select the new window with traps disabled... |
|
|
285 rd %psr, %g6 |
|
|
286 ! preserve ET, clear CWP |
|
|
287 andn %g6, __WINBITS_MAXIMAL, %g6 |
|
|
288 andn %g6, 0x20, %g5 ! clear ET also into %g5 |
|
|
289 |
|
|
290 ! get new CWP from %g0 save place... |
|
|
291 ld [%g7 + 16 * 4], %g4 ! %g7 holds the new stack pointer |
|
|
292 and %g4, __WINBITS, %g4 ! preserve CWP bits |
|
|
293 |
|
|
294 ! calculate a new WIM... |
|
|
295 add %g4, 1, %g3 ! required invalid window number |
|
|
296 and %g3, __WINBITS, %g3 ! modulo 8 |
|
|
297 mov 1, %g2 |
|
|
298 sll %g2, %g3, %g2 ! converted to a mask for the WIM |
|
|
299 |
|
|
300 ! DISABLE INTERRUPTS |
|
|
301 wr %g5, %g4, %psr ! set CWP to new window, disable traps |
|
|
302 wr %g2, %wim ! and WIM to new value |
|
|
303 nop |
|
|
304 nop |
|
|
305 nop |
|
|
306 |
|
|
307 ! Must do this atomically so that the registers match the stack. |
|
|
308 ! After locals and ins are loaded, we are conformant to the PCS |
|
|
309 ! so can re-enable interrupts. |
|
|
310 |
|
|
311 ldd [%g7 + 0 * 4], %l0 ! restore L & I registers |
|
|
312 ldd [%g7 + 2 * 4], %l2 |
|
|
313 ldd [%g7 + 4 * 4], %l4 |
|
|
314 ldd [%g7 + 6 * 4], %l6 |
|
|
315 |
|
|
316 ldd [%g7 + 8 * 4], %i0 |
|
|
317 ldd [%g7 + 10 * 4], %i2 |
|
|
318 ldd [%g7 + 12 * 4], %i4 |
|
|
319 ldd [%g7 + 14 * 4], %i6 |
|
|
320 |
|
|
321 ld [%g7 + 30 * 4], %sp ! %o6 = %sp, set up now so as to conform |
|
|
322 ! to PCS and so be interruptible |
|
|
323 ! ENABLE INTERRUPTS |
|
|
324 wr %g6, %g4, %psr ! set new CWP and old ET |
|
|
325 nop |
|
|
326 nop |
|
|
327 nop |
|
|
328 |
|
|
329 ! now load the rest of the context; we can be interrupted here, but |
|
|
330 ! that is OK, other state will be preserved in that case... |
|
|
331 #ifdef CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM |
|
|
332 ! we are not preserving globals... |
|
|
333 ! %o6 = %sp, already set up |
|
|
334 ld [%g7 + 31 * 4], %o7 ! "return" address |
|
|
335 retl ! %g1 still holds the return value |
|
|
336 mov %g1, %o0 |
|
|
337 |
|
|
338 #else // load a maximal context |
|
|
339 mov %g7, %o0 ! original pointer was in %o0 anyway |
|
|
340 |
|
|
341 ldd [%o0 + 18 * 4], %g2 |
|
|
342 ldd [%o0 + 20 * 4], %g4 |
|
|
343 ldd [%o0 + 22 * 4], %g6 |
|
|
344 |
|
|
345 ld [%o0 + 25 * 4], %o1 ! %o0 = original pointer |
|
|
346 ldd [%o0 + 26 * 4], %o2 |
|
|
347 ldd [%o0 + 28 * 4], %o4 |
|
|
348 ! %o6 = %sp, already set up |
|
|
349 ld [%o0 + 31 * 4], %o7 ! "return" address |
|
|
350 |
|
|
351 ! %g1 still holds the return value; want to get this into %o0 |
|
|
352 ! and restore %g1 from the saved state; %o0 is the state pointer: |
|
|
353 ! g1 = R, o0 = P |
|
|
354 xor %o0, %g1, %g1 ! g1 = R^P, o0 = P |
|
|
355 xor %o0, %g1, %o0 ! g1 = R^P, o0 = R |
|
|
356 xor %o0, %g1, %g1 ! g1 = P, o0 = R all done |
|
|
357 |
|
|
358 retl |
|
|
359 ld [%g1 + 17 * 4], %g1 ! and finally restore %g1 |
|
|
360 #endif // !CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM |
|
|
361 |
|
|
362 ! ------------------------------------------------------------------------------ |
|
|
363 ! end of context.S |
|
|
364 |
|
|
365 |
|
|
366 |