source: rtems/cpukit/score/cpu/i386/include/rtems/score/cpu.h @ 4c20da4b

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

doxygen: Rename Score* groups in RTEMSScore*

Update #3706

  • Property mode set to 100644
File size: 17.2 KB
Line 
1/**
2 * @file
3 *
4 * @brief Intel I386 CPU Dependent Source
5 *
6 * This include file contains information pertaining to the Intel
7 * i386 processor.
8 */
9
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
27extern "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   
36/**
37 * @defgroup RTEMSScoreCPUi386 i386 Specific Support
38 *
39 * @ingroup RTEMSScoreCPUi386
40 *
41 * @brief i386 specific support.
42 */
43/**@{**/
44
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
131typedef 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
142}   Context_Control;
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(
156    Context_Control *context,
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 */
185typedef struct {
186        uint32_t  mxcsr;
187        uint16_t  fpucw;
188} Context_Control_fp;
189
190#else
191
192typedef struct {
193  uint8_t     fp_save_area[108];    /* context size area for I80387 */
194                                    /*  28 bytes for environment    */
195} Context_Control_fp;
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
216struct Context_Control_sse;
217
218typedef 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;
233} CPU_Exception_frame;
234
235#ifdef __SSE__
236typedef 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];
256} Context_Control_sse
257__attribute__((aligned(16)))
258;
259#endif
260
261typedef void (*cpuExcHandlerType) (CPU_Exception_frame*);
262extern cpuExcHandlerType _currentExcHandler;
263extern 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
282typedef struct {
283  uint32_t todo_replace_with_apt_registers;
284} CPU_Interrupt_frame;
285
286typedef 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
321extern Context_Control_fp _CPU_Null_fp_context;
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
408RTEMS_INLINE_ROUTINE bool _CPU_ISR_Is_enabled( uint32_t level )
409{
410  return ( level & EFLAGS_INTR_ENABLE ) != 0;
411}
412
413uint32_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
444void _CPU_Context_Initialize(
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
495extern void _CPU_Fatal_halt(uint32_t source, uint32_t error)
496  RTEMS_NO_RETURN;
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
549void _CPU_Initialize(void);
550
551typedef void ( *CPU_ISR_handler )( void );
552
553void _CPU_ISR_install_vector(
554  uint32_t         vector,
555  CPU_ISR_handler  new_handler,
556  CPU_ISR_handler *old_handler
557);
558
559void *_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
567void _CPU_Context_switch(
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
579void _CPU_Context_restore(
580  Context_Control *new_context
581) RTEMS_NO_RETURN;
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
602void _CPU_Context_save_fp(
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
623void _CPU_Context_restore_fp(
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
645void _CPU_Exception_frame_print( const CPU_Exception_frame *frame );
646
647typedef uint32_t CPU_Counter_ticks;
648
649uint32_t _CPU_Counter_frequency( void );
650
651CPU_Counter_ticks _CPU_Counter_read( void );
652
653static 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
661/**@}**/
662
663/** Type that can store a 32-bit integer or a pointer. */
664typedef uintptr_t CPU_Uint32ptr;
665
666#endif /* ASM */
667
668#ifdef __cplusplus
669}
670#endif
671
672#endif
Note: See TracBrowser for help on using the repository browser.