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