Use the "new" LDT set call on Linux.
[wine] / memory / selector.c
1 /*
2  * Selector manipulation functions
3  *
4  * Copyright 1995 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <string.h>
25
26 #include "winerror.h"
27 #include "wine/winbase16.h"
28 #include "miscemu.h"
29 #include "selectors.h"
30 #include "stackframe.h"
31 #include "wine/server.h"
32 #include "wine/debug.h"
33 #include "toolhelp.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(selector);
36
37 #define LDT_SIZE 8192
38
39 /* get the number of selectors needed to cover up to the selector limit */
40 inline static WORD get_sel_count( WORD sel )
41 {
42     return (wine_ldt_copy.limit[sel >> __AHSHIFT] >> 16) + 1;
43 }
44
45 static const LDT_ENTRY null_entry;  /* all-zeros, used to clear LDT entries */
46
47 /***********************************************************************
48  *           SELECTOR_AllocArray
49  *
50  * Allocate a selector array without setting the LDT entries
51  */
52 static WORD SELECTOR_AllocArray( WORD count )
53 {
54     WORD i, sel, size = 0;
55
56     if (!count) return 0;
57     for (i = FIRST_LDT_ENTRY_TO_ALLOC; i < LDT_SIZE; i++)
58     {
59         if (wine_ldt_copy.flags[i] & WINE_LDT_FLAGS_ALLOCATED) size = 0;
60         else if (++size >= count) break;
61     }
62     if (i == LDT_SIZE) return 0;
63     sel = i - size + 1;
64
65     /* mark selectors as allocated */
66     for (i = 0; i < count; i++) wine_ldt_copy.flags[sel + i] |= WINE_LDT_FLAGS_ALLOCATED;
67
68     return (sel << __AHSHIFT) | 7;
69 }
70
71
72 /***********************************************************************
73  *           AllocSelectorArray   (KERNEL.206)
74  */
75 WORD WINAPI AllocSelectorArray16( WORD count )
76 {
77     WORD i, sel = SELECTOR_AllocArray( count );
78
79     if (sel)
80     {
81         LDT_ENTRY entry;
82         wine_ldt_set_base( &entry, 0 );
83         wine_ldt_set_limit( &entry, 1 ); /* avoid 0 base and limit */
84         wine_ldt_set_flags( &entry, WINE_LDT_FLAGS_DATA );
85         for (i = 0; i < count; i++) wine_ldt_set_entry( sel + (i << __AHSHIFT), &entry );
86     }
87     return sel;
88 }
89
90
91 /***********************************************************************
92  *           AllocSelector   (KERNEL.175)
93  */
94 WORD WINAPI AllocSelector16( WORD sel )
95 {
96     WORD newsel, count, i;
97
98     count = sel ? get_sel_count(sel) : 1;
99     newsel = SELECTOR_AllocArray( count );
100     TRACE("(%04x): returning %04x\n", sel, newsel );
101     if (!newsel) return 0;
102     if (!sel) return newsel;  /* nothing to copy */
103     for (i = 0; i < count; i++)
104     {
105         LDT_ENTRY entry;
106         wine_ldt_get_entry( sel + (i << __AHSHIFT), &entry );
107         wine_ldt_set_entry( newsel + (i << __AHSHIFT), &entry );
108     }
109     return newsel;
110 }
111
112
113 /***********************************************************************
114  *           FreeSelector   (KERNEL.176)
115  */
116 WORD WINAPI FreeSelector16( WORD sel )
117 {
118     if (IS_SELECTOR_FREE(sel)) return sel;  /* error */
119
120 #ifdef __i386__
121     /* Check if we are freeing current %fs or %gs selector */
122     if (!((wine_get_fs() ^ sel) & ~3))
123     {
124         WARN("Freeing %%fs selector (%04x), not good.\n", wine_get_fs() );
125         wine_set_fs( 0 );
126     }
127     if (!((wine_get_gs() ^ sel) & ~3)) wine_set_gs( 0 );
128 #endif  /* __i386__ */
129
130     wine_ldt_set_entry( sel, &null_entry );
131     wine_ldt_copy.flags[sel >> __AHSHIFT] &= ~WINE_LDT_FLAGS_ALLOCATED;
132     return 0;
133 }
134
135
136 /***********************************************************************
137  *           SELECTOR_FreeFs
138  *
139  * Free the current %fs selector.
140  */
141 void SELECTOR_FreeFs(void)
142 {
143     WORD fs = wine_get_fs();
144     if (fs)
145     {
146         wine_ldt_copy.flags[fs >> __AHSHIFT] &= ~WINE_LDT_FLAGS_ALLOCATED;
147         wine_set_fs(0);
148         wine_ldt_set_entry( fs, &null_entry );
149     }
150 }
151
152
153 /***********************************************************************
154  *           SELECTOR_SetEntries
155  *
156  * Set the LDT entries for an array of selectors.
157  */
158 static void SELECTOR_SetEntries( WORD sel, const void *base, DWORD size, unsigned char flags )
159 {
160     LDT_ENTRY entry;
161     WORD i, count;
162
163     wine_ldt_set_base( &entry, base );
164     wine_ldt_set_limit( &entry, size - 1 );
165     wine_ldt_set_flags( &entry, flags );
166     count = (size + 0xffff) / 0x10000;
167     for (i = 0; i < count; i++)
168     {
169         wine_ldt_set_entry( sel + (i << __AHSHIFT), &entry );
170         wine_ldt_set_base( &entry, (char*)wine_ldt_get_base(&entry) + 0x10000);
171         /* yep, Windows sets limit like that, not 64K sel units */
172         wine_ldt_set_limit( &entry, wine_ldt_get_limit(&entry) - 0x10000 );
173     }
174 }
175
176
177 /***********************************************************************
178  *           SELECTOR_AllocBlock
179  *
180  * Allocate selectors for a block of linear memory.
181  */
182 WORD SELECTOR_AllocBlock( const void *base, DWORD size, unsigned char flags )
183 {
184     WORD sel, count;
185
186     if (!size) return 0;
187     count = (size + 0xffff) / 0x10000;
188     sel = SELECTOR_AllocArray( count );
189     if (sel) SELECTOR_SetEntries( sel, base, size, flags );
190     return sel;
191 }
192
193
194 /***********************************************************************
195  *           SELECTOR_FreeBlock
196  *
197  * Free a block of selectors.
198  */
199 void SELECTOR_FreeBlock( WORD sel )
200 {
201     WORD i, count = get_sel_count( sel );
202
203     TRACE("(%04x,%d)\n", sel, count );
204     for (i = 0; i < count; i++) FreeSelector16( sel + (i << __AHSHIFT) );
205 }
206
207
208 /***********************************************************************
209  *           SELECTOR_ReallocBlock
210  *
211  * Change the size of a block of selectors.
212  */
213 WORD SELECTOR_ReallocBlock( WORD sel, const void *base, DWORD size )
214 {
215     LDT_ENTRY entry;
216     WORD i, oldcount, newcount;
217
218     if (!size) size = 1;
219     oldcount = get_sel_count( sel );
220     newcount = (size + 0xffff) >> 16;
221     wine_ldt_get_entry( sel, &entry );
222
223     if (oldcount < newcount)  /* We need to add selectors */
224     {
225         WORD index = sel >> __AHSHIFT;
226           /* Check if the next selectors are free */
227         if (index + newcount > LDT_SIZE) i = oldcount;
228         else
229             for (i = oldcount; i < newcount; i++)
230                 if (wine_ldt_copy.flags[index+i] & WINE_LDT_FLAGS_ALLOCATED) break;
231
232         if (i < newcount)  /* they are not free */
233         {
234             SELECTOR_FreeBlock( sel );
235             sel = SELECTOR_AllocArray( newcount );
236         }
237         else  /* mark the selectors as allocated */
238         {
239             for (i = oldcount; i < newcount; i++)
240                 wine_ldt_copy.flags[index+i] |= WINE_LDT_FLAGS_ALLOCATED;
241         }
242     }
243     else if (oldcount > newcount) /* We need to remove selectors */
244     {
245         SELECTOR_FreeBlock( sel + (newcount << __AHSHIFT) );
246     }
247     if (sel) SELECTOR_SetEntries( sel, base, size, wine_ldt_get_flags(&entry) );
248     return sel;
249 }
250
251
252 /***********************************************************************
253  *           PrestoChangoSelector   (KERNEL.177)
254  */
255 WORD WINAPI PrestoChangoSelector16( WORD selSrc, WORD selDst )
256 {
257     LDT_ENTRY entry;
258     wine_ldt_get_entry( selSrc, &entry );
259     /* toggle the executable bit */
260     entry.HighWord.Bits.Type ^= (WINE_LDT_FLAGS_CODE ^ WINE_LDT_FLAGS_DATA);
261     wine_ldt_set_entry( selDst, &entry );
262     return selDst;
263 }
264
265
266 /***********************************************************************
267  *           AllocCStoDSAlias   (KERNEL.170)
268  *           AllocAlias         (KERNEL.172)
269  */
270 WORD WINAPI AllocCStoDSAlias16( WORD sel )
271 {
272     WORD newsel;
273     LDT_ENTRY entry;
274
275     newsel = SELECTOR_AllocArray( 1 );
276     TRACE("(%04x): returning %04x\n",
277                       sel, newsel );
278     if (!newsel) return 0;
279     wine_ldt_get_entry( sel, &entry );
280     entry.HighWord.Bits.Type = WINE_LDT_FLAGS_DATA;
281     wine_ldt_set_entry( newsel, &entry );
282     return newsel;
283 }
284
285
286 /***********************************************************************
287  *           AllocDStoCSAlias   (KERNEL.171)
288  */
289 WORD WINAPI AllocDStoCSAlias16( WORD sel )
290 {
291     WORD newsel;
292     LDT_ENTRY entry;
293
294     newsel = SELECTOR_AllocArray( 1 );
295     TRACE("(%04x): returning %04x\n",
296                       sel, newsel );
297     if (!newsel) return 0;
298     wine_ldt_get_entry( sel, &entry );
299     entry.HighWord.Bits.Type = WINE_LDT_FLAGS_CODE;
300     wine_ldt_set_entry( newsel, &entry );
301     return newsel;
302 }
303
304
305 /***********************************************************************
306  *           LongPtrAdd   (KERNEL.180)
307  */
308 void WINAPI LongPtrAdd16( DWORD ptr, DWORD add )
309 {
310     LDT_ENTRY entry;
311     wine_ldt_get_entry( SELECTOROF(ptr), &entry );
312     wine_ldt_set_base( &entry, (char *)wine_ldt_get_base(&entry) + add );
313     wine_ldt_set_entry( SELECTOROF(ptr), &entry );
314 }
315
316
317 /***********************************************************************
318  *           GetSelectorBase   (KERNEL.186)
319  */
320 DWORD WINAPI WIN16_GetSelectorBase( WORD sel )
321 {
322     /*
323      * Note: For Win32s processes, the whole linear address space is
324      *       shifted by 0x10000 relative to the OS linear address space.
325      *       See the comment in msdos/vxd.c.
326      */
327
328     DWORD base = GetSelectorBase( sel );
329     return W32S_WINE2APP( base );
330 }
331 DWORD WINAPI GetSelectorBase( WORD sel )
332 {
333     void *base = wine_ldt_copy.base[sel >> __AHSHIFT];
334
335     /* if base points into DOSMEM, assume we have to
336      * return pointer into physical lower 1MB */
337
338     return DOSMEM_MapLinearToDos( base );
339 }
340
341
342 /***********************************************************************
343  *           SetSelectorBase   (KERNEL.187)
344  */
345 DWORD WINAPI WIN16_SetSelectorBase( WORD sel, DWORD base )
346 {
347     /*
348      * Note: For Win32s processes, the whole linear address space is
349      *       shifted by 0x10000 relative to the OS linear address space.
350      *       See the comment in msdos/vxd.c.
351      */
352
353     SetSelectorBase( sel, W32S_APP2WINE( base ) );
354     return sel;
355 }
356 WORD WINAPI SetSelectorBase( WORD sel, DWORD base )
357 {
358     LDT_ENTRY entry;
359     wine_ldt_get_entry( sel, &entry );
360     wine_ldt_set_base( &entry, DOSMEM_MapDosToLinear(base) );
361     wine_ldt_set_entry( sel, &entry );
362     return sel;
363 }
364
365
366 /***********************************************************************
367  *           GetSelectorLimit   (KERNEL.188)
368  */
369 DWORD WINAPI GetSelectorLimit16( WORD sel )
370 {
371     return wine_ldt_copy.limit[sel >> __AHSHIFT];
372 }
373
374
375 /***********************************************************************
376  *           SetSelectorLimit   (KERNEL.189)
377  */
378 WORD WINAPI SetSelectorLimit16( WORD sel, DWORD limit )
379 {
380     LDT_ENTRY entry;
381     wine_ldt_get_entry( sel, &entry );
382     wine_ldt_set_limit( &entry, limit );
383     wine_ldt_set_entry( sel, &entry );
384     return sel;
385 }
386
387
388 /***********************************************************************
389  *           SelectorAccessRights   (KERNEL.196)
390  */
391 WORD WINAPI SelectorAccessRights16( WORD sel, WORD op, WORD val )
392 {
393     LDT_ENTRY entry;
394     wine_ldt_get_entry( sel, &entry );
395
396     if (op == 0)  /* get */
397     {
398         return entry.HighWord.Bytes.Flags1 | ((entry.HighWord.Bytes.Flags2 << 8) & 0xf0);
399     }
400     else  /* set */
401     {
402         entry.HighWord.Bytes.Flags1 = LOBYTE(val) | 0xf0;
403         entry.HighWord.Bytes.Flags2 = (entry.HighWord.Bytes.Flags2 & 0x0f) | (HIBYTE(val) & 0xf0);
404         wine_ldt_set_entry( sel, &entry );
405         return 0;
406     }
407 }
408
409
410 /***********************************************************************
411  *           IsBadCodePtr   (KERNEL.336)
412  */
413 BOOL16 WINAPI IsBadCodePtr16( SEGPTR lpfn )
414 {
415     WORD sel;
416     LDT_ENTRY entry;
417
418     sel = SELECTOROF(lpfn);
419     if (!sel) return TRUE;
420     if (IS_SELECTOR_FREE(sel)) return TRUE;
421     wine_ldt_get_entry( sel, &entry );
422     /* check for code segment, ignoring conforming, read-only and accessed bits */
423     if ((entry.HighWord.Bits.Type ^ WINE_LDT_FLAGS_CODE) & 0x18) return TRUE;
424     if (OFFSETOF(lpfn) > wine_ldt_get_limit(&entry)) return TRUE;
425     return FALSE;
426 }
427
428
429 /***********************************************************************
430  *           IsBadStringPtr   (KERNEL.337)
431  */
432 BOOL16 WINAPI IsBadStringPtr16( SEGPTR ptr, UINT16 size )
433 {
434     WORD sel;
435     LDT_ENTRY entry;
436
437     sel = SELECTOROF(ptr);
438     if (!sel) return TRUE;
439     if (IS_SELECTOR_FREE(sel)) return TRUE;
440     wine_ldt_get_entry( sel, &entry );
441     /* check for data or readable code segment */
442     if (!(entry.HighWord.Bits.Type & 0x10)) return TRUE;  /* system descriptor */
443     if ((entry.HighWord.Bits.Type & 0x0a) == 0x08) return TRUE;  /* non-readable code segment */
444     if (strlen(MapSL(ptr)) < size) size = strlen(MapSL(ptr)) + 1;
445     if (size && (OFFSETOF(ptr) + size - 1 > wine_ldt_get_limit(&entry))) return TRUE;
446     return FALSE;
447 }
448
449
450 /***********************************************************************
451  *           IsBadHugeReadPtr   (KERNEL.346)
452  */
453 BOOL16 WINAPI IsBadHugeReadPtr16( SEGPTR ptr, DWORD size )
454 {
455     WORD sel;
456     LDT_ENTRY entry;
457
458     sel = SELECTOROF(ptr);
459     if (!sel) return TRUE;
460     if (IS_SELECTOR_FREE(sel)) return TRUE;
461     wine_ldt_get_entry( sel, &entry );
462     /* check for data or readable code segment */
463     if (!(entry.HighWord.Bits.Type & 0x10)) return TRUE;  /* system descriptor */
464     if ((entry.HighWord.Bits.Type & 0x0a) == 0x08) return TRUE;  /* non-readable code segment */
465     if (size && (OFFSETOF(ptr) + size - 1 > wine_ldt_get_limit( &entry ))) return TRUE;
466     return FALSE;
467 }
468
469
470 /***********************************************************************
471  *           IsBadHugeWritePtr   (KERNEL.347)
472  */
473 BOOL16 WINAPI IsBadHugeWritePtr16( SEGPTR ptr, DWORD size )
474 {
475     WORD sel;
476     LDT_ENTRY entry;
477
478     sel = SELECTOROF(ptr);
479     if (!sel) return TRUE;
480     if (IS_SELECTOR_FREE(sel)) return TRUE;
481     wine_ldt_get_entry( sel, &entry );
482     /* check for writeable data segment, ignoring expand-down and accessed flags */
483     if ((entry.HighWord.Bits.Type ^ WINE_LDT_FLAGS_DATA) & ~5) return TRUE;
484     if (size && (OFFSETOF(ptr) + size - 1 > wine_ldt_get_limit( &entry ))) return TRUE;
485     return FALSE;
486 }
487
488 /***********************************************************************
489  *           IsBadReadPtr   (KERNEL.334)
490  */
491 BOOL16 WINAPI IsBadReadPtr16( SEGPTR ptr, UINT16 size )
492 {
493     return IsBadHugeReadPtr16( ptr, size );
494 }
495
496
497 /***********************************************************************
498  *           IsBadWritePtr   (KERNEL.335)
499  */
500 BOOL16 WINAPI IsBadWritePtr16( SEGPTR ptr, UINT16 size )
501 {
502     return IsBadHugeWritePtr16( ptr, size );
503 }
504
505
506 /***********************************************************************
507  *           IsBadFlatReadWritePtr   (KERNEL.627)
508  */
509 BOOL16 WINAPI IsBadFlatReadWritePtr16( SEGPTR ptr, DWORD size, BOOL16 bWrite )
510 {
511     return bWrite? IsBadHugeWritePtr16( ptr, size )
512                  : IsBadHugeReadPtr16( ptr, size );
513 }
514
515
516 /***********************************************************************
517  *           MemoryRead   (TOOLHELP.78)
518  */
519 DWORD WINAPI MemoryRead16( WORD sel, DWORD offset, void *buffer, DWORD count )
520 {
521     WORD index = sel >> __AHSHIFT;
522
523     if (!(wine_ldt_copy.flags[index] & WINE_LDT_FLAGS_ALLOCATED)) return 0;
524     if (offset > wine_ldt_copy.limit[index]) return 0;
525     if (offset + count > wine_ldt_copy.limit[index] + 1)
526         count = wine_ldt_copy.limit[index] + 1 - offset;
527     memcpy( buffer, (char *)wine_ldt_copy.base[index] + offset, count );
528     return count;
529 }
530
531
532 /***********************************************************************
533  *           MemoryWrite   (TOOLHELP.79)
534  */
535 DWORD WINAPI MemoryWrite16( WORD sel, DWORD offset, void *buffer, DWORD count )
536 {
537     WORD index = sel >> __AHSHIFT;
538
539     if (!(wine_ldt_copy.flags[index] & WINE_LDT_FLAGS_ALLOCATED)) return 0;
540     if (offset > wine_ldt_copy.limit[index]) return 0;
541     if (offset + count > wine_ldt_copy.limit[index] + 1)
542         count = wine_ldt_copy.limit[index] + 1 - offset;
543     memcpy( (char *)wine_ldt_copy.base[index] + offset, buffer, count );
544     return count;
545 }
546
547 /************************************* Win95 pointer mapping functions *
548  *
549  */
550
551 struct mapls_entry
552 {
553     struct mapls_entry *next;
554     void               *addr;   /* linear address */
555     int                 count;  /* ref count */
556     WORD                sel;    /* selector */
557 };
558
559 static struct mapls_entry *first_entry;
560
561
562 /***********************************************************************
563  *           MapLS   (KERNEL32.@)
564  *           MapLS   (KERNEL.358)
565  *
566  * Maps linear pointer to segmented.
567  */
568 SEGPTR WINAPI MapLS( LPCVOID ptr )
569 {
570     struct mapls_entry *entry, *free = NULL;
571     void *base;
572     SEGPTR ret = 0;
573
574     if (!HIWORD(ptr)) return (SEGPTR)ptr;
575
576     base = (char *)ptr - ((unsigned int)ptr & 0x7fff);
577     HeapLock( GetProcessHeap() );
578     for (entry = first_entry; entry; entry = entry->next)
579     {
580         if (entry->addr == base) break;
581         if (!entry->count) free = entry;
582     }
583
584     if (!entry)
585     {
586         if (!free)  /* no free entry found, create a new one */
587         {
588             if (!(free = HeapAlloc( GetProcessHeap(), 0, sizeof(*free) ))) goto done;
589             if (!(free->sel = SELECTOR_AllocBlock( base, 0x10000, WINE_LDT_FLAGS_DATA )))
590             {
591                 HeapFree( GetProcessHeap(), 0, free );
592                 goto done;
593             }
594             free->count = 0;
595             free->next = first_entry;
596             first_entry = free;
597         }
598         SetSelectorBase( free->sel, (DWORD)base );
599         free->addr = base;
600         entry = free;
601     }
602     entry->count++;
603     ret = MAKESEGPTR( entry->sel, (char *)ptr - (char *)entry->addr );
604  done:
605     HeapUnlock( GetProcessHeap() );
606     return ret;
607 }
608
609 /***********************************************************************
610  *           UnMapLS   (KERNEL32.@)
611  *           UnMapLS   (KERNEL.359)
612  *
613  * Free mapped selector.
614  */
615 void WINAPI UnMapLS( SEGPTR sptr )
616 {
617     struct mapls_entry *entry;
618     WORD sel = SELECTOROF(sptr);
619
620     if (sel)
621     {
622         HeapLock( GetProcessHeap() );
623         for (entry = first_entry; entry; entry = entry->next) if (entry->sel == sel) break;
624         if (entry && entry->count > 0) entry->count--;
625         HeapUnlock( GetProcessHeap() );
626     }
627 }
628
629 /***********************************************************************
630  *           MapSL   (KERNEL32.@)
631  *           MapSL   (KERNEL.357)
632  *
633  * Maps fixed segmented pointer to linear.
634  */
635 LPVOID WINAPI MapSL( SEGPTR sptr )
636 {
637     return (char *)wine_ldt_copy.base[SELECTOROF(sptr) >> __AHSHIFT] + OFFSETOF(sptr);
638 }
639
640 /***********************************************************************
641  *           MapSLFix   (KERNEL32.@)
642  *
643  * FIXME: MapSLFix and UnMapSLFixArray should probably prevent
644  * unexpected linear address change when GlobalCompact() shuffles
645  * moveable blocks.
646  */
647
648 LPVOID WINAPI MapSLFix( SEGPTR sptr )
649 {
650     return MapSL(sptr);
651 }
652
653 /***********************************************************************
654  *           UnMapSLFixArray   (KERNEL32.@)
655  */
656
657 void WINAPI UnMapSLFixArray( SEGPTR sptr[], INT length, CONTEXT86 *context )
658 {
659     /* Must not change EAX, hence defined as 'register' function */
660 }
661
662 /***********************************************************************
663  *           GetThreadSelectorEntry   (KERNEL32.@)
664  */
665 BOOL WINAPI GetThreadSelectorEntry( HANDLE hthread, DWORD sel, LPLDT_ENTRY ldtent)
666 {
667 #ifdef __i386__
668     BOOL ret;
669
670     if (!(sel & 4))  /* GDT selector */
671     {
672         sel &= ~3;  /* ignore RPL */
673         if (!sel)  /* null selector */
674         {
675             memset( ldtent, 0, sizeof(*ldtent) );
676             return TRUE;
677         }
678         ldtent->BaseLow                   = 0;
679         ldtent->HighWord.Bits.BaseMid     = 0;
680         ldtent->HighWord.Bits.BaseHi      = 0;
681         ldtent->LimitLow                  = 0xffff;
682         ldtent->HighWord.Bits.LimitHi     = 0xf;
683         ldtent->HighWord.Bits.Dpl         = 3;
684         ldtent->HighWord.Bits.Sys         = 0;
685         ldtent->HighWord.Bits.Pres        = 1;
686         ldtent->HighWord.Bits.Granularity = 1;
687         ldtent->HighWord.Bits.Default_Big = 1;
688         ldtent->HighWord.Bits.Type        = 0x12;
689         /* it has to be one of the system GDT selectors */
690         if (sel == (wine_get_ds() & ~3)) return TRUE;
691         if (sel == (wine_get_ss() & ~3)) return TRUE;
692         if (sel == (wine_get_cs() & ~3))
693         {
694             ldtent->HighWord.Bits.Type |= 8;  /* code segment */
695             return TRUE;
696         }
697         SetLastError( ERROR_NOACCESS );
698         return FALSE;
699     }
700
701     SERVER_START_REQ( get_selector_entry )
702     {
703         req->handle = hthread;
704         req->entry = sel >> __AHSHIFT;
705         if ((ret = !wine_server_call_err( req )))
706         {
707             if (!(reply->flags & WINE_LDT_FLAGS_ALLOCATED))
708             {
709                 SetLastError( ERROR_MR_MID_NOT_FOUND );  /* sic */
710                 ret = FALSE;
711             }
712             else
713             {
714                 wine_ldt_set_base( ldtent, (void *)reply->base );
715                 wine_ldt_set_limit( ldtent, reply->limit );
716                 wine_ldt_set_flags( ldtent, reply->flags );
717             }
718         }
719     }
720     SERVER_END_REQ;
721     return ret;
722 #else
723     SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
724     return FALSE;
725 #endif
726 }
727
728
729 /**********************************************************************
730  *              SMapLS*         (KERNEL32)
731  * These functions map linear pointers at [EBP+xxx] to segmented pointers
732  * and return them.
733  * Win95 uses some kind of alias structs, which it stores in [EBP+x] to
734  * unravel them at SUnMapLS. We just store the segmented pointer there.
735  */
736 static void
737 x_SMapLS_IP_EBP_x(CONTEXT86 *context,int argoff) {
738     DWORD       val,ptr;
739
740     val =*(DWORD*)(context->Ebp + argoff);
741     if (val<0x10000) {
742         ptr=val;
743         *(DWORD*)(context->Ebp + argoff) = 0;
744     } else {
745         ptr = MapLS((LPVOID)val);
746         *(DWORD*)(context->Ebp + argoff) = ptr;
747     }
748     context->Eax = ptr;
749 }
750
751 /***********************************************************************
752  *              SMapLS_IP_EBP_8 (KERNEL32.@)
753  */
754 void WINAPI SMapLS_IP_EBP_8 (CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context, 8);}
755
756 /***********************************************************************
757  *              SMapLS_IP_EBP_12 (KERNEL32.@)
758  */
759 void WINAPI SMapLS_IP_EBP_12(CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context,12);}
760
761 /***********************************************************************
762  *              SMapLS_IP_EBP_16 (KERNEL32.@)
763  */
764 void WINAPI SMapLS_IP_EBP_16(CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context,16);}
765
766 /***********************************************************************
767  *              SMapLS_IP_EBP_20 (KERNEL32.@)
768  */
769 void WINAPI SMapLS_IP_EBP_20(CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context,20);}
770
771 /***********************************************************************
772  *              SMapLS_IP_EBP_24 (KERNEL32.@)
773  */
774 void WINAPI SMapLS_IP_EBP_24(CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context,24);}
775
776 /***********************************************************************
777  *              SMapLS_IP_EBP_28 (KERNEL32.@)
778  */
779 void WINAPI SMapLS_IP_EBP_28(CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context,28);}
780
781 /***********************************************************************
782  *              SMapLS_IP_EBP_32 (KERNEL32.@)
783  */
784 void WINAPI SMapLS_IP_EBP_32(CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context,32);}
785
786 /***********************************************************************
787  *              SMapLS_IP_EBP_36 (KERNEL32.@)
788  */
789 void WINAPI SMapLS_IP_EBP_36(CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context,36);}
790
791 /***********************************************************************
792  *              SMapLS_IP_EBP_40 (KERNEL32.@)
793  */
794 void WINAPI SMapLS_IP_EBP_40(CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context,40);}
795
796 /***********************************************************************
797  *              SMapLS (KERNEL32.@)
798  */
799 void WINAPI SMapLS( CONTEXT86 *context )
800 {
801     if (HIWORD(context->Eax))
802     {
803         context->Eax = MapLS( (LPVOID)context->Eax );
804         context->Edx = context->Eax;
805     } else {
806         context->Edx = 0;
807     }
808 }
809
810 /***********************************************************************
811  *              SUnMapLS (KERNEL32.@)
812  */
813
814 void WINAPI SUnMapLS( CONTEXT86 *context )
815 {
816     if (HIWORD(context->Eax)) UnMapLS( (SEGPTR)context->Eax );
817 }
818
819 inline static void x_SUnMapLS_IP_EBP_x(CONTEXT86 *context,int argoff)
820 {
821     SEGPTR *ptr = (SEGPTR *)(context->Ebp + argoff);
822     if (*ptr)
823     {
824         UnMapLS( *ptr );
825         *ptr = 0;
826     }
827 }
828
829 /***********************************************************************
830  *              SUnMapLS_IP_EBP_8 (KERNEL32.@)
831  */
832 void WINAPI SUnMapLS_IP_EBP_8 (CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context, 8); }
833
834 /***********************************************************************
835  *              SUnMapLS_IP_EBP_12 (KERNEL32.@)
836  */
837 void WINAPI SUnMapLS_IP_EBP_12(CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context,12); }
838
839 /***********************************************************************
840  *              SUnMapLS_IP_EBP_16 (KERNEL32.@)
841  */
842 void WINAPI SUnMapLS_IP_EBP_16(CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context,16); }
843
844 /***********************************************************************
845  *              SUnMapLS_IP_EBP_20 (KERNEL32.@)
846  */
847 void WINAPI SUnMapLS_IP_EBP_20(CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context,20); }
848
849 /***********************************************************************
850  *              SUnMapLS_IP_EBP_24 (KERNEL32.@)
851  */
852 void WINAPI SUnMapLS_IP_EBP_24(CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context,24); }
853
854 /***********************************************************************
855  *              SUnMapLS_IP_EBP_28 (KERNEL32.@)
856  */
857 void WINAPI SUnMapLS_IP_EBP_28(CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context,28); }
858
859 /***********************************************************************
860  *              SUnMapLS_IP_EBP_32 (KERNEL32.@)
861  */
862 void WINAPI SUnMapLS_IP_EBP_32(CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context,32); }
863
864 /***********************************************************************
865  *              SUnMapLS_IP_EBP_36 (KERNEL32.@)
866  */
867 void WINAPI SUnMapLS_IP_EBP_36(CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context,36); }
868
869 /***********************************************************************
870  *              SUnMapLS_IP_EBP_40 (KERNEL32.@)
871  */
872 void WINAPI SUnMapLS_IP_EBP_40(CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context,40); }
873
874 /**********************************************************************
875  *              AllocMappedBuffer       (KERNEL32.38)
876  *
877  * This is a undocumented KERNEL32 function that
878  * SMapLS's a GlobalAlloc'ed buffer.
879  *
880  * Input:   EDI register: size of buffer to allocate
881  * Output:  EDI register: pointer to buffer
882  *
883  * Note: The buffer is preceded by 8 bytes:
884  *        ...
885  *       edi+0   buffer
886  *       edi-4   SEGPTR to buffer
887  *       edi-8   some magic Win95 needs for SUnMapLS
888  *               (we use it for the memory handle)
889  *
890  *       The SEGPTR is used by the caller!
891  */
892
893 void WINAPI AllocMappedBuffer( CONTEXT86 *context )
894 {
895     HGLOBAL handle = GlobalAlloc(0, context->Edi + 8);
896     DWORD *buffer = (DWORD *)GlobalLock(handle);
897     SEGPTR ptr = 0;
898
899     if (buffer)
900         if (!(ptr = MapLS(buffer + 2)))
901         {
902             GlobalUnlock(handle);
903             GlobalFree(handle);
904         }
905
906     if (!ptr)
907         context->Eax = context->Edi = 0;
908     else
909     {
910         buffer[0] = (DWORD)handle;
911         buffer[1] = ptr;
912
913         context->Eax = (DWORD) ptr;
914         context->Edi = (DWORD)(buffer + 2);
915     }
916 }
917
918 /**********************************************************************
919  *              FreeMappedBuffer        (KERNEL32.39)
920  *
921  * Free a buffer allocated by AllocMappedBuffer
922  *
923  * Input: EDI register: pointer to buffer
924  */
925
926 void WINAPI FreeMappedBuffer( CONTEXT86 *context )
927 {
928     if (context->Edi)
929     {
930         DWORD *buffer = (DWORD *)context->Edi - 2;
931
932         UnMapLS(buffer[1]);
933
934         GlobalUnlock((HGLOBAL)buffer[0]);
935         GlobalFree((HGLOBAL)buffer[0]);
936     }
937 }