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