Release 980315
[wine/multimedia.git] / memory / selector.c
blobe277ea5ccb2bf191a49d95a727690d71d9a8e158
1 /*
2 * Selector manipulation functions
4 * Copyright 1995 Alexandre Julliard
5 */
7 #include <string.h>
8 #include "windows.h"
9 #include "ldt.h"
10 #include "miscemu.h"
11 #include "selectors.h"
12 #include "stackframe.h"
13 #include "debug.h"
16 #define FIRST_LDT_ENTRY_TO_ALLOC 17
19 /***********************************************************************
20 * AllocSelectorArray (KERNEL.206)
22 WORD WINAPI AllocSelectorArray( WORD count )
24 WORD i, sel, size = 0;
25 ldt_entry entry;
27 if (!count) return 0;
28 for (i = FIRST_LDT_ENTRY_TO_ALLOC; i < LDT_SIZE; i++)
30 if (!IS_LDT_ENTRY_FREE(i)) size = 0;
31 else if (++size >= count) break;
33 if (i == LDT_SIZE) return 0;
34 sel = i - size + 1;
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 */
43 for (i = 0; i < count; i++)
45 /* Mark selector as allocated */
46 ldt_flags_copy[sel + i] |= LDT_FLAGS_ALLOCATED;
47 LDT_SetEntry( sel + i, &entry );
49 return ENTRY_TO_SELECTOR( sel );
53 /***********************************************************************
54 * AllocSelector (KERNEL.175)
56 WORD WINAPI AllocSelector( WORD sel )
58 WORD newsel, count, i;
60 count = sel ? ((GET_SEL_LIMIT(sel) >> 16) + 1) : 1;
61 newsel = AllocSelectorArray( count );
62 TRACE(selector, "(%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++)
68 ldt_entry entry;
69 LDT_GetEntry( SELECTOR_TO_ENTRY(sel) + i, &entry );
70 LDT_SetEntry( SELECTOR_TO_ENTRY(newsel) + i, &entry );
72 return newsel;
76 /***********************************************************************
77 * FreeSelector (KERNEL.176)
79 WORD WINAPI FreeSelector( WORD sel )
81 if (IS_SELECTOR_FREE(sel)) return sel; /* error */
82 SELECTOR_FreeBlock( sel, 1 );
83 return 0;
87 /***********************************************************************
88 * SELECTOR_SetEntries
90 * Set the LDT entries for an array of selectors.
92 static void SELECTOR_SetEntries( WORD sel, const void *base, DWORD size,
93 enum seg_type type, BOOL32 is32bit,
94 BOOL32 readonly )
96 ldt_entry entry;
97 WORD i, count;
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++)
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;
122 /***********************************************************************
123 * SELECTOR_AllocBlock
125 * Allocate selectors for a block of linear memory.
127 WORD SELECTOR_AllocBlock( const void *base, DWORD size, enum seg_type type,
128 BOOL32 is32bit, BOOL32 readonly )
130 WORD sel, count;
132 if (!size) return 0;
133 count = (size + 0xffff) / 0x10000;
134 sel = AllocSelectorArray( count );
135 if (sel) SELECTOR_SetEntries( sel, base, size, type, is32bit, readonly );
136 return sel;
140 /***********************************************************************
141 * SELECTOR_FreeBlock
143 * Free a block of selectors.
145 void SELECTOR_FreeBlock( WORD sel, WORD count )
147 WORD i, nextsel;
148 ldt_entry entry;
149 STACK16FRAME *frame;
151 TRACE(selector, "(%04x,%d)\n", sel, count );
152 sel &= ~(__AHINCR - 1); /* clear bottom bits of selector */
153 nextsel = sel + (count << __AHSHIFT);
155 #ifdef __i386__
157 /* Check if we are freeing current %fs or %gs selector */
159 WORD fs, gs;
160 GET_FS(fs);
161 if ((fs >= sel) && (fs < nextsel))
163 fprintf( stderr, "SELECTOR_FreeBlock: freeing %%fs selector (%04x), not good.\n", fs );
164 SET_FS( 0 );
166 GET_GS(gs);
167 if ((gs >= sel) && (gs < nextsel)) SET_GS( 0 );
169 #endif /* __i386__ */
171 memset( &entry, 0, sizeof(entry) ); /* clear the LDT entries */
172 for (i = SELECTOR_TO_ENTRY(sel); count; i++, count--)
174 LDT_SetEntry( i, &entry );
175 ldt_flags_copy[i] &= ~LDT_FLAGS_ALLOCATED;
178 /* Clear the saved 16-bit selector */
179 frame = CURRENT_STACK16;
180 while (frame)
182 if ((frame->ds >= sel) && (frame->ds < nextsel)) frame->ds = 0;
183 if ((frame->es >= sel) && (frame->es < nextsel)) frame->es = 0;
184 if (!frame->frame32) break;
185 frame = PTR_SEG_TO_LIN( frame->frame32->frame16 );
190 /***********************************************************************
191 * SELECTOR_ReallocBlock
193 * Change the size of a block of selectors.
195 WORD SELECTOR_ReallocBlock( WORD sel, const void *base, DWORD size,
196 enum seg_type type, BOOL32 is32bit, BOOL32 readonly)
198 WORD i, oldcount, newcount;
200 if (!size) size = 1;
201 oldcount = (GET_SEL_LIMIT(sel) >> 16) + 1;
202 newcount = (size + 0xffff) >> 16;
204 if (oldcount < newcount) /* We need to add selectors */
206 /* Check if the next selectors are free */
207 if (SELECTOR_TO_ENTRY(sel) + newcount > LDT_SIZE) i = oldcount;
208 else
209 for (i = oldcount; i < newcount; i++)
210 if (!IS_LDT_ENTRY_FREE(SELECTOR_TO_ENTRY(sel)+i)) break;
212 if (i < newcount) /* they are not free */
214 SELECTOR_FreeBlock( sel, oldcount );
215 sel = AllocSelectorArray( newcount );
217 else /* mark the selectors as allocated */
219 for (i = oldcount; i < newcount; i++)
220 ldt_flags_copy[SELECTOR_TO_ENTRY(sel)+i] |=LDT_FLAGS_ALLOCATED;
223 else if (oldcount > newcount) /* We need to remove selectors */
225 SELECTOR_FreeBlock( ENTRY_TO_SELECTOR(SELECTOR_TO_ENTRY(sel)+newcount),
226 oldcount - newcount );
228 if (sel) SELECTOR_SetEntries( sel, base, size, type, is32bit, readonly );
229 return sel;
233 /***********************************************************************
234 * PrestoChangoSelector (KERNEL.177)
236 WORD WINAPI PrestoChangoSelector( WORD selSrc, WORD selDst )
238 ldt_entry entry;
239 LDT_GetEntry( SELECTOR_TO_ENTRY( selSrc ), &entry );
240 entry.type ^= SEGMENT_CODE; /* toggle the executable bit */
241 LDT_SetEntry( SELECTOR_TO_ENTRY( selDst ), &entry );
242 return selDst;
246 /***********************************************************************
247 * AllocCStoDSAlias (KERNEL.170)
249 WORD WINAPI AllocCStoDSAlias( WORD sel )
251 WORD newsel;
252 ldt_entry entry;
254 newsel = AllocSelectorArray( 1 );
255 TRACE(selector, "(%04x): returning %04x\n",
256 sel, newsel );
257 if (!newsel) return 0;
258 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
259 entry.type = SEGMENT_DATA;
260 LDT_SetEntry( SELECTOR_TO_ENTRY(newsel), &entry );
261 return newsel;
265 /***********************************************************************
266 * AllocDStoCSAlias (KERNEL.171)
268 WORD WINAPI AllocDStoCSAlias( WORD sel )
270 WORD newsel;
271 ldt_entry entry;
273 newsel = AllocSelectorArray( 1 );
274 TRACE(selector, "(%04x): returning %04x\n",
275 sel, newsel );
276 if (!newsel) return 0;
277 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
278 entry.type = SEGMENT_CODE;
279 LDT_SetEntry( SELECTOR_TO_ENTRY(newsel), &entry );
280 return newsel;
284 /***********************************************************************
285 * LongPtrAdd (KERNEL.180)
287 void WINAPI LongPtrAdd( DWORD ptr, DWORD add )
289 ldt_entry entry;
290 LDT_GetEntry( SELECTOR_TO_ENTRY(SELECTOROF(ptr)), &entry );
291 entry.base += add;
292 LDT_SetEntry( SELECTOR_TO_ENTRY(SELECTOROF(ptr)), &entry );
296 /***********************************************************************
297 * GetSelectorBase (KERNEL.186)
299 DWORD WINAPI GetSelectorBase( WORD sel )
301 DWORD base = GET_SEL_BASE(sel);
303 /* if base points into DOSMEM, assume we have to
304 * return pointer into physical lower 1MB */
306 return DOSMEM_MapLinearToDos( (LPVOID)base );
310 /***********************************************************************
311 * SetSelectorBase (KERNEL.187)
313 WORD WINAPI SetSelectorBase( WORD sel, DWORD base )
315 ldt_entry entry;
317 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
319 entry.base = (DWORD)DOSMEM_MapDosToLinear(base);
321 LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
322 return sel;
326 /***********************************************************************
327 * GetSelectorLimit (KERNEL.188)
329 DWORD WINAPI GetSelectorLimit( WORD sel )
331 return GET_SEL_LIMIT(sel);
335 /***********************************************************************
336 * SetSelectorLimit (KERNEL.189)
338 WORD WINAPI SetSelectorLimit( WORD sel, DWORD limit )
340 ldt_entry entry;
341 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
342 entry.limit_in_pages = (limit >= 0x100000);
343 if (entry.limit_in_pages) entry.limit = limit >> 12;
344 else entry.limit = limit;
345 LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
346 return sel;
350 /***********************************************************************
351 * SelectorAccessRights (KERNEL.196)
353 WORD WINAPI SelectorAccessRights( WORD sel, WORD op, WORD val )
355 ldt_entry entry;
356 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
357 if (op == 0) /* get */
359 return 0x01 | /* accessed */
360 0x10 | /* not system */
361 0x60 | /* DPL 3 */
362 0x80 | /* present */
363 ((entry.read_only == 0) << 1) |
364 (entry.type << 2) |
365 (entry.seg_32bit << 14) |
366 (entry.limit_in_pages << 15);
368 else /* set */
370 entry.read_only = ((val & 2) == 0);
371 entry.type = (val >> 2) & 3;
372 entry.seg_32bit = val & 0x4000;
373 entry.limit_in_pages = val & 0x8000;
374 LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
375 return 0;
380 /***********************************************************************
381 * IsBadCodePtr16 (KERNEL.336)
383 BOOL16 WINAPI IsBadCodePtr16( SEGPTR lpfn )
385 WORD sel;
386 ldt_entry entry;
388 sel = SELECTOROF(lpfn);
389 if (!sel) return TRUE;
390 if (IS_SELECTOR_FREE(sel)) return TRUE;
391 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
392 if (entry.type != SEGMENT_CODE) return TRUE;
393 if (OFFSETOF(lpfn) > entry.limit) return TRUE;
394 return FALSE;
398 /***********************************************************************
399 * IsBadStringPtr16 (KERNEL.337)
401 BOOL16 WINAPI IsBadStringPtr16( SEGPTR ptr, UINT16 size )
403 WORD sel;
404 ldt_entry entry;
406 sel = SELECTOROF(ptr);
407 if (!sel) return TRUE;
408 if (IS_SELECTOR_FREE(sel)) return TRUE;
409 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
410 if ((entry.type == SEGMENT_CODE) && entry.read_only) return TRUE;
411 if (strlen(PTR_SEG_TO_LIN(ptr)) < size) size = strlen(PTR_SEG_TO_LIN(ptr));
412 if (OFFSETOF(ptr) + size - 1 > entry.limit) return TRUE;
413 return FALSE;
417 /***********************************************************************
418 * IsBadHugeReadPtr16 (KERNEL.346)
420 BOOL16 WINAPI IsBadHugeReadPtr16( SEGPTR ptr, DWORD size )
422 WORD sel;
423 ldt_entry entry;
425 sel = SELECTOROF(ptr);
426 if (!sel) return TRUE;
427 if (IS_SELECTOR_FREE(sel)) return TRUE;
428 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
429 if ((entry.type == SEGMENT_CODE) && entry.read_only) return TRUE;
430 if (OFFSETOF(ptr) + size - 1 > entry.limit) return TRUE;
431 return FALSE;
435 /***********************************************************************
436 * IsBadHugeWritePtr16 (KERNEL.347)
438 BOOL16 WINAPI IsBadHugeWritePtr16( SEGPTR ptr, DWORD size )
440 WORD sel;
441 ldt_entry entry;
443 sel = SELECTOROF(ptr);
444 if (!sel) return TRUE;
445 if (IS_SELECTOR_FREE(sel)) return TRUE;
446 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
447 if ((entry.type == SEGMENT_CODE) || entry.read_only) return TRUE;
448 if (OFFSETOF(ptr) + size - 1 > entry.limit) return TRUE;
449 return FALSE;
452 /***********************************************************************
453 * IsBadReadPtr16 (KERNEL.334)
455 BOOL16 WINAPI IsBadReadPtr16( SEGPTR ptr, UINT16 size )
457 return IsBadHugeReadPtr16( ptr, size );
461 /***********************************************************************
462 * IsBadWritePtr16 (KERNEL.335)
464 BOOL16 WINAPI IsBadWritePtr16( SEGPTR ptr, UINT16 size )
466 return IsBadHugeWritePtr16( ptr, size );
470 /***********************************************************************
471 * MemoryRead (TOOLHELP.78)
473 DWORD WINAPI MemoryRead( WORD sel, DWORD offset, void *buffer, DWORD count )
475 if (IS_SELECTOR_FREE(sel)) return 0;
476 if (offset > GET_SEL_LIMIT(sel)) return 0;
477 if (offset + count > GET_SEL_LIMIT(sel) + 1)
478 count = GET_SEL_LIMIT(sel) + 1 - offset;
479 memcpy( buffer, ((char *)GET_SEL_BASE(sel)) + offset, count );
480 return count;
484 /***********************************************************************
485 * MemoryWrite (TOOLHELP.79)
487 DWORD WINAPI MemoryWrite( WORD sel, DWORD offset, void *buffer, DWORD count )
489 if (IS_SELECTOR_FREE(sel)) return 0;
490 if (offset > GET_SEL_LIMIT(sel)) return 0;
491 if (offset + count > GET_SEL_LIMIT(sel) + 1)
492 count = GET_SEL_LIMIT(sel) + 1 - offset;
493 memcpy( ((char *)GET_SEL_BASE(sel)) + offset, buffer, count );
494 return count;
497 /************************************* Win95 pointer mapping functions *
499 * NOTE: MapSLFix and UnMapSLFixArray are probably needed to prevent
500 * unexpected linear address change when GlobalCompact() shuffles
501 * moveable blocks.
504 /***********************************************************************
505 * MapSL (KERNEL32.662)
507 * Maps fixed segmented pointer to linear.
509 LPVOID WINAPI MapSL( SEGPTR sptr )
511 return (LPVOID)PTR_SEG_TO_LIN(sptr);
515 /***********************************************************************
516 * MapLS (KERNEL32.679)
518 * Maps linear pointer to segmented.
520 SEGPTR WINAPI MapLS( LPVOID ptr )
522 WORD sel = SELECTOR_AllocBlock( ptr, 0x10000, SEGMENT_DATA, FALSE, FALSE );
523 return PTR_SEG_OFF_TO_SEGPTR( sel, 0 );
527 /***********************************************************************
528 * UnMapLS (KERNEL32.680)
530 * Free mapped selector.
532 void WINAPI UnMapLS( SEGPTR sptr )
534 if (!__winelib) SELECTOR_FreeBlock( SELECTOROF(sptr), 1 );
537 /***********************************************************************
538 * GetThreadSelectorEntry (KERNEL32)
539 * FIXME: add #ifdef i386 for non x86
541 BOOL32 WINAPI GetThreadSelectorEntry( HANDLE32 hthread, DWORD sel,
542 LPLDT_ENTRY ldtent)
544 ldt_entry ldtentry;
546 LDT_GetEntry(SELECTOR_TO_ENTRY(sel),&ldtentry);
547 ldtent->BaseLow = ldtentry.base & 0x0000ffff;
548 ldtent->HighWord.Bits.BaseMid = (ldtentry.base & 0x00ff0000) >> 16;
549 ldtent->HighWord.Bits.BaseHi = (ldtentry.base & 0xff000000) >> 24;
550 ldtent->LimitLow = ldtentry.limit & 0x0000ffff;
551 ldtent->HighWord.Bits.LimitHi = (ldtentry.limit & 0x00ff0000) >> 16;
552 ldtent->HighWord.Bits.Dpl = 3;
553 ldtent->HighWord.Bits.Sys = 0;
554 ldtent->HighWord.Bits.Pres = 1;
555 ldtent->HighWord.Bits.Type = 0x10|(ldtentry.type << 2);
556 if (ldtentry.read_only)
557 ldtent->HighWord.Bits.Type|=0x2;
558 ldtent->HighWord.Bits.Granularity = ldtentry.limit_in_pages;
559 ldtent->HighWord.Bits.Default_Big = ldtentry.seg_32bit;
560 return TRUE;
564 /**********************************************************************
565 * SMapLS* (KERNEL32)
566 * These functions map linear pointers at [EBP+xxx] to segmented pointers
567 * and return them.
568 * Win95 uses some kind of alias structs, which it stores in [EBP+x] to
569 * unravel them at SUnMapLS. We just store the segmented pointer there.
571 static void
572 x_SMapLS_IP_EBP_x(CONTEXT *context,int argoff) {
573 DWORD val,ptr;
575 val =*(DWORD*)(EBP_reg(context)+argoff);
576 if (val<0x10000) {
577 ptr=val;
578 *(DWORD*)(EBP_reg(context)+argoff) = 0;
579 } else {
580 ptr = MapLS((LPVOID)val);
581 *(DWORD*)(EBP_reg(context)+argoff) = ptr;
583 EAX_reg(context) = ptr;
586 void WINAPI SMapLS_IP_EBP_8(CONTEXT *context) {x_SMapLS_IP_EBP_x(context,8);}
587 void WINAPI SMapLS_IP_EBP_12(CONTEXT *context) {x_SMapLS_IP_EBP_x(context,12);}
588 void WINAPI SMapLS_IP_EBP_16(CONTEXT *context) {x_SMapLS_IP_EBP_x(context,16);}
589 void WINAPI SMapLS_IP_EBP_20(CONTEXT *context) {x_SMapLS_IP_EBP_x(context,20);}
590 void WINAPI SMapLS_IP_EBP_24(CONTEXT *context) {x_SMapLS_IP_EBP_x(context,24);}
591 void WINAPI SMapLS_IP_EBP_28(CONTEXT *context) {x_SMapLS_IP_EBP_x(context,28);}
592 void WINAPI SMapLS_IP_EBP_32(CONTEXT *context) {x_SMapLS_IP_EBP_x(context,32);}
593 void WINAPI SMapLS_IP_EBP_36(CONTEXT *context) {x_SMapLS_IP_EBP_x(context,36);}
594 void WINAPI SMapLS_IP_EBP_40(CONTEXT *context) {x_SMapLS_IP_EBP_x(context,40);}
596 void WINAPI SMapLS(CONTEXT *context)
598 if (EAX_reg(context)>=0x10000) {
599 EAX_reg(context) = MapLS((LPVOID)EAX_reg(context));
600 EDX_reg(context) = EAX_reg(context);
601 } else {
602 EDX_reg(context) = 0;
606 void WINAPI SUnMapLS(CONTEXT *context)
608 if (EAX_reg(context)>=0x10000)
609 UnMapLS((SEGPTR)EAX_reg(context));
612 static void
613 x_SUnMapLS_IP_EBP_x(CONTEXT *context,int argoff) {
614 if (*(DWORD*)(EBP_reg(context)+argoff))
615 UnMapLS(*(DWORD*)(EBP_reg(context)+argoff));
616 *(DWORD*)(EBP_reg(context)+argoff)=0;
618 void WINAPI SUnMapLS_IP_EBP_8(CONTEXT *context) { x_SUnMapLS_IP_EBP_x(context,12); }
619 void WINAPI SUnMapLS_IP_EBP_12(CONTEXT *context) { x_SUnMapLS_IP_EBP_x(context,12); }
620 void WINAPI SUnMapLS_IP_EBP_16(CONTEXT *context) { x_SUnMapLS_IP_EBP_x(context,16); }
621 void WINAPI SUnMapLS_IP_EBP_20(CONTEXT *context) { x_SUnMapLS_IP_EBP_x(context,20); }
622 void WINAPI SUnMapLS_IP_EBP_24(CONTEXT *context) { x_SUnMapLS_IP_EBP_x(context,24); }
623 void WINAPI SUnMapLS_IP_EBP_28(CONTEXT *context) { x_SUnMapLS_IP_EBP_x(context,28); }
624 void WINAPI SUnMapLS_IP_EBP_32(CONTEXT *context) { x_SUnMapLS_IP_EBP_x(context,32); }
625 void WINAPI SUnMapLS_IP_EBP_36(CONTEXT *context) { x_SUnMapLS_IP_EBP_x(context,36); }
626 void WINAPI SUnMapLS_IP_EBP_40(CONTEXT *context) { x_SUnMapLS_IP_EBP_x(context,40); }
628 /**********************************************************************
629 * WOWGetVDMPointer (KERNEL32.55)
630 * Get linear from segmented pointer. (MSDN lib)
632 LPVOID WINAPI WOWGetVDMPointer(DWORD vp,DWORD nrofbytes,BOOL32 protected)
634 /* FIXME: add size check too */
635 if (protected)
636 return PTR_SEG_TO_LIN(vp);
637 else
638 return DOSMEM_MapRealToLinear(vp);
641 /**********************************************************************
642 * GetVDMPointer32W (KERNEL.516)
644 LPVOID WINAPI GetVDMPointer32W(DWORD vp,DWORD mode)
646 return WOWGetVDMPointer(vp,0,mode);
649 /**********************************************************************
650 * WOWGetVDMPointerFix (KERNEL32.55)
651 * Dito, but fix heapsegment (MSDN lib)
653 LPVOID WINAPI WOWGetVDMPointerFix(DWORD vp,DWORD nrofbytes,BOOL32 protected)
655 /* FIXME: fix heapsegment */
656 return WOWGetVDMPointer(vp,nrofbytes,protected);
659 /**********************************************************************
660 * WOWGetVDMPointerUnFix (KERNEL32.56)
662 void WINAPI WOWGetVDMPointerUnfix(DWORD vp)
664 /* FIXME: unfix heapsegment */
667 /***********************************************************************
668 * UTSelectorOffsetToLinear (WIN32S16.48)
670 * rough guesswork, but seems to work (I had no "reasonable" docu)
672 LPVOID WINAPI UTSelectorOffsetToLinear(SEGPTR sptr)
674 return PTR_SEG_TO_LIN(sptr);
677 /***********************************************************************
678 * UTLinearToSelectorOffset (WIN32S16.49)
680 * FIXME: I don't know if that's the right way to do linear -> segmented
682 SEGPTR WINAPI UTLinearToSelectorOffset(LPVOID lptr)
684 fprintf( stderr, "UTLinearToSelectorOffset(%p): stub\n", lptr );
685 return (SEGPTR)lptr;