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

5
Last change on this file since 9510742 was 9510742, checked in by Sebastian Huber <sebastian.huber@…>, on 06/27/18 at 06:35:13

riscv: Fix CPU_STACK_ALIGNMENT

According to the RISC-V psABI

https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md

the stack alignment is 128 bits (16 bytes).

Update #3433.

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