source: rtems/cpukit/score/cpu/sparc/cpu.c @ 11b05f1

4.115
Last change on this file since 11b05f1 was 11b05f1, checked in by Sebastian Huber <sebastian.huber@…>, on 05/08/14 at 08:11:13

score: Fix CPU context usage on SMP

We must not alter the is executing indicator in
_CPU_Context_Initialize() since this would cause an invalid state during
a self restart.

The is executing indicator must be valid at creation time since
otherwise _Thread_Kill_zombies() uses an undefined value for not started
threads. This could result in a system life lock.

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