source: rtems/cpukit/score/cpu/riscv/include/rtems/score/cpu.h @ 715d616

5
Last change on this file since 715d616 was c8df844, checked in by Sebastian Huber <sebastian.huber@…>, on 06/19/18 at 12:59:51

score: Add CPU_INTERRUPT_STACK_ALIGNMENT

Add CPU port define for the interrupt stack alignment. The alignment
should take the stack ABI and the cache line size into account.

Update #3459.

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