source: rtems/c/src/exec/score/cpu/sparc/cpu.c @ 4159370

4.104.114.84.95
Last change on this file since 4159370 was 4159370, checked in by Joel Sherrill <joel.sherrill@…>, on Jul 11, 2000 at 9:16:53 PM

Reworked score/cpu/sparc so it can be safely compiled multilib. All
routines and structures that require CPU model specific information
are now in libcpu. This primarily required moving erc32 specific
information from score/cpu files to libcpu/sparc and the erc32 BSP.

  • Property mode set to 100644
File size: 9.9 KB
Line 
1/*
2 *  SPARC Dependent Source
3 *
4 *  COPYRIGHT (c) 1989-1999.
5 *  On-Line Applications Research Corporation (OAR).
6 *
7 *  The license and distribution terms for this file may be
8 *  found in the file LICENSE in this distribution or at
9 *  http://www.OARcorp.com/rtems/license.html.
10 *
11 *  $Id$
12 */
13
14#include <rtems/system.h>
15#include <rtems/score/isr.h>
16
17/*
18 *  This initializes the set of opcodes placed in each trap
19 *  table entry.  The routine which installs a handler is responsible
20 *  for filling in the fields for the _handler address and the _vector
21 *  trap type.
22 *
23 *  The constants following this structure are masks for the fields which
24 *  must be filled in when the handler is installed.
25 */
26
27const CPU_Trap_table_entry _CPU_Trap_slot_template = {
28  0xa1480000,      /* mov   %psr, %l0           */
29  0x29000000,      /* sethi %hi(_handler), %l4  */
30  0x81c52000,      /* jmp   %l4 + %lo(_handler) */
31  0xa6102000       /* mov   _vector, %l3        */
32};
33
34/*PAGE
35 *
36 *  _CPU_Initialize
37 *
38 *  This routine performs processor dependent initialization.
39 *
40 *  Input Parameters:
41 *    cpu_table       - CPU table to initialize
42 *    thread_dispatch - address of disptaching routine
43 *
44 *  Output Parameters: NONE
45 *
46 *  NOTE: There is no need to save the pointer to the thread dispatch routine.
47 *        The SPARC's assembly code can reference it directly with no problems.
48 */
49
50void _CPU_Initialize(
51  rtems_cpu_table  *cpu_table,
52  void            (*thread_dispatch)      /* ignored on this CPU */
53)
54{
55  void                  *pointer;
56
57#ifndef NO_TABLE_MOVE
58  unsigned32             trap_table_start;
59  unsigned32             tbr_value;
60  CPU_Trap_table_entry  *old_tbr;
61  CPU_Trap_table_entry  *trap_table;
62
63  /*
64   *  Install the executive's trap table.  All entries from the original
65   *  trap table are copied into the executive's trap table.  This is essential
66   *  since this preserves critical trap handlers such as the window underflow
67   *  and overflow handlers.  It is the responsibility of the BSP to provide
68   *  install these in the initial trap table.
69   */
70
71 
72  trap_table_start = (unsigned32) &_CPU_Trap_Table_area;
73  if (trap_table_start & (SPARC_TRAP_TABLE_ALIGNMENT-1))
74    trap_table_start = (trap_table_start + SPARC_TRAP_TABLE_ALIGNMENT) & 
75                       ~(SPARC_TRAP_TABLE_ALIGNMENT-1);
76
77  trap_table = (CPU_Trap_table_entry *) trap_table_start;
78
79  sparc_get_tbr( tbr_value );
80
81  old_tbr = (CPU_Trap_table_entry *) (tbr_value & 0xfffff000);
82
83  memcpy( trap_table, (void *) old_tbr, 256 * sizeof( CPU_Trap_table_entry ) );
84
85  sparc_set_tbr( trap_table_start );
86
87#endif
88
89  /*
90   *  This seems to be the most appropriate way to obtain an initial
91   *  FP context on the SPARC.  The NULL fp context is copied it to
92   *  the task's FP context during Context_Initialize.
93   */
94
95  pointer = &_CPU_Null_fp_context;
96  _CPU_Context_save_fp( &pointer );
97
98  /*
99   *  Grab our own copy of the user's CPU table.
100   */
101
102  _CPU_Table = *cpu_table;
103}
104
105/*PAGE
106 *
107 *  _CPU_ISR_Get_level
108 *
109 *  Input Parameters: NONE
110 *
111 *  Output Parameters:
112 *    returns the current interrupt level (PIL field of the PSR)
113 */
114 
115unsigned32 _CPU_ISR_Get_level( void )
116{
117  unsigned32 level;
118 
119  sparc_get_interrupt_level( level );
120 
121  return level;
122}
123
124/*PAGE
125 *
126 *  _CPU_ISR_install_raw_handler
127 *
128 *  This routine installs the specified handler as a "raw" non-executive
129 *  supported trap handler (a.k.a. interrupt service routine).
130 *
131 *  Input Parameters:
132 *    vector      - trap table entry number plus synchronous
133 *                    vs. asynchronous information
134 *    new_handler - address of the handler to be installed
135 *    old_handler - pointer to an address of the handler previously installed
136 *
137 *  Output Parameters: NONE
138 *    *new_handler - address of the handler previously installed
139 *
140 *  NOTE:
141 *
142 *  On the SPARC, there are really only 256 vectors.  However, the executive
143 *  has no easy, fast, reliable way to determine which traps are synchronous
144 *  and which are asynchronous.  By default, synchronous traps return to the
145 *  instruction which caused the interrupt.  So if you install a software
146 *  trap handler as an executive interrupt handler (which is desirable since
147 *  RTEMS takes care of window and register issues), then the executive needs
148 *  to know that the return address is to the trap rather than the instruction
149 *  following the trap.
150 *
151 *  So vectors 0 through 255 are treated as regular asynchronous traps which
152 *  provide the "correct" return address.  Vectors 256 through 512 are assumed
153 *  by the executive to be synchronous and to require that the return address
154 *  be fudged.
155 *
156 *  If you use this mechanism to install a trap handler which must reexecute
157 *  the instruction which caused the trap, then it should be installed as
158 *  an asynchronous trap.  This will avoid the executive changing the return
159 *  address.
160 */
161 
162void _CPU_ISR_install_raw_handler(
163  unsigned32  vector,
164  proc_ptr    new_handler,
165  proc_ptr   *old_handler
166)
167{
168  unsigned32             real_vector;
169  CPU_Trap_table_entry  *tbr;
170  CPU_Trap_table_entry  *slot;
171  unsigned32             u32_tbr;
172  unsigned32             u32_handler;
173
174  /*
175   *  Get the "real" trap number for this vector ignoring the synchronous
176   *  versus asynchronous indicator included with our vector numbers.
177   */
178
179  real_vector = SPARC_REAL_TRAP_NUMBER( vector );
180
181  /*
182   *  Get the current base address of the trap table and calculate a pointer
183   *  to the slot we are interested in.
184   */
185
186  sparc_get_tbr( u32_tbr );
187
188  u32_tbr &= 0xfffff000;
189
190  tbr = (CPU_Trap_table_entry *) u32_tbr;
191
192  slot = &tbr[ real_vector ];
193
194  /*
195   *  Get the address of the old_handler from the trap table.
196   *
197   *  NOTE: The old_handler returned will be bogus if it does not follow
198   *        the RTEMS model.
199   */
200
201#define HIGH_BITS_MASK   0xFFFFFC00
202#define HIGH_BITS_SHIFT  10
203#define LOW_BITS_MASK    0x000003FF
204
205  if ( slot->mov_psr_l0 == _CPU_Trap_slot_template.mov_psr_l0 ) {
206    u32_handler = 
207      ((slot->sethi_of_handler_to_l4 & HIGH_BITS_MASK) << HIGH_BITS_SHIFT) |
208      (slot->jmp_to_low_of_handler_plus_l4 & LOW_BITS_MASK);
209    *old_handler = (proc_ptr) u32_handler;
210  } else
211    *old_handler = 0;
212
213  /*
214   *  Copy the template to the slot and then fix it.
215   */
216
217  *slot = _CPU_Trap_slot_template;
218
219  u32_handler = (unsigned32) new_handler;
220
221  slot->mov_vector_l3 |= vector;
222  slot->sethi_of_handler_to_l4 |= 
223    (u32_handler & HIGH_BITS_MASK) >> HIGH_BITS_SHIFT;
224  slot->jmp_to_low_of_handler_plus_l4 |= (u32_handler & LOW_BITS_MASK);
225}
226
227/*PAGE
228 *
229 *  _CPU_ISR_install_vector
230 *
231 *  This kernel routine installs the RTEMS handler for the
232 *  specified vector.
233 *
234 *  Input parameters:
235 *    vector       - interrupt vector number
236 *    new_handler  - replacement ISR for this vector number
237 *    old_handler  - pointer to former ISR for this vector number
238 *
239 *  Output parameters:
240 *    *old_handler - former ISR for this vector number
241 *
242 */
243
244void _CPU_ISR_install_vector(
245  unsigned32  vector,
246  proc_ptr    new_handler,
247  proc_ptr   *old_handler
248)
249{
250   unsigned32 real_vector;
251   proc_ptr   ignored;
252
253  /*
254   *  Get the "real" trap number for this vector ignoring the synchronous
255   *  versus asynchronous indicator included with our vector numbers.
256   */
257
258   real_vector = SPARC_REAL_TRAP_NUMBER( vector );
259
260   /*
261    *  Return the previous ISR handler.
262    */
263
264   *old_handler = _ISR_Vector_table[ real_vector ];
265
266   /*
267    *  Install the wrapper so this ISR can be invoked properly.
268    */
269
270   _CPU_ISR_install_raw_handler( vector, _ISR_Handler, &ignored );
271
272   /*
273    *  We put the actual user ISR address in '_ISR_vector_table'.  This will
274    *  be used by the _ISR_Handler so the user gets control.
275    */
276
277    _ISR_Vector_table[ real_vector ] = new_handler;
278}
279
280/*PAGE
281 *
282 *  _CPU_Context_Initialize
283 *
284 *  This kernel routine initializes the basic non-FP context area associated
285 *  with each thread.
286 *
287 *  Input parameters:
288 *    the_context  - pointer to the context area
289 *    stack_base   - address of memory for the SPARC
290 *    size         - size in bytes of the stack area
291 *    new_level    - interrupt level for this context area
292 *    entry_point  - the starting execution point for this this context
293 *    is_fp        - TRUE if this context is associated with an FP thread
294 *
295 *  Output parameters: NONE
296 */
297
298void _CPU_Context_Initialize(
299  Context_Control  *the_context,
300  unsigned32       *stack_base,
301  unsigned32        size,
302  unsigned32        new_level,
303  void             *entry_point,
304  boolean           is_fp
305)
306{
307    unsigned32   stack_high;  /* highest "stack aligned" address */
308    unsigned32   the_size;
309    unsigned32   tmp_psr;
310 
311    /*
312     *  On CPUs with stacks which grow down (i.e. SPARC), we build the stack
313     *  based on the stack_high address. 
314     */
315 
316    stack_high = ((unsigned32)(stack_base) + size);
317    stack_high &= ~(CPU_STACK_ALIGNMENT - 1);
318 
319    the_size = size & ~(CPU_STACK_ALIGNMENT - 1);
320 
321    /*
322     *  See the README in this directory for a diagram of the stack.
323     */
324 
325    the_context->o7    = ((unsigned32) entry_point) - 8;
326    the_context->o6_sp = stack_high - CPU_MINIMUM_STACK_FRAME_SIZE;
327    the_context->i6_fp = stack_high;
328
329    /*
330     *  Build the PSR for the task.  Most everything can be 0 and the
331     *  CWP is corrected during the context switch.
332     *
333     *  The EF bit determines if the floating point unit is available.
334     *  The FPU is ONLY enabled if the context is associated with an FP task
335     *  and this SPARC model has an FPU.
336     */
337
338    sparc_get_psr( tmp_psr );
339    tmp_psr &= ~SPARC_PSR_PIL_MASK;
340    tmp_psr |= (new_level << 8) & SPARC_PSR_PIL_MASK;
341    tmp_psr &= ~SPARC_PSR_EF_MASK;      /* disabled by default */
342   
343#if (SPARC_HAS_FPU == 1)
344    /*
345     *  If this bit is not set, then a task gets a fault when it accesses
346     *  a floating point register.  This is a nice way to detect floating
347     *  point tasks which are not currently declared as such.
348     */
349
350    if ( is_fp )
351      tmp_psr |= SPARC_PSR_EF_MASK;
352#endif
353    the_context->psr = tmp_psr;
354}
Note: See TracBrowser for help on using the repository browser.