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