source: rtems/cpukit/score/cpu/sparc/cpu.c @ 4c89fbcd

Last change on this file since 4c89fbcd was 4c89fbcd, checked in by Sebastian Huber <sebastian.huber@…>, on 09/27/22 at 05:43:37

score: Add CPU_THREAD_LOCAL_STORAGE_VARIANT

Update #3835.

  • Property mode set to 100644
File size: 9.9 KB
Line 
1/* SPDX-License-Identifier: BSD-2-Clause */
2
3/**
4 * @file
5 *
6 * @ingroup RTEMSScoreCPUSPARC
7 *
8 * @brief This source file contains static assertions to ensure the consistency
9 *   of interfaces used in C and assembler and it contains the SPARC-specific
10 *   implementation of _CPU_Initialize(), _CPU_ISR_Get_level(), and
11 *   _CPU_Context_Initialize().
12 */
13
14/*
15 *  COPYRIGHT (c) 1989-2007.
16 *  On-Line Applications Research Corporation (OAR).
17 *
18 *  Copyright (c) 2017 embedded brains GmbH
19 *
20 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted provided that the following conditions
22 * are met:
23 * 1. Redistributions of source code must retain the above copyright
24 *    notice, this list of conditions and the following disclaimer.
25 * 2. Redistributions in binary form must reproduce the above copyright
26 *    notice, this list of conditions and the following disclaimer in the
27 *    documentation and/or other materials provided with the distribution.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
30 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
33 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
34 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39 * POSSIBILITY OF SUCH DAMAGE.
40 */
41
42#ifdef HAVE_CONFIG_H
43#include "config.h"
44#endif
45
46#include <rtems/score/percpu.h>
47#include <rtems/score/tls.h>
48#include <rtems/score/thread.h>
49
50#if SPARC_HAS_FPU == 1
51  RTEMS_STATIC_ASSERT(
52    offsetof( Per_CPU_Control, cpu_per_cpu.fsr)
53      == SPARC_PER_CPU_FSR_OFFSET,
54    SPARC_PER_CPU_FSR_OFFSET
55  );
56
57  #if defined(SPARC_USE_LAZY_FP_SWITCH)
58    RTEMS_STATIC_ASSERT(
59      offsetof( Per_CPU_Control, cpu_per_cpu.fp_owner)
60        == SPARC_PER_CPU_FP_OWNER_OFFSET,
61      SPARC_PER_CPU_FP_OWNER_OFFSET
62    );
63  #endif
64#endif
65
66#define SPARC_ASSERT_OFFSET(field, off) \
67  RTEMS_STATIC_ASSERT( \
68    offsetof(Context_Control, field) == off ## _OFFSET, \
69    Context_Control_offset_ ## field \
70  )
71
72SPARC_ASSERT_OFFSET(g5, G5);
73SPARC_ASSERT_OFFSET(g7, G7);
74
75RTEMS_STATIC_ASSERT(
76  offsetof(Context_Control, l0_and_l1) == L0_OFFSET,
77  Context_Control_offset_L0
78);
79
80RTEMS_STATIC_ASSERT(
81  offsetof(Context_Control, l0_and_l1) + 4 == L1_OFFSET,
82  Context_Control_offset_L1
83);
84
85SPARC_ASSERT_OFFSET(l2, L2);
86SPARC_ASSERT_OFFSET(l3, L3);
87SPARC_ASSERT_OFFSET(l4, L4);
88SPARC_ASSERT_OFFSET(l5, L5);
89SPARC_ASSERT_OFFSET(l6, L6);
90SPARC_ASSERT_OFFSET(l7, L7);
91SPARC_ASSERT_OFFSET(i0, I0);
92SPARC_ASSERT_OFFSET(i1, I1);
93SPARC_ASSERT_OFFSET(i2, I2);
94SPARC_ASSERT_OFFSET(i3, I3);
95SPARC_ASSERT_OFFSET(i4, I4);
96SPARC_ASSERT_OFFSET(i5, I5);
97SPARC_ASSERT_OFFSET(i6_fp, I6_FP);
98SPARC_ASSERT_OFFSET(i7, I7);
99SPARC_ASSERT_OFFSET(o6_sp, O6_SP);
100SPARC_ASSERT_OFFSET(o7, O7);
101SPARC_ASSERT_OFFSET(psr, PSR);
102SPARC_ASSERT_OFFSET(isr_dispatch_disable, ISR_DISPATCH_DISABLE_STACK);
103
104#if defined(RTEMS_SMP)
105SPARC_ASSERT_OFFSET(is_executing, SPARC_CONTEXT_CONTROL_IS_EXECUTING);
106#endif
107
108#define SPARC_ASSERT_ISF_OFFSET(field, off) \
109  RTEMS_STATIC_ASSERT( \
110    offsetof(CPU_Interrupt_frame, field) == ISF_ ## off ## _OFFSET, \
111    CPU_Interrupt_frame_offset_ ## field \
112  )
113
114SPARC_ASSERT_ISF_OFFSET(psr, PSR);
115SPARC_ASSERT_ISF_OFFSET(pc, PC);
116SPARC_ASSERT_ISF_OFFSET(npc, NPC);
117SPARC_ASSERT_ISF_OFFSET(g1, G1);
118SPARC_ASSERT_ISF_OFFSET(g2, G2);
119SPARC_ASSERT_ISF_OFFSET(g3, G3);
120SPARC_ASSERT_ISF_OFFSET(g4, G4);
121SPARC_ASSERT_ISF_OFFSET(g5, G5);
122SPARC_ASSERT_ISF_OFFSET(g7, G7);
123SPARC_ASSERT_ISF_OFFSET(i0, I0);
124SPARC_ASSERT_ISF_OFFSET(i1, I1);
125SPARC_ASSERT_ISF_OFFSET(i2, I2);
126SPARC_ASSERT_ISF_OFFSET(i3, I3);
127SPARC_ASSERT_ISF_OFFSET(i4, I4);
128SPARC_ASSERT_ISF_OFFSET(i5, I5);
129SPARC_ASSERT_ISF_OFFSET(i6_fp, I6_FP);
130SPARC_ASSERT_ISF_OFFSET(i7, I7);
131SPARC_ASSERT_ISF_OFFSET(y, Y);
132SPARC_ASSERT_ISF_OFFSET(tpc, TPC);
133
134#define SPARC_ASSERT_FP_OFFSET(field, off) \
135  RTEMS_STATIC_ASSERT( \
136    offsetof(Context_Control_fp, field) == SPARC_FP_CONTEXT_OFFSET_ ## off, \
137    Context_Control_fp_offset_ ## field \
138  )
139
140SPARC_ASSERT_FP_OFFSET(f0_f1, F0_F1);
141SPARC_ASSERT_FP_OFFSET(f2_f3, F2_F3);
142SPARC_ASSERT_FP_OFFSET(f4_f5, F4_F5);
143SPARC_ASSERT_FP_OFFSET(f6_f7, F6_F7);
144SPARC_ASSERT_FP_OFFSET(f8_f9, F8_F9);
145SPARC_ASSERT_FP_OFFSET(f10_f11, F10_F11);
146SPARC_ASSERT_FP_OFFSET(f12_f13, F12_F13);
147SPARC_ASSERT_FP_OFFSET(f14_f15, F14_F15);
148SPARC_ASSERT_FP_OFFSET(f16_f17, F16_F17);
149SPARC_ASSERT_FP_OFFSET(f18_f19, F18_F19);
150SPARC_ASSERT_FP_OFFSET(f20_f21, F20_F21);
151SPARC_ASSERT_FP_OFFSET(f22_f23, F22_F23);
152SPARC_ASSERT_FP_OFFSET(f24_f25, F24_F25);
153SPARC_ASSERT_FP_OFFSET(f26_f27, F26_F27);
154SPARC_ASSERT_FP_OFFSET(f28_f29, F28_F29);
155SPARC_ASSERT_FP_OFFSET(f30_f31, F30_F31);
156SPARC_ASSERT_FP_OFFSET(fsr, FSR);
157
158RTEMS_STATIC_ASSERT(
159  sizeof(SPARC_Minimum_stack_frame) == SPARC_MINIMUM_STACK_FRAME_SIZE,
160  SPARC_MINIMUM_STACK_FRAME_SIZE
161);
162
163/* https://devel.rtems.org/ticket/2352 */
164RTEMS_STATIC_ASSERT(
165  sizeof(CPU_Interrupt_frame) % CPU_ALIGNMENT == 0,
166  CPU_Interrupt_frame_alignment
167);
168
169#define SPARC_ASSERT_REGISTER_WINDOW_OFFSET( member, off ) \
170  RTEMS_STATIC_ASSERT( \
171    offsetof( SPARC_Register_window, member ) == \
172      RTEMS_XCONCAT( SPARC_REGISTER_WINDOW_OFFSET_, off ), \
173    SPARC_Register_window ## member \
174  )
175
176SPARC_ASSERT_REGISTER_WINDOW_OFFSET( local[ 0 ], LOCAL( 0 ) );
177SPARC_ASSERT_REGISTER_WINDOW_OFFSET( local[ 1 ], LOCAL( 1 ) );
178SPARC_ASSERT_REGISTER_WINDOW_OFFSET( input[ 0 ], INPUT( 0 ) );
179SPARC_ASSERT_REGISTER_WINDOW_OFFSET( input[ 1 ], INPUT( 1 ) );
180
181RTEMS_STATIC_ASSERT(
182  sizeof( SPARC_Register_window ) == SPARC_REGISTER_WINDOW_SIZE,
183  SPARC_REGISTER_WINDOW_SIZE
184);
185
186#define SPARC_ASSERT_EXCEPTION_OFFSET( member, off ) \
187  RTEMS_STATIC_ASSERT( \
188    offsetof( CPU_Exception_frame, member ) == \
189      RTEMS_XCONCAT( SPARC_EXCEPTION_OFFSET_, off ), \
190    CPU_Exception_frame_offset_ ## member \
191  )
192
193SPARC_ASSERT_EXCEPTION_OFFSET( psr, PSR );
194SPARC_ASSERT_EXCEPTION_OFFSET( pc, PC );
195SPARC_ASSERT_EXCEPTION_OFFSET( npc, NPC );
196SPARC_ASSERT_EXCEPTION_OFFSET( trap, TRAP );
197SPARC_ASSERT_EXCEPTION_OFFSET( wim, WIM );
198SPARC_ASSERT_EXCEPTION_OFFSET( y, Y );
199SPARC_ASSERT_EXCEPTION_OFFSET( global[ 0 ], GLOBAL( 0 ) );
200SPARC_ASSERT_EXCEPTION_OFFSET( global[ 1 ], GLOBAL( 1 ) );
201SPARC_ASSERT_EXCEPTION_OFFSET( output[ 0 ], OUTPUT( 0 ) );
202SPARC_ASSERT_EXCEPTION_OFFSET( output[ 1 ], OUTPUT( 1 ) );
203
204#if SPARC_HAS_FPU == 1
205SPARC_ASSERT_EXCEPTION_OFFSET( fsr, FSR );
206SPARC_ASSERT_EXCEPTION_OFFSET( fp[ 0 ], FP( 0 ) );
207SPARC_ASSERT_EXCEPTION_OFFSET( fp[ 1 ], FP( 1 ) );
208#endif
209
210RTEMS_STATIC_ASSERT(
211  sizeof( CPU_Exception_frame ) == SPARC_EXCEPTION_FRAME_SIZE,
212  SPARC_EXCEPTION_FRAME_SIZE
213);
214
215RTEMS_STATIC_ASSERT(
216  sizeof( CPU_Exception_frame ) % CPU_ALIGNMENT == 0,
217  CPU_Exception_frame_alignment
218);
219
220/*
221 *  _CPU_Initialize
222 *
223 *  This routine performs processor dependent initialization.
224 *
225 *  INPUT PARAMETERS: NONE
226 *
227 *  Output Parameters: NONE
228 *
229 *  NOTE: There is no need to save the pointer to the thread dispatch routine.
230 *        The SPARC's assembly code can reference it directly with no problems.
231 */
232
233void _CPU_Initialize(void)
234{
235#if defined(SPARC_USE_LAZY_FP_SWITCH)
236  __asm__ volatile (
237    ".global SPARC_THREAD_CONTROL_REGISTERS_FP_CONTEXT_OFFSET\n"
238    ".set SPARC_THREAD_CONTROL_REGISTERS_FP_CONTEXT_OFFSET, %0\n"
239    ".global SPARC_THREAD_CONTROL_FP_CONTEXT_OFFSET\n"
240    ".set SPARC_THREAD_CONTROL_FP_CONTEXT_OFFSET, %1\n"
241    :
242    : "i" (offsetof(Thread_Control, Registers.fp_context)),
243      "i" (offsetof(Thread_Control, fp_context))
244  );
245#endif
246}
247
248uint32_t   _CPU_ISR_Get_level( void )
249{
250  uint32_t   level;
251
252  sparc_get_interrupt_level( level );
253
254  return level;
255}
256
257void _CPU_Context_Initialize(
258  Context_Control  *the_context,
259  uint32_t         *stack_base,
260  uint32_t          size,
261  uint32_t          new_level,
262  void             *entry_point,
263  bool              is_fp,
264  void             *tls_area
265)
266{
267    uint32_t     stack_high;  /* highest "stack aligned" address */
268    uint32_t     tmp_psr;
269
270    /*
271     *  On CPUs with stacks which grow down (i.e. SPARC), we build the stack
272     *  based on the stack_high address.
273     */
274
275    stack_high = ((uint32_t)(stack_base) + size);
276    stack_high &= ~(CPU_STACK_ALIGNMENT - 1);
277
278    /*
279     *  See the README in this directory for a diagram of the stack.
280     */
281
282    the_context->o7    = ((uint32_t) entry_point) - 8;
283    the_context->o6_sp = stack_high - SPARC_MINIMUM_STACK_FRAME_SIZE;
284    the_context->i6_fp = 0;
285
286    /*
287     *  Build the PSR for the task.  Most everything can be 0 and the
288     *  CWP is corrected during the context switch.
289     *
290     *  The EF bit determines if the floating point unit is available.
291     *  The FPU is ONLY enabled if the context is associated with an FP task
292     *  and this SPARC model has an FPU.
293     */
294
295    sparc_get_psr( tmp_psr );
296    tmp_psr &= ~SPARC_PSR_PIL_MASK;
297    tmp_psr |= (new_level << 8) & SPARC_PSR_PIL_MASK;
298    tmp_psr &= ~SPARC_PSR_EF_MASK;      /* disabled by default */
299
300    /* _CPU_Context_restore_heir() relies on this */
301    _Assert( ( tmp_psr & SPARC_PSR_ET_MASK ) != 0 );
302
303#if (SPARC_HAS_FPU == 1)
304    /*
305     *  If this bit is not set, then a task gets a fault when it accesses
306     *  a floating point register.  This is a nice way to detect floating
307     *  point tasks which are not currently declared as such.
308     */
309
310    if ( is_fp )
311      tmp_psr |= SPARC_PSR_EF_MASK;
312#endif
313    the_context->psr = tmp_psr;
314
315  /*
316   *  Since THIS thread is being created, there is no way that THIS
317   *  thread can have an interrupt stack frame on its stack.
318   */
319  the_context->isr_dispatch_disable = 0;
320
321  if ( tls_area != NULL ) {
322    void *tcb = _TLS_Initialize_area( tls_area );
323
324    the_context->g7 = (uintptr_t) tcb;
325  }
326}
Note: See TracBrowser for help on using the repository browser.