source: rtems/cpukit/score/cpu/sparc/cpu.c @ 8df1f408

4.11
Last change on this file since 8df1f408 was 8df1f408, checked in by Christian Mauderer <Christian.Mauderer@…>, on Jun 2, 2014 at 2:31:51 PM

score/sparc: Add support for paravirtualization

Guest systems in paravirtualization environments run usually in user
mode. Thus it is not possible to directly access the PSR and TBR
registers. Use functions instead of inline assembler to access these
registers if RTEMS_PARAVIRT is defined.

  • Property mode set to 100644
File size: 8.6 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 *  _CPU_Initialize
76 *
77 *  This routine performs processor dependent initialization.
78 *
79 *  INPUT PARAMETERS: NONE
80 *
81 *  Output Parameters: NONE
82 *
83 *  NOTE: There is no need to save the pointer to the thread dispatch routine.
84 *        The SPARC's assembly code can reference it directly with no problems.
85 */
86
87void _CPU_Initialize(void)
88{
89#if (SPARC_HAS_FPU == 1)
90  Context_Control_fp *pointer;
91
92  /*
93   *  This seems to be the most appropriate way to obtain an initial
94   *  FP context on the SPARC.  The NULL fp context is copied it to
95   *  the task's FP context during Context_Initialize.
96   */
97
98  pointer = &_CPU_Null_fp_context;
99  _CPU_Context_save_fp( &pointer );
100#endif
101}
102
103uint32_t   _CPU_ISR_Get_level( void )
104{
105  uint32_t   level;
106
107  sparc_get_interrupt_level( level );
108
109  return level;
110}
111
112/*
113 *  _CPU_ISR_install_raw_handler
114 *
115 *  This routine installs the specified handler as a "raw" non-executive
116 *  supported trap handler (a.k.a. interrupt service routine).
117 *
118 *  Input Parameters:
119 *    vector      - trap table entry number plus synchronous
120 *                    vs. asynchronous information
121 *    new_handler - address of the handler to be installed
122 *    old_handler - pointer to an address of the handler previously installed
123 *
124 *  Output Parameters: NONE
125 *    *new_handler - address of the handler previously installed
126 *
127 *  NOTE:
128 *
129 *  On the SPARC, there are really only 256 vectors.  However, the executive
130 *  has no easy, fast, reliable way to determine which traps are synchronous
131 *  and which are asynchronous.  By default, synchronous traps return to the
132 *  instruction which caused the interrupt.  So if you install a software
133 *  trap handler as an executive interrupt handler (which is desirable since
134 *  RTEMS takes care of window and register issues), then the executive needs
135 *  to know that the return address is to the trap rather than the instruction
136 *  following the trap.
137 *
138 *  So vectors 0 through 255 are treated as regular asynchronous traps which
139 *  provide the "correct" return address.  Vectors 256 through 512 are assumed
140 *  by the executive to be synchronous and to require that the return address
141 *  be fudged.
142 *
143 *  If you use this mechanism to install a trap handler which must reexecute
144 *  the instruction which caused the trap, then it should be installed as
145 *  an asynchronous trap.  This will avoid the executive changing the return
146 *  address.
147 */
148
149void _CPU_ISR_install_raw_handler(
150  uint32_t    vector,
151  proc_ptr    new_handler,
152  proc_ptr   *old_handler
153)
154{
155  uint32_t               real_vector;
156  CPU_Trap_table_entry  *tbr;
157  CPU_Trap_table_entry  *slot;
158  uint32_t               u32_tbr;
159  uint32_t               u32_handler;
160
161  /*
162   *  Get the "real" trap number for this vector ignoring the synchronous
163   *  versus asynchronous indicator included with our vector numbers.
164   */
165
166  real_vector = SPARC_REAL_TRAP_NUMBER( vector );
167
168  /*
169   *  Get the current base address of the trap table and calculate a pointer
170   *  to the slot we are interested in.
171   */
172
173  sparc_get_tbr( u32_tbr );
174
175  u32_tbr &= 0xfffff000;
176
177  tbr = (CPU_Trap_table_entry *) u32_tbr;
178
179  slot = &tbr[ real_vector ];
180
181  /*
182   *  Get the address of the old_handler from the trap table.
183   *
184   *  NOTE: The old_handler returned will be bogus if it does not follow
185   *        the RTEMS model.
186   */
187
188#define HIGH_BITS_MASK   0xFFFFFC00
189#define HIGH_BITS_SHIFT  10
190#define LOW_BITS_MASK    0x000003FF
191
192  if ( slot->mov_psr_l0 == _CPU_Trap_slot_template.mov_psr_l0 ) {
193    u32_handler =
194      (slot->sethi_of_handler_to_l4 << HIGH_BITS_SHIFT) |
195      (slot->jmp_to_low_of_handler_plus_l4 & LOW_BITS_MASK);
196    *old_handler = (proc_ptr) u32_handler;
197  } else
198    *old_handler = 0;
199
200  /*
201   *  Copy the template to the slot and then fix it.
202   */
203
204  *slot = _CPU_Trap_slot_template;
205
206  u32_handler = (uint32_t) new_handler;
207
208  slot->mov_vector_l3 |= vector;
209  slot->sethi_of_handler_to_l4 |=
210    (u32_handler & HIGH_BITS_MASK) >> HIGH_BITS_SHIFT;
211  slot->jmp_to_low_of_handler_plus_l4 |= (u32_handler & LOW_BITS_MASK);
212
213  /* need to flush icache after this !!! */
214
215  rtems_cache_invalidate_entire_instruction();
216
217}
218
219void _CPU_ISR_install_vector(
220  uint32_t    vector,
221  proc_ptr    new_handler,
222  proc_ptr   *old_handler
223)
224{
225   uint32_t   real_vector;
226   proc_ptr   ignored;
227
228  /*
229   *  Get the "real" trap number for this vector ignoring the synchronous
230   *  versus asynchronous indicator included with our vector numbers.
231   */
232
233   real_vector = SPARC_REAL_TRAP_NUMBER( vector );
234
235   /*
236    *  Return the previous ISR handler.
237    */
238
239   *old_handler = _ISR_Vector_table[ real_vector ];
240
241   /*
242    *  Install the wrapper so this ISR can be invoked properly.
243    */
244
245   _CPU_ISR_install_raw_handler( vector, _ISR_Handler, &ignored );
246
247   /*
248    *  We put the actual user ISR address in '_ISR_vector_table'.  This will
249    *  be used by the _ISR_Handler so the user gets control.
250    */
251
252    _ISR_Vector_table[ real_vector ] = new_handler;
253}
254
255void _CPU_Context_Initialize(
256  Context_Control  *the_context,
257  uint32_t         *stack_base,
258  uint32_t          size,
259  uint32_t          new_level,
260  void             *entry_point,
261  bool              is_fp,
262  void             *tls_area
263)
264{
265    uint32_t     stack_high;  /* highest "stack aligned" address */
266    uint32_t     tmp_psr;
267
268    /*
269     *  On CPUs with stacks which grow down (i.e. SPARC), we build the stack
270     *  based on the stack_high address.
271     */
272
273    stack_high = ((uint32_t)(stack_base) + size);
274    stack_high &= ~(CPU_STACK_ALIGNMENT - 1);
275
276    /*
277     *  See the README in this directory for a diagram of the stack.
278     */
279
280    the_context->o7    = ((uint32_t) entry_point) - 8;
281    the_context->o6_sp = stack_high - CPU_MINIMUM_STACK_FRAME_SIZE;
282    the_context->i6_fp = 0;
283
284    /*
285     *  Build the PSR for the task.  Most everything can be 0 and the
286     *  CWP is corrected during the context switch.
287     *
288     *  The EF bit determines if the floating point unit is available.
289     *  The FPU is ONLY enabled if the context is associated with an FP task
290     *  and this SPARC model has an FPU.
291     */
292
293    sparc_get_psr( tmp_psr );
294    tmp_psr &= ~SPARC_PSR_PIL_MASK;
295    tmp_psr |= (new_level << 8) & SPARC_PSR_PIL_MASK;
296    tmp_psr &= ~SPARC_PSR_EF_MASK;      /* disabled by default */
297
298#if (SPARC_HAS_FPU == 1)
299    /*
300     *  If this bit is not set, then a task gets a fault when it accesses
301     *  a floating point register.  This is a nice way to detect floating
302     *  point tasks which are not currently declared as such.
303     */
304
305    if ( is_fp )
306      tmp_psr |= SPARC_PSR_EF_MASK;
307#endif
308    the_context->psr = tmp_psr;
309
310  /*
311   *  Since THIS thread is being created, there is no way that THIS
312   *  thread can have an _ISR_Dispatch stack frame on its stack.
313   */
314    the_context->isr_dispatch_disable = 0;
315
316  if ( tls_area != NULL ) {
317    void *tcb = _TLS_TCB_after_TLS_block_initialize( tls_area );
318
319    the_context->g7 = (uintptr_t) tcb;
320  }
321}
Note: See TracBrowser for help on using the repository browser.