]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/hal/sparc/arch/v2_0/src/icontext.c
Initial revision
[karo-tx-redboot.git] / packages / hal / sparc / arch / v2_0 / src / icontext.c
1 /*=============================================================================
2 //
3 //      icontext.c
4 //
5 //      SPARC HAL context init function
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):   hmt
44 // Contributors:        hmt
45 // Date:        1998-12-14
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.
49 //
50 //####DESCRIPTIONEND####
51 //
52 //===========================================================================*/
53
54 #include <pkgconf/hal.h>
55
56 #include <cyg/hal/hal_arch.h>           // HAL header
57
58 #include <cyg/infra/cyg_type.h>
59
60 #include <cyg/hal/vectors.h>            // SAVE_REGS_SIZE, __WINSIZE, ...
61
62 /*---------------------------------------------------------------------------*/
63
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)
67  *                             Return Arg pointer
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.
73  *
74  * ie.    frame pointer ->
75  *                          struct HAL_FrameStructure
76  *        stack pointer ->  struct HAL_SavedRegisters
77  *
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.
82  *
83  *
84  * Thus the stack is the same if created from an already executing context:
85  *
86  *        frame pointer -----> 
87  *                             [temporaries and locals]
88  *                             [more arguments]
89  *                             Argument spill area (6 words)
90  *                             Return Arg pointer
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.
96  */
97
98 CYG_ADDRESS
99 hal_thread_init_context(  CYG_WORD sparg,
100                           CYG_WORD thread,
101                           CYG_WORD entry,
102                           CYG_WORD id )
103 {
104     register CYG_WORD fp = sparg;
105     register CYG_WORD sp = 0;
106     register HAL_SavedRegisters *regs;
107     register HAL_FrameStructure *frame;
108     int i;
109
110     if ( 0 == (id & 0xffff0000) )
111         id <<= 16;
112
113     fp &= ~15;                          // round down to double alignment
114
115     frame = (HAL_FrameStructure *)(
116         fp - sizeof( HAL_FrameStructure ) );
117     
118     regs = (HAL_SavedRegisters *)(
119         ((CYG_WORD)frame) - sizeof(HAL_SavedRegisters) );
120
121     sp = (CYG_WORD)regs;
122     
123     for ( i = 0; i < 6; i++ ) {
124         frame->spill_args[i] = id | 0xa0 | i;
125     }    
126     frame->composite_return_ptr = 0;
127
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 );
135     }
136
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
141
142     // and set up other saved regs as if called from just before
143     // the entry point:
144     regs->o[7] = (entry - 8);
145     regs->o[6] = sp;
146
147     // this is the argument that the entry point is called with
148     regs->o[0] = thread;
149
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().
152
153     regs->g[0] = 0x0e0 + __WIN_INIT; // PIL zero, ET, S, PS and CWP set.
154
155     return (CYG_ADDRESS)sp;
156 }
157
158 // ---------------------------------------------------------------------------
159
160 //#define THREAD_DEBUG_SERIAL_VERBOSE
161
162 #ifdef THREAD_DEBUG_SERIAL_VERBOSE         // NOT INCLUDED
163
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...
169
170 #include <cyg/hal/hal_diag.h>
171
172 #undef  HAL_DIAG_WRITE_CHAR
173 #define HAL_DIAG_WRITE_CHAR(_c_) CYG_MACRO_START                    \
174     SLEB_LED = (_c_);                                               \
175     HAL_DIAG_WRITE_CHAR_DIRECT( _c_ );                              \
176 CYG_MACRO_END
177
178 static void swritec( char c )
179 {
180     HAL_DIAG_WRITE_CHAR( c );
181 }
182
183 static void swrites( char *s )
184 {
185     char c;
186     while ( 0 != (c = *s++) )
187         HAL_DIAG_WRITE_CHAR( c );
188 }
189
190 static void swritex( cyg_uint32 x )
191 {
192     int i;
193     swrites( "0x" );
194     for ( i = 28; i >= 0; i-= 4 ) {
195         char c = "0123456789abcdef"[ 0xf & (x >> i) ];
196         HAL_DIAG_WRITE_CHAR( c );
197     }
198 }
199
200 #define newline() swrites( "\n\r" )
201
202 static void x8( char *s, unsigned long *xp )
203 {
204     int i;
205     for ( i = 0; i < 8; i++ ) {
206         swrites( s );
207         swritec( '0' + i );
208         swrites( " = " );
209         swritex( xp[i] );
210         if ( 3 == (i & 3) )
211             newline();
212         else
213             swrites( "    " );
214     }
215 }
216
217 #endif // THREAD_DEBUG_SERIAL_VERBOSE ... NOT INCLUDED
218
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.
222
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,
227
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};
233
234 typedef unsigned long target_register_t;
235
236 void
237 cyg_hal_sparc_get_gdb_regs( void *gdb_regset,
238                             HAL_SavedRegisters *eCos_regset )
239 {
240     target_register_t *gdb = (target_register_t *)gdb_regset;
241     int reg;
242     cyg_uint32 scratch = 0;
243     cyg_uint32 *sptrap;
244     HAL_SavedWindow *trapli, *ctxli;
245
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
255
256         ctxli = (HAL_SavedWindow *)(trapli->i[6]); // (the frame pointer)
257                                         // and get at the interruptee's regs
258
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];
265         }
266     
267         // Clear out G0 which is always 0 (but abused in eCos_regset)
268         // and the FP regs which we do not have:
269         gdb[ G0 ] = 0;
270         for ( reg = F0; reg <= F31; reg++ )
271             gdb[ reg ] = 0;
272     
273         // In the save context _of the trap handler_ registers are as follows:
274         // %l0 = psr (with this CWP/window-level in it)
275         // %l1 = pc
276         // %l2 = npc
277         // %l3 = vector number (1-15 for interrupts)
278         // %l4 = Y register preserved
279         gdb[ Y ]    = trapli->l[4];
280         
281         scratch = trapli->l[0];         // the PSR in the trap handler
282 #if 8 == __WINSIZE
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;
294 #endif // __WINSIZE
295         
296         // Read _a_ TBR value and ignore the current trap details:
297         asm volatile ( "rd %%tbr, %0" : "=r"(scratch) : );
298         gdb[ TBR ]  = (scratch &~ 0xfff);
299         
300         gdb[ PC ]   = trapli->l[1];
301         gdb[ NPC ]  = trapli->l[2];
302     
303         gdb[ FPSR ] = 0;
304         gdb[ CPSR ] = 0;
305
306 #ifdef THREAD_DEBUG_SERIAL_VERBOSE
307         newline();
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();
320 #endif
321
322     }
323     else {
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
328             gdb[ G0 + reg ] = 0;
329             gdb[ O0 + reg ] = 0;
330 #else
331             gdb[ G0 + reg ] = eCos_regset->g[reg];
332             gdb[ O0 + reg ] = eCos_regset->o[reg];
333 #endif
334             gdb[ L0 + reg ] = eCos_regset->li.l[reg];
335             gdb[ I0 + reg ] = eCos_regset->li.i[reg];
336         }
337
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 ];
342 #else
343         // Clear out G0 which is always 0 (but abused in eCos_regset)
344         gdb[ G0 ] = 0;
345 #endif
346         // and clear the FP regs which we do not have:
347         for ( reg = F0; reg <= F31; reg++ )
348             gdb[ reg ] = 0;
349     
350         gdb[ Y ]    = 0;                // it's not preserved.
351         
352         scratch = eCos_regset->g[ 0 ];  // the PSR in the saved context
353         gdb[ PSR ]  = scratch;          // return it verbatim.
354 #if 8 == __WINSIZE
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;
360 #endif // __WINSIZE
361     
362         // Read _a_ TBR value and ignore the current trap details:
363         asm volatile ( "rd %%tbr, %0" : "=r"(scratch) : );
364         gdb[ TBR ]  = (scratch &~ 0xfff);
365         
366         gdb[ PC ]   = eCos_regset->o[ 7 ]; // the return address
367         gdb[ NPC ]  = 4 + gdb[ PC ];
368     
369         gdb[ FPSR ] = 0;
370         gdb[ CPSR ] = 0;
371
372 #ifdef THREAD_DEBUG_SERIAL_VERBOSE
373         newline();
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();
384 #endif
385     }
386
387 }
388
389 // ---------------------------------------------------------------------------
390
391 void
392 cyg_hal_sparc_set_gdb_regs( HAL_SavedRegisters *eCos_regset,
393                             void *gdb_regset )
394 {
395     target_register_t *gdb = (target_register_t *)gdb_regset;
396     int reg;
397     cyg_uint32 scratch = 0;
398     cyg_uint32 *sptrap;
399     HAL_SavedWindow *trapli, *ctxli;
400
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
411
412         ctxli = (HAL_SavedWindow *)(trapli->i[6]); // (the frame pointer)
413                                         // and get at the interruptee's regs
414
415         scratch = eCos_regset->g[0];
416
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 ] ;
423         }
424     
425         // Put back the eCos G0 which is always 0 (but abused in eCos_regset)
426         eCos_regset->g[0] = scratch;
427
428         // In the save context _of the trap handler_ registers are as follows:
429         // %l0 = psr (with this CWP/window-level in it)
430         // %l1 = pc
431         // %l2 = npc
432         // %l3 = vector number (1-15 for interrupts)
433         // %l4 = Y register preserved
434         trapli->l[4] = gdb[ Y ];
435         
436         // I am *not* interfering with the saved PSR, nor the TBR nor WIM.
437         
438         // put back return PC and NPC
439         trapli->l[1] = gdb[ PC ] ;
440         trapli->l[2] = gdb[ NPC ];
441     
442 #ifdef THREAD_DEBUG_SERIAL_VERBOSE
443         newline();
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();
456 #endif
457
458     }
459     else {
460         // It's a synchronous context switch that led to this object.
461         // Pick up interruptee's registers from the saved context:
462
463         scratch = eCos_regset->g[0];
464
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 ];
470         }
471
472         // Put back the eCos G0 which is always 0 (but abused in eCos_regset)
473         eCos_regset->g[0] = scratch;
474         
475         // I am *not* interfering with the saved PSR, nor the TBR nor WIM.
476
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.
479
480 #ifdef THREAD_DEBUG_SERIAL_VERBOSE
481         newline();
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();
492 #endif
493     }
494
495 }
496
497 /*---------------------------------------------------------------------------*/
498 // EOF icontext.c