RTEMS  5.0.0
cpu.h
Go to the documentation of this file.
1 
6 /*
7  * Copyright (c) 2018 embedded brains GmbH
8  *
9  * Copyright (c) 2015 University of York.
10  * Hesham Almatary <hesham@alumni.york.ac.uk>
11  *
12  * COPYRIGHT (c) 1989-1999.
13  * On-Line Applications Research Corporation (OAR).
14  *
15  * Redistribution and use in source and binary forms, with or without
16  * modification, are permitted provided that the following conditions
17  * are met:
18  * 1. Redistributions of source code must retain the above copyright
19  * notice, this list of conditions and the following disclaimer.
20  * 2. Redistributions in binary form must reproduce the above copyright
21  * notice, this list of conditions and the following disclaimer in the
22  * documentation and/or other materials provided with the distribution.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 #ifndef _RISCV_CPU_H
38 #define _RISCV_CPU_H
39 
40 #ifdef __cplusplus
41 extern "C" {
42 #endif
43 
44 #include <rtems/score/basedefs.h>
45 #include <rtems/score/riscv.h>
46 
47 #define RISCV_MSTATUS_MIE 0x8
48 
49 #define CPU_ISR_PASSES_FRAME_POINTER FALSE
50 
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 
57 #define CPU_ENABLE_ROBUST_THREAD_DISPATCH TRUE
58 
59 #define CPU_STACK_GROWS_UP FALSE
60 
61 #define CPU_STRUCTURE_ALIGNMENT __attribute__ ((aligned (64)))
62 #define CPU_BIG_ENDIAN FALSE
63 #define CPU_LITTLE_ENDIAN TRUE
64 #define CPU_MODES_INTERRUPT_MASK 0x0000000000000001
65 
66 #define CPU_CACHE_LINE_BYTES 64
67 
68 #if __riscv_xlen == 32
69 
70 #define CPU_SIZEOF_POINTER 4
71 
72 #define CPU_STACK_MINIMUM_SIZE 4096
73 
74 #elif __riscv_xlen == 64
75 
76 #define CPU_SIZEOF_POINTER 8
77 
78 #define CPU_STACK_MINIMUM_SIZE 8192
79 
80 #endif /* __riscv_xlen */
81 
82 /* RISC-V ELF psABI specification */
83 #define CPU_ALIGNMENT 16
84 
85 #define CPU_HEAP_ALIGNMENT CPU_ALIGNMENT
86 
87 /* RISC-V ELF psABI specification */
88 #define CPU_STACK_ALIGNMENT 16
89 
90 #define CPU_INTERRUPT_STACK_ALIGNMENT CPU_CACHE_LINE_BYTES
91 
92 /*
93  * Processor defined structures required for cpukit/score.
94  */
95 
96 #ifndef ASM
97 
98 #if __riscv_flen == 32
99 typedef float RISCV_Float;
100 #elif __riscv_flen == 64
101 typedef double RISCV_Float;
102 #endif
103 
104 typedef struct {
105 #ifdef RTEMS_SMP
106  volatile uint32_t is_executing;
107 #else
108  uint32_t reserved;
109 #endif
111  uintptr_t ra;
112  uintptr_t sp;
113  uintptr_t tp;
114  uintptr_t s0;
115  uintptr_t s1;
116  uintptr_t s2;
117  uintptr_t s3;
118  uintptr_t s4;
119  uintptr_t s5;
120  uintptr_t s6;
121  uintptr_t s7;
122  uintptr_t s8;
123  uintptr_t s9;
124  uintptr_t s10;
125  uintptr_t s11;
126 #if __riscv_flen > 0
127  uint32_t fcsr;
128  RISCV_Float fs0;
129  RISCV_Float fs1;
130  RISCV_Float fs2;
131  RISCV_Float fs3;
132  RISCV_Float fs4;
133  RISCV_Float fs5;
134  RISCV_Float fs6;
135  RISCV_Float fs7;
136  RISCV_Float fs8;
137  RISCV_Float fs9;
138  RISCV_Float fs10;
139  RISCV_Float fs11;
140 #endif
142 
143 #define _CPU_Context_Get_SP( _context ) \
144  (_context)->sp
145 
146 #define CPU_MPCI_RECEIVE_SERVER_EXTRA_STACK 0
147 
148 #define CPU_PROVIDES_ISR_IS_IN_PROGRESS FALSE
149 
150 #define _CPU_Initialize_vectors()
151 
152 static inline uint32_t riscv_interrupt_disable( void )
153 {
154  unsigned long mstatus;
155 
156  __asm__ volatile (
157  "csrrc %0, mstatus, " RTEMS_XSTRING( RISCV_MSTATUS_MIE ) :
158  "=&r" ( mstatus )
159  );
160 
161  return mstatus & RISCV_MSTATUS_MIE;
162 }
163 
164 static inline void riscv_interrupt_enable( uint32_t level )
165 {
166  __asm__ volatile ( "csrrs zero, mstatus, %0" : : "r" ( level ) );
167 }
168 
169 #define _CPU_ISR_Disable( _level ) \
170  _level = riscv_interrupt_disable()
171 
172 #define _CPU_ISR_Enable( _level ) \
173  riscv_interrupt_enable( _level )
174 
175 #define _CPU_ISR_Flash( _level ) \
176  do{ \
177  _CPU_ISR_Enable( _level ); \
178  riscv_interrupt_disable(); \
179  } while(0)
180 
181 RTEMS_INLINE_ROUTINE bool _CPU_ISR_Is_enabled( unsigned long level )
182 {
183  return ( level & RISCV_MSTATUS_MIE ) != 0;
184 }
185 
187 {
188  if ( ( level & CPU_MODES_INTERRUPT_MASK) == 0 ) {
189  __asm__ volatile (
190  "csrrs zero, mstatus, " RTEMS_XSTRING( RISCV_MSTATUS_MIE )
191  );
192  } else {
193  __asm__ volatile (
194  "csrrc zero, mstatus, " RTEMS_XSTRING( RISCV_MSTATUS_MIE )
195  );
196  }
197 }
198 
199 uint32_t _CPU_ISR_Get_level( void );
200 
201 /* end of ISR handler macros */
202 
205  void *stack_area_begin,
206  size_t stack_area_size,
207  uint32_t new_level,
208  void ( *entry_point )( void ),
209  bool is_fp,
210  void *tls_area
211 );
212 
213 #define _CPU_Context_Restart_self( _the_context ) \
214  _CPU_Context_restore( (_the_context) )
215 
216 extern void _CPU_Fatal_halt(uint32_t source, uint32_t error) RTEMS_NO_RETURN;
217 
218 #define CPU_USE_GENERIC_BITFIELD_CODE TRUE
219 
220 #define CPU_USE_GENERIC_BITFIELD_DATA TRUE
221 
222 #define CPU_MAXIMUM_PROCESSORS 32
223 
224 typedef uint16_t Priority_bit_map_Word;
225 
226 /*
227  * See The RISC-V Instruction Set Manual, Volume II: RISC-V Privileged
228  * Architectures V1.10, Table 3.6: Machine cause register (mcause) values after
229  * trap.
230  */
231 typedef enum {
232  RISCV_INTERRUPT_SOFTWARE_USER = 0,
233  RISCV_INTERRUPT_SOFTWARE_SUPERVISOR = 1,
234  RISCV_INTERRUPT_SOFTWARE_MACHINE = 3,
235  RISCV_INTERRUPT_TIMER_USER = 4,
236  RISCV_INTERRUPT_TIMER_SUPERVISOR = 5,
237  RISCV_INTERRUPT_TIMER_MACHINE = 7,
238  RISCV_INTERRUPT_EXTERNAL_USER = 8,
239  RISCV_INTERRUPT_EXTERNAL_SUPERVISOR = 9,
240  RISCV_INTERRUPT_EXTERNAL_MACHINE = 11
241 } RISCV_Interrupt_code;
242 
243 /*
244  * See The RISC-V Instruction Set Manual, Volume II: RISC-V Privileged
245  * Architectures V1.10, Table 3.6: Machine cause register (mcause) values after
246  * trap.
247  */
248 typedef enum {
249  RISCV_EXCEPTION_INSTRUCTION_ADDRESS_MISALIGNED = 0,
250  RISCV_EXCEPTION_INSTRUCTION_ACCESS_FAULT = 1,
251  RISCV_EXCEPTION_ILLEGAL_INSTRUCTION = 2,
252  RISCV_EXCEPTION_BREAKPOINT = 3,
253  RISCV_EXCEPTION_LOAD_ADDRESS_MISALIGNED = 4,
254  RISCV_EXCEPTION_LOAD_ACCESS_FAULT = 5,
255  RISCV_EXCEPTION_STORE_OR_AMO_ADDRESS_MISALIGNED = 6,
256  RISCV_EXCEPTION_STORE_OR_AMO_ACCESS_FAULT = 7,
257  RISCV_EXCEPTION_ENVIRONMENT_CALL_FROM_U_MODE = 8,
258  RISCV_EXCEPTION_ENVIRONMENT_CALL_FROM_S_MODE = 9,
259  RISCV_EXCEPTION_ENVIRONMENT_CALL_FROM_M_MODE = 11,
260  RISCV_EXCEPTION_INSTRUCTION_PAGE_FAULT = 12,
261  RISCV_EXCEPTION_LOAD_PAGE_FAULT = 13,
262  RISCV_EXCEPTION_STORE_OR_AMO_PAGE_FAULT = 15
263 } RISCV_Exception_code;
264 
265 typedef struct {
266  uintptr_t mstatus;
267  uintptr_t mepc;
268  uintptr_t a2;
269  uintptr_t s0;
270  uintptr_t s1;
271  uintptr_t ra;
272  uintptr_t a3;
273  uintptr_t a4;
274  uintptr_t a5;
275  uintptr_t a6;
276  uintptr_t a7;
277  uintptr_t t0;
278  uintptr_t t1;
279  uintptr_t t2;
280  uintptr_t t3;
281  uintptr_t t4;
282  uintptr_t t5;
283  uintptr_t t6;
284 #if __riscv_flen > 0
285  uint32_t fcsr;
286  RISCV_Float ft0;
287  RISCV_Float ft1;
288  RISCV_Float ft2;
289  RISCV_Float ft3;
290  RISCV_Float ft4;
291  RISCV_Float ft5;
292  RISCV_Float ft6;
293  RISCV_Float ft7;
294  RISCV_Float ft8;
295  RISCV_Float ft9;
296  RISCV_Float ft10;
297  RISCV_Float ft11;
298  RISCV_Float fa0;
299  RISCV_Float fa1;
300  RISCV_Float fa2;
301  RISCV_Float fa3;
302  RISCV_Float fa4;
303  RISCV_Float fa5;
304  RISCV_Float fa6;
305  RISCV_Float fa7;
306 #endif
307  uintptr_t a0;
308  uintptr_t a1;
310 
311 typedef struct {
312  CPU_Interrupt_frame Interrupt_frame;
313  uintptr_t mcause;
314  uintptr_t sp;
315  uintptr_t gp;
316  uintptr_t tp;
317  uintptr_t s2;
318  uintptr_t s3;
319  uintptr_t s4;
320  uintptr_t s5;
321  uintptr_t s6;
322  uintptr_t s7;
323  uintptr_t s8;
324  uintptr_t s9;
325  uintptr_t s10;
326  uintptr_t s11;
327 #if __riscv_flen > 0
328  RISCV_Float fs0;
329  RISCV_Float fs1;
330  RISCV_Float fs2;
331  RISCV_Float fs3;
332  RISCV_Float fs4;
333  RISCV_Float fs5;
334  RISCV_Float fs6;
335  RISCV_Float fs7;
336  RISCV_Float fs8;
337  RISCV_Float fs9;
338  RISCV_Float fs10;
339  RISCV_Float fs11;
340 #endif
342 
349 
350 
351 /* end of Priority handler macros */
352 
353 /* functions */
354 
355 /*
356  * _CPU_Initialize
357  *
358  * This routine performs CPU dependent initialization.
359  *
360  */
361 
362 void _CPU_Initialize(
363  void
364 );
365 
366 void *_CPU_Thread_Idle_body( uintptr_t ignored );
367 
368 /*
369  * _CPU_Context_switch
370  *
371  * This routine switches from the run context to the heir context.
372  *
373  * RISCV Specific Information:
374  *
375  * Please see the comments in the .c file for a description of how
376  * this function works. There are several things to be aware of.
377  */
378 
380  Context_Control *run,
381  Context_Control *heir
382 );
383 
384 /*
385  * _CPU_Context_restore
386  *
387  * This routine is generally used only to restart self in an
388  * efficient manner. It may simply be a label in _CPU_Context_switch.
389  *
390  * NOTE: May be unnecessary to reload some registers.
391  *
392  */
393 
395  Context_Control *new_context
397 
398 /* The following routine swaps the endian format of an unsigned int.
399  * It must be static because it is referenced indirectly.
400  *
401  * This version will work on any processor, but if there is a better
402  * way for your CPU PLEASE use it. The most common way to do this is to:
403  *
404  * swap least significant two bytes with 16-bit rotate
405  * swap upper and lower 16-bits
406  * swap most significant two bytes with 16-bit rotate
407  *
408  * Some CPUs have special instructions which swap a 32-bit quantity in
409  * a single instruction (e.g. i486). It is probably best to avoid
410  * an "endian swapping control bit" in the CPU. One good reason is
411  * that interrupts would probably have to be disabled to insure that
412  * an interrupt does not try to access the same "chunk" with the wrong
413  * endian. Another good reason is that on some CPUs, the endian bit
414  * endianness for ALL fetches -- both code and data -- so the code
415  * will be fetched incorrectly.
416  *
417  */
418 
419 static inline uint32_t CPU_swap_u32(
420  uint32_t value
421 )
422 {
423  uint32_t byte1, byte2, byte3, byte4, swapped;
424 
425  byte4 = (value >> 24) & 0xff;
426  byte3 = (value >> 16) & 0xff;
427  byte2 = (value >> 8) & 0xff;
428  byte1 = value & 0xff;
429 
430  swapped = (byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4;
431  return ( swapped );
432 }
433 
434 #define CPU_swap_u16( value ) \
435  (((value&0xff) << 8) | ((value >> 8)&0xff))
436 
437 typedef uint32_t CPU_Counter_ticks;
438 
439 uint32_t _CPU_Counter_frequency( void );
440 
441 extern volatile uint32_t * const _RISCV_Counter;
442 
443 CPU_Counter_ticks _CPU_Counter_read( void );
444 
445 static inline CPU_Counter_ticks _CPU_Counter_difference(
446  CPU_Counter_ticks second,
447  CPU_Counter_ticks first
448 )
449 {
450  return second - first;
451 }
452 
453 #ifdef RTEMS_SMP
454 
455 uint32_t _CPU_SMP_Initialize( void );
456 
457 bool _CPU_SMP_Start_processor( uint32_t cpu_index );
458 
459 void _CPU_SMP_Finalize_initialization( uint32_t cpu_count );
460 
461 void _CPU_SMP_Prepare_start_multitasking( void );
462 
463 static inline uint32_t _CPU_SMP_Get_current_processor( void )
464 {
465  unsigned long mhartid;
466 
467  __asm__ volatile ( "csrr %0, mhartid" : "=&r" ( mhartid ) );
468 
469  return (uint32_t) mhartid;
470 }
471 
472 void _CPU_SMP_Send_interrupt( uint32_t target_processor_index );
473 
474 static inline void _CPU_SMP_Processor_event_broadcast( void )
475 {
476  __asm__ volatile ( "" : : : "memory" );
477 }
478 
479 static inline void _CPU_SMP_Processor_event_receive( void )
480 {
481  __asm__ volatile ( "" : : : "memory" );
482 }
483 
484 static inline bool _CPU_Context_Get_is_executing(
485  const Context_Control *context
486 )
487 {
488  return context->is_executing;
489 }
490 
491 static inline void _CPU_Context_Set_is_executing(
492  Context_Control *context,
493  bool is_executing
494 )
495 {
496  context->is_executing = is_executing;
497 }
498 
499 #endif /* RTEMS_SMP */
500 
502 typedef uintptr_t CPU_Uint32ptr;
503 
504 #endif /* ASM */
505 
506 #ifdef __cplusplus
507 }
508 #endif
509 
510 #endif
#define sp
stack-pointer */
Definition: regs.h:64
void _CPU_Exception_frame_print(const CPU_Exception_frame *frame)
Prints the exception frame via printk().
Definition: vectorexceptions.c:45
void _CPU_ISR_Set_level(uint32_t level)
Sets the hardware interrupt level by the level value.
Definition: cpu.c:57
CPU_Counter_ticks _CPU_Counter_read(void)
Returns the current CPU counter value.
Definition: system-clocks.c:117
Thread register context.
Definition: cpu.h:196
uint32_t isr_dispatch_disable
Definition: cpu.h:110
void * _CPU_Thread_Idle_body(uintptr_t ignored)
Definition: idle-mcf5272.c:20
#define RTEMS_INLINE_ROUTINE
Definition: basedefs.h:65
Interrupt stack frame (ISF).
Definition: cpu.h:306
void _CPU_Context_Initialize(Context_Control *context, void *stack_area_begin, size_t stack_area_size, uint32_t new_level, void(*entry_point)(void), bool is_fp, void *tls_area)
Initializes the CPU context.
Definition: epiphany-context-initialize.c:40
void _CPU_Context_switch(Context_Control *run, Context_Control *heir)
CPU switch context.
Definition: cpu_asm.c:91
#define CPU_STACK_ALIGNMENT
Definition: cpu.h:446
void _CPU_Initialize(void)
CPU initialization.
Definition: cpu.c:45
register struct Per_CPU_Control *_SPARC_Per_CPU_current __asm__("g6")
The pointer to the current per-CPU control is available via register g6.
uint32_t CPU_Counter_ticks
Unsigned integer type for CPU counter values.
Definition: cpu.h:1202
#define RTEMS_NO_RETURN
Definition: basedefs.h:101
uint32_t _CPU_ISR_Get_level(void)
Definition: cpu.c:88
#define RTEMS_XSTRING(_x)
Stringifies expansion of _x.
Definition: basedefs.h:509
#define RTEMS_ALIGNED(_alignment)
Instructs the compiler to enforce the specified alignment.
Definition: basedefs.h:204
unsigned context
Definition: tlb.h:108
bool _CPU_ISR_Is_enabled(uint32_t level)
Returns true if interrupts are enabled in the specified ISR level, otherwise returns false...
Definition: cpu.h:381
void _CPU_Context_restore(Context_Control *new_context) RTEMS_NO_RETURN
Definition: cpu_asm.c:111
uintptr_t CPU_Uint32ptr
Definition: cpu.h:668
uint32_t _CPU_Counter_frequency(void)
Returns the current CPU counter frequency in Hz.
Definition: system-clocks.c:112
Basic Definitions.
#define ra
return address */
Definition: regs.h:66
void _CPU_Fatal_halt(uint32_t source, uint32_t error) RTEMS_NO_RETURN
Definition: bsp_fatal_halt.c:12
The set of registers that specifies the complete processor state.
Definition: cpu.h:635
#define CPU_MODES_INTERRUPT_MASK
Definition: cpu.h:161
#define gp
global data pointer */
Definition: regs.h:63