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

5
Last change on this file since 8db3f0e was 8db3f0e, checked in by Sebastian Huber <sebastian.huber@…>, on 07/19/18 at 10:11:19

riscv: Rework exception handling

Remove _CPU_ISR_install_raw_handler() and _CPU_ISR_install_vector()
functions. Applications can install an exception handler via the fatal
error handler to handle synchronous exceptions.

Handle interrupt exceptions via _RISCV_Interrupt_dispatch() which must
be provided by the BSP.

Update #3433.

  • Property mode set to 100644
File size: 12.3 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_ISR_PASSES_FRAME_POINTER FALSE
49
50#define CPU_HARDWARE_FP                  FALSE
51#define CPU_SOFTWARE_FP                  FALSE
52#define CPU_ALL_TASKS_ARE_FP             FALSE
53#define CPU_IDLE_TASK_IS_FP              FALSE
54#define CPU_USE_DEFERRED_FP_SWITCH       FALSE
55#define CPU_PROVIDES_IDLE_THREAD_BODY    TRUE
56#define CPU_STACK_GROWS_UP               FALSE
57
58#define CPU_STRUCTURE_ALIGNMENT __attribute__ ((aligned (64)))
59#define CPU_BIG_ENDIAN                           FALSE
60#define CPU_LITTLE_ENDIAN                        TRUE
61#define CPU_MODES_INTERRUPT_MASK   0x0000000000000001
62
63#define CPU_CACHE_LINE_BYTES 64
64
65#if __riscv_xlen == 32
66
67#define CPU_SIZEOF_POINTER 4
68
69#define CPU_STACK_MINIMUM_SIZE 4096
70
71#elif __riscv_xlen == 64
72
73#define CPU_SIZEOF_POINTER 8
74
75#define CPU_STACK_MINIMUM_SIZE 8192
76
77#endif /* __riscv_xlen */
78
79#define CPU_ALIGNMENT 8
80
81#define CPU_HEAP_ALIGNMENT CPU_ALIGNMENT
82
83#define CPU_PARTITION_ALIGNMENT CPU_ALIGNMENT
84
85#define CPU_STACK_ALIGNMENT 16
86
87#define CPU_INTERRUPT_STACK_ALIGNMENT CPU_CACHE_LINE_BYTES
88
89/*
90 *  Processor defined structures required for cpukit/score.
91 */
92
93#ifndef ASM
94
95#if __riscv_flen == 32
96typedef float RISCV_Float;
97#elif __riscv_flen == 64
98typedef double RISCV_Float;
99#endif
100
101typedef struct {
102#ifdef RTEMS_SMP
103  volatile uint32_t is_executing;
104#else
105  uint32_t reserved;
106#endif
107  uint32_t isr_dispatch_disable;
108  uintptr_t ra;
109  uintptr_t sp;
110  uintptr_t tp;
111  uintptr_t s0;
112  uintptr_t s1;
113  uintptr_t s2;
114  uintptr_t s3;
115  uintptr_t s4;
116  uintptr_t s5;
117  uintptr_t s6;
118  uintptr_t s7;
119  uintptr_t s8;
120  uintptr_t s9;
121  uintptr_t s10;
122  uintptr_t s11;
123#if __riscv_flen > 0
124  uint32_t fcsr;
125  RISCV_Float fs0;
126  RISCV_Float fs1;
127  RISCV_Float fs2;
128  RISCV_Float fs3;
129  RISCV_Float fs4;
130  RISCV_Float fs5;
131  RISCV_Float fs6;
132  RISCV_Float fs7;
133  RISCV_Float fs8;
134  RISCV_Float fs9;
135  RISCV_Float fs10;
136  RISCV_Float fs11;
137#endif
138} Context_Control;
139
140#define _CPU_Context_Get_SP( _context ) \
141  (_context)->sp
142
143#define CPU_MPCI_RECEIVE_SERVER_EXTRA_STACK 0
144
145#define CPU_PROVIDES_ISR_IS_IN_PROGRESS FALSE
146
147#define _CPU_Initialize_vectors()
148
149static inline uint32_t riscv_interrupt_disable( void )
150{
151  unsigned long mstatus;
152
153  __asm__ volatile (
154    "csrrc %0, mstatus, " RTEMS_XSTRING( RISCV_MSTATUS_MIE ) :
155      "=&r" ( mstatus )
156  );
157
158  return mstatus & RISCV_MSTATUS_MIE;
159}
160
161static inline void riscv_interrupt_enable( uint32_t level )
162{
163  __asm__ volatile ( "csrrs zero, mstatus, %0" : : "r" ( level ) );
164}
165
166#define _CPU_ISR_Disable( _level ) \
167    _level = riscv_interrupt_disable()
168
169#define _CPU_ISR_Enable( _level )  \
170  riscv_interrupt_enable( _level )
171
172#define _CPU_ISR_Flash( _level ) \
173  do{ \
174      _CPU_ISR_Enable( _level ); \
175      riscv_interrupt_disable(); \
176    } while(0)
177
178RTEMS_INLINE_ROUTINE bool _CPU_ISR_Is_enabled( unsigned long level )
179{
180  return ( level & RISCV_MSTATUS_MIE ) != 0;
181}
182
183RTEMS_INLINE_ROUTINE void _CPU_ISR_Set_level( uint32_t level )
184{
185  if ( ( level & CPU_MODES_INTERRUPT_MASK) == 0 ) {
186    __asm__ volatile (
187      "csrrs zero, mstatus, " RTEMS_XSTRING( RISCV_MSTATUS_MIE )
188    );
189  } else {
190    __asm__ volatile (
191      "csrrc zero, mstatus, " RTEMS_XSTRING( RISCV_MSTATUS_MIE )
192    );
193  }
194}
195
196uint32_t _CPU_ISR_Get_level( void );
197
198/* end of ISR handler macros */
199
200void _CPU_Context_Initialize(
201  Context_Control *context,
202  void            *stack_area_begin,
203  size_t           stack_area_size,
204  uint32_t         new_level,
205  void          ( *entry_point )( void ),
206  bool             is_fp,
207  void            *tls_area
208);
209
210#define _CPU_Context_Restart_self( _the_context ) \
211   _CPU_Context_restore( (_the_context) )
212
213extern void _CPU_Fatal_halt(uint32_t source, uint32_t error) RTEMS_NO_RETURN;
214
215#define CPU_USE_GENERIC_BITFIELD_CODE TRUE
216
217#define CPU_USE_GENERIC_BITFIELD_DATA TRUE
218
219#define CPU_MAXIMUM_PROCESSORS 32
220
221typedef uint16_t Priority_bit_map_Word;
222
223/*
224 * See The RISC-V Instruction Set Manual, Volume II: RISC-V Privileged
225 * Architectures V1.10, Table 3.6: Machine cause register (mcause) values after
226 * trap.
227 */
228typedef enum {
229  RISCV_INTERRUPT_SOFTWARE_USER = 0,
230  RISCV_INTERRUPT_SOFTWARE_SUPERVISOR = 1,
231  RISCV_INTERRUPT_SOFTWARE_MACHINE = 3,
232  RISCV_INTERRUPT_TIMER_USER = 4,
233  RISCV_INTERRUPT_TIMER_SUPERVISOR = 5,
234  RISCV_INTERRUPT_TIMER_MACHINE = 7,
235  RISCV_INTERRUPT_EXTERNAL_USER = 8,
236  RISCV_INTERRUPT_EXTERNAL_SUPERVISOR = 9,
237  RISCV_INTERRUPT_EXTERNAL_MACHINE = 11
238} RISCV_Interrupt_code;
239
240/*
241 * See The RISC-V Instruction Set Manual, Volume II: RISC-V Privileged
242 * Architectures V1.10, Table 3.6: Machine cause register (mcause) values after
243 * trap.
244 */
245typedef enum {
246  RISCV_EXCEPTION_INSTRUCTION_ADDRESS_MISALIGNED = 0,
247  RISCV_EXCEPTION_INSTRUCTION_ACCESS_FAULT = 1,
248  RISCV_EXCEPTION_ILLEGAL_INSTRUCTION = 2,
249  RISCV_EXCEPTION_BREAKPOINT = 3,
250  RISCV_EXCEPTION_LOAD_ADDRESS_MISALIGNED = 4,
251  RISCV_EXCEPTION_LOAD_ACCESS_FAULT = 5,
252  RISCV_EXCEPTION_STORE_OR_AMO_ADDRESS_MISALIGNED = 6,
253  RISCV_EXCEPTION_STORE_OR_AMO_ACCESS_FAULT = 7,
254  RISCV_EXCEPTION_ENVIRONMENT_CALL_FROM_U_MODE = 8,
255  RISCV_EXCEPTION_ENVIRONMENT_CALL_FROM_S_MODE = 9,
256  RISCV_EXCEPTION_ENVIRONMENT_CALL_FROM_M_MODE = 11,
257  RISCV_EXCEPTION_INSTRUCTION_PAGE_FAULT = 12,
258  RISCV_EXCEPTION_LOAD_PAGE_FAULT = 13,
259  RISCV_EXCEPTION_STORE_OR_AMO_PAGE_FAULT = 15
260} RISCV_Exception_code;
261
262typedef struct {
263  uintptr_t mstatus;
264  uintptr_t mepc;
265  uintptr_t a2;
266  uintptr_t s0;
267  uintptr_t s1;
268  uintptr_t ra;
269  uintptr_t a3;
270  uintptr_t a4;
271  uintptr_t a5;
272  uintptr_t a6;
273  uintptr_t a7;
274  uintptr_t t0;
275  uintptr_t t1;
276  uintptr_t t2;
277  uintptr_t t3;
278  uintptr_t t4;
279  uintptr_t t5;
280  uintptr_t t6;
281#if __riscv_flen > 0
282  uint32_t fcsr;
283  RISCV_Float ft0;
284  RISCV_Float ft1;
285  RISCV_Float ft2;
286  RISCV_Float ft3;
287  RISCV_Float ft4;
288  RISCV_Float ft5;
289  RISCV_Float ft6;
290  RISCV_Float ft7;
291  RISCV_Float ft8;
292  RISCV_Float ft9;
293  RISCV_Float ft10;
294  RISCV_Float ft11;
295  RISCV_Float fa0;
296  RISCV_Float fa1;
297  RISCV_Float fa2;
298  RISCV_Float fa3;
299  RISCV_Float fa4;
300  RISCV_Float fa5;
301  RISCV_Float fa6;
302  RISCV_Float fa7;
303#endif
304  uintptr_t a0;
305  uintptr_t a1;
306} RTEMS_ALIGNED( CPU_STACK_ALIGNMENT ) CPU_Interrupt_frame;
307
308typedef struct {
309  CPU_Interrupt_frame Interrupt_frame;
310  uintptr_t mcause;
311  uintptr_t sp;
312  uintptr_t gp;
313  uintptr_t tp;
314  uintptr_t s2;
315  uintptr_t s3;
316  uintptr_t s4;
317  uintptr_t s5;
318  uintptr_t s6;
319  uintptr_t s7;
320  uintptr_t s8;
321  uintptr_t s9;
322  uintptr_t s10;
323  uintptr_t s11;
324#if __riscv_flen > 0
325  RISCV_Float fs0;
326  RISCV_Float fs1;
327  RISCV_Float fs2;
328  RISCV_Float fs3;
329  RISCV_Float fs4;
330  RISCV_Float fs5;
331  RISCV_Float fs6;
332  RISCV_Float fs7;
333  RISCV_Float fs8;
334  RISCV_Float fs9;
335  RISCV_Float fs10;
336  RISCV_Float fs11;
337#endif
338} CPU_Exception_frame;
339
340/**
341 * @brief Prints the exception frame via printk().
342 *
343 * @see rtems_fatal() and RTEMS_FATAL_SOURCE_EXCEPTION.
344 */
345void _CPU_Exception_frame_print( const CPU_Exception_frame *frame );
346
347
348/* end of Priority handler macros */
349
350/* functions */
351
352/*
353 *  _CPU_Initialize
354 *
355 *  This routine performs CPU dependent initialization.
356 *
357 */
358
359void _CPU_Initialize(
360  void
361);
362
363/*
364 *  _CPU_Thread_Idle_body
365 *
366 *  This routine is the CPU dependent IDLE thread body.
367 *
368 *  NOTE:  It need only be provided if CPU_PROVIDES_IDLE_THREAD_BODY
369 *         is TRUE.
370 *
371 */
372
373void *_CPU_Thread_Idle_body( uintptr_t ignored );
374
375/*
376 *  _CPU_Context_switch
377 *
378 *  This routine switches from the run context to the heir context.
379 *
380 *  RISCV Specific Information:
381 *
382 *  Please see the comments in the .c file for a description of how
383 *  this function works. There are several things to be aware of.
384 */
385
386void _CPU_Context_switch(
387  Context_Control  *run,
388  Context_Control  *heir
389);
390
391/*
392 *  _CPU_Context_restore
393 *
394 *  This routine is generally used only to restart self in an
395 *  efficient manner.  It may simply be a label in _CPU_Context_switch.
396 *
397 *  NOTE: May be unnecessary to reload some registers.
398 *
399 */
400
401void _CPU_Context_restore(
402  Context_Control *new_context
403) RTEMS_NO_RETURN;
404
405/*  The following routine swaps the endian format of an unsigned int.
406 *  It must be static because it is referenced indirectly.
407 *
408 *  This version will work on any processor, but if there is a better
409 *  way for your CPU PLEASE use it.  The most common way to do this is to:
410 *
411 *     swap least significant two bytes with 16-bit rotate
412 *     swap upper and lower 16-bits
413 *     swap most significant two bytes with 16-bit rotate
414 *
415 *  Some CPUs have special instructions which swap a 32-bit quantity in
416 *  a single instruction (e.g. i486).  It is probably best to avoid
417 *  an "endian swapping control bit" in the CPU.  One good reason is
418 *  that interrupts would probably have to be disabled to insure that
419 *  an interrupt does not try to access the same "chunk" with the wrong
420 *  endian.  Another good reason is that on some CPUs, the endian bit
421 *  endianness for ALL fetches -- both code and data -- so the code
422 *  will be fetched incorrectly.
423 *
424 */
425
426static inline uint32_t CPU_swap_u32(
427  uint32_t value
428)
429{
430  uint32_t   byte1, byte2, byte3, byte4, swapped;
431
432  byte4 = (value >> 24) & 0xff;
433  byte3 = (value >> 16) & 0xff;
434  byte2 = (value >> 8)  & 0xff;
435  byte1 =  value        & 0xff;
436
437  swapped = (byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4;
438  return ( swapped );
439}
440
441#define CPU_swap_u16( value ) \
442  (((value&0xff) << 8) | ((value >> 8)&0xff))
443
444typedef uint32_t CPU_Counter_ticks;
445
446uint32_t _CPU_Counter_frequency( void );
447
448static inline CPU_Counter_ticks _CPU_Counter_read( void )
449{
450  unsigned long ticks;
451
452  __asm__ volatile ( "rdtime %0" : "=&r" ( ticks ) );
453
454  return (uint32_t) ticks;
455}
456
457static inline CPU_Counter_ticks _CPU_Counter_difference(
458  CPU_Counter_ticks second,
459  CPU_Counter_ticks first
460)
461{
462  return second - first;
463}
464
465#ifdef RTEMS_SMP
466
467uint32_t _CPU_SMP_Initialize( void );
468
469bool _CPU_SMP_Start_processor( uint32_t cpu_index );
470
471void _CPU_SMP_Finalize_initialization( uint32_t cpu_count );
472
473void _CPU_SMP_Prepare_start_multitasking( void );
474
475static inline uint32_t _CPU_SMP_Get_current_processor( void )
476{
477  unsigned long mhartid;
478
479  __asm__ volatile ( "csrr %0, mhartid" : "=&r" ( mhartid ) );
480
481  return (uint32_t) mhartid;
482}
483
484void _CPU_SMP_Send_interrupt( uint32_t target_processor_index );
485
486static inline void _CPU_SMP_Processor_event_broadcast( void )
487{
488  __asm__ volatile ( "" : : : "memory" );
489}
490
491static inline void _CPU_SMP_Processor_event_receive( void )
492{
493  __asm__ volatile ( "" : : : "memory" );
494}
495
496static inline bool _CPU_Context_Get_is_executing(
497  const Context_Control *context
498)
499{
500  return context->is_executing;
501}
502
503static inline void _CPU_Context_Set_is_executing(
504  Context_Control *context,
505  bool is_executing
506)
507{
508  context->is_executing = is_executing;
509}
510
511#endif /* RTEMS_SMP */
512
513/** Type that can store a 32-bit integer or a pointer. */
514typedef uintptr_t CPU_Uint32ptr;
515
516#endif /* ASM */
517
518#ifdef __cplusplus
519}
520#endif
521
522#endif
Note: See TracBrowser for help on using the repository browser.