source: rtems/cpukit/score/cpu/riscv/include/rtems/score/cpu.h @ 9b2ef07f

Last change on this file since 9b2ef07f was 511dc4b, checked in by Sebastian Huber <sebastian.huber@…>, on Jun 19, 2018 at 7:09:51 AM

Rework initialization and interrupt stack support

Statically initialize the interrupt stack area
(_Configuration_Interrupt_stack_area_begin,
_Configuration_Interrupt_stack_area_end, and
_Configuration_Interrupt_stack_size) via <rtems/confdefs.h>. Place the
interrupt stack area in a special section ".rtemsstack.interrupt". Let
BSPs define the optimal placement of this section in their linker
command files (e.g. in a fast on-chip memory).

This change makes makes the CPU_HAS_SOFTWARE_INTERRUPT_STACK and
CPU_HAS_HARDWARE_INTERRUPT_STACK CPU port defines superfluous, since the
low level initialization code has all information available via global
symbols.

This change makes the CPU_ALLOCATE_INTERRUPT_STACK CPU port define
superfluous, since the interrupt stacks are allocated by confdefs.h for
all architectures. There is no need for BSP-specific linker command
file magic (except the section placement), see previous ARM linker
command file as a bad example.

Remove _CPU_Install_interrupt_stack(). Initialize the hardware
interrupt stack in _CPU_Initialize() if necessary (e.g.
m68k_install_interrupt_stack()).

The optional _CPU_Interrupt_stack_setup() is still useful to customize
the registration of the interrupt stack area in the per-CPU information.

The initialization stack can reuse the interrupt stack, since

  • interrupts are disabled during the sequential system initialization, and
  • the boot_card() function does not return.

This stack resuse saves memory.

Changes per architecture:

arm:

  • Mostly replace the linker symbol based configuration of stacks with the standard <rtems/confdefs.h> configuration via CONFIGURE_INTERRUPT_STACK_SIZE. The size of the FIQ, ABT and UND mode stack is still defined via linker symbols. These modes are rarely used in applications and the default values provided by the BSP should be sufficient in most cases.
  • Remove the bsp_processor_count linker symbol hack used for the SMP support. This is possible since the interrupt stack area is now allocated by the linker and not allocated from the heap. This makes some configure.ac stuff obsolete. Remove the now superfluous BSP variants altcycv_devkit_smp and realview_pbx_a9_qemu_smp.

bfin:

  • Remove unused magic linker command file allocation of initialization stack. Maybe a previous linker command file copy and paste problem? In the start.S the initialization stack is set to a hard coded value.

lm32, m32c, mips, nios2, riscv, sh, v850:

  • Remove magic linker command file allocation of initialization stack. Reuse interrupt stack for initialization stack.

m68k:

  • Remove magic linker command file allocation of initialization stack. Reuse interrupt stack for initialization stack.

powerpc:

  • Remove magic linker command file allocation of initialization stack. Reuse interrupt stack for initialization stack.
  • Used dedicated memory region (REGION_RTEMSSTACK) for the interrupt stack on BSPs using the shared linkcmds.base (replacement for REGION_RWEXTRA).

sparc:

  • Remove the hard coded initialization stack. Use the interrupt stack for the initialization stack on the boot processor. This saves 16KiB of RAM.

Update #3459.

  • Property mode set to 100644
File size: 15.3 KB
Line 
1/**
2 * @file rtems/score/cpu.h
3 */
4
5/*
6 *
7 * Copyright (c) 2015 University of York.
8 * Hesham Almatary <hesham@alumni.york.ac.uk>
9 *
10 * COPYRIGHT (c) 1989-1999.
11 * On-Line Applications Research Corporation (OAR).
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 *    notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 *    notice, this list of conditions and the following disclaimer in the
20 *    documentation and/or other materials provided with the distribution.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#ifndef _RISCV_CPU_H
36#define _RISCV_CPU_H
37
38#ifdef __cplusplus
39extern "C" {
40#endif
41
42#include <rtems/score/basedefs.h>
43#include <rtems/score/riscv.h> /* pick up machine definitions */
44#include <rtems/score/riscv-utility.h>
45#ifndef ASM
46#include <rtems/bspIo.h>
47#include <stdint.h>
48#include <stdio.h> /* for printk */
49#endif
50
51#define CPU_INLINE_ENABLE_DISPATCH       FALSE
52#define CPU_UNROLL_ENQUEUE_PRIORITY      TRUE
53#define CPU_ISR_PASSES_FRAME_POINTER 1
54#define CPU_HARDWARE_FP                  FALSE
55#define CPU_SOFTWARE_FP                  FALSE
56#define CPU_ALL_TASKS_ARE_FP             FALSE
57#define CPU_IDLE_TASK_IS_FP              FALSE
58#define CPU_USE_DEFERRED_FP_SWITCH       FALSE
59#define CPU_PROVIDES_IDLE_THREAD_BODY    TRUE
60#define CPU_STACK_GROWS_UP               FALSE
61
62#define CPU_STRUCTURE_ALIGNMENT __attribute__ ((aligned (64)))
63#define CPU_HAS_OWN_HOST_TO_NETWORK_ROUTINES     FALSE
64#define CPU_BIG_ENDIAN                           FALSE
65#define CPU_LITTLE_ENDIAN                        TRUE
66#define CPU_MODES_INTERRUPT_MASK   0x0000000000000001
67
68/*
69 *  Processor defined structures required for cpukit/score.
70 */
71
72#ifndef ASM
73
74typedef struct {
75  /* riscv has 32 xlen-bit (where xlen can be 32 or 64) general purpose registers (x0-x31)*/
76  unsigned long x[32];
77
78  /* Special purpose registers */
79  unsigned long mstatus;
80  unsigned long mcause;
81  unsigned long mepc;
82#ifdef RTEMS_SMP
83  /**
84   * @brief On SMP configurations the thread context must contain a boolean
85   * indicator to signal if this context is executing on a processor.
86   *
87   * This field must be updated during a context switch.  The context switch
88   * to the heir must wait until the heir context indicates that it is no
89   * longer executing on a processor.  The context switch must also check if
90   * a thread dispatch is necessary to honor updates of the heir thread for
91   * this processor.  This indicator must be updated using an atomic test and
92   * set operation to ensure that at most one processor uses the heir
93   * context at the same time.
94   *
95   * @code
96   * void _CPU_Context_switch(
97   *   Context_Control *executing,
98   *   Context_Control *heir
99   * )
100   * {
101   *   save( executing );
102   *
103   *   executing->is_executing = false;
104   *   memory_barrier();
105   *
106   *   if ( test_and_set( &heir->is_executing ) ) {
107   *     do {
108   *       Per_CPU_Control *cpu_self = _Per_CPU_Get_snapshot();
109   *
110   *       if ( cpu_self->dispatch_necessary ) {
111   *         heir = _Thread_Get_heir_and_make_it_executing( cpu_self );
112   *       }
113   *     } while ( test_and_set( &heir->is_executing ) );
114   *   }
115   *
116   *   restore( heir );
117   * }
118   * @endcode
119   */
120  volatile bool is_executing;
121#endif
122} Context_Control;
123
124#define _CPU_Context_Get_SP( _context ) \
125  (_context)->x[2]
126
127typedef struct {
128  /** TODO FPU registers are listed here */
129  double  some_float_register;
130} Context_Control_fp;
131
132typedef Context_Control CPU_Interrupt_frame;
133
134#define CPU_CONTEXT_FP_SIZE  0
135Context_Control_fp  _CPU_Null_fp_context;
136
137#define CPU_CACHE_LINE_BYTES 64
138
139#define CPU_MPCI_RECEIVE_SERVER_EXTRA_STACK 0
140#if __riscv_xlen == 32
141#define CPU_STACK_MINIMUM_SIZE  4096
142#else
143#define CPU_STACK_MINIMUM_SIZE  4096 * 2
144#endif
145#define CPU_ALIGNMENT 8
146#define CPU_PROVIDES_ISR_IS_IN_PROGRESS FALSE
147#define CPU_HEAP_ALIGNMENT         CPU_ALIGNMENT
148#define CPU_PARTITION_ALIGNMENT    CPU_ALIGNMENT
149#define CPU_STACK_ALIGNMENT        8
150
151#define CPU_INTERRUPT_STACK_ALIGNMENT CPU_CACHE_LINE_BYTES
152
153#define _CPU_Initialize_vectors()
154
155/*
156 *  Disable all interrupts for an RTEMS critical section.  The previous
157 *  level is returned in _level.
158 *
159 */
160
161static inline unsigned long riscv_interrupt_disable( void )
162{
163  unsigned long status = read_csr(mstatus);
164  clear_csr(mstatus, MSTATUS_MIE);
165  return status;
166}
167
168static inline void riscv_interrupt_enable(unsigned long level)
169{
170  write_csr(mstatus, level);
171}
172
173#define _CPU_ISR_Disable( _level ) \
174    _level = riscv_interrupt_disable()
175
176#define _CPU_ISR_Enable( _level )  \
177  riscv_interrupt_enable( _level )
178
179#define _CPU_ISR_Flash( _level ) \
180  do{ \
181      _CPU_ISR_Enable( _level ); \
182      riscv_interrupt_disable(); \
183    } while(0)
184
185RTEMS_INLINE_ROUTINE bool _CPU_ISR_Is_enabled( unsigned long level )
186{
187  return ( level & MSTATUS_MIE ) != 0;
188}
189
190void _CPU_ISR_Set_level( unsigned long level );
191
192unsigned long _CPU_ISR_Get_level( void );
193
194/* end of ISR handler macros */
195
196/* Context handler macros */
197#define RISCV_GCC_RED_ZONE_SIZE 128
198
199void _CPU_Context_Initialize(
200  Context_Control *context,
201  void *stack_area_begin,
202  size_t stack_area_size,
203  unsigned long new_level,
204  void (*entry_point)( void ),
205  bool is_fp,
206  void *tls_area
207);
208
209#define _CPU_Context_Restart_self( _the_context ) \
210   _CPU_Context_restore( (_the_context) )
211
212
213#define _CPU_Context_Fp_start( _base, _offset ) \
214   ( (void *) _Addresses_Add_offset( (_base), (_offset) ) )
215
216#define _CPU_Context_Initialize_fp( _destination ) \
217  { \
218   *(*(_destination)) = _CPU_Null_fp_context; \
219  }
220
221extern void _CPU_Fatal_halt(uint32_t source, uint32_t error) RTEMS_NO_RETURN;
222
223/* end of Fatal Error manager macros */
224
225#define CPU_USE_GENERIC_BITFIELD_CODE TRUE
226#define CPU_USE_GENERIC_BITFIELD_DATA TRUE
227
228#if (CPU_USE_GENERIC_BITFIELD_CODE == FALSE)
229
230#define _CPU_Bitfield_Find_first_bit( _value, _output ) \
231  { \
232    (_output) = 0;   /* do something to prevent warnings */ \
233  }
234#endif
235
236/* end of Bitfield handler macros */
237
238/*
239 *  This routine builds the mask which corresponds to the bit fields
240 *  as searched by _CPU_Bitfield_Find_first_bit().  See the discussion
241 *  for that routine.
242 *
243 */
244
245#if (CPU_USE_GENERIC_BITFIELD_CODE == FALSE)
246
247#define _CPU_Priority_Mask( _bit_number ) \
248    (1 << _bit_number)
249
250#endif
251
252#if (CPU_USE_GENERIC_BITFIELD_CODE == FALSE)
253
254#define _CPU_Priority_bits_index( _priority ) \
255  (_priority)
256
257#endif
258
259#define CPU_MAXIMUM_PROCESSORS 32
260
261#define CPU_TIMESTAMP_USE_STRUCT_TIMESPEC FALSE
262#define CPU_TIMESTAMP_USE_INT64 TRUE
263#define CPU_TIMESTAMP_USE_INT64_INLINE FALSE
264
265typedef struct {
266  /* There is no CPU specific per-CPU state */
267} CPU_Per_CPU_control;
268#endif /* ASM */
269
270#if __riscv_xlen == 32
271#define CPU_SIZEOF_POINTER 4
272
273/* 32-bit load/store instructions */
274#define LREG lw
275#define SREG sw
276
277#define CPU_EXCEPTION_FRAME_SIZE 128
278#else /* xlen = 64 */
279#define CPU_SIZEOF_POINTER 8
280
281/* 64-bit load/store instructions */
282#define LREG ld
283#define SREG sd
284
285#define CPU_EXCEPTION_FRAME_SIZE 256
286#endif
287
288#define CPU_PER_CPU_CONTROL_SIZE 0
289
290#ifndef ASM
291typedef uint16_t Priority_bit_map_Word;
292
293typedef struct {
294  unsigned long x[32];;
295} CPU_Exception_frame;
296
297/**
298 * @brief Prints the exception frame via printk().
299 *
300 * @see rtems_fatal() and RTEMS_FATAL_SOURCE_EXCEPTION.
301 */
302void _CPU_Exception_frame_print( const CPU_Exception_frame *frame );
303
304
305/* end of Priority handler macros */
306
307/* functions */
308
309/*
310 *  _CPU_Initialize
311 *
312 *  This routine performs CPU dependent initialization.
313 *
314 */
315
316void _CPU_Initialize(
317  void
318);
319
320/*
321 *  _CPU_ISR_install_raw_handler
322 *
323 *  This routine installs a "raw" interrupt handler directly into the
324 *  processor's vector table.
325 *
326 */
327
328void _CPU_ISR_install_raw_handler(
329  uint32_t    vector,
330  proc_ptr    new_handler,
331  proc_ptr   *old_handler
332);
333
334/*
335 *  _CPU_ISR_install_vector
336 *
337 *  This routine installs an interrupt vector.
338 *
339 *  NO_CPU Specific Information:
340 *
341 *  XXX document implementation including references if appropriate
342 */
343
344void _CPU_ISR_install_vector(
345  unsigned long    vector,
346  proc_ptr   new_handler,
347  proc_ptr   *old_handler
348);
349
350/*
351 *  _CPU_Thread_Idle_body
352 *
353 *  This routine is the CPU dependent IDLE thread body.
354 *
355 *  NOTE:  It need only be provided if CPU_PROVIDES_IDLE_THREAD_BODY
356 *         is TRUE.
357 *
358 */
359
360void *_CPU_Thread_Idle_body( uintptr_t ignored );
361
362/*
363 *  _CPU_Context_switch
364 *
365 *  This routine switches from the run context to the heir context.
366 *
367 *  RISCV Specific Information:
368 *
369 *  Please see the comments in the .c file for a description of how
370 *  this function works. There are several things to be aware of.
371 */
372
373void _CPU_Context_switch(
374  Context_Control  *run,
375  Context_Control  *heir
376);
377
378/*
379 *  _CPU_Context_restore
380 *
381 *  This routine is generally used only to restart self in an
382 *  efficient manner.  It may simply be a label in _CPU_Context_switch.
383 *
384 *  NOTE: May be unnecessary to reload some registers.
385 *
386 */
387
388void _CPU_Context_restore(
389  Context_Control *new_context
390) RTEMS_NO_RETURN;
391
392/*
393 *  _CPU_Context_save_fp
394 *
395 *  This routine saves the floating point context passed to it.
396 *
397 */
398
399void _CPU_Context_save_fp(
400  void **fp_context_ptr
401);
402
403/*
404 *  _CPU_Context_restore_fp
405 *
406 *  This routine restores the floating point context passed to it.
407 *
408 */
409
410void _CPU_Context_restore_fp(
411  void **fp_context_ptr
412);
413
414/*  The following routine swaps the endian format of an unsigned int.
415 *  It must be static because it is referenced indirectly.
416 *
417 *  This version will work on any processor, but if there is a better
418 *  way for your CPU PLEASE use it.  The most common way to do this is to:
419 *
420 *     swap least significant two bytes with 16-bit rotate
421 *     swap upper and lower 16-bits
422 *     swap most significant two bytes with 16-bit rotate
423 *
424 *  Some CPUs have special instructions which swap a 32-bit quantity in
425 *  a single instruction (e.g. i486).  It is probably best to avoid
426 *  an "endian swapping control bit" in the CPU.  One good reason is
427 *  that interrupts would probably have to be disabled to insure that
428 *  an interrupt does not try to access the same "chunk" with the wrong
429 *  endian.  Another good reason is that on some CPUs, the endian bit
430 *  endianness for ALL fetches -- both code and data -- so the code
431 *  will be fetched incorrectly.
432 *
433 */
434
435static inline uint32_t CPU_swap_u32(
436  uint32_t value
437)
438{
439  uint32_t   byte1, byte2, byte3, byte4, swapped;
440
441  byte4 = (value >> 24) & 0xff;
442  byte3 = (value >> 16) & 0xff;
443  byte2 = (value >> 8)  & 0xff;
444  byte1 =  value        & 0xff;
445
446  swapped = (byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4;
447  return ( swapped );
448}
449
450#define CPU_swap_u16( value ) \
451  (((value&0xff) << 8) | ((value >> 8)&0xff))
452
453static inline void _CPU_Context_volatile_clobber( uintptr_t pattern )
454{
455  /* TODO */
456}
457
458static inline void _CPU_Context_validate( uintptr_t pattern )
459{
460  while (1) {
461    /* TODO */
462  }
463}
464
465typedef uint32_t CPU_Counter_ticks;
466
467uint32_t _CPU_Counter_frequency( void );
468
469CPU_Counter_ticks _CPU_Counter_read( void );
470
471#ifdef RTEMS_SMP
472/**
473 * @brief Performs CPU specific SMP initialization in the context of the boot
474 * processor.
475 *
476 * This function is invoked on the boot processor during system
477 * initialization.  All interrupt stacks are allocated at this point in case
478 * the CPU port allocates the interrupt stacks.  This function is called
479 * before _CPU_SMP_Start_processor() or _CPU_SMP_Finalize_initialization() is
480 * used.
481 *
482 * @return The count of physically or virtually available processors.
483 * Depending on the configuration the application may use not all processors.
484 */
485uint32_t _CPU_SMP_Initialize( void );
486
487/**
488 * @brief Starts a processor specified by its index.
489 *
490 * This function is invoked on the boot processor during system
491 * initialization.
492 *
493 * This function will be called after _CPU_SMP_Initialize().
494 *
495 * @param[in] cpu_index The processor index.
496 *
497 * @retval true Successful operation.
498 * @retval false Unable to start this processor.
499 */
500bool _CPU_SMP_Start_processor( uint32_t cpu_index );
501
502/**
503 * @brief Performs final steps of CPU specific SMP initialization in the
504 * context of the boot processor.
505 *
506 * This function is invoked on the boot processor during system
507 * initialization.
508 *
509 * This function will be called after all processors requested by the
510 * application have been started.
511 *
512 * @param[in] cpu_count The minimum value of the count of processors
513 * requested by the application configuration and the count of physically or
514 * virtually available processors.
515 */
516void _CPU_SMP_Finalize_initialization( uint32_t cpu_count );
517
518/**
519 * @brief Returns the index of the current processor.
520 *
521 * An architecture specific method must be used to obtain the index of the
522 * current processor in the system.  The set of processor indices is the
523 * range of integers starting with zero up to the processor count minus one.
524 */
525uint32_t _CPU_SMP_Get_current_processor( void );
526
527/**
528 * @brief Sends an inter-processor interrupt to the specified target
529 * processor.
530 *
531 * This operation is undefined for target processor indices out of range.
532 *
533 * @param[in] target_processor_index The target processor index.
534 */
535void _CPU_SMP_Send_interrupt( uint32_t target_processor_index );
536
537/**
538 * @brief Broadcasts a processor event.
539 *
540 * Some architectures provide a low-level synchronization primitive for
541 * processors in a multi-processor environment.  Processors waiting for this
542 * event may go into a low-power state and stop generating system bus
543 * transactions.  This function must ensure that preceding store operations
544 * can be observed by other processors.
545 *
546 * @see _CPU_SMP_Processor_event_receive().
547 */
548void _CPU_SMP_Processor_event_broadcast( void );
549
550/**
551 * @brief Receives a processor event.
552 *
553 * This function will wait for the processor event and may wait forever if no
554 * such event arrives.
555 *
556 * @see _CPU_SMP_Processor_event_broadcast().
557 */
558static inline void _CPU_SMP_Processor_event_receive( void )
559{
560  __asm__ volatile ( "" : : : "memory" );
561}
562
563/**
564 * @brief Gets the is executing indicator of the thread context.
565 *
566 * @param[in] context The context.
567 */
568static inline bool _CPU_Context_Get_is_executing(
569  const Context_Control *context
570)
571{
572  return context->is_executing;
573}
574
575/**
576 * @brief Sets the is executing indicator of the thread context.
577 *
578 * @param[in] context The context.
579 * @param[in] is_executing The new value for the is executing indicator.
580 */
581static inline void _CPU_Context_Set_is_executing(
582  Context_Control *context,
583  bool is_executing
584)
585{
586  context->is_executing = is_executing;
587}
588#endif /* RTEMS_SMP */
589
590/** Type that can store a 32-bit integer or a pointer. */
591typedef uintptr_t CPU_Uint32ptr;
592
593#endif /* ASM */
594
595#ifdef __cplusplus
596}
597#endif
598
599#endif
Note: See TracBrowser for help on using the repository browser.