RTEMS  5.0.0
cpu.h
Go to the documentation of this file.
1 
10 /*
11  * COPYRIGHT (c) 1989-2011.
12  * On-Line Applications Research Corporation (OAR).
13  *
14  * The license and distribution terms for this file may be
15  * found in the file LICENSE in this distribution or at
16  * http://www.rtems.org/license/LICENSE.
17  */
18 
19 #ifndef _RTEMS_SCORE_CPU_H
20 #define _RTEMS_SCORE_CPU_H
21 
22 #ifndef ASM
23 #include <string.h> /* for memcpy */
24 #endif
25 
26 #ifdef __cplusplus
27 extern "C" {
28 #endif
29 
30 #include <rtems/score/basedefs.h>
31 #if defined(RTEMS_PARAVIRT)
32 #include <rtems/score/paravirt.h>
33 #endif
34 #include <rtems/score/i386.h>
35 
45 /* conditional compilation parameters */
46 
47 /*
48  * Does the CPU follow the simple vectored interrupt model?
49  *
50  * If TRUE, then RTEMS allocates the vector table it internally manages.
51  * If FALSE, then the BSP is assumed to allocate and manage the vector
52  * table
53  *
54  * PowerPC Specific Information:
55  *
56  * The PowerPC and x86 were the first to use the PIC interrupt model.
57  * They do not use the simple vectored interrupt model.
58  */
59 #define CPU_SIMPLE_VECTORED_INTERRUPTS FALSE
60 
61 /*
62  * Does the RTEMS invoke the user's ISR with the vector number and
63  * a pointer to the saved interrupt frame (1) or just the vector
64  * number (0)?
65  */
66 
67 #define CPU_ISR_PASSES_FRAME_POINTER FALSE
68 
69 /*
70  * Some family members have no FP, some have an FPU such as the i387
71  * for the i386, others have it built in (i486DX, Pentium).
72  */
73 
74 #ifdef __SSE__
75 #define CPU_HARDWARE_FP TRUE
76 #define CPU_SOFTWARE_FP FALSE
77 
78 #define CPU_ALL_TASKS_ARE_FP TRUE
79 #define CPU_IDLE_TASK_IS_FP TRUE
80 #define CPU_USE_DEFERRED_FP_SWITCH FALSE
81 #else /* __SSE__ */
82 
83 #if ( I386_HAS_FPU == 1 )
84 #define CPU_HARDWARE_FP TRUE /* i387 for i386 */
85 #else
86 #define CPU_HARDWARE_FP FALSE
87 #endif
88 #define CPU_SOFTWARE_FP FALSE
89 
90 #define CPU_ALL_TASKS_ARE_FP FALSE
91 #define CPU_IDLE_TASK_IS_FP FALSE
92 #if defined(RTEMS_SMP)
93  #define CPU_USE_DEFERRED_FP_SWITCH FALSE
94 #else
95  #define CPU_USE_DEFERRED_FP_SWITCH TRUE
96 #endif
97 #endif /* __SSE__ */
98 
99 #define CPU_ENABLE_ROBUST_THREAD_DISPATCH FALSE
100 
101 #define CPU_STACK_GROWS_UP FALSE
102 
103 /* FIXME: The Pentium 4 used 128 bytes, it this processor still relevant? */
104 #define CPU_CACHE_LINE_BYTES 64
105 
106 #define CPU_STRUCTURE_ALIGNMENT
107 
108 #define CPU_MAXIMUM_PROCESSORS 32
109 
110 #define I386_CONTEXT_CONTROL_EFLAGS_OFFSET 0
111 #define I386_CONTEXT_CONTROL_ESP_OFFSET 4
112 #define I386_CONTEXT_CONTROL_EBP_OFFSET 8
113 #define I386_CONTEXT_CONTROL_EBX_OFFSET 12
114 #define I386_CONTEXT_CONTROL_ESI_OFFSET 16
115 #define I386_CONTEXT_CONTROL_EDI_OFFSET 20
116 #define I386_CONTEXT_CONTROL_GS_0_OFFSET 24
117 #define I386_CONTEXT_CONTROL_GS_1_OFFSET 28
118 
119 #ifdef RTEMS_SMP
120  #define I386_CONTEXT_CONTROL_IS_EXECUTING_OFFSET 32
121 #endif
122 
123 /* structures */
124 
125 #ifndef ASM
126 
127 /*
128  * Basic integer context for the i386 family.
129  */
130 
131 typedef struct {
132  uint32_t eflags; /* extended flags register */
133  void *esp; /* extended stack pointer register */
134  void *ebp; /* extended base pointer register */
135  uint32_t ebx; /* extended bx register */
136  uint32_t esi; /* extended source index register */
137  uint32_t edi; /* extended destination index flags register */
138  segment_descriptors gs; /* gs segment descriptor */
139 #ifdef RTEMS_SMP
140  volatile bool is_executing;
141 #endif
143 
144 #define _CPU_Context_Get_SP( _context ) \
145  (_context)->esp
146 
147 #ifdef RTEMS_SMP
148  static inline bool _CPU_Context_Get_is_executing(
149  const Context_Control *context
150  )
151  {
152  return context->is_executing;
153  }
154 
155  static inline void _CPU_Context_Set_is_executing(
157  bool is_executing
158  )
159  {
160  context->is_executing = is_executing;
161  }
162 #endif
163 
164 /*
165  * FP context save area for the i387 numeric coprocessors.
166  */
167 #ifdef __SSE__
168 /* All FPU and SSE registers are volatile; hence, as long
169  * as we are within normally executing C code (including
170  * a task switch) there is no need for saving/restoring
171  * any of those registers.
172  * We must save/restore the full FPU/SSE context across
173  * interrupts and exceptions, however:
174  * - after ISR execution a _Thread_Dispatch() may happen
175  * and it is therefore necessary to save the FPU/SSE
176  * registers to be restored when control is returned
177  * to the interrupted task.
178  * - gcc may implicitly use FPU/SSE instructions in
179  * an ISR.
180  *
181  * Even though there is no explicit mentioning of the FPU
182  * control word in the SYSV ABI (i386) being non-volatile
183  * we maintain MXCSR and the FPU control-word for each task.
184  */
185 typedef struct {
186  uint32_t mxcsr;
187  uint16_t fpucw;
189 
190 #else
191 
192 typedef struct {
193  uint8_t fp_save_area[108]; /* context size area for I80387 */
194  /* 28 bytes for environment */
196 
197 #endif
198 
199 
200 /*
201  * The following structure defines the set of information saved
202  * on the current stack by RTEMS upon receipt of execptions.
203  *
204  * idtIndex is either the interrupt number or the trap/exception number.
205  * faultCode is the code pushed by the processor on some exceptions.
206  *
207  * Since the first registers are directly pushed by the CPU they
208  * may not respect 16-byte stack alignment, which is, however,
209  * mandatory for the SSE register area.
210  * Therefore, these registers are stored at an aligned address
211  * and a pointer is stored in the CPU_Exception_frame.
212  * If the executive was compiled without SSE support then
213  * this pointer is NULL.
214  */
215 
216 struct Context_Control_sse;
217 
218 typedef struct {
219  struct Context_Control_sse *fp_ctxt;
220  uint32_t edi;
221  uint32_t esi;
222  uint32_t ebp;
223  uint32_t esp0;
224  uint32_t ebx;
225  uint32_t edx;
226  uint32_t ecx;
227  uint32_t eax;
228  uint32_t idtIndex;
229  uint32_t faultCode;
230  uint32_t eip;
231  uint32_t cs;
232  uint32_t eflags;
234 
235 #ifdef __SSE__
236 typedef struct Context_Control_sse {
237  uint16_t fcw;
238  uint16_t fsw;
239  uint8_t ftw;
240  uint8_t res_1;
241  uint16_t fop;
242  uint32_t fpu_ip;
243  uint16_t cs;
244  uint16_t res_2;
245  uint32_t fpu_dp;
246  uint16_t ds;
247  uint16_t res_3;
248  uint32_t mxcsr;
249  uint32_t mxcsr_mask;
250  struct {
251  uint8_t fpreg[10];
252  uint8_t res_4[ 6];
253  } fp_mmregs[8];
254  uint8_t xmmregs[8][16];
255  uint8_t res_5[224];
257 __attribute__((aligned(16)))
258 ;
259 #endif
260 
261 typedef void (*cpuExcHandlerType) (CPU_Exception_frame*);
262 extern cpuExcHandlerType _currentExcHandler;
263 extern void rtems_exception_init_mngt(void);
264 
265 #ifdef RTEMS_SMP
266  /* Throw compile-time error to indicate incomplete support */
267  #error "i386 targets do not support SMP.\
268  See: https://devel.rtems.org/ticket/3335"
269 
270  /*
271  * This size must match the size of the CPU_Interrupt_frame, which must be
272  * used in the SMP context switch code, which is incomplete at the moment.
273  */
274  #define CPU_INTERRUPT_FRAME_SIZE 4
275 #endif
276 
277 /*
278  * This port does not pass any frame info to the
279  * interrupt handler.
280  */
281 
282 typedef struct {
283  uint32_t todo_replace_with_apt_registers;
285 
286 typedef enum {
287  I386_EXCEPTION_DIVIDE_BY_ZERO = 0,
288  I386_EXCEPTION_DEBUG = 1,
289  I386_EXCEPTION_NMI = 2,
290  I386_EXCEPTION_BREAKPOINT = 3,
291  I386_EXCEPTION_OVERFLOW = 4,
292  I386_EXCEPTION_BOUND = 5,
293  I386_EXCEPTION_ILLEGAL_INSTR = 6,
294  I386_EXCEPTION_MATH_COPROC_UNAVAIL = 7,
295  I386_EXCEPTION_DOUBLE_FAULT = 8,
296  I386_EXCEPTION_I386_COPROC_SEG_ERR = 9,
297  I386_EXCEPTION_INVALID_TSS = 10,
298  I386_EXCEPTION_SEGMENT_NOT_PRESENT = 11,
299  I386_EXCEPTION_STACK_SEGMENT_FAULT = 12,
300  I386_EXCEPTION_GENERAL_PROT_ERR = 13,
301  I386_EXCEPTION_PAGE_FAULT = 14,
302  I386_EXCEPTION_INTEL_RES15 = 15,
303  I386_EXCEPTION_FLOAT_ERROR = 16,
304  I386_EXCEPTION_ALIGN_CHECK = 17,
305  I386_EXCEPTION_MACHINE_CHECK = 18,
306  I386_EXCEPTION_ENTER_RDBG = 50 /* to enter manually RDBG */
307 
308 } Intel_symbolic_exception_name;
309 
310 
311 /*
312  * context size area for floating point
313  *
314  * NOTE: This is out of place on the i386 to avoid a forward reference.
315  */
316 
317 #define CPU_CONTEXT_FP_SIZE sizeof( Context_Control_fp )
318 
319 /* variables */
320 
322 
323 #endif /* ASM */
324 
325 /* constants */
326 
327 /*
328  * This defines the number of levels and the mask used to pick those
329  * bits out of a thread mode.
330  */
331 
332 #define CPU_MODES_INTERRUPT_MASK 0x00000001 /* interrupt level in mode */
333 
334 /*
335  * extra stack required by the MPCI receive server thread
336  */
337 
338 #define CPU_MPCI_RECEIVE_SERVER_EXTRA_STACK 1024
339 
340 /*
341  * This is defined if the port has a special way to report the ISR nesting
342  * level. Most ports maintain the variable _ISR_Nest_level.
343  */
344 
345 #define CPU_PROVIDES_ISR_IS_IN_PROGRESS FALSE
346 
347 /*
348  * Minimum size of a thread's stack.
349  */
350 
351 #define CPU_STACK_MINIMUM_SIZE 4096
352 
353 #define CPU_SIZEOF_POINTER 4
354 
355 /*
356  * i386 is pretty tolerant of alignment. Just put things on 4 byte boundaries.
357  */
358 
359 #define CPU_ALIGNMENT 4
360 #define CPU_HEAP_ALIGNMENT CPU_ALIGNMENT
361 
362 /*
363  * On i386 thread stacks require no further alignment after allocation
364  * from the Workspace. However, since gcc maintains 16-byte alignment
365  * we try to respect that. If you find an option to let gcc squeeze
366  * the stack more tightly then setting CPU_STACK_ALIGNMENT to 16 still
367  * doesn't waste much space since this only determines the *initial*
368  * alignment.
369  */
370 
371 #define CPU_STACK_ALIGNMENT 16
372 
373 #define CPU_INTERRUPT_STACK_ALIGNMENT CPU_CACHE_LINE_BYTES
374 
375 /* macros */
376 
377 #ifndef ASM
378 /*
379  * ISR handler macros
380  *
381  * These macros perform the following functions:
382  * + initialize the RTEMS vector table
383  * + disable all maskable CPU interrupts
384  * + restore previous interrupt level (enable)
385  * + temporarily restore interrupts (flash)
386  * + set a particular level
387  */
388 
389 #if !defined(I386_DISABLE_INLINE_ISR_DISABLE_ENABLE)
390 #define _CPU_ISR_Disable( _level ) i386_disable_interrupts( _level )
391 
392 #define _CPU_ISR_Enable( _level ) i386_enable_interrupts( _level )
393 
394 #define _CPU_ISR_Flash( _level ) i386_flash_interrupts( _level )
395 
396 #define _CPU_ISR_Set_level( _new_level ) \
397  { \
398  if ( _new_level ) __asm__ volatile ( "cli" ); \
399  else __asm__ volatile ( "sti" ); \
400  }
401 #else
402 #define _CPU_ISR_Disable( _level ) _level = i386_disable_interrupts()
403 #define _CPU_ISR_Enable( _level ) i386_enable_interrupts( _level )
404 #define _CPU_ISR_Flash( _level ) i386_flash_interrupts( _level )
405 #define _CPU_ISR_Set_level( _new_level ) i386_set_interrupt_level(_new_level)
406 #endif
407 
408 RTEMS_INLINE_ROUTINE bool _CPU_ISR_Is_enabled( uint32_t level )
409 {
410  return ( level & EFLAGS_INTR_ENABLE ) != 0;
411 }
412 
413 uint32_t _CPU_ISR_Get_level( void );
414 
415 /* Make sure interrupt stack has space for ISR
416  * 'vector' arg at the top and that it is aligned
417  * properly.
418  */
419 
420 #define _CPU_Interrupt_stack_setup( _lo, _hi ) \
421  do { \
422  _hi = (void*)(((uintptr_t)(_hi) - 4) & ~ (CPU_STACK_ALIGNMENT - 1)); \
423  } while (0)
424 
425 #endif /* ASM */
426 
427 /* end of ISR handler macros */
428 
429 /*
430  * Context handler macros
431  *
432  * These macros perform the following functions:
433  * + initialize a context area
434  * + restart the current thread
435  * + calculate the initial pointer into a FP context area
436  * + initialize an FP context area
437  */
438 
439 #define CPU_EFLAGS_INTERRUPTS_ON 0x00003202
440 #define CPU_EFLAGS_INTERRUPTS_OFF 0x00003002
441 
442 #ifndef ASM
443 
445  Context_Control *the_context,
446  void *stack_area_begin,
447  size_t stack_area_size,
448  uint32_t new_level,
449  void (*entry_point)( void ),
450  bool is_fp,
451  void *tls_area
452 );
453 
454 #define _CPU_Context_Restart_self( _the_context ) \
455  _CPU_Context_restore( (_the_context) );
456 
457 #if defined(RTEMS_SMP)
458  uint32_t _CPU_SMP_Initialize( void );
459 
460  bool _CPU_SMP_Start_processor( uint32_t cpu_index );
461 
462  void _CPU_SMP_Finalize_initialization( uint32_t cpu_count );
463 
464  void _CPU_SMP_Prepare_start_multitasking( void );
465 
466  uint32_t _CPU_SMP_Get_current_processor( void );
467 
468  void _CPU_SMP_Send_interrupt( uint32_t target_processor_index );
469 
470  static inline void _CPU_SMP_Processor_event_broadcast( void )
471  {
472  __asm__ volatile ( "" : : : "memory" );
473  }
474 
475  static inline void _CPU_SMP_Processor_event_receive( void )
476  {
477  __asm__ volatile ( "" : : : "memory" );
478  }
479 #endif
480 
481 #define _CPU_Context_Initialize_fp( _fp_area ) \
482  { \
483  memcpy( *_fp_area, &_CPU_Null_fp_context, CPU_CONTEXT_FP_SIZE ); \
484  }
485 
486 /* end of Context handler macros */
487 
488 /*
489  * Fatal Error manager macros
490  *
491  * These macros perform the following functions:
492  * + disable interrupts and halt the CPU
493  */
494 
495 extern void _CPU_Fatal_halt(uint32_t source, uint32_t error)
497 
498 #endif /* ASM */
499 
500 /* end of Fatal Error manager macros */
501 
502 /*
503  * Bitfield handler macros
504  *
505  * These macros perform the following functions:
506  * + scan for the highest numbered (MSB) set in a 16 bit bitfield
507  */
508 
509 #define CPU_USE_GENERIC_BITFIELD_CODE FALSE
510 
511 #define _CPU_Bitfield_Find_first_bit( _value, _output ) \
512  { \
513  uint16_t __value_in_register = ( _value ); \
514  uint16_t __output = 0; \
515  __asm__ volatile ( "bsfw %0,%1 " \
516  : "=r" ( __value_in_register ), "=r" ( __output ) \
517  : "0" ( __value_in_register ), "1" ( __output ) \
518  ); \
519  ( _output ) = __output; \
520  }
521 
522 /* end of Bitfield handler macros */
523 
524 /*
525  * Priority handler macros
526  *
527  * These macros perform the following functions:
528  * + return a mask with the bit for this major/minor portion of
529  * of thread priority set.
530  * + translate the bit number returned by "Bitfield_find_first_bit"
531  * into an index into the thread ready chain bit maps
532  */
533 
534 #define _CPU_Priority_Mask( _bit_number ) \
535  ( 1 << (_bit_number) )
536 
537 #define _CPU_Priority_bits_index( _priority ) \
538  (_priority)
539 
540 /* functions */
541 
542 #ifndef ASM
543 /*
544  * _CPU_Initialize
545  *
546  * This routine performs CPU dependent initialization.
547  */
548 
549 void _CPU_Initialize(void);
550 
551 typedef void ( *CPU_ISR_handler )( void );
552 
554  uint32_t vector,
555  CPU_ISR_handler new_handler,
556  CPU_ISR_handler *old_handler
557 );
558 
559 void *_CPU_Thread_Idle_body( uintptr_t ignored );
560 
561 /*
562  * _CPU_Context_switch
563  *
564  * This routine switches from the run context to the heir context.
565  */
566 
568  Context_Control *run,
569  Context_Control *heir
570 );
571 
572 /*
573  * _CPU_Context_restore
574  *
575  * This routine is generally used only to restart self in an
576  * efficient manner and avoid stack conflicts.
577  */
578 
580  Context_Control *new_context
582 
583 /*
584  * _CPU_Context_save_fp
585  *
586  * This routine saves the floating point context passed to it.
587  */
588 
589 #ifdef __SSE__
590 #define _CPU_Context_save_fp(fp_context_pp) \
591  do { \
592  __asm__ __volatile__( \
593  "fstcw %0" \
594  :"=m"((*(fp_context_pp))->fpucw) \
595  ); \
596  __asm__ __volatile__( \
597  "stmxcsr %0" \
598  :"=m"((*(fp_context_pp))->mxcsr) \
599  ); \
600  } while (0)
601 #else
603  Context_Control_fp **fp_context_ptr
604 );
605 #endif
606 
607 /*
608  * _CPU_Context_restore_fp
609  *
610  * This routine restores the floating point context passed to it.
611  */
612 #ifdef __SSE__
613 #define _CPU_Context_restore_fp(fp_context_pp) \
614  do { \
615  __asm__ __volatile__( \
616  "fldcw %0" \
617  ::"m"((*(fp_context_pp))->fpucw) \
618  :"fpcr" \
619  ); \
620  __builtin_ia32_ldmxcsr(_Thread_Executing->fp_context->mxcsr); \
621  } while (0)
622 #else
624  Context_Control_fp **fp_context_ptr
625 );
626 #endif
627 
628 #ifdef __SSE__
629 #define _CPU_Context_Initialization_at_thread_begin() \
630  do { \
631  __asm__ __volatile__( \
632  "finit" \
633  : \
634  : \
635  :"st","st(1)","st(2)","st(3)", \
636  "st(4)","st(5)","st(6)","st(7)", \
637  "fpsr","fpcr" \
638  ); \
639  if ( _Thread_Executing->fp_context ) { \
640  _CPU_Context_restore_fp(&_Thread_Executing->fp_context); \
641  } \
642  } while (0)
643 #endif
644 
646 
647 typedef uint32_t CPU_Counter_ticks;
648 
649 uint32_t _CPU_Counter_frequency( void );
650 
651 CPU_Counter_ticks _CPU_Counter_read( void );
652 
653 static inline CPU_Counter_ticks _CPU_Counter_difference(
654  CPU_Counter_ticks second,
655  CPU_Counter_ticks first
656 )
657 {
658  return second - first;
659 }
660 
664 typedef uintptr_t CPU_Uint32ptr;
665 
666 #endif /* ASM */
667 
668 #ifdef __cplusplus
669 }
670 #endif
671 
672 #endif
void _CPU_Exception_frame_print(const CPU_Exception_frame *frame)
Prints the exception frame via printk().
Definition: vectorexceptions.c:45
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
void * _CPU_Thread_Idle_body(uintptr_t ignored)
Definition: idle-mcf5272.c:20
#define RTEMS_INLINE_ROUTINE
Definition: basedefs.h:65
void _CPU_Context_restore_fp(Context_Control_fp **fp_context_ptr)
Definition: cpu.c:207
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
Intel I386 CPU Dependent Source.
typedef __attribute__
Disable IRQ Interrupts.
Definition: cmsis_gcc.h:69
void _CPU_Initialize(void)
CPU initialization.
Definition: cpu.c:45
SPARC basic context.
Definition: cpu.h:242
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
Definition: sse_test.c:126
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.
void _CPU_Fatal_halt(uint32_t source, uint32_t error) RTEMS_NO_RETURN
Definition: bsp_fatal_halt.c:12
RTEMS_INLINE_ROUTINE void _CPU_ISR_install_vector(uint32_t vector, CPU_ISR_handler new_handler, CPU_ISR_handler *old_handler)
SPARC specific RTEMS ISR installer.
Definition: cpu.h:605
void _CPU_Context_save_fp(Context_Control_fp **fp_context_ptr)
Definition: cpu.c:198
The set of registers that specifies the complete processor state.
Definition: cpu.h:635
Context_Control_fp _CPU_Null_fp_context
Definition: cpu.c:45