1 /*=============================================================================
5 // SPARC HAL context init function
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####
46 // Purpose: HAL context initialization function
47 // Description: Initialize a HAL context for SPARC; this is in C and out
48 // of line because there is too much of it for a simple macro.
50 //####DESCRIPTIONEND####
52 //===========================================================================*/
54 #include <pkgconf/hal.h>
56 #include <cyg/hal/hal_arch.h> // HAL header
58 #include <cyg/infra/cyg_type.h>
60 #include <cyg/hal/vectors.h> // SAVE_REGS_SIZE, __WINSIZE, ...
62 /*---------------------------------------------------------------------------*/
64 /* We lay out the stack in the manner that the PCS demands:
65 * frame pointer -----> [top of stack]
66 * Argument spill area (6 words)
68 * Initial saved register window (i[8], l[8])
69 * for use by program when it starts
70 * [rest of] saved register object (various)
71 * stack pointer -----> saved register window (i[8], l[8])
72 * to allow us to be interrupted.
74 * ie. frame pointer ->
75 * struct HAL_FrameStructure
76 * stack pointer -> struct HAL_SavedRegisters
78 * and when the context "resumes" sp is incremented by 40 * 4, the size of
79 * a _struct HAL_SavedRegisters_ which points it at the extant but unused
80 * _struct HAL_FrameStructure_ as the PCS requires. The frame pointer is
81 * left pointing off the top of stack.
84 * Thus the stack is the same if created from an already executing context:
86 * frame pointer ----->
87 * [temporaries and locals]
89 * Argument spill area (6 words)
91 * [sp at entry]------> Previous saved register window (i[8], l[8])
92 * for use by program when it starts
93 * [rest of] saved register object (various)
94 * stack pointer -----> saved register window (i[8], l[8])
95 * to allow us to be interrupted.
99 hal_thread_init_context( CYG_WORD sparg,
104 register CYG_WORD fp = sparg;
105 register CYG_WORD sp = 0;
106 register HAL_SavedRegisters *regs;
107 register HAL_FrameStructure *frame;
110 if ( 0 == (id & 0xffff0000) )
113 fp &= ~15; // round down to double alignment
115 frame = (HAL_FrameStructure *)(
116 fp - sizeof( HAL_FrameStructure ) );
118 regs = (HAL_SavedRegisters *)(
119 ((CYG_WORD)frame) - sizeof(HAL_SavedRegisters) );
123 for ( i = 0; i < 6; i++ ) {
124 frame->spill_args[i] = id | 0xa0 | i;
126 frame->composite_return_ptr = 0;
128 for ( i = 0; i < 8; i++ ) {
129 frame->li.i[i] = id | ( 56 + i );
130 frame->li.l[i] = id | ( 48 + i );
131 regs ->li.i[i] = id | ( 24 + i );
132 regs ->li.l[i] = id | ( 16 + i );
133 regs ->o[i] = id | ( 8 + i );
134 regs ->g[i] = id | ( i );
137 // first terminate the linked list on the stack in the initial
138 // (already saved) register window:
139 frame->li.i[6] = regs->li.i[6] = (cyg_uint32)fp; // frame pointer
140 frame->li.i[7] = regs->li.i[7] = (cyg_uint32)0; // no ret addr here
142 // and set up other saved regs as if called from just before
144 regs->o[7] = (entry - 8);
147 // this is the argument that the entry point is called with
150 // this is the initial CWP and interrupt state; CWP is quite arbitrary
151 // really, the WIM is set up accordingly in hal_thread_load_context().
153 regs->g[0] = 0x0e0 + __WIN_INIT; // PIL zero, ET, S, PS and CWP set.
155 return (CYG_ADDRESS)sp;
158 // ---------------------------------------------------------------------------
160 //#define THREAD_DEBUG_SERIAL_VERBOSE
162 #ifdef THREAD_DEBUG_SERIAL_VERBOSE // NOT INCLUDED
164 // This is unpleasant to try to debug, because these routines are called
165 // WHEN THE PROGRAM IS NOT RUNNING from the CygMon's GDB stubs - so you
166 // can't use any normal output: these little routines use the serial
167 // line directly, so are best used when debugging via Ethernet, so you
168 // just have a separate output stream to read. Nasty...
170 #include <cyg/hal/hal_diag.h>
172 #undef HAL_DIAG_WRITE_CHAR
173 #define HAL_DIAG_WRITE_CHAR(_c_) CYG_MACRO_START \
175 HAL_DIAG_WRITE_CHAR_DIRECT( _c_ ); \
178 static void swritec( char c )
180 HAL_DIAG_WRITE_CHAR( c );
183 static void swrites( char *s )
186 while ( 0 != (c = *s++) )
187 HAL_DIAG_WRITE_CHAR( c );
190 static void swritex( cyg_uint32 x )
194 for ( i = 28; i >= 0; i-= 4 ) {
195 char c = "0123456789abcdef"[ 0xf & (x >> i) ];
196 HAL_DIAG_WRITE_CHAR( c );
200 #define newline() swrites( "\n\r" )
202 static void x8( char *s, unsigned long *xp )
205 for ( i = 0; i < 8; i++ ) {
217 #endif // THREAD_DEBUG_SERIAL_VERBOSE ... NOT INCLUDED
219 // ---------------------------------------------------------------------------
220 // Routines in icontext.c used here because they're quite large for
221 // the SPARC (note param order); these are used in talking to GDB.
223 enum regnames {G0 = 0, G1, G2, G3, G4, G5, G6, G7,
224 O0, O1, O2, O3, O4, O5, SP, O7,
225 L0, L1, L2, L3, L4, L5, L6, L7,
226 I0, I1, I2, I3, I4, I5, FP, I7,
228 F0, F1, F2, F3, F4, F5, F6, F7,
229 F8, F9, F10, F11, F12, F13, F14, F15,
230 F16, F17, F18, F19, F20, F21, F22, F23,
231 F24, F25, F26, F27, F28, F29, F30, F31,
232 Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR};
234 typedef unsigned long target_register_t;
237 cyg_hal_sparc_get_gdb_regs( void *gdb_regset,
238 HAL_SavedRegisters *eCos_regset )
240 target_register_t *gdb = (target_register_t *)gdb_regset;
242 cyg_uint32 scratch = 0;
244 HAL_SavedWindow *trapli, *ctxli;
246 if ( 0 == eCos_regset->g[0] ||
247 0xc0 == (0xe0 & eCos_regset->g[0]) ) {
248 // Then it's an interrupt stack saved state:
249 // (either minimal, or a saved PSR with traps disabled)
250 // The saved register set is pretty minimal, so we have to grub
251 // around in the stack to find out some truth...
252 sptrap = (cyg_uint32 *)eCos_regset; // point to the IL save area for
253 sptrap -= 24; // the trap handler, for PC, NPC
254 trapli = (HAL_SavedWindow *)sptrap; // Get at those regs
256 ctxli = (HAL_SavedWindow *)(trapli->i[6]); // (the frame pointer)
257 // and get at the interruptee's regs
259 // Pick up interruptee's registers from all over the stack:
260 for ( reg = 0; reg < 8 ; reg++ ) {
261 gdb[ G0 + reg ] = eCos_regset->g[reg];
262 gdb[ O0 + reg ] = trapli->i[reg];
263 gdb[ L0 + reg ] = ctxli->l[reg];
264 gdb[ I0 + reg ] = ctxli->i[reg];
267 // Clear out G0 which is always 0 (but abused in eCos_regset)
268 // and the FP regs which we do not have:
270 for ( reg = F0; reg <= F31; reg++ )
273 // In the save context _of the trap handler_ registers are as follows:
274 // %l0 = psr (with this CWP/window-level in it)
277 // %l3 = vector number (1-15 for interrupts)
278 // %l4 = Y register preserved
279 gdb[ Y ] = trapli->l[4];
281 scratch = trapli->l[0]; // the PSR in the trap handler
283 scratch++; // back to interupted thread's window
284 scratch &=~ 0x38; // clear ET and any __WINSIZE overflow
285 gdb[ PSR ] = scratch;
286 gdb[ WIM ] = 1 << ((__WINBITS & (1 + scratch)));
287 #else // 6 or 7 windows only
288 reg = (int)(scratch & __WINBITS);
289 scratch &=~ (__WINBITS_MAXIMAL | 0x20); // clear ET and CWP
290 if ( __WINSIZE <= ++reg ) reg = 0; // back to intr'd window
291 gdb[ PSR ] = scratch | reg;
292 if ( __WINSIZE <= ++reg ) reg = 0; // good index for WIM
293 gdb[ WIM ] = 1 << reg;
296 // Read _a_ TBR value and ignore the current trap details:
297 asm volatile ( "rd %%tbr, %0" : "=r"(scratch) : );
298 gdb[ TBR ] = (scratch &~ 0xfff);
300 gdb[ PC ] = trapli->l[1];
301 gdb[ NPC ] = trapli->l[2];
306 #ifdef THREAD_DEBUG_SERIAL_VERBOSE
308 swrites( "-----------------------------------------------------" ); newline();
309 swrites( "-------------- INTERRUPT STACK GET ------------------" ); newline();
310 swrites( "eCos regset at " ); swritex( eCos_regset ); newline();
311 swrites( " trapli " ); swritex( trapli ); newline();
312 swrites( " ctxli " ); swritex( ctxli ); newline();
313 x8( "global ", &(gdb[G0]) );
314 x8( " in ", &(gdb[I0]) );
315 x8( " local ", &(gdb[L0]) );
316 x8( " out ", &(gdb[O0]) );
317 swrites( "gdb PC = " ); swritex( gdb[ PC ] ); newline();
318 swrites( "gdb NPC = " ); swritex( gdb[ NPC ] ); newline();
319 swrites( "gdb PSR = " ); swritex( gdb[ PSR ] ); newline();
324 // It's a synchronous context switch that led to this object.
325 // Pick up interruptee's registers from the saved context:
326 for ( reg = 0; reg < 8 ; reg++ ) {
327 #ifdef CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM
331 gdb[ G0 + reg ] = eCos_regset->g[reg];
332 gdb[ O0 + reg ] = eCos_regset->o[reg];
334 gdb[ L0 + reg ] = eCos_regset->li.l[reg];
335 gdb[ I0 + reg ] = eCos_regset->li.i[reg];
338 #ifdef CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM
339 // Set up the stack pointer by arithmetic and the return address
340 gdb[ SP ] = ((cyg_uint32)(eCos_regset));
341 gdb[ O7 ] = eCos_regset->o[ 7 ];
343 // Clear out G0 which is always 0 (but abused in eCos_regset)
346 // and clear the FP regs which we do not have:
347 for ( reg = F0; reg <= F31; reg++ )
350 gdb[ Y ] = 0; // it's not preserved.
352 scratch = eCos_regset->g[ 0 ]; // the PSR in the saved context
353 gdb[ PSR ] = scratch; // return it verbatim.
355 gdb[ WIM ] = 1 << ((__WINBITS & (1 + scratch)));
356 #else // 6 or 7 windows only
357 reg = (int)(scratch & __WINBITS);
358 if ( __WINSIZE <= ++reg ) reg = 0; // good index for WIM
359 gdb[ WIM ] = 1 << reg;
362 // Read _a_ TBR value and ignore the current trap details:
363 asm volatile ( "rd %%tbr, %0" : "=r"(scratch) : );
364 gdb[ TBR ] = (scratch &~ 0xfff);
366 gdb[ PC ] = eCos_regset->o[ 7 ]; // the return address
367 gdb[ NPC ] = 4 + gdb[ PC ];
372 #ifdef THREAD_DEBUG_SERIAL_VERBOSE
374 swrites( "-----------------------------------------------------" ); newline();
375 swrites( "-------------- SYNCHRONOUS SWITCH GET----------------" ); newline();
376 swrites( "eCos regset at " ); swritex( eCos_regset ); newline();
377 x8( "global ", &(gdb[G0]) );
378 x8( " in ", &(gdb[I0]) );
379 x8( " local ", &(gdb[L0]) );
380 x8( " out ", &(gdb[O0]) );
381 swrites( "gdb PC = " ); swritex( gdb[ PC ] ); newline();
382 swrites( "gdb NPC = " ); swritex( gdb[ NPC ] ); newline();
383 swrites( "gdb PSR = " ); swritex( gdb[ PSR ] ); newline();
389 // ---------------------------------------------------------------------------
392 cyg_hal_sparc_set_gdb_regs( HAL_SavedRegisters *eCos_regset,
395 target_register_t *gdb = (target_register_t *)gdb_regset;
397 cyg_uint32 scratch = 0;
399 HAL_SavedWindow *trapli, *ctxli;
401 // Guess where the eCos register set really is:
402 if ( 0 == eCos_regset->g[0] ||
403 0xc0 == (0xe0 & eCos_regset->g[0]) ) {
404 // Then it's an interrupt stack saved state:
405 // (either minimal, or a saved PSR with traps disabled)
406 // The saved register set is pretty minimal, so we have to grub
407 // around in the stack to find out some truth...
408 sptrap = (cyg_uint32 *)eCos_regset; // point to the IL save area for
409 sptrap -= 24; // the trap handler, for PC, NPC
410 trapli = (HAL_SavedWindow *)sptrap; // Get at those regs
412 ctxli = (HAL_SavedWindow *)(trapli->i[6]); // (the frame pointer)
413 // and get at the interruptee's regs
415 scratch = eCos_regset->g[0];
417 // Put back interruptee's registers all over the stack:
418 for ( reg = 0; reg < 8 ; reg++ ) {
419 eCos_regset->g[reg] = gdb[ G0 + reg ] ;
420 trapli->i[reg] = gdb[ O0 + reg ] ;
421 ctxli->l[reg] = gdb[ L0 + reg ] ;
422 ctxli->i[reg] = gdb[ I0 + reg ] ;
425 // Put back the eCos G0 which is always 0 (but abused in eCos_regset)
426 eCos_regset->g[0] = scratch;
428 // In the save context _of the trap handler_ registers are as follows:
429 // %l0 = psr (with this CWP/window-level in it)
432 // %l3 = vector number (1-15 for interrupts)
433 // %l4 = Y register preserved
434 trapli->l[4] = gdb[ Y ];
436 // I am *not* interfering with the saved PSR, nor the TBR nor WIM.
438 // put back return PC and NPC
439 trapli->l[1] = gdb[ PC ] ;
440 trapli->l[2] = gdb[ NPC ];
442 #ifdef THREAD_DEBUG_SERIAL_VERBOSE
444 swrites( "-----------------------------------------------------" ); newline();
445 swrites( "-------------- INTERRUPT STACK SET ------------------" ); newline();
446 swrites( "eCos regset at " ); swritex( eCos_regset ); newline();
447 swrites( " trapli " ); swritex( trapli ); newline();
448 swrites( " ctxli " ); swritex( ctxli ); newline();
449 x8( "global ", &(gdb[G0]) );
450 x8( " in ", &(gdb[I0]) );
451 x8( " local ", &(gdb[L0]) );
452 x8( " out ", &(gdb[O0]) );
453 swrites( "gdb PC = " ); swritex( gdb[ PC ] ); newline();
454 swrites( "gdb NPC = " ); swritex( gdb[ NPC ] ); newline();
455 swrites( "gdb PSR = " ); swritex( gdb[ PSR ] ); newline();
460 // It's a synchronous context switch that led to this object.
461 // Pick up interruptee's registers from the saved context:
463 scratch = eCos_regset->g[0];
465 for ( reg = 0; reg < 8 ; reg++ ) {
466 eCos_regset->g[reg] = gdb[ G0 + reg ];
467 eCos_regset->o[reg] = gdb[ O0 + reg ];
468 eCos_regset->li.l[reg] = gdb[ L0 + reg ];
469 eCos_regset->li.i[reg] = gdb[ I0 + reg ];
472 // Put back the eCos G0 which is always 0 (but abused in eCos_regset)
473 eCos_regset->g[0] = scratch;
475 // I am *not* interfering with the saved PSR, nor the TBR nor WIM.
477 // The PC is in o7, altering it via GDB's PC is not on.
478 // Setting the NPC in a voluntary context is meaningless.
480 #ifdef THREAD_DEBUG_SERIAL_VERBOSE
482 swrites( "-----------------------------------------------------" ); newline();
483 swrites( "-------------- SYNCHRONOUS SWITCH SET ---------------" ); newline();
484 swrites( "eCos regset at " ); swritex( eCos_regset ); newline();
485 x8( "global ", &(gdb[G0]) );
486 x8( " in ", &(gdb[I0]) );
487 x8( " local ", &(gdb[L0]) );
488 x8( " out ", &(gdb[O0]) );
489 swrites( "gdb PC = " ); swritex( gdb[ PC ] ); newline();
490 swrites( "gdb NPC = " ); swritex( gdb[ NPC ] ); newline();
491 swrites( "gdb PSR = " ); swritex( gdb[ PSR ] ); newline();
497 /*---------------------------------------------------------------------------*/