source: rtems/cpukit/score/cpu/i386/rtems/score/i386.h @ 328bd35

5
Last change on this file since 328bd35 was 328bd35, checked in by Joel Sherrill <joel@…>, on 01/23/16 at 19:06:22

i386: refactor libcpu/cpu.h into rtems/score/i386.h

Fixes #2515.

  • Property mode set to 100644
File size: 17.3 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-2016.
12 *  On-Line Applications Research Corporation (OAR).
13 *
14 *  Copyright (C) 1998  Eric Valette (valette@crf.canon.fr)
15 *                     Canon Centre Recherche France.
16 *
17 *  The license and distribution terms for this file may be
18 *  found in the file LICENSE in this distribution or at
19 *  http://www.rtems.org/license/LICENSE.
20 */
21
22#ifndef _RTEMS_SCORE_I386_H
23#define _RTEMS_SCORE_I386_H
24
25#ifdef __cplusplus
26extern "C" {
27#endif
28
29#include <rtems/score/interrupts.h>
30#include <rtems/score/registers.h>
31
32/*
33 *  This section contains the information required to build
34 *  RTEMS for a particular member of the Intel i386
35 *  family when executing in protected mode.  It does
36 *  this by setting variables to indicate which implementation
37 *  dependent features are present in a particular member
38 *  of the family.
39 *
40 *  Currently recognized:
41 *    i386_fp    (i386 DX or SX w/i387)
42 *    i486dx
43 *    pentium
44 *    pentiumpro
45 *
46 *  CPU Model Feature Flags:
47 *
48 *  I386_HAS_BSWAP:  Defined to "1" if the instruction for endian swapping
49 *                   (bswap) should be used.  This instruction appears to
50 *                   be present in all i486's and above.
51 *
52 *  I386_HAS_FPU:    Defined to "1" if the CPU has an FPU.
53 *                   As of at least gcc 4.7, i386 soft-float was obsoleted.
54 *                   Thus this is always set to "1".
55 */
56#define I386_HAS_FPU 1
57
58#if defined(__pentiumpro__)
59
60  #define CPU_MODEL_NAME  "Pentium Pro"
61
62#elif defined(__i586__)
63
64  #if defined(__pentium__)
65    #define CPU_MODEL_NAME "Pentium"
66  #elif defined(__k6__)
67    #define CPU_MODEL_NAME "K6"
68  #else
69    #define CPU_MODEL_NAME "i586"
70  #endif
71
72#elif defined(__i486__)
73
74  #define CPU_MODEL_NAME  "i486dx"
75
76#elif defined(__i386__)
77
78  #define I386_HAS_BSWAP  0
79  #define CPU_MODEL_NAME  "i386 with i387"
80
81#else
82  #error "Unknown CPU Model"
83#endif
84
85/*
86 *  Set default values for CPU model feature flags
87 *
88 *  NOTE: These settings are chosen to reflect most of the family members.
89 */
90#ifndef I386_HAS_BSWAP
91#define I386_HAS_BSWAP 1
92#endif
93
94/*
95 *  Define the name of the CPU family.
96 */
97#define CPU_NAME "Intel i386"
98
99#ifndef ASM
100
101/*
102 *  The following routine swaps the endian format of an unsigned int.
103 *  It must be static so it can be referenced indirectly.
104 */
105
106static inline uint32_t i386_swap_u32(
107  uint32_t value
108)
109{
110  uint32_t lout;
111
112#if (I386_HAS_BSWAP == 0)
113  __asm__ volatile( "rorw  $8,%%ax;"
114                "rorl  $16,%0;"
115                "rorw  $8,%%ax" : "=a" (lout) : "0" (value) );
116#else
117    __asm__ volatile( "bswap %0" : "=r"  (lout) : "0"   (value));
118#endif
119  return( lout );
120}
121#define CPU_swap_u32( _value )  i386_swap_u32( _value )
122
123static inline uint16_t i386_swap_u16(
124  uint16_t value
125)
126{
127  unsigned short      sout;
128
129  __asm__ volatile( "rorw $8,%0" : "=r"  (sout) : "0"   (value));
130  return (sout);
131}
132#define CPU_swap_u16( _value )  i386_swap_u16( _value )
133
134/*
135 * Added for pagination management
136 */
137static inline unsigned int i386_get_cr0(void)
138{
139  register unsigned int segment = 0;
140
141  __asm__ volatile ( "movl %%cr0,%0" : "=r" (segment) : "0" (segment) );
142
143  return segment;
144}
145
146static inline void i386_set_cr0(unsigned int segment)
147{
148  __asm__ volatile ( "movl %0,%%cr0" : "=r" (segment) : "0" (segment) );
149}
150
151static inline unsigned int i386_get_cr2(void)
152{
153  register unsigned int segment = 0;
154
155  __asm__ volatile ( "movl %%cr2,%0" : "=r" (segment) : "0" (segment) );
156
157  return segment;
158}
159
160static inline unsigned int i386_get_cr3(void)
161{
162  register unsigned int segment = 0;
163
164  __asm__ volatile ( "movl %%cr3,%0" : "=r" (segment) : "0" (segment) );
165
166  return segment;
167}
168
169static inline void i386_set_cr3(unsigned int segment)
170{
171  __asm__ volatile ( "movl %0,%%cr3" : "=r" (segment) : "0" (segment) );
172}
173
174/* routines */
175
176/*
177 *  i386_Logical_to_physical
178 *
179 *  Converts logical address to physical address.
180 */
181void *i386_Logical_to_physical(
182  unsigned short  segment,
183  void           *address
184);
185
186/*
187 *  i386_Physical_to_logical
188 *
189 *  Converts physical address to logical address.
190 */
191void *i386_Physical_to_logical(
192  unsigned short  segment,
193  void           *address
194);
195
196/**
197 * @brief Converts real mode pointer {segment, offset} to physical address.
198 *
199 * i386_Real_to_physical
200 *
201 * @param[in] segment used with \p offset to compute physical address
202 * @param[in] offset used with \p segment to compute physical address
203 * @retval    physical address
204 */
205RTEMS_INLINE_ROUTINE void *i386_Real_to_physical(
206    uint16_t segment,
207    uint16_t offset)
208{
209    return (void *)(((uint32_t)segment<<4)+offset);
210}
211
212/**
213 * @brief Retrieves real mode pointer elements {segmnet, offset} from
214 * physical address.
215 *
216 * i386_Physical_to_real
217 * Function returns the highest segment (base) address possible.
218 * Example:    input   address - 0x4B3A2
219 *             output  segment - 0x4B3A
220 *                     offset  - 0x2
221 *             input   address - 0x10F12E
222 *             output  segment - 0xFFFF
223 *                     offset  - 0xF13E
224 *
225 * @param[in]  address address to be converted, must be less than 0x10FFEF
226 * @param[out] segment segment computed from \p address
227 * @param[out] offset offset computed from \p address
228 * @retval  0 address not convertible
229 * @retval  1 segment and offset extracted
230 */
231int i386_Physical_to_real(
232  void *address,
233  uint16_t *segment,
234  uint16_t *offset
235);
236
237/*
238 *  Segment Access Routines
239 *
240 *  NOTE:  Unfortunately, these are still static inlines even when the
241 *         "macro" implementation of the generic code is used.
242 */
243
244static __inline__ unsigned short i386_get_cs(void)
245{
246  register unsigned short segment = 0;
247
248  __asm__ volatile ( "movw %%cs,%0" : "=r" (segment) : "0" (segment) );
249
250  return segment;
251}
252
253static __inline__ unsigned short i386_get_ds(void)
254{
255  register unsigned short segment = 0;
256
257  __asm__ volatile ( "movw %%ds,%0" : "=r" (segment) : "0" (segment) );
258
259  return segment;
260}
261
262static __inline__ unsigned short i386_get_es(void)
263{
264  register unsigned short segment = 0;
265
266  __asm__ volatile ( "movw %%es,%0" : "=r" (segment) : "0" (segment) );
267
268  return segment;
269}
270
271static __inline__ unsigned short i386_get_ss(void)
272{
273  register unsigned short segment = 0;
274
275  __asm__ volatile ( "movw %%ss,%0" : "=r" (segment) : "0" (segment) );
276
277  return segment;
278}
279
280static __inline__ unsigned short i386_get_fs(void)
281{
282  register unsigned short segment = 0;
283
284  __asm__ volatile ( "movw %%fs,%0" : "=r" (segment) : "0" (segment) );
285
286  return segment;
287}
288
289static __inline__ unsigned short i386_get_gs(void)
290{
291  register unsigned short segment = 0;
292
293  __asm__ volatile ( "movw %%gs,%0" : "=r" (segment) : "0" (segment) );
294
295  return segment;
296}
297
298/*
299 *  IO Port Access Routines
300 */
301
302#define i386_outport_byte( _port, _value ) \
303do { register unsigned short __port  = _port; \
304     register unsigned char  __value = _value; \
305     \
306     __asm__ volatile ( "outb %0,%1" : : "a" (__value), "d" (__port) ); \
307   } while (0)
308
309#define i386_outport_word( _port, _value ) \
310do { register unsigned short __port  = _port; \
311     register unsigned short __value = _value; \
312     \
313     __asm__ volatile ( "outw %0,%1" : : "a" (__value), "d" (__port) ); \
314   } while (0)
315
316#define i386_outport_long( _port, _value ) \
317do { register unsigned short __port  = _port; \
318     register unsigned int  __value = _value; \
319     \
320     __asm__ volatile ( "outl %0,%1" : : "a" (__value), "d" (__port) ); \
321   } while (0)
322
323#define i386_inport_byte( _port, _value ) \
324do { register unsigned short __port  = _port; \
325     register unsigned char  __value = 0; \
326     \
327     __asm__ volatile ( "inb %1,%0" : "=a" (__value) \
328                                : "d"  (__port) \
329                  ); \
330     _value = __value; \
331   } while (0)
332
333#define i386_inport_word( _port, _value ) \
334do { register unsigned short __port  = _port; \
335     register unsigned short __value = 0; \
336     \
337     __asm__ volatile ( "inw %1,%0" : "=a" (__value) \
338                                : "d"  (__port) \
339                  ); \
340     _value = __value; \
341   } while (0)
342
343#define i386_inport_long( _port, _value ) \
344do { register unsigned short __port  = _port; \
345     register unsigned int  __value = 0; \
346     \
347     __asm__ volatile ( "inl %1,%0" : "=a" (__value) \
348                                : "d"  (__port) \
349                  ); \
350     _value = __value; \
351   } while (0)
352
353/*
354 * Type definition for raw interrupts.
355 */
356
357typedef unsigned char  rtems_vector_offset;
358
359typedef struct __rtems_raw_irq_connect_data__{
360 /*
361  * IDT vector offset (IRQ line + PC386_IRQ_VECTOR_BASE)
362  */
363  rtems_vector_offset           idtIndex;
364  /*
365   * IDT raw handler. See comment on handler properties below in function prototype.
366   */
367  rtems_raw_irq_hdl             hdl;
368  /*
369   * function for enabling raw interrupts. In order to be consistent
370   * with the fact that the raw connexion can defined in the
371   * libcpu library, this library should have no knowledge of
372   * board specific hardware to manage interrupts and thus the
373   * "on" routine must enable the irq both at device and PIC level.
374   *
375   */
376    rtems_raw_irq_enable        on;
377  /*
378   * function for disabling raw interrupts. In order to be consistent
379   * with the fact that the raw connexion can defined in the
380   * libcpu library, this library should have no knowledge of
381   * board specific hardware to manage interrupts and thus the
382   * "on" routine must disable the irq both at device and PIC level.
383   *
384   */
385  rtems_raw_irq_disable         off;
386  /*
387   * function enabling to know what interrupt may currently occur
388   */
389  rtems_raw_irq_is_enabled      isOn;
390}rtems_raw_irq_connect_data;
391
392typedef struct {
393  /*
394   * size of all the table fields (*Tbl) described below.
395   */
396  unsigned int                  idtSize;
397  /*
398   * Default handler used when disconnecting interrupts.
399   */
400  rtems_raw_irq_connect_data    defaultRawEntry;
401  /*
402   * Table containing initials/current value.
403   */
404  rtems_raw_irq_connect_data*   rawIrqHdlTbl;
405}rtems_raw_irq_global_settings;
406
407#include <rtems/score/idtr.h>
408
409/*
410 * C callable function enabling to get handler currently connected to a vector
411 *
412 */
413rtems_raw_irq_hdl get_hdl_from_vector(rtems_vector_offset);
414
415/*
416 * C callable function enabling to set up one raw idt entry
417 */
418extern int i386_set_idt_entry (const rtems_raw_irq_connect_data*);
419
420/*
421 * C callable function enabling to get one current raw idt entry
422 */
423extern int i386_get_current_idt_entry (rtems_raw_irq_connect_data*);
424
425/*
426 * C callable function enabling to remove one current raw idt entry
427 */
428extern int i386_delete_idt_entry (const rtems_raw_irq_connect_data*);
429
430/*
431 * C callable function enabling to init idt.
432 *
433 * CAUTION : this function assumes that the IDTR register
434 * has been already set.
435 */
436extern int i386_init_idt (rtems_raw_irq_global_settings* config);
437
438/*
439 * C callable function enabling to get actual idt configuration
440 */
441extern int i386_get_idt_config (rtems_raw_irq_global_settings** config);
442
443
444/*
445 * See page 11.12 Figure 11-8.
446 *
447 */
448/**
449 * @brief describes one entry of Global/Local Descriptor Table
450 */
451typedef struct {
452  unsigned int limit_15_0               : 16;
453  unsigned int base_address_15_0        : 16;
454  unsigned int base_address_23_16       : 8;
455  unsigned int type                     : 4;
456  unsigned int descriptor_type          : 1;
457  unsigned int privilege                : 2;
458  unsigned int present                  : 1;
459  unsigned int limit_19_16              : 4;
460  unsigned int available                : 1;
461  unsigned int fixed_value_bits         : 1;
462  unsigned int operation_size           : 1;
463  unsigned int granularity              : 1;
464  unsigned int base_address_31_24       : 8;
465} RTEMS_PACKED segment_descriptors;
466
467/*
468 * C callable function enabling to get easilly usable info from
469 * the actual value of GDT register.
470 */
471extern void i386_get_info_from_GDTR (segment_descriptors** table,
472                                     uint16_t* limit);
473/*
474 * C callable function enabling to change the value of GDT register. Must be called
475 * with interrupts masked at processor level!!!.
476 */
477extern void i386_set_GDTR (segment_descriptors*,
478                           uint16_t limit);
479
480/**
481 * @brief Allows to set a GDT entry.
482 *
483 * Puts global descriptor \p sd to the global descriptor table on index
484 * \p segment_selector_index
485 *
486 * @param[in] segment_selector_index index to GDT entry
487 * @param[in] sd structure to be coppied to given \p segment_selector in GDT
488 * @retval  0 FAILED out of GDT range or index is 0, which is not valid
489 *                   index in GDT
490 * @retval  1 SUCCESS
491 */
492extern uint32_t i386_raw_gdt_entry (uint16_t segment_selector_index,
493                               segment_descriptors* sd);
494
495/**
496 * @brief fills \p sd with provided \p base in appropriate fields of \p sd
497 *
498 * @param[in] base 32-bit address to be set as descriptor's base
499 * @param[out] sd descriptor being filled with \p base
500 */
501extern void i386_fill_segment_desc_base (uint32_t base,
502                                         segment_descriptors* sd);
503
504/**
505 * @brief fills \p sd with provided \p limit in appropriate fields of \p sd
506 *
507 * sets granularity bit if necessary
508 *
509 * @param[in] limit 32-bit value representing number of limit bytes
510 * @param[out] sd descriptor being filled with \p limit
511 */
512extern void i386_fill_segment_desc_limit (uint32_t limit,
513                                          segment_descriptors* sd);
514
515/*
516 * C callable function enabling to set up one raw interrupt handler
517 */
518extern uint32_t i386_set_gdt_entry (uint16_t segment_selector,
519                                    uint32_t base,
520                                    uint32_t limit);
521
522/**
523 * @brief Returns next empty descriptor in GDT.
524 *
525 * Number of descriptors that can be returned depends on \a GDT_SIZE
526 *
527 * @retval  0 FAILED GDT is full
528 * @retval  <1;65535> segment_selector number as index to GDT
529 */
530extern uint16_t i386_next_empty_gdt_entry (void);
531
532/**
533 * @brief Copies GDT entry at index \p segment_selector to structure
534 * pointed to by \p struct_to_fill
535 *
536 * @param[in] segment_selector index to GDT table specifying descriptor to copy
537 * @param[out] struct_to_fill pointer to memory where will be descriptor coppied
538 * @retval  0 FAILED segment_selector out of GDT range
539 * @retval  <1;65535> retrieved segment_selector
540 */
541extern uint16_t i386_cpy_gdt_entry (uint16_t segment_selector,
542                                    segment_descriptors* struct_to_fill);
543
544/**
545 * @brief Returns pointer to GDT table at index given by \p segment_selector
546 *
547 * @param[in] sgmnt_selector index to GDT table for specifying descriptor to get
548 * @retval  NULL FAILED segment_selector out of GDT range
549 * @retval  pointer to GDT table at \p segment_selector
550 */
551extern segment_descriptors* i386_get_gdt_entry (uint16_t sgmnt_selector);
552
553/**
554 * @brief Extracts base address from GDT entry pointed to by \p gdt_entry
555 *
556 * @param[in]  gdt_entry pointer to entry from which base should be retrieved
557 * @retval base address from GDT entry
558*/
559RTEMS_INLINE_ROUTINE void* i386_base_gdt_entry (segment_descriptors* gdt_entry)
560{
561    return (void*)(gdt_entry->base_address_15_0 |
562            (gdt_entry->base_address_23_16<<16) |
563            (gdt_entry->base_address_31_24<<24));
564}
565
566/**
567 * @brief Extracts limit in bytes from GDT entry pointed to by \p gdt_entry
568 *
569 * @param[in]  gdt_entry pointer to entry from which limit should be retrieved
570 * @retval limit value in bytes from GDT entry
571 */
572extern uint32_t i386_limit_gdt_entry (segment_descriptors* gdt_entry);
573
574/*
575 * See page 11.18 Figure 11-12.
576 *
577 */
578
579typedef struct {
580  unsigned int offset                   : 12;
581  unsigned int page                     : 10;
582  unsigned int directory                : 10;
583}la_bits;
584
585typedef union {
586  la_bits       bits;
587  unsigned int  address;
588}linear_address;
589
590
591/*
592 * See page 11.20 Figure 11-14.
593 *
594 */
595
596typedef struct {
597  unsigned int present                  : 1;
598  unsigned int writable                 : 1;
599  unsigned int user                     : 1;
600  unsigned int write_through            : 1;
601  unsigned int cache_disable            : 1;
602  unsigned int accessed                 : 1;
603  unsigned int reserved1                : 1;
604  unsigned int page_size                : 1;
605  unsigned int reserved2                : 1;
606  unsigned int available                : 3;
607  unsigned int page_frame_address       : 20;
608}page_dir_bits;
609
610typedef union {
611  page_dir_bits bits;
612  unsigned int  dir_entry;
613}page_dir_entry;
614
615typedef struct {
616  unsigned int present                  : 1;
617  unsigned int writable                 : 1;
618  unsigned int user                     : 1;
619  unsigned int write_through            : 1;
620  unsigned int cache_disable            : 1;
621  unsigned int accessed                 : 1;
622  unsigned int dirty                    : 1;
623  unsigned int reserved2                : 2;
624  unsigned int available                : 3;
625  unsigned int page_frame_address       : 20;
626}page_table_bits;
627
628typedef union {
629  page_table_bits       bits;
630  unsigned int          table_entry;
631} page_table_entry;
632
633/*
634 * definitions related to page table entry
635 */
636#define PG_SIZE 0x1000
637#define MASK_OFFSET 0xFFF
638#define MAX_ENTRY (PG_SIZE/sizeof(page_dir_entry))
639#define FOUR_MB       0x400000
640#define MASK_FLAGS 0x1A
641
642#define PTE_PRESENT             0x01
643#define PTE_WRITABLE            0x02
644#define PTE_USER                0x04
645#define PTE_WRITE_THROUGH       0x08
646#define PTE_CACHE_DISABLE       0x10
647
648typedef struct {
649  page_dir_entry pageDirEntry[MAX_ENTRY];
650} page_directory;
651
652typedef struct {
653  page_table_entry pageTableEntry[MAX_ENTRY];
654} page_table;
655
656/* Simpler names for the i80x86 I/O instructions */
657#define outport_byte( _port, _value ) i386_outport_byte( _port, _value )
658#define outport_word( _port, _value ) i386_outport_word( _port, _value )
659#define outport_long( _port, _value ) i386_outport_long( _port, _value )
660#define inport_byte( _port, _value )  i386_inport_byte( _port, _value )
661#define inport_word( _port, _value )  i386_inport_word( _port, _value )
662#define inport_long( _port, _value )  i386_inport_long( _port, _value )
663
664#ifdef __cplusplus
665}
666#endif
667
668#endif /* !ASM */
669
670#endif
Note: See TracBrowser for help on using the repository browser.