On Windows windef.h must be included before winbase.h.
[wine] / library / ldt.c
1 /*
2  * LDT manipulation functions
3  *
4  * Copyright 1993 Robert J. Amstadt
5  * Copyright 1995 Alexandre Julliard
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This 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  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <errno.h>
29
30 #include "winbase.h"
31 #include "wine/library.h"
32
33 #ifdef __i386__
34
35 #ifdef linux
36
37 #ifdef HAVE_SYS_SYSCALL_H
38 # include <sys/syscall.h>
39 #endif
40
41 struct modify_ldt_s
42 {
43     unsigned int  entry_number;
44     unsigned long base_addr;
45     unsigned int  limit;
46     unsigned int  seg_32bit : 1;
47     unsigned int  contents : 2;
48     unsigned int  read_exec_only : 1;
49     unsigned int  limit_in_pages : 1;
50     unsigned int  seg_not_present : 1;
51     unsigned int  useable:1;
52 };
53
54 static inline int modify_ldt( int func, struct modify_ldt_s *ptr,
55                                   unsigned long count )
56 {
57     int res;
58 #ifdef __PIC__
59     __asm__ __volatile__( "pushl %%ebx\n\t"
60                           "movl %2,%%ebx\n\t"
61                           "int $0x80\n\t"
62                           "popl %%ebx"
63                           : "=a" (res)
64                           : "0" (SYS_modify_ldt),
65                             "r" (func),
66                             "c" (ptr),
67                             "d" (count) );
68 #else
69     __asm__ __volatile__("int $0x80"
70                          : "=a" (res)
71                          : "0" (SYS_modify_ldt),
72                            "b" (func),
73                            "c" (ptr),
74                            "d" (count) );
75 #endif  /* __PIC__ */
76     if (res >= 0) return res;
77     errno = -res;
78     return -1;
79 }
80
81 #endif  /* linux */
82
83 #if defined(__svr4__) || defined(_SCO_DS)
84 #include <sys/sysi86.h>
85 extern int sysi86(int,void*);
86 #ifndef __sun__
87 #include <sys/seg.h>
88 #endif
89 #endif
90
91 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
92 #include <machine/segments.h>
93
94 extern int i386_get_ldt(int, union descriptor *, int);
95 extern int i386_set_ldt(int, union descriptor *, int);
96 #endif  /* __NetBSD__ || __FreeBSD__ || __OpenBSD__ */
97
98 #endif  /* __i386__ */
99
100 /* local copy of the LDT */
101 struct __wine_ldt_copy wine_ldt_copy;
102
103
104 /***********************************************************************
105  *           ldt_get_entry
106  *
107  * Retrieve an LDT entry.
108  */
109 void wine_ldt_get_entry( unsigned short sel, LDT_ENTRY *entry )
110 {
111     int index = sel >> 3;
112     wine_ldt_set_base(  entry, wine_ldt_copy.base[index] );
113     wine_ldt_set_limit( entry, wine_ldt_copy.limit[index] );
114     wine_ldt_set_flags( entry, wine_ldt_copy.flags[index] );
115 }
116
117
118 /***********************************************************************
119  *           ldt_set_entry
120  *
121  * Set an LDT entry.
122  */
123 int wine_ldt_set_entry( unsigned short sel, const LDT_ENTRY *entry )
124 {
125     int ret = 0, index = sel >> 3;
126
127     /* Entry 0 must not be modified; its base and limit are always 0 */
128     if (!index) return 0;
129
130 #ifdef __i386__
131
132 #ifdef linux
133     {
134         struct modify_ldt_s ldt_info;
135
136         ldt_info.entry_number    = index;
137         ldt_info.base_addr       = (unsigned long)wine_ldt_get_base(entry);
138         ldt_info.limit           = entry->LimitLow | (entry->HighWord.Bits.LimitHi << 16);
139         ldt_info.seg_32bit       = entry->HighWord.Bits.Default_Big;
140         ldt_info.contents        = (entry->HighWord.Bits.Type >> 2) & 3;
141         ldt_info.read_exec_only  = !(entry->HighWord.Bits.Type & 2);
142         ldt_info.limit_in_pages  = entry->HighWord.Bits.Granularity;
143         ldt_info.seg_not_present = !entry->HighWord.Bits.Pres;
144         ldt_info.useable         = entry->HighWord.Bits.Sys;
145
146         if ((ret = modify_ldt(0x11, &ldt_info, sizeof(ldt_info))) < 0)
147             perror( "modify_ldt" );
148     }
149 #endif  /* linux */
150
151 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
152     {
153         LDT_ENTRY entry_copy = *entry;
154         /* The kernel will only let us set LDTs with user priority level */
155         if (entry_copy.HighWord.Bits.Pres
156             && entry_copy.HighWord.Bits.Dpl != 3)
157                 entry_copy.HighWord.Bits.Dpl = 3;
158         ret = i386_set_ldt(index, (union descriptor *)&entry_copy, 1);
159         if (ret < 0)
160         {
161             perror("i386_set_ldt");
162             fprintf( stderr, "Did you reconfigure the kernel with \"options USER_LDT\"?\n" );
163             exit(1);
164         }
165     }
166 #endif  /* __NetBSD__ || __FreeBSD__ || __OpenBSD__ */
167
168 #if defined(__svr4__) || defined(_SCO_DS)
169     {
170         struct ssd ldt_mod;
171         ldt_mod.sel  = sel;
172         ldt_mod.bo   = (unsigned long)wine_ldt_get_base(entry);
173         ldt_mod.ls   = entry->LimitLow | (entry->HighWord.Bits.LimitHi << 16);
174         ldt_mod.acc1 = entry->HighWord.Bytes.Flags1;
175         ldt_mod.acc2 = entry->HighWord.Bytes.Flags2 >> 4;
176         if ((ret = sysi86(SI86DSCR, &ldt_mod)) == -1) perror("sysi86");
177     }
178 #endif
179
180 #endif  /* __i386__ */
181
182     if (ret >= 0)
183     {
184         wine_ldt_copy.base[index]  = wine_ldt_get_base(entry);
185         wine_ldt_copy.limit[index] = wine_ldt_get_limit(entry);
186         wine_ldt_copy.flags[index] = (entry->HighWord.Bits.Type |
187                                  (entry->HighWord.Bits.Default_Big ? WINE_LDT_FLAGS_32BIT : 0) |
188                                  (wine_ldt_copy.flags[index] & WINE_LDT_FLAGS_ALLOCATED));
189     }
190     return ret;
191 }
192
193
194 /***********************************************************************
195  *           selector access functions
196  */
197 #ifdef __i386__
198 # ifndef _MSC_VER
199 /* Nothing needs to be done for MS C, it will do with inline versions from the winnt.h */
200 __ASM_GLOBAL_FUNC( wine_get_cs, "movw %cs,%ax\n\tret" )
201 __ASM_GLOBAL_FUNC( wine_get_ds, "movw %ds,%ax\n\tret" )
202 __ASM_GLOBAL_FUNC( wine_get_es, "movw %es,%ax\n\tret" )
203 __ASM_GLOBAL_FUNC( wine_get_fs, "movw %fs,%ax\n\tret" )
204 __ASM_GLOBAL_FUNC( wine_get_gs, "movw %gs,%ax\n\tret" )
205 __ASM_GLOBAL_FUNC( wine_get_ss, "movw %ss,%ax\n\tret" )
206 __ASM_GLOBAL_FUNC( wine_set_fs, "movl 4(%esp),%eax\n\tmovw %ax,%fs\n\tret" )
207 __ASM_GLOBAL_FUNC( wine_set_gs, "movl 4(%esp),%eax\n\tmovw %ax,%gs\n\tret" )
208 # endif /* defined(_MSC_VER) */
209 #endif /* defined(__i386__) */