source: rtems/c/src/exec/score/cpu/i386/i386.h @ b0aba4c4

4.104.114.84.95
Last change on this file since b0aba4c4 was b0aba4c4, checked in by Joel Sherrill <joel.sherrill@…>, on 04/27/98 at 16:10:16

Added swap of unsigned16

  • Property mode set to 100644
File size: 12.1 KB
Line 
1/*  i386.h
2 *
3 *  This include file contains information pertaining to the Intel
4 *  i386 processor.
5 *
6 *  COPYRIGHT (c) 1989-1998.
7 *  On-Line Applications Research Corporation (OAR).
8 *  Copyright assigned to U.S. Government, 1994.
9 *
10 *  The license and distribution terms for this file may be
11 *  found in the file LICENSE in this distribution or at
12 *  http://www.OARcorp.com/rtems/license.html.
13 *
14 *  $Id$
15 */
16
17#ifndef __i386_h
18#define __i386_h
19
20#ifdef __cplusplus
21extern "C" {
22#endif
23
24/*
25 *  This section contains the information required to build
26 *  RTEMS for a particular member of the Intel i386
27 *  family when executing in protected mode.  It does
28 *  this by setting variables to indicate which implementation
29 *  dependent features are present in a particular member
30 *  of the family.
31 *
32 *  Currently recognized:
33 *    i386_fp    (i386 DX or SX w/i387)
34 *    i386_fp    (i386 DX or SX w/o i387)
35 *    i486dx
36 *    i486sx
37 *    pentium
38 *
39 *  Floating point is the only feature which currently varies.  Eventually
40 *  the i486-plus level instruction for endian swapping should be added
41 *  to this feature list.
42 */
43
44#if defined(i386_fp)
45
46#define CPU_MODEL_NAME  "i386 with i387"
47#define I386_HAS_FPU 1
48
49#elif defined(i386_nofp)
50
51#define CPU_MODEL_NAME  "i386 w/o i387"
52#define I386_HAS_FPU 0
53
54#elif defined(i486dx)
55
56#define CPU_MODEL_NAME  "i486dx"
57#define I386_HAS_FPU 1
58
59#elif defined(i486sx)
60
61#define CPU_MODEL_NAME  "i486sx"
62#define I386_HAS_FPU 0
63
64#elif defined(pentium)
65
66#define CPU_MODEL_NAME  "Pentium"
67#define I386_HAS_FPU 1
68
69#else
70
71#error "Unsupported CPU Model"
72
73#endif
74
75/*
76 *  Define the name of the CPU family.
77 */
78
79#define CPU_NAME "Intel i386"
80
81#ifndef ASM
82
83/*
84 *  Structure which makes it easier to deal with LxDT and SxDT instructions.
85 */
86 
87typedef struct {
88  unsigned short limit;
89  unsigned short physical_address[ 2 ];
90} i386_DTR_load_save_format;
91 
92/* See Chapter 5 - Memory Management in i386 manual */
93 
94typedef struct {
95  unsigned short limit_0_15;
96  unsigned short base_0_15;
97  unsigned char  base_16_23;
98  unsigned char  type_dt_dpl_p;
99  unsigned char  limit_16_19_granularity;
100  unsigned char  base_24_31;
101}   i386_GDT_slot;
102 
103/* See Chapter 9 - Exceptions and Interrupts in i386 manual
104 *
105 *  NOTE: This is the IDT entry for interrupt gates ONLY.
106 */
107 
108typedef struct {
109  unsigned short offset_0_15;
110  unsigned short segment_selector;
111  unsigned char  reserved;
112  unsigned char  p_dpl;
113  unsigned short offset_16_31;
114}   i386_IDT_slot;
115
116/*
117 *  Interrupt Level Macros
118 */
119
120#define i386_disable_interrupts( _level ) \
121  { \
122    _level = 0;   /* avoids warnings */ \
123    asm volatile ( "pushf ; \
124                    cli ; \
125                    pop %0" \
126                    : "=r" ((_level)) : "0" ((_level)) \
127    ); \
128  }
129
130#define i386_enable_interrupts( _level )  \
131  { \
132    asm volatile ( "push %0 ; \
133                    popf" \
134                    : "=r" ((_level)) : "0" ((_level)) \
135    ); \
136  }
137
138#define i386_flash_interrupts( _level ) \
139  { \
140    asm volatile ( "push %0 ; \
141                    popf ; \
142                    cli" \
143                    : "=r" ((_level)) : "0" ((_level)) \
144    ); \
145  }
146
147#define i386_get_interrupt_level( _level ) \
148  do { \
149    register unsigned32 _eflags = 0; \
150    \
151    asm volatile ( "pushf ; \
152                    pop %0" \
153                    : "=r" ((_eflags)) : "0" ((_eflags)) \
154    ); \
155    \
156    _level = (_eflags & 0x0200) ? 0 : 1; \
157  } while (0)
158
159/*
160 *  The following routine swaps the endian format of an unsigned int.
161 *  It must be static so it can be referenced indirectly.
162 */
163
164static inline unsigned int i386_swap_U32(
165  unsigned int value
166)
167{
168  unsigned long lout;
169
170  asm volatile( "rorw  $8,%%ax;"
171                "rorl  $16,%0;"
172                "rorw  $8,%%ax" : "=a" (lout) : "0" (value) );
173/* this should be better for i486dx and above */
174/*
175    __asm__ volatile( "bswap %0" : "=r"  (lout) : "0"   (lin));
176*/
177  return( lout );
178}
179
180static inline unsigned int i386_swap_U16(
181  unsigned int value
182)
183{
184    unsigned short      sout;
185
186    __asm__ volatile( "rorw $8,%0" : "=r"  (sout) : "0"   (value));
187    return (sout);
188}
189
190/*
191 *  Segment Access Routines
192 *
193 *  NOTE:  Unfortunately, these are still static inlines even when the
194 *         "macro" implementation of the generic code is used.
195 */
196
197static inline unsigned short i386_get_cs()
198{
199  register unsigned short segment = 0;
200
201  asm volatile ( "movw %%cs,%0" : "=r" (segment) : "0" (segment) );
202
203  return segment;
204}
205
206static inline unsigned short i386_get_ds()
207{
208  register unsigned short segment = 0;
209
210  asm volatile ( "movw %%ds,%0" : "=r" (segment) : "0" (segment) );
211
212  return segment;
213}
214
215static inline unsigned short i386_get_es()
216{
217  register unsigned short segment = 0;
218
219  asm volatile ( "movw %%es,%0" : "=r" (segment) : "0" (segment) );
220
221  return segment;
222}
223
224static inline unsigned short i386_get_ss()
225{
226  register unsigned short segment = 0;
227
228  asm volatile ( "movw %%ss,%0" : "=r" (segment) : "0" (segment) );
229
230  return segment;
231}
232
233static inline unsigned short i386_get_fs()
234{
235  register unsigned short segment = 0;
236
237  asm volatile ( "movw %%fs,%0" : "=r" (segment) : "0" (segment) );
238
239  return segment;
240}
241
242static inline unsigned short i386_get_gs()
243{
244  register unsigned short segment = 0;
245
246  asm volatile ( "movw %%gs,%0" : "=r" (segment) : "0" (segment) );
247
248  return segment;
249}
250
251/*
252 *  IO Port Access Routines
253 */
254
255#define i386_outport_byte( _port, _value ) \
256   { register unsigned short __port  = _port; \
257     register unsigned char  __value = _value; \
258     \
259     asm volatile ( "outb %0,%1" : "=a" (__value), "=d" (__port) \
260                                 : "0"   (__value), "1"  (__port) \
261                  ); \
262   }
263
264#define i386_outport_word( _port, _value ) \
265   { register unsigned short __port  = _port; \
266     register unsigned short __value = _value; \
267     \
268     asm volatile ( "outw %0,%1" : "=a" (__value), "=d" (__port) \
269                                 : "0"   (__value), "1"  (__port) \
270                  ); \
271   }
272
273#define i386_outport_long( _port, _value ) \
274   { register unsigned short __port  = _port; \
275     register unsigned int  __value = _value; \
276     \
277     asm volatile ( "outl %0,%1" : "=a" (__value), "=d" (__port) \
278                                 : "0"   (__value), "1"  (__port) \
279                  ); \
280   }
281
282#define i386_inport_byte( _port, _value ) \
283   { register unsigned short __port  = _port; \
284     register unsigned char  __value = 0; \
285     \
286     asm volatile ( "inb %1,%0" : "=a" (__value), "=d" (__port) \
287                                : "0"   (__value), "1"  (__port) \
288                  ); \
289     _value = __value; \
290   }
291
292#define i386_inport_word( _port, _value ) \
293   { register unsigned short __port  = _port; \
294     register unsigned short __value = 0; \
295     \
296     asm volatile ( "inw %1,%0" : "=a" (__value), "=d" (__port) \
297                                : "0"   (__value), "1"  (__port) \
298                  ); \
299     _value = __value; \
300   }
301
302#define i386_inport_long( _port, _value ) \
303   { register unsigned short __port  = _port; \
304     register unsigned int  __value = 0; \
305     \
306     asm volatile ( "inl %1,%0" : "=a" (__value), "=d" (__port) \
307                                : "0"   (__value), "1"  (__port) \
308                  ); \
309     _value = __value; \
310   }
311
312/*
313 *  Descriptor Table helper routines
314 */
315
316
317#define i386_get_GDTR( _gdtr_address ) \
318  { \
319    void *_gdtr = (_gdtr_address); \
320    \
321    asm volatile( "sgdt   (%0)" : "=r" (_gdtr) : "0" (_gdtr) ); \
322  }
323
324#define i386_get_GDT_slot( _gdtr_base, _segment, _slot_address ) \
325  { \
326    register unsigned int   _gdt_slot  = (_gdtr_base) + (_segment); \
327    register volatile void *_slot      = (_slot_address); \
328    register unsigned int   _temporary = 0; \
329    \
330    asm volatile( "movl %%gs:(%0),%1 ; \
331                   movl %1,(%2) ; \
332                   movl %%gs:4(%0),%1 ; \
333                   movl %1,4(%2)"  \
334                     : "=r" (_gdt_slot), "=r" (_temporary), "=r" (_slot) \
335                     : "0"  (_gdt_slot), "1"  (_temporary), "2"  (_slot) \
336                );  \
337  }
338
339#define i386_set_GDT_slot( _gdtr_base, _segment, _slot_address ) \
340  { \
341    register unsigned int   _gdt_slot  = (_gdtr_base) + (_segment); \
342    register volatile void *_slot      = (_slot_address); \
343    register unsigned int   _temporary = 0; \
344    \
345    asm volatile( "movl (%2),%1 ; \
346                   movl %1,%%gs:(%0) ; \
347                   movl 4(%2),%1 ; \
348                   movl %1,%%gs:4(%0) \
349                  " \
350                     : "=r" (_gdt_slot), "=r" (_temporary), "=r" (_slot) \
351                     : "0"  (_gdt_slot), "1"  (_temporary), "2"  (_slot) \
352                );  \
353  }
354
355static inline void i386_set_segment(
356  unsigned short segment,
357  unsigned int  base,
358  unsigned int  limit
359)
360{
361  i386_DTR_load_save_format         gdtr;
362  volatile i386_GDT_slot            Gdt_slot;
363  volatile i386_GDT_slot           *gdt_slot = &Gdt_slot;
364  unsigned short                    tmp_segment = 0;
365  unsigned int                      limit_adjusted;
366
367  /* load physical address of the GDT */
368
369  i386_get_GDTR( &gdtr );
370
371  gdt_slot->type_dt_dpl_p  = 0x92;             /* present, dpl=0,      */
372                                               /* application=1,       */
373                                               /* type=data read/write */
374  gdt_slot->limit_16_19_granularity = 0x40;    /* 32 bit segment       */
375
376  limit_adjusted = limit;
377  if ( limit > 4095 ) {
378    gdt_slot->limit_16_19_granularity |= 0x80; /* set granularity bit */
379    limit_adjusted /= 4096;
380  }
381
382  gdt_slot->limit_16_19_granularity |= (limit_adjusted >> 16) & 0xff;
383  gdt_slot->limit_0_15               = limit_adjusted & 0xffff;
384
385  gdt_slot->base_0_15  = base & 0xffff;
386  gdt_slot->base_16_23 = (base >> 16) & 0xff;
387  gdt_slot->base_24_31 = (base >> 24);
388
389  i386_set_GDT_slot(
390    gdtr.physical_address[0] + (gdtr.physical_address[1] << 16),
391    segment,
392    gdt_slot
393  );
394
395  /* Now, reload all segment registers so the limit takes effect. */
396
397  asm volatile( "movw %%ds,%0 ; movw %0,%%ds
398                 movw %%es,%0 ; movw %0,%%es
399                 movw %%fs,%0 ; movw %0,%%fs
400                 movw %%gs,%0 ; movw %0,%%gs
401                 movw %%ss,%0 ; movw %0,%%ss"
402                   : "=r" (tmp_segment)
403                   : "0"  (tmp_segment)
404              );
405
406}
407
408/* routines */
409
410/*
411 *  i386_Logical_to_physical
412 *
413 *  Converts logical address to physical address.
414 */
415
416void *i386_Logical_to_physical(
417  unsigned short  segment,
418  void           *address
419);
420
421/*
422 *  i386_Physical_to_logical
423 *
424 *  Converts physical address to logical address.
425 */
426
427void *i386_Physical_to_logical(
428  unsigned short  segment,
429  void           *address
430);
431
432/*
433 *  i386_Install_idt
434 *
435 *  This routine installs an IDT entry.
436 */
437
438void i386_Install_idt(
439  unsigned int   source_offset,
440  unsigned short destination_segment,
441  unsigned int   destination_offset
442);
443
444/*
445 *  "Simpler" names for a lot of the things defined in this file
446 */
447
448/* segment access routines */
449 
450#define get_cs()   i386_get_cs()
451#define get_ds()   i386_get_ds()
452#define get_es()   i386_get_es()
453#define get_ss()   i386_get_ss()
454#define get_fs()   i386_get_fs()
455#define get_gs()   i386_get_gs()
456 
457#define CPU_swap_u32( _value )  i386_swap_U32( _value )
458#define CPU_swap_u16( _value )  i386_swap_U16( _value )
459 
460/* i80x86 I/O instructions */
461 
462#define outport_byte( _port, _value ) i386_outport_byte( _port, _value )
463#define outport_word( _port, _value ) i386_outport_word( _port, _value )
464#define outport_long( _port, _value ) i386_outport_long( _port, _value )
465#define inport_byte( _port, _value )  i386_inport_byte( _port, _value )
466#define inport_word( _port, _value )  i386_inport_word( _port, _value )
467#define inport_long( _port, _value )  i386_inport_long( _port, _value )
468 
469/* complicated static inline functions */
470 
471#define get_GDTR( _gdtr_address ) \
472        i386_get_GDTR( _gdtr_address )
473 
474#define get_GDT_slot( _gdtr_base, _segment, _slot_address ) \
475        i386_get_GDT_slot( _gdtr_base, _segment, _slot_address )
476 
477#define set_GDT_slot( _gdtr_base, _segment, _slot_address ) \
478        i386_set_GDT_slot( _gdtr_base, _segment, _slot_address )
479 
480#define set_segment( _segment, _base, _limit ) \
481  i386_set_segment( _segment, _base, _limit )
482 
483
484#ifdef __cplusplus
485}
486#endif
487
488#endif /* !ASM */
489
490#endif
491/* end of include file */
Note: See TracBrowser for help on using the repository browser.