Implemented GetThreadSelectorEntry through the server.
[wine] / memory / selector.c
1 /*
2  * Selector manipulation functions
3  *
4  * Copyright 1995 Alexandre Julliard
5  */
6
7 #include <string.h>
8 #include "winerror.h"
9 #include "wine/winbase16.h"
10 #include "ldt.h"
11 #include "miscemu.h"
12 #include "selectors.h"
13 #include "stackframe.h"
14 #include "process.h"
15 #include "server.h"
16 #include "debugtools.h"
17 #include "toolhelp.h"
18
19 DEFAULT_DEBUG_CHANNEL(selector);
20
21
22 /***********************************************************************
23  *           AllocSelectorArray   (KERNEL.206)
24  */
25 WORD WINAPI AllocSelectorArray16( WORD count )
26 {
27     WORD i, sel, size = 0;
28     ldt_entry entry;
29
30     if (!count) return 0;
31     for (i = FIRST_LDT_ENTRY_TO_ALLOC; i < LDT_SIZE; i++)
32     {
33         if (!IS_LDT_ENTRY_FREE(i)) size = 0;
34         else if (++size >= count) break;
35     }
36     if (i == LDT_SIZE) return 0;
37     sel = i - size + 1;
38
39     entry.base           = 0;
40     entry.type           = SEGMENT_DATA;
41     entry.seg_32bit      = FALSE;
42     entry.read_only      = FALSE;
43     entry.limit_in_pages = FALSE;
44     entry.limit          = 1;  /* avoid 0 base and limit */
45
46     for (i = 0; i < count; i++)
47     {
48         /* Mark selector as allocated */
49         ldt_flags_copy[sel + i] |= LDT_FLAGS_ALLOCATED;
50         LDT_SetEntry( sel + i, &entry );
51     }
52     return ENTRY_TO_SELECTOR( sel );
53 }
54
55
56 /***********************************************************************
57  *           AllocSelector   (KERNEL.175)
58  */
59 WORD WINAPI AllocSelector16( WORD sel )
60 {
61     WORD newsel, count, i;
62
63     count = sel ? ((GET_SEL_LIMIT(sel) >> 16) + 1) : 1;
64     newsel = AllocSelectorArray16( count );
65     TRACE("(%04x): returning %04x\n",
66                       sel, newsel );
67     if (!newsel) return 0;
68     if (!sel) return newsel;  /* nothing to copy */
69     for (i = 0; i < count; i++)
70     {
71         ldt_entry entry;
72         LDT_GetEntry( SELECTOR_TO_ENTRY(sel) + i, &entry );
73         LDT_SetEntry( SELECTOR_TO_ENTRY(newsel) + i, &entry );
74     }
75     return newsel;
76 }
77
78
79 /***********************************************************************
80  *           FreeSelector   (KERNEL.176)
81  */
82 WORD WINAPI FreeSelector16( WORD sel )
83 {
84     if (IS_SELECTOR_FREE(sel)) return sel;  /* error */
85     SELECTOR_FreeBlock( sel, 1 );
86     return 0;
87 }
88
89
90 /***********************************************************************
91  *           SELECTOR_SetEntries
92  *
93  * Set the LDT entries for an array of selectors.
94  */
95 static void SELECTOR_SetEntries( WORD sel, const void *base, DWORD size,
96                                  enum seg_type type, BOOL is32bit,
97                                  BOOL readonly )
98 {
99     ldt_entry entry;
100     WORD i, count;
101
102     /* The limit for the first selector is the whole */
103     /* block. The next selectors get a 64k limit.    */
104     entry.base           = (unsigned long)base;
105     entry.type           = type;
106     entry.seg_32bit      = is32bit;
107     entry.read_only      = readonly;
108     entry.limit_in_pages = (size > 0x100000);
109     if (entry.limit_in_pages) entry.limit = ((size + 0xfff) >> 12) - 1;
110     else entry.limit = size - 1;
111     /* Make sure base and limit are not 0 together if the size is not 0 */
112     if (!base && !entry.limit && size) entry.limit = 1;
113     count = (size + 0xffff) / 0x10000;
114     for (i = 0; i < count; i++)
115     {
116         LDT_SetEntry( SELECTOR_TO_ENTRY(sel) + i, &entry );
117         entry.base += 0x10000;
118         /* Apparently the next selectors should *not* get a 64k limit. */
119         /* Can't remember where I read they should... --AJ */
120         entry.limit -= entry.limit_in_pages ? 0x10 : 0x10000;
121     }
122 }
123
124
125 /***********************************************************************
126  *           SELECTOR_AllocBlock
127  *
128  * Allocate selectors for a block of linear memory.
129  */
130 WORD SELECTOR_AllocBlock( const void *base, DWORD size, enum seg_type type,
131                           BOOL is32bit, BOOL readonly )
132 {
133     WORD sel, count;
134
135     if (!size) return 0;
136     count = (size + 0xffff) / 0x10000;
137     sel = AllocSelectorArray16( count );
138     if (sel) SELECTOR_SetEntries( sel, base, size, type, is32bit, readonly );
139     return sel;
140 }
141
142
143 /***********************************************************************
144  *           SELECTOR_MoveBlock
145  *
146  * Move a block of selectors in linear memory.
147  */
148 void SELECTOR_MoveBlock( WORD sel, const void *new_base )
149 {
150     WORD i, count = (GET_SEL_LIMIT(sel) >> 16) + 1;
151
152     for (i = 0; i < count; i++)
153     {
154         ldt_entry entry;
155         LDT_GetEntry( SELECTOR_TO_ENTRY(sel) + i, &entry );
156         entry.base = (unsigned long)new_base;
157         LDT_SetEntry( SELECTOR_TO_ENTRY(sel) + i, &entry );
158     }
159 }
160
161
162 /***********************************************************************
163  *           SELECTOR_FreeBlock
164  *
165  * Free a block of selectors.
166  */
167 void SELECTOR_FreeBlock( WORD sel, WORD count )
168 {
169     WORD i, nextsel;
170     ldt_entry entry;
171
172     TRACE("(%04x,%d)\n", sel, count );
173     sel &= ~(__AHINCR - 1);  /* clear bottom bits of selector */
174     nextsel = sel + (count << __AHSHIFT);
175
176 #ifdef __i386__
177     {
178         /* Check if we are freeing current %fs or %gs selector */
179
180         WORD fs, gs;
181         GET_FS(fs);
182         if ((fs >= sel) && (fs < nextsel))
183         {
184             WARN("Freeing %%fs selector (%04x), not good.\n", fs );
185             SET_FS( 0 );
186         }
187         GET_GS(gs);
188         if ((gs >= sel) && (gs < nextsel)) SET_GS( 0 );
189     }
190 #endif  /* __i386__ */
191
192     memset( &entry, 0, sizeof(entry) );  /* clear the LDT entries */
193     for (i = SELECTOR_TO_ENTRY(sel); count; i++, count--)
194     {
195         LDT_SetEntry( i, &entry );
196         ldt_flags_copy[i] &= ~LDT_FLAGS_ALLOCATED;
197     }
198 }
199
200
201 /***********************************************************************
202  *           SELECTOR_ReallocBlock
203  *
204  * Change the size of a block of selectors.
205  */
206 WORD SELECTOR_ReallocBlock( WORD sel, const void *base, DWORD size )
207 {
208     ldt_entry entry;
209     WORD i, oldcount, newcount;
210
211     if (!size) size = 1;
212     oldcount = (GET_SEL_LIMIT(sel) >> 16) + 1;
213     newcount = (size + 0xffff) >> 16;
214     LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
215
216     if (oldcount < newcount)  /* We need to add selectors */
217     {
218           /* Check if the next selectors are free */
219         if (SELECTOR_TO_ENTRY(sel) + newcount > LDT_SIZE) i = oldcount;
220         else
221             for (i = oldcount; i < newcount; i++)
222                 if (!IS_LDT_ENTRY_FREE(SELECTOR_TO_ENTRY(sel)+i)) break;
223
224         if (i < newcount)  /* they are not free */
225         {
226             SELECTOR_FreeBlock( sel, oldcount );
227             sel = AllocSelectorArray16( newcount );
228         }
229         else  /* mark the selectors as allocated */
230         {
231             for (i = oldcount; i < newcount; i++)
232                 ldt_flags_copy[SELECTOR_TO_ENTRY(sel)+i] |=LDT_FLAGS_ALLOCATED;
233         }
234     }
235     else if (oldcount > newcount) /* We need to remove selectors */
236     {
237         SELECTOR_FreeBlock( ENTRY_TO_SELECTOR(SELECTOR_TO_ENTRY(sel)+newcount),
238                             oldcount - newcount );
239     }
240     if (sel) SELECTOR_SetEntries( sel, base, size, entry.type,
241                                   entry.seg_32bit, entry.read_only );
242     return sel;
243 }
244
245
246 /***********************************************************************
247  *           PrestoChangoSelector   (KERNEL.177)
248  */
249 WORD WINAPI PrestoChangoSelector16( WORD selSrc, WORD selDst )
250 {
251     ldt_entry entry;
252     LDT_GetEntry( SELECTOR_TO_ENTRY( selSrc ), &entry );
253     entry.type ^= SEGMENT_CODE;  /* toggle the executable bit */
254     LDT_SetEntry( SELECTOR_TO_ENTRY( selDst ), &entry );
255     return selDst;
256 }
257
258
259 /***********************************************************************
260  *           AllocCStoDSAlias   (KERNEL.170)
261  */
262 WORD WINAPI AllocCStoDSAlias16( WORD sel )
263 {
264     WORD newsel;
265     ldt_entry entry;
266
267     newsel = AllocSelectorArray16( 1 );
268     TRACE("(%04x): returning %04x\n",
269                       sel, newsel );
270     if (!newsel) return 0;
271     LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
272     entry.type = SEGMENT_DATA;
273     LDT_SetEntry( SELECTOR_TO_ENTRY(newsel), &entry );
274     return newsel;
275 }
276
277
278 /***********************************************************************
279  *           AllocDStoCSAlias   (KERNEL.171)
280  */
281 WORD WINAPI AllocDStoCSAlias16( WORD sel )
282 {
283     WORD newsel;
284     ldt_entry entry;
285
286     newsel = AllocSelectorArray16( 1 );
287     TRACE("(%04x): returning %04x\n",
288                       sel, newsel );
289     if (!newsel) return 0;
290     LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
291     entry.type = SEGMENT_CODE;
292     LDT_SetEntry( SELECTOR_TO_ENTRY(newsel), &entry );
293     return newsel;
294 }
295
296
297 /***********************************************************************
298  *           LongPtrAdd   (KERNEL.180)
299  */
300 void WINAPI LongPtrAdd16( DWORD ptr, DWORD add )
301 {
302     ldt_entry entry;
303     LDT_GetEntry( SELECTOR_TO_ENTRY(SELECTOROF(ptr)), &entry );
304     entry.base += add;
305     LDT_SetEntry( SELECTOR_TO_ENTRY(SELECTOROF(ptr)), &entry );
306 }
307
308
309 /***********************************************************************
310  *           GetSelectorBase   (KERNEL.186)
311  */
312 DWORD WINAPI WIN16_GetSelectorBase( WORD sel )
313 {
314     /*
315      * Note: For Win32s processes, the whole linear address space is
316      *       shifted by 0x10000 relative to the OS linear address space.
317      *       See the comment in msdos/vxd.c.
318      */
319
320     DWORD base = GetSelectorBase( sel );
321     return W32S_WINE2APP( base, W32S_APPLICATION() ? W32S_OFFSET : 0 );
322 }
323 DWORD WINAPI GetSelectorBase( WORD sel )
324 {
325     DWORD base = GET_SEL_BASE(sel);
326
327     /* if base points into DOSMEM, assume we have to
328      * return pointer into physical lower 1MB */
329
330     return DOSMEM_MapLinearToDos( (LPVOID)base );
331 }
332
333
334 /***********************************************************************
335  *           SetSelectorBase   (KERNEL.187)
336  */
337 DWORD WINAPI WIN16_SetSelectorBase( WORD sel, DWORD base )
338 {
339     /*
340      * Note: For Win32s processes, the whole linear address space is
341      *       shifted by 0x10000 relative to the OS linear address space.
342      *       See the comment in msdos/vxd.c.
343      */
344
345     SetSelectorBase( sel,
346         W32S_APP2WINE( base, W32S_APPLICATION() ? W32S_OFFSET : 0 ) );
347     return sel;
348 }
349 WORD WINAPI SetSelectorBase( WORD sel, DWORD base )
350 {
351     ldt_entry entry;
352
353     LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
354
355     entry.base = (DWORD)DOSMEM_MapDosToLinear(base);
356
357     LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
358     return sel;
359 }
360
361
362 /***********************************************************************
363  *           GetSelectorLimit   (KERNEL.188)
364  */
365 DWORD WINAPI GetSelectorLimit16( WORD sel )
366 {
367     return GET_SEL_LIMIT(sel);
368 }
369
370
371 /***********************************************************************
372  *           SetSelectorLimit   (KERNEL.189)
373  */
374 WORD WINAPI SetSelectorLimit16( WORD sel, DWORD limit )
375 {
376     ldt_entry entry;
377     LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
378     entry.limit_in_pages = (limit >= 0x100000);
379     if (entry.limit_in_pages) entry.limit = limit >> 12;
380     else entry.limit = limit;
381     LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
382     return sel;
383 }
384
385
386 /***********************************************************************
387  *           SelectorAccessRights   (KERNEL.196)
388  */
389 WORD WINAPI SelectorAccessRights16( WORD sel, WORD op, WORD val )
390 {
391     ldt_entry entry;
392     LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
393     if (op == 0)  /* get */
394     {
395         return 0x01 | /* accessed */
396                0x10 | /* not system */
397                0x60 | /* DPL 3 */
398                0x80 | /* present */
399                ((entry.read_only == 0) << 1) |
400                (entry.type << 2) |
401                (entry.seg_32bit << 14) |
402                (entry.limit_in_pages << 15);
403     }
404     else  /* set */
405     {
406         entry.read_only = ((val & 2) == 0);
407         entry.type = (val >> 2) & 3;
408         entry.seg_32bit = val & 0x4000;
409         entry.limit_in_pages = val & 0x8000;
410         LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
411         return 0;
412     }
413 }
414
415
416 /***********************************************************************
417  *           IsBadCodePtr16   (KERNEL.336)
418  */
419 BOOL16 WINAPI IsBadCodePtr16( SEGPTR lpfn )
420 {
421     WORD sel;
422     ldt_entry entry;
423
424     sel = SELECTOROF(lpfn);
425     if (!sel) return TRUE;
426     if (IS_SELECTOR_FREE(sel)) return TRUE;
427     LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
428     if (entry.type != SEGMENT_CODE) return TRUE;
429     if (OFFSETOF(lpfn) > GET_SEL_LIMIT(sel)) return TRUE;
430     return FALSE;
431 }
432
433
434 /***********************************************************************
435  *           IsBadStringPtr16   (KERNEL.337)
436  */
437 BOOL16 WINAPI IsBadStringPtr16( SEGPTR ptr, UINT16 size )
438 {
439     WORD sel;
440     ldt_entry entry;
441
442     sel = SELECTOROF(ptr);
443     if (!sel) return TRUE;
444     if (IS_SELECTOR_FREE(sel)) return TRUE;
445     LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
446     if ((entry.type == SEGMENT_CODE) && entry.read_only) return TRUE;
447     if (strlen(PTR_SEG_TO_LIN(ptr)) < size) size = strlen(PTR_SEG_TO_LIN(ptr)) + 1;
448     if (size && (OFFSETOF(ptr) + size - 1 > GET_SEL_LIMIT(sel))) return TRUE;
449     return FALSE;
450 }
451
452
453 /***********************************************************************
454  *           IsBadHugeReadPtr16   (KERNEL.346)
455  */
456 BOOL16 WINAPI IsBadHugeReadPtr16( SEGPTR ptr, DWORD size )
457 {
458     WORD sel;
459     ldt_entry entry;
460
461     sel = SELECTOROF(ptr);
462     if (!sel) return TRUE;
463     if (IS_SELECTOR_FREE(sel)) return TRUE;
464     LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
465     if ((entry.type == SEGMENT_CODE) && entry.read_only) return TRUE;
466     if (size && (OFFSETOF(ptr) + size - 1 > GET_SEL_LIMIT(sel))) return TRUE;
467     return FALSE;
468 }
469
470
471 /***********************************************************************
472  *           IsBadHugeWritePtr16   (KERNEL.347)
473  */
474 BOOL16 WINAPI IsBadHugeWritePtr16( SEGPTR ptr, DWORD size )
475 {
476     WORD sel;
477     ldt_entry entry;
478
479     sel = SELECTOROF(ptr);
480     if (!sel) return TRUE;
481     if (IS_SELECTOR_FREE(sel)) return TRUE;
482     LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
483     if ((entry.type == SEGMENT_CODE) || entry.read_only) return TRUE;
484     if (size && (OFFSETOF(ptr) + size - 1 > GET_SEL_LIMIT(sel))) return TRUE;
485     return FALSE;
486 }
487
488 /***********************************************************************
489  *           IsBadReadPtr16   (KERNEL.334)
490  */
491 BOOL16 WINAPI IsBadReadPtr16( SEGPTR ptr, UINT16 size )
492 {
493     return IsBadHugeReadPtr16( ptr, size );
494 }
495
496
497 /***********************************************************************
498  *           IsBadWritePtr16   (KERNEL.335)
499  */
500 BOOL16 WINAPI IsBadWritePtr16( SEGPTR ptr, UINT16 size )
501 {
502     return IsBadHugeWritePtr16( ptr, size );
503 }
504
505
506 /***********************************************************************
507  *           IsBadFlatReadWritePtr16   (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     if (IS_SELECTOR_FREE(sel)) return 0;
522     if (offset > GET_SEL_LIMIT(sel)) return 0;
523     if (offset + count > GET_SEL_LIMIT(sel) + 1)
524         count = GET_SEL_LIMIT(sel) + 1 - offset;
525     memcpy( buffer, ((char *)GET_SEL_BASE(sel)) + offset, count );
526     return count;
527 }
528
529
530 /***********************************************************************
531  *           MemoryWrite   (TOOLHELP.79)
532  */
533 DWORD WINAPI MemoryWrite16( WORD sel, DWORD offset, void *buffer, DWORD count )
534 {
535     if (IS_SELECTOR_FREE(sel)) return 0;
536     if (offset > GET_SEL_LIMIT(sel)) return 0;
537     if (offset + count > GET_SEL_LIMIT(sel) + 1)
538         count = GET_SEL_LIMIT(sel) + 1 - offset;
539     memcpy( ((char *)GET_SEL_BASE(sel)) + offset, buffer, count );
540     return count;
541 }
542
543 /************************************* Win95 pointer mapping functions *
544  *
545  */
546
547 /***********************************************************************
548  *           MapSL   (KERNEL32.523)
549  *
550  * Maps fixed segmented pointer to linear.
551  */
552 LPVOID WINAPI MapSL( SEGPTR sptr )
553 {
554     return (LPVOID)PTR_SEG_TO_LIN(sptr);
555 }
556
557 /***********************************************************************
558  *           MapSLFix   (KERNEL32.524)
559  *
560  * FIXME: MapSLFix and UnMapSLFixArray should probably prevent
561  * unexpected linear address change when GlobalCompact() shuffles
562  * moveable blocks.
563  */
564
565 LPVOID WINAPI MapSLFix( SEGPTR sptr )
566 {
567     return (LPVOID)PTR_SEG_TO_LIN(sptr);
568 }
569
570 /***********************************************************************
571  *           UnMapSLFixArray   (KERNEL32.701)
572  */
573
574 void WINAPI UnMapSLFixArray( SEGPTR sptr[], INT length, CONTEXT86 *context )
575 {
576     /* Must not change EAX, hence defined as 'register' function */
577 }
578
579 /***********************************************************************
580  *           MapLS   (KERNEL32.522)
581  *
582  * Maps linear pointer to segmented.
583  */
584 SEGPTR WINAPI MapLS( LPVOID ptr )
585 {
586     if (!HIWORD(ptr))
587         return (SEGPTR)ptr;
588     else
589     {
590         WORD sel = SELECTOR_AllocBlock( ptr, 0x10000, SEGMENT_DATA, FALSE, FALSE );
591         return PTR_SEG_OFF_TO_SEGPTR( sel, 0 );
592     }
593 }
594
595
596 /***********************************************************************
597  *           UnMapLS   (KERNEL32.700)
598  *
599  * Free mapped selector.
600  */
601 void WINAPI UnMapLS( SEGPTR sptr )
602 {
603     if (SELECTOROF(sptr)) 
604         SELECTOR_FreeBlock( SELECTOROF(sptr), 1 );
605 }
606
607 /***********************************************************************
608  *           GetThreadSelectorEntry   (KERNEL32)
609  */
610 BOOL WINAPI GetThreadSelectorEntry( HANDLE hthread, DWORD sel, LPLDT_ENTRY ldtent)
611 {
612 #ifdef __i386__
613     struct get_selector_entry_request *req = get_req_buffer();
614
615     if (!(sel & 4))  /* GDT selector */
616     {
617         WORD seg;
618         sel &= ~3;  /* ignore RPL */
619         if (!sel)  /* null selector */
620         {
621             memset( ldtent, 0, sizeof(*ldtent) );
622             return TRUE;
623         }
624         ldtent->BaseLow                   = 0;
625         ldtent->HighWord.Bits.BaseMid     = 0;
626         ldtent->HighWord.Bits.BaseHi      = 0;
627         ldtent->LimitLow                  = 0xffff;
628         ldtent->HighWord.Bits.LimitHi     = 0xf;
629         ldtent->HighWord.Bits.Dpl         = 3;
630         ldtent->HighWord.Bits.Sys         = 0;
631         ldtent->HighWord.Bits.Pres        = 1;
632         ldtent->HighWord.Bits.Granularity = 1;
633         ldtent->HighWord.Bits.Default_Big = 1;
634         ldtent->HighWord.Bits.Type        = 0x12;
635         /* it has to be one of the system GDT selectors */
636         GET_DS(seg);
637         if (sel == (seg & ~3)) return TRUE;
638         GET_SS(seg);
639         if (sel == (seg & ~3)) return TRUE;
640         GET_CS(seg);
641         if (sel == (seg & ~3))
642         {
643             ldtent->HighWord.Bits.Type |= 8;  /* code segment */
644             return TRUE;
645         }
646         SetLastError( ERROR_NOACCESS );
647         return FALSE;
648     }
649
650     req->handle = hthread;
651     req->entry = sel >> __AHSHIFT;
652     if (server_call( REQ_GET_SELECTOR_ENTRY )) return FALSE;
653
654     if (!(req->flags & LDT_FLAGS_ALLOCATED))
655     {
656         SetLastError( ERROR_MR_MID_NOT_FOUND );  /* sic */
657         return FALSE;
658     }
659     if (req->flags & LDT_FLAGS_BIG) req->limit >>= 12;
660     ldtent->BaseLow                   = req->base & 0x0000ffff;
661     ldtent->HighWord.Bits.BaseMid     = (req->base & 0x00ff0000) >> 16;
662     ldtent->HighWord.Bits.BaseHi      = (req->base & 0xff000000) >> 24;
663     ldtent->LimitLow                  = req->limit & 0x0000ffff;
664     ldtent->HighWord.Bits.LimitHi     = (req->limit & 0x000f0000) >> 16;
665     ldtent->HighWord.Bits.Dpl         = 3;
666     ldtent->HighWord.Bits.Sys         = 0;
667     ldtent->HighWord.Bits.Pres        = 1;
668     ldtent->HighWord.Bits.Granularity = (req->flags & LDT_FLAGS_BIG) !=0;
669     ldtent->HighWord.Bits.Default_Big = (req->flags & LDT_FLAGS_32BIT) != 0;
670     ldtent->HighWord.Bits.Type        = ((req->flags & LDT_FLAGS_TYPE) << 2) | 0x10;
671     if (!(req->flags & LDT_FLAGS_READONLY)) ldtent->HighWord.Bits.Type |= 0x2;
672     return TRUE;
673 #else
674     SetLastError( ERROR_NOT_IMPLEMENTED );
675     return FALSE;
676 #endif
677 }
678
679
680 /**********************************************************************
681  *              SMapLS*         (KERNEL32)
682  * These functions map linear pointers at [EBP+xxx] to segmented pointers
683  * and return them.
684  * Win95 uses some kind of alias structs, which it stores in [EBP+x] to
685  * unravel them at SUnMapLS. We just store the segmented pointer there.
686  */
687 static void
688 x_SMapLS_IP_EBP_x(CONTEXT86 *context,int argoff) {
689     DWORD       val,ptr; 
690
691     val =*(DWORD*)(EBP_reg(context)+argoff);
692     if (val<0x10000) {
693         ptr=val;
694         *(DWORD*)(EBP_reg(context)+argoff) = 0;
695     } else {
696         ptr = MapLS((LPVOID)val);
697         *(DWORD*)(EBP_reg(context)+argoff) = ptr;
698     }
699     EAX_reg(context) = ptr;
700 }
701
702 void WINAPI SMapLS_IP_EBP_8 (CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context, 8);}
703 void WINAPI SMapLS_IP_EBP_12(CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context,12);}
704 void WINAPI SMapLS_IP_EBP_16(CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context,16);}
705 void WINAPI SMapLS_IP_EBP_20(CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context,20);}
706 void WINAPI SMapLS_IP_EBP_24(CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context,24);}
707 void WINAPI SMapLS_IP_EBP_28(CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context,28);}
708 void WINAPI SMapLS_IP_EBP_32(CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context,32);}
709 void WINAPI SMapLS_IP_EBP_36(CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context,36);}
710 void WINAPI SMapLS_IP_EBP_40(CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context,40);}
711
712 void WINAPI SMapLS( CONTEXT86 *context )
713 {
714     if (EAX_reg(context)>=0x10000) {
715         EAX_reg(context) = MapLS((LPVOID)EAX_reg(context));
716         EDX_reg(context) = EAX_reg(context);
717     } else {
718         EDX_reg(context) = 0;
719     }
720 }
721
722 void WINAPI SUnMapLS( CONTEXT86 *context )
723 {
724     if (EAX_reg(context)>=0x10000)
725         UnMapLS((SEGPTR)EAX_reg(context));
726 }
727
728 static void
729 x_SUnMapLS_IP_EBP_x(CONTEXT86 *context,int argoff) {
730         if (*(DWORD*)(EBP_reg(context)+argoff))
731                 UnMapLS(*(DWORD*)(EBP_reg(context)+argoff));
732         *(DWORD*)(EBP_reg(context)+argoff)=0;
733 }
734 void WINAPI SUnMapLS_IP_EBP_8 (CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context, 8); }
735 void WINAPI SUnMapLS_IP_EBP_12(CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context,12); }
736 void WINAPI SUnMapLS_IP_EBP_16(CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context,16); }
737 void WINAPI SUnMapLS_IP_EBP_20(CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context,20); }
738 void WINAPI SUnMapLS_IP_EBP_24(CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context,24); }
739 void WINAPI SUnMapLS_IP_EBP_28(CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context,28); }
740 void WINAPI SUnMapLS_IP_EBP_32(CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context,32); }
741 void WINAPI SUnMapLS_IP_EBP_36(CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context,36); }
742 void WINAPI SUnMapLS_IP_EBP_40(CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context,40); }
743
744 /**********************************************************************
745  *              AllocMappedBuffer       (KERNEL32.38)
746  *
747  * This is a undocumented KERNEL32 function that 
748  * SMapLS's a GlobalAlloc'ed buffer.
749  *
750  * Input:   EDI register: size of buffer to allocate
751  * Output:  EDI register: pointer to buffer
752  *
753  * Note: The buffer is preceeded by 8 bytes:
754  *        ...
755  *       edi+0   buffer
756  *       edi-4   SEGPTR to buffer
757  *       edi-8   some magic Win95 needs for SUnMapLS
758  *               (we use it for the memory handle)
759  *
760  *       The SEGPTR is used by the caller!
761  */
762
763 void WINAPI AllocMappedBuffer( CONTEXT86 *context )
764 {
765     HGLOBAL handle = GlobalAlloc(0, EDI_reg(context) + 8);
766     DWORD *buffer = (DWORD *)GlobalLock(handle);
767     SEGPTR ptr = 0;
768
769     if (buffer)
770         if (!(ptr = MapLS(buffer + 2)))
771         {
772             GlobalUnlock(handle);
773             GlobalFree(handle);
774         }
775
776     if (!ptr)
777         EAX_reg(context) = EDI_reg(context) = 0;
778     else
779     {
780         buffer[0] = handle;
781         buffer[1] = ptr;
782
783         EAX_reg(context) = (DWORD) ptr;
784         EDI_reg(context) = (DWORD)(buffer + 2);
785     }
786 }
787
788 /**********************************************************************
789  *              FreeMappedBuffer        (KERNEL32.39)
790  *
791  * Free a buffer allocated by AllocMappedBuffer
792  *
793  * Input: EDI register: pointer to buffer
794  */
795
796 void WINAPI FreeMappedBuffer( CONTEXT86 *context )
797 {
798     if (EDI_reg(context))
799     {
800         DWORD *buffer = (DWORD *)EDI_reg(context) - 2;
801
802         UnMapLS(buffer[1]);
803
804         GlobalUnlock(buffer[0]);
805         GlobalFree(buffer[0]);
806     }
807 }
808
809
810 /***********************************************************************
811  *           UTSelectorOffsetToLinear       (WIN32S16.48)
812  *
813  * rough guesswork, but seems to work (I had no "reasonable" docu)
814  */
815 LPVOID WINAPI UTSelectorOffsetToLinear16(SEGPTR sptr)
816 {
817         return PTR_SEG_TO_LIN(sptr);
818 }
819
820 /***********************************************************************
821  *           UTLinearToSelectorOffset       (WIN32S16.49)
822  *
823  * FIXME: I don't know if that's the right way to do linear -> segmented
824  */
825 SEGPTR WINAPI UTLinearToSelectorOffset16(LPVOID lptr)
826 {
827     return (SEGPTR)lptr;
828 }