Mon Jun 24 19:57:01 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
[kopensolaris-gnu/glibc.git] / sysdeps / standalone / i386 / i386.h
1 /* Copyright (C) 1994 Free Software Foundation, Inc.
2    Contributed by Joel Sherrill (jsherril@redstone-emh2.army.mil),
3      On-Line Applications Research Corporation.
4  
5 This file is part of the GNU C Library.
6  
7 The GNU C Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
11  
12 The GNU C Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 Library General Public License for more details.
16  
17 You should have received a copy of the GNU Library General Public
18 License along with the GNU C Library; see the file COPYING.LIB.  If
19 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
20 Cambridge, MA 02139, USA.  */
21
22 /*  i386.h
23  *
24  *  This file contains macros which are used to access i80386 
25  *  registers which are not addressable by C.  This file contains
26  *  functions which are useful to those developing target 
27  *  specific support routines.
28  */
29
30 #ifndef i386_h__
31 #define i386_h__
32
33 typedef unsigned char   unsigned8;
34 typedef unsigned short  unsigned16;
35 typedef unsigned int    unsigned32;
36
37 #define disable_intr( isrlevel ) \
38   { (isrlevel) = 0; \
39     asm volatile ( "pushf ; \
40                     pop  %0 ; \
41                     cli   " \
42                     : "=r" ((isrlevel)) : "0" ((isrlevel)) ); \
43   }
44
45
46 #define enable_intr( isrlevel ) \
47   { asm volatile ( "push %0 ; \
48                     popf " \
49                     : "=r" ((isrlevel)) : "0" ((isrlevel)) ); \
50   }
51
52 #define delay( _microseconds ) \
53   { \
54     unsigned32 _counter; \
55     \
56     _counter = (_microseconds); \
57     \
58     asm volatile ( "0: nop;" \
59                    " mov %0,%0 ;" \
60                    " loop 0" : "=c" (_counter) \
61                                       : "0"  (_counter) \
62                  ); \
63     \
64   }
65
66 /* segment access functions */
67
68 static inline unsigned16 get_cs()
69 {
70   register unsigned16 segment = 0;
71
72   asm volatile ( "movw %%cs,%0" : "=r" (segment) : "0" (segment) ); 
73
74   return segment;
75 }
76
77 static inline unsigned16 get_ds()
78 {
79   register unsigned16 segment = 0;
80
81   asm volatile ( "movw %%ds,%0" : "=r" (segment) : "0" (segment) ); 
82
83   return segment;
84 }
85
86 static inline unsigned16 get_es()
87 {
88   register unsigned16 segment = 0;
89
90   asm volatile ( "movw %%es,%0" : "=r" (segment) : "0" (segment) ); 
91
92   return segment;
93 }
94
95 static inline unsigned16 get_ss()
96 {
97   register unsigned16 segment = 0;
98
99   asm volatile ( "movw %%ss,%0" : "=r" (segment) : "0" (segment) ); 
100
101   return segment;
102 }
103
104 static inline unsigned16 get_fs()
105 {
106   register unsigned16 segment = 0;
107
108   asm volatile ( "movw %%fs,%0" : "=r" (segment) : "0" (segment) ); 
109
110   return segment;
111 }
112
113 static inline unsigned16 get_gs()
114 {
115   register unsigned16 segment = 0;
116
117   asm volatile ( "movw %%gs,%0" : "=r" (segment) : "0" (segment) ); 
118
119   return segment;
120 }
121
122 /* i80x86 I/O instructions */
123
124 #define outport_byte( _port, _value ) \
125    { register unsigned16 __port  = _port; \
126      register unsigned8  __value = _value; \
127      \
128      asm volatile ( "outb %0,%1" : "=a" (__value), "=d" (__port) \
129                                  : "0"   (__value), "1"  (__port) \
130                   ); \
131    }
132
133 #define outport_word( _port, _value ) \
134    { register unsigned16 __port  = _port; \
135      register unsigned16 __value = _value; \
136      \
137      asm volatile ( "outw %0,%1" : "=a" (__value), "=d" (__port) \
138                                  : "0"   (__value), "1"  (__port) \
139                   ); \
140    }
141
142 #define outport_long( _port, _value ) \
143    { register unsigned16 __port  = _port; \
144      register unsigned32 __value = _value; \
145      \
146      asm volatile ( "outl %0,%1" : "=a" (__value), "=d" (__port) \
147                                  : "0"   (__value), "1"  (__port) \
148                   ); \
149    }
150
151 #define inport_byte( _port, _value ) \
152    { register unsigned16 __port  = _port; \
153      register unsigned8  __value = 0; \
154      \
155      asm volatile ( "inb %1,%0" : "=a" (__value), "=d" (__port) \
156                                 : "0"   (__value), "1"  (__port) \
157                   ); \
158      _value = __value; \
159    }
160
161 #define inport_word( _port, _value ) \
162    { register unsigned16 __port  = _port; \
163      register unsigned16 __value = 0; \
164      \
165      asm volatile ( "inw %1,%0" : "=a" (__value), "=d" (__port) \
166                                 : "0"   (__value), "1"  (__port) \
167                   ); \
168      _value = __value; \
169    }
170
171 #define inport_long( _port, _value ) \
172    { register unsigned16 __port  = _port; \
173      register unsigned32 __value = 0; \
174      \
175      asm volatile ( "inl %1,%0" : "=a" (__value), "=d" (__port) \
176                                 : "0"   (__value), "1"  (__port) \
177                   ); \
178      _value = __value; \
179    }
180
181 /* structures */
182
183 /* See Chapter 5 - Memory Management in i386 manual */
184
185 struct GDT_slot {
186   unsigned16 limit_0_15;
187   unsigned16 base_0_15;
188   unsigned8  base_16_23;
189   unsigned8  type_dt_dpl_p;
190   unsigned8  limit_16_19_granularity;
191   unsigned8  base_24_31;
192 };
193
194 /* See Chapter 9 - Exceptions and Interrupts in i386 manual 
195  *
196  *  NOTE: This is the IDT entry for interrupt gates ONLY.
197  */
198
199 struct IDT_slot {
200   unsigned16 offset_0_15;
201   unsigned16 segment_selector;
202   unsigned8  reserved;
203   unsigned8  p_dpl;
204   unsigned16 offset_16_31;
205 };
206
207 struct DTR_load_save_format {
208   unsigned16 limit;
209   unsigned32 physical_address;
210 };
211
212 /* variables */
213
214 extern struct IDT_slot Interrupt_descriptor_table[ 256 ];
215 extern struct GDT_slot Global_descriptor_table[ 8192 ];
216
217 /* functions */
218
219 #ifdef CPU_INITIALIZE
220 #define EXTERN
221 #else
222 #undef EXTERN
223 #define EXTERN extern
224 #endif
225
226 void *Logical_to_physical(
227   unsigned16  segment,
228   void             *address
229 );
230
231 void *Physical_to_logical(
232   unsigned16  segment,
233   void             *address
234 );
235
236 /* complicated static inline functions */
237
238 #define get_GDTR( _gdtr_address ) \
239   { \
240     void                        *_gdtr = (_gdtr_address); \
241     \
242     asm volatile( "sgdt   (%0)" : "=r" (_gdtr) : "0" (_gdtr) ); \
243   }
244
245 #define get_GDT_slot( _gdtr_base, _segment, _slot_address ) \
246   { \
247     register unsigned32  _gdt_slot  = (_gdtr_base) + (_segment); \
248     register volatile void    *_slot      = (_slot_address); \
249     register unsigned32  _temporary = 0; \
250     \
251     asm volatile( "movl %%gs:(%0),%1 ; \
252                    movl %1,(%2) ; \
253                    movl %%gs:4(%0),%1 ; \
254                    movl %1,4(%2)"  \
255                      : "=r" (_gdt_slot), "=r" (_temporary), "=r" (_slot) \
256                      : "0"  (_gdt_slot), "1"  (_temporary), "2"  (_slot) \
257                 );  \
258   }
259
260 #define set_GDT_slot( _gdtr_base, _segment, _slot_address ) \
261   { \
262     register unsigned32  _gdt_slot  = (_gdtr_base) + (_segment); \
263     register volatile void    *_slot      = (_slot_address); \
264     register unsigned32  _temporary = 0; \
265     \
266     asm volatile( "movl (%2),%1 ; \
267                    movl %1,%%gs:(%0) ; \
268                    movl 4(%2),%1 ; \
269                    movl %1,%%gs:4(%0) \
270                   " \
271                      : "=r" (_gdt_slot), "=r" (_temporary), "=r" (_slot) \
272                      : "0"  (_gdt_slot), "1"  (_temporary), "2"  (_slot) \
273                 );  \
274   }
275
276 static inline void set_segment( 
277   unsigned16 segment, 
278   unsigned32 base,
279   unsigned32 limit 
280
281
282   struct DTR_load_save_format  gdtr; 
283   volatile struct GDT_slot     Gdt_slot;
284   volatile struct GDT_slot    *gdt_slot = &Gdt_slot;
285   unsigned16             tmp_segment = 0;
286   unsigned32             limit_adjusted;
287  
288   
289   /* load physical address of the GDT */
290
291   get_GDTR( &gdtr );
292  
293   gdt_slot->type_dt_dpl_p  = 0x92;             /* present, dpl=0,      */
294                                                /* application=1,       */
295                                                /* type=data read/write */
296   gdt_slot->limit_16_19_granularity = 0x40;    /* 32 bit segment       */
297
298   limit_adjusted = limit;
299   if ( limit > 4095 ) {
300     gdt_slot->limit_16_19_granularity |= 0x80; /* set granularity bit */
301     limit_adjusted /= 4096;
302   } 
303  
304   gdt_slot->limit_16_19_granularity |= (limit_adjusted >> 16) & 0xff;
305   gdt_slot->limit_0_15               = limit_adjusted & 0xffff;
306  
307   gdt_slot->base_0_15  = base & 0xffff;
308   gdt_slot->base_16_23 = (base >> 16) & 0xff;
309   gdt_slot->base_24_31 = (base >> 24);
310  
311   set_GDT_slot( gdtr.physical_address, segment, gdt_slot );
312
313   /* Now, reload all segment registers so the limit takes effect. */
314
315   asm volatile( "movw %%ds,%0 ; movw %0,%%ds
316                  movw %%es,%0 ; movw %0,%%es
317                  movw %%fs,%0 ; movw %0,%%fs
318                  movw %%gs,%0 ; movw %0,%%gs
319                  movw %%ss,%0 ; movw %0,%%ss"
320                    : "=r" (tmp_segment) 
321                    : "0"  (tmp_segment)
322               );
323                  
324 }
325
326 #endif
327 /* end of include file */