ok() does not support '%S'. Store the Ansi version, convert to Unicode
[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 #define WINE_EXPORT_LDT_COPY
32 #include "wine/library.h"
33
34 #ifdef __i386__
35
36 #ifdef linux
37
38 #ifdef HAVE_SYS_SYSCALL_H
39 # include <sys/syscall.h>
40 #endif
41
42 struct modify_ldt_s
43 {
44     unsigned int  entry_number;
45     unsigned long base_addr;
46     unsigned int  limit;
47     unsigned int  seg_32bit : 1;
48     unsigned int  contents : 2;
49     unsigned int  read_exec_only : 1;
50     unsigned int  limit_in_pages : 1;
51     unsigned int  seg_not_present : 1;
52     unsigned int  useable:1;
53 };
54
55 static inline int modify_ldt( int func, struct modify_ldt_s *ptr,
56                                   unsigned long count )
57 {
58     int res;
59 #ifdef __PIC__
60     __asm__ __volatile__( "pushl %%ebx\n\t"
61                           "movl %2,%%ebx\n\t"
62                           "int $0x80\n\t"
63                           "popl %%ebx"
64                           : "=a" (res)
65                           : "0" (SYS_modify_ldt),
66                             "r" (func),
67                             "c" (ptr),
68                             "d" (count) );
69 #else
70     __asm__ __volatile__("int $0x80"
71                          : "=a" (res)
72                          : "0" (SYS_modify_ldt),
73                            "b" (func),
74                            "c" (ptr),
75                            "d" (count) );
76 #endif  /* __PIC__ */
77     if (res >= 0) return res;
78     errno = -res;
79     return -1;
80 }
81
82 #endif  /* linux */
83
84 #if defined(__svr4__) || defined(_SCO_DS)
85 #include <sys/sysi86.h>
86 extern int sysi86(int,void*);
87 #ifndef __sun__
88 #include <sys/seg.h>
89 #endif
90 #endif
91
92 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
93 #include <machine/segments.h>
94
95 extern int i386_get_ldt(int, union descriptor *, int);
96 extern int i386_set_ldt(int, union descriptor *, int);
97 #endif  /* __NetBSD__ || __FreeBSD__ || __OpenBSD__ */
98
99 #endif  /* __i386__ */
100
101 /* local copy of the LDT */
102 struct __wine_ldt_copy wine_ldt_copy;
103
104
105 /***********************************************************************
106  *           ldt_get_entry
107  *
108  * Retrieve an LDT entry.
109  */
110 void wine_ldt_get_entry( unsigned short sel, LDT_ENTRY *entry )
111 {
112     int index = sel >> 3;
113     wine_ldt_set_base(  entry, wine_ldt_copy.base[index] );
114     wine_ldt_set_limit( entry, wine_ldt_copy.limit[index] );
115     wine_ldt_set_flags( entry, wine_ldt_copy.flags[index] );
116 }
117
118
119 /***********************************************************************
120  *           ldt_set_entry
121  *
122  * Set an LDT entry.
123  */
124 int wine_ldt_set_entry( unsigned short sel, const LDT_ENTRY *entry )
125 {
126     int ret = 0, index = sel >> 3;
127
128     /* Entry 0 must not be modified; its base and limit are always 0 */
129     if (!index) return 0;
130
131 #ifdef __i386__
132
133 #ifdef linux
134     {
135         struct modify_ldt_s ldt_info;
136
137         ldt_info.entry_number    = index;
138         ldt_info.base_addr       = (unsigned long)wine_ldt_get_base(entry);
139         ldt_info.limit           = entry->LimitLow | (entry->HighWord.Bits.LimitHi << 16);
140         ldt_info.seg_32bit       = entry->HighWord.Bits.Default_Big;
141         ldt_info.contents        = (entry->HighWord.Bits.Type >> 2) & 3;
142         ldt_info.read_exec_only  = !(entry->HighWord.Bits.Type & 2);
143         ldt_info.limit_in_pages  = entry->HighWord.Bits.Granularity;
144         ldt_info.seg_not_present = !entry->HighWord.Bits.Pres;
145         ldt_info.useable         = entry->HighWord.Bits.Sys;
146
147         if ((ret = modify_ldt(0x11, &ldt_info, sizeof(ldt_info))) < 0)
148             perror( "modify_ldt" );
149     }
150 #endif  /* linux */
151
152 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
153     {
154         LDT_ENTRY entry_copy = *entry;
155         /* The kernel will only let us set LDTs with user priority level */
156         if (entry_copy.HighWord.Bits.Pres
157             && entry_copy.HighWord.Bits.Dpl != 3)
158                 entry_copy.HighWord.Bits.Dpl = 3;
159         ret = i386_set_ldt(index, (union descriptor *)&entry_copy, 1);
160         if (ret < 0)
161         {
162             perror("i386_set_ldt");
163             fprintf( stderr, "Did you reconfigure the kernel with \"options USER_LDT\"?\n" );
164             exit(1);
165         }
166     }
167 #endif  /* __NetBSD__ || __FreeBSD__ || __OpenBSD__ */
168
169 #if defined(__svr4__) || defined(_SCO_DS)
170     {
171         struct ssd ldt_mod;
172         ldt_mod.sel  = sel;
173         ldt_mod.bo   = (unsigned long)wine_ldt_get_base(entry);
174         ldt_mod.ls   = entry->LimitLow | (entry->HighWord.Bits.LimitHi << 16);
175         ldt_mod.acc1 = entry->HighWord.Bytes.Flags1;
176         ldt_mod.acc2 = entry->HighWord.Bytes.Flags2 >> 4;
177         if ((ret = sysi86(SI86DSCR, &ldt_mod)) == -1) perror("sysi86");
178     }
179 #endif
180
181 #endif  /* __i386__ */
182
183     if (ret >= 0)
184     {
185         wine_ldt_copy.base[index]  = wine_ldt_get_base(entry);
186         wine_ldt_copy.limit[index] = wine_ldt_get_limit(entry);
187         wine_ldt_copy.flags[index] = (entry->HighWord.Bits.Type |
188                                  (entry->HighWord.Bits.Default_Big ? WINE_LDT_FLAGS_32BIT : 0) |
189                                  (wine_ldt_copy.flags[index] & WINE_LDT_FLAGS_ALLOCATED));
190     }
191     return ret;
192 }
193
194
195 /***********************************************************************
196  *           selector access functions
197  */
198 #ifdef __i386__
199 # ifndef _MSC_VER
200 /* Nothing needs to be done for MS C, it will do with inline versions from the winnt.h */
201 __ASM_GLOBAL_FUNC( wine_get_cs, "movw %cs,%ax\n\tret" )
202 __ASM_GLOBAL_FUNC( wine_get_ds, "movw %ds,%ax\n\tret" )
203 __ASM_GLOBAL_FUNC( wine_get_es, "movw %es,%ax\n\tret" )
204 __ASM_GLOBAL_FUNC( wine_get_fs, "movw %fs,%ax\n\tret" )
205 __ASM_GLOBAL_FUNC( wine_get_gs, "movw %gs,%ax\n\tret" )
206 __ASM_GLOBAL_FUNC( wine_get_ss, "movw %ss,%ax\n\tret" )
207 __ASM_GLOBAL_FUNC( wine_set_fs, "movl 4(%esp),%eax\n\tmovw %ax,%fs\n\tret" )
208 __ASM_GLOBAL_FUNC( wine_set_gs, "movl 4(%esp),%eax\n\tmovw %ax,%gs\n\tret" )
209 # endif /* defined(_MSC_VER) */
210 #endif /* defined(__i386__) */