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