2 * Selector manipulation functions
4 * Copyright 1995 Alexandre Julliard
11 #include "selectors.h"
12 #include "stackframe.h"
17 #define FIRST_LDT_ENTRY_TO_ALLOC 17
20 /***********************************************************************
21 * AllocSelectorArray (KERNEL.206)
23 WORD WINAPI AllocSelectorArray( WORD count )
25 WORD i, sel, size = 0;
29 for (i = FIRST_LDT_ENTRY_TO_ALLOC; i < LDT_SIZE; i++)
31 if (!IS_LDT_ENTRY_FREE(i)) size = 0;
32 else if (++size >= count) break;
34 if (i == LDT_SIZE) return 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 */
44 for (i = 0; i < count; i++)
46 /* Mark selector as allocated */
47 ldt_flags_copy[sel + i] |= LDT_FLAGS_ALLOCATED;
48 LDT_SetEntry( sel + i, &entry );
50 return ENTRY_TO_SELECTOR( sel );
54 /***********************************************************************
55 * AllocSelector (KERNEL.175)
57 WORD WINAPI AllocSelector( WORD sel )
59 WORD newsel, count, i;
61 count = sel ? ((GET_SEL_LIMIT(sel) >> 16) + 1) : 1;
62 newsel = AllocSelectorArray( count );
63 dprintf_selector( stddeb, "AllocSelector(%04x): returning %04x\n",
65 if (!newsel) return 0;
66 if (!sel) return newsel; /* nothing to copy */
67 for (i = 0; i < count; i++)
70 LDT_GetEntry( SELECTOR_TO_ENTRY(sel) + i, &entry );
71 LDT_SetEntry( SELECTOR_TO_ENTRY(newsel) + i, &entry );
77 /***********************************************************************
78 * FreeSelector (KERNEL.176)
80 WORD WINAPI FreeSelector( WORD sel )
82 if (IS_SELECTOR_FREE(sel)) return sel; /* error */
83 SELECTOR_FreeBlock( sel, 1 );
88 /***********************************************************************
91 * Set the LDT entries for an array of selectors.
93 static void SELECTOR_SetEntries( WORD sel, const void *base, DWORD size,
94 enum seg_type type, BOOL32 is32bit,
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;
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++)
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;
123 /***********************************************************************
124 * SELECTOR_AllocBlock
126 * Allocate selectors for a block of linear memory.
128 WORD SELECTOR_AllocBlock( const void *base, DWORD size, enum seg_type type,
129 BOOL32 is32bit, BOOL32 readonly )
134 count = (size + 0xffff) / 0x10000;
135 sel = AllocSelectorArray( count );
136 if (sel) SELECTOR_SetEntries( sel, base, size, type, is32bit, readonly );
141 /***********************************************************************
144 * Free a block of selectors.
146 void SELECTOR_FreeBlock( WORD sel, WORD count )
152 dprintf_selector( stddeb, "SELECTOR_FreeBlock(%04x,%d)\n", sel, count );
153 sel &= ~(__AHINCR - 1); /* clear bottom bits of selector */
154 nextsel = sel + (count << __AHSHIFT);
158 /* Check if we are freeing current %fs or %gs selector */
162 if ((fs >= sel) && (fs < nextsel))
164 fprintf( stderr, "SELECTOR_FreeBlock: freeing %%fs selector (%04x), not good.\n", fs );
168 if ((gs >= sel) && (gs < nextsel)) SET_GS( 0 );
170 #endif /* __i386__ */
172 memset( &entry, 0, sizeof(entry) ); /* clear the LDT entries */
173 for (i = SELECTOR_TO_ENTRY(sel); count; i++, count--)
175 LDT_SetEntry( i, &entry );
176 ldt_flags_copy[i] &= ~LDT_FLAGS_ALLOCATED;
179 /* Clear the saved 16-bit selector */
180 frame = CURRENT_STACK16;
183 if ((frame->ds >= sel) && (frame->ds < nextsel)) frame->ds = 0;
184 if ((frame->es >= sel) && (frame->es < nextsel)) frame->es = 0;
185 if (!frame->frame32) break;
186 frame = PTR_SEG_TO_LIN( frame->frame32->frame16 );
191 /***********************************************************************
192 * SELECTOR_ReallocBlock
194 * Change the size of a block of selectors.
196 WORD SELECTOR_ReallocBlock( WORD sel, const void *base, DWORD size,
197 enum seg_type type, BOOL32 is32bit, BOOL32 readonly)
199 WORD i, oldcount, newcount;
202 oldcount = (GET_SEL_LIMIT(sel) >> 16) + 1;
203 newcount = (size + 0xffff) >> 16;
205 if (oldcount < newcount) /* We need to add selectors */
207 /* Check if the next selectors are free */
208 if (SELECTOR_TO_ENTRY(sel) + newcount > LDT_SIZE) i = oldcount;
210 for (i = oldcount; i < newcount; i++)
211 if (!IS_LDT_ENTRY_FREE(SELECTOR_TO_ENTRY(sel)+i)) break;
213 if (i < newcount) /* they are not free */
215 SELECTOR_FreeBlock( sel, oldcount );
216 sel = AllocSelectorArray( newcount );
218 else /* mark the selectors as allocated */
220 for (i = oldcount; i < newcount; i++)
221 ldt_flags_copy[SELECTOR_TO_ENTRY(sel)+i] |=LDT_FLAGS_ALLOCATED;
224 else if (oldcount > newcount) /* We need to remove selectors */
226 SELECTOR_FreeBlock( ENTRY_TO_SELECTOR(SELECTOR_TO_ENTRY(sel)+newcount),
227 oldcount - newcount );
229 if (sel) SELECTOR_SetEntries( sel, base, size, type, is32bit, readonly );
234 /***********************************************************************
235 * PrestoChangoSelector (KERNEL.177)
237 WORD WINAPI PrestoChangoSelector( WORD selSrc, WORD selDst )
240 LDT_GetEntry( SELECTOR_TO_ENTRY( selSrc ), &entry );
241 entry.type ^= SEGMENT_CODE; /* toggle the executable bit */
242 LDT_SetEntry( SELECTOR_TO_ENTRY( selDst ), &entry );
247 /***********************************************************************
248 * AllocCStoDSAlias (KERNEL.170)
250 WORD WINAPI AllocCStoDSAlias( WORD sel )
255 newsel = AllocSelectorArray( 1 );
256 dprintf_selector( stddeb, "AllocCStoDSAlias(%04x): returning %04x\n",
258 if (!newsel) return 0;
259 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
260 entry.type = SEGMENT_DATA;
261 LDT_SetEntry( SELECTOR_TO_ENTRY(newsel), &entry );
266 /***********************************************************************
267 * AllocDStoCSAlias (KERNEL.171)
269 WORD WINAPI AllocDStoCSAlias( WORD sel )
274 newsel = AllocSelectorArray( 1 );
275 dprintf_selector( stddeb, "AllocDStoCSAlias(%04x): returning %04x\n",
277 if (!newsel) return 0;
278 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
279 entry.type = SEGMENT_CODE;
280 LDT_SetEntry( SELECTOR_TO_ENTRY(newsel), &entry );
285 /***********************************************************************
286 * LongPtrAdd (KERNEL.180)
288 void WINAPI LongPtrAdd( DWORD ptr, DWORD add )
291 LDT_GetEntry( SELECTOR_TO_ENTRY(SELECTOROF(ptr)), &entry );
293 LDT_SetEntry( SELECTOR_TO_ENTRY(SELECTOROF(ptr)), &entry );
297 /***********************************************************************
298 * GetSelectorBase (KERNEL.186)
300 DWORD WINAPI GetSelectorBase( WORD sel )
302 DWORD base = GET_SEL_BASE(sel);
304 /* if base points into DOSMEM, assume we have to
305 * return pointer into physical lower 1MB */
307 return DOSMEM_MapLinearToDos( (LPVOID)base );
311 /***********************************************************************
312 * SetSelectorBase (KERNEL.187)
314 WORD WINAPI SetSelectorBase( WORD sel, DWORD base )
318 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
320 entry.base = (DWORD)DOSMEM_MapDosToLinear(base);
322 LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
327 /***********************************************************************
328 * GetSelectorLimit (KERNEL.188)
330 DWORD WINAPI GetSelectorLimit( WORD sel )
332 return GET_SEL_LIMIT(sel);
336 /***********************************************************************
337 * SetSelectorLimit (KERNEL.189)
339 WORD WINAPI SetSelectorLimit( WORD sel, DWORD limit )
342 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
343 entry.limit_in_pages = (limit >= 0x100000);
344 if (entry.limit_in_pages) entry.limit = limit >> 12;
345 else entry.limit = limit;
346 LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
351 /***********************************************************************
352 * SelectorAccessRights (KERNEL.196)
354 WORD WINAPI SelectorAccessRights( WORD sel, WORD op, WORD val )
357 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
358 if (op == 0) /* get */
360 return 0x01 | /* accessed */
361 0x10 | /* not system */
364 ((entry.read_only == 0) << 1) |
366 (entry.seg_32bit << 14) |
367 (entry.limit_in_pages << 15);
371 entry.read_only = ((val & 2) == 0);
372 entry.type = (val >> 2) & 3;
373 entry.seg_32bit = val & 0x4000;
374 entry.limit_in_pages = val & 0x8000;
375 LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
381 /***********************************************************************
382 * IsBadCodePtr16 (KERNEL.336)
384 BOOL16 WINAPI IsBadCodePtr16( SEGPTR lpfn )
389 sel = SELECTOROF(lpfn);
390 if (!sel) return TRUE;
391 if (IS_SELECTOR_FREE(sel)) return TRUE;
392 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
393 if (entry.type != SEGMENT_CODE) return TRUE;
394 if (OFFSETOF(lpfn) > entry.limit) return TRUE;
399 /***********************************************************************
400 * IsBadStringPtr16 (KERNEL.337)
402 BOOL16 WINAPI IsBadStringPtr16( SEGPTR ptr, UINT16 size )
407 sel = SELECTOROF(ptr);
408 if (!sel) return TRUE;
409 if (IS_SELECTOR_FREE(sel)) return TRUE;
410 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
411 if ((entry.type == SEGMENT_CODE) && entry.read_only) return TRUE;
412 if (strlen(PTR_SEG_TO_LIN(ptr)) < size) size = strlen(PTR_SEG_TO_LIN(ptr));
413 if (OFFSETOF(ptr) + size - 1 > entry.limit) return TRUE;
418 /***********************************************************************
419 * IsBadHugeReadPtr16 (KERNEL.346)
421 BOOL16 WINAPI IsBadHugeReadPtr16( SEGPTR ptr, DWORD size )
426 sel = SELECTOROF(ptr);
427 if (!sel) return TRUE;
428 if (IS_SELECTOR_FREE(sel)) return TRUE;
429 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
430 if ((entry.type == SEGMENT_CODE) && entry.read_only) return TRUE;
431 if (OFFSETOF(ptr) + size - 1 > entry.limit) return TRUE;
436 /***********************************************************************
437 * IsBadHugeWritePtr16 (KERNEL.347)
439 BOOL16 WINAPI IsBadHugeWritePtr16( SEGPTR ptr, DWORD size )
444 sel = SELECTOROF(ptr);
445 if (!sel) return TRUE;
446 if (IS_SELECTOR_FREE(sel)) return TRUE;
447 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
448 if ((entry.type == SEGMENT_CODE) || entry.read_only) return TRUE;
449 if (OFFSETOF(ptr) + size - 1 > entry.limit) return TRUE;
453 /***********************************************************************
454 * IsBadReadPtr16 (KERNEL.334)
456 BOOL16 WINAPI IsBadReadPtr16( SEGPTR ptr, UINT16 size )
458 return IsBadHugeReadPtr16( ptr, size );
462 /***********************************************************************
463 * IsBadWritePtr16 (KERNEL.335)
465 BOOL16 WINAPI IsBadWritePtr16( SEGPTR ptr, UINT16 size )
467 return IsBadHugeWritePtr16( ptr, size );
471 /***********************************************************************
472 * MemoryRead (TOOLHELP.78)
474 DWORD WINAPI MemoryRead( WORD sel, DWORD offset, void *buffer, DWORD count )
476 if (IS_SELECTOR_FREE(sel)) return 0;
477 if (offset > GET_SEL_LIMIT(sel)) return 0;
478 if (offset + count > GET_SEL_LIMIT(sel) + 1)
479 count = GET_SEL_LIMIT(sel) + 1 - offset;
480 memcpy( buffer, ((char *)GET_SEL_BASE(sel)) + offset, count );
485 /***********************************************************************
486 * MemoryWrite (TOOLHELP.79)
488 DWORD WINAPI MemoryWrite( WORD sel, DWORD offset, void *buffer, DWORD count )
490 if (IS_SELECTOR_FREE(sel)) return 0;
491 if (offset > GET_SEL_LIMIT(sel)) return 0;
492 if (offset + count > GET_SEL_LIMIT(sel) + 1)
493 count = GET_SEL_LIMIT(sel) + 1 - offset;
494 memcpy( ((char *)GET_SEL_BASE(sel)) + offset, buffer, count );
498 /************************************* Win95 pointer mapping functions *
500 * NOTE: MapSLFix and UnMapSLFixArray are probably needed to prevent
501 * unexpected linear address change when GlobalCompact() shuffles
505 /***********************************************************************
506 * MapSL (KERNEL32.662)
508 * Maps fixed segmented pointer to linear.
510 LPVOID WINAPI MapSL( SEGPTR sptr )
512 return (LPVOID)PTR_SEG_TO_LIN(sptr);
516 /***********************************************************************
517 * MapLS (KERNEL32.679)
519 * Maps linear pointer to segmented.
521 SEGPTR WINAPI MapLS( LPVOID ptr )
523 WORD sel = SELECTOR_AllocBlock( ptr, 0x10000, SEGMENT_DATA, FALSE, FALSE );
524 return PTR_SEG_OFF_TO_SEGPTR( sel, 0 );
528 /***********************************************************************
529 * UnMapLS (KERNEL32.680)
531 * Free mapped selector.
533 void WINAPI UnMapLS( SEGPTR sptr )
535 if (!__winelib) SELECTOR_FreeBlock( SELECTOROF(sptr), 1 );
538 /***********************************************************************
539 * GetThreadSelectorEntry (KERNEL32)
540 * FIXME: add #ifdef i386 for non x86
542 BOOL32 WINAPI GetThreadSelectorEntry( HANDLE32 hthread, DWORD sel,
547 LDT_GetEntry(SELECTOR_TO_ENTRY(sel),&ldtentry);
548 ldtent->BaseLow = ldtentry.base & 0x0000ffff;
549 ldtent->HighWord.Bits.BaseMid = (ldtentry.base & 0x00ff0000) >> 16;
550 ldtent->HighWord.Bits.BaseHi = (ldtentry.base & 0xff000000) >> 24;
551 ldtent->LimitLow = ldtentry.limit & 0x0000ffff;
552 ldtent->HighWord.Bits.LimitHi = (ldtentry.limit & 0x00ff0000) >> 16;
553 ldtent->HighWord.Bits.Dpl = 3;
554 ldtent->HighWord.Bits.Sys = 0;
555 ldtent->HighWord.Bits.Pres = 1;
556 ldtent->HighWord.Bits.Type = 0x10|(ldtentry.type << 2);
557 if (ldtentry.read_only)
558 ldtent->HighWord.Bits.Type|=0x2;
559 ldtent->HighWord.Bits.Granularity = ldtentry.limit_in_pages;
560 ldtent->HighWord.Bits.Default_Big = ldtentry.seg_32bit;
565 /**********************************************************************
567 * These functions map linear pointers at [EBP+xxx] to segmented pointers
569 * Win95 uses some kind of alias structs, which it stores in [EBP+x] to
570 * unravel them at SUnMapLS. We just store the segmented pointer there.
573 x_SMapLS_IP_EBP_x(CONTEXT *context,int argoff) {
576 val =*(DWORD*)(EBP_reg(context)+argoff);
579 *(DWORD*)(EBP_reg(context)+argoff) = 0;
581 ptr = MapLS((LPVOID)val);
582 *(DWORD*)(EBP_reg(context)+argoff) = ptr;
584 EAX_reg(context) = ptr;
587 void WINAPI SMapLS_IP_EBP_8(CONTEXT *context) {x_SMapLS_IP_EBP_x(context,8);}
588 void WINAPI SMapLS_IP_EBP_12(CONTEXT *context) {x_SMapLS_IP_EBP_x(context,12);}
589 void WINAPI SMapLS_IP_EBP_16(CONTEXT *context) {x_SMapLS_IP_EBP_x(context,16);}
590 void WINAPI SMapLS_IP_EBP_20(CONTEXT *context) {x_SMapLS_IP_EBP_x(context,20);}
591 void WINAPI SMapLS_IP_EBP_24(CONTEXT *context) {x_SMapLS_IP_EBP_x(context,24);}
592 void WINAPI SMapLS_IP_EBP_28(CONTEXT *context) {x_SMapLS_IP_EBP_x(context,28);}
593 void WINAPI SMapLS_IP_EBP_32(CONTEXT *context) {x_SMapLS_IP_EBP_x(context,32);}
594 void WINAPI SMapLS_IP_EBP_36(CONTEXT *context) {x_SMapLS_IP_EBP_x(context,36);}
595 void WINAPI SMapLS_IP_EBP_40(CONTEXT *context) {x_SMapLS_IP_EBP_x(context,40);}
597 void WINAPI SMapLS(CONTEXT *context)
599 if (EAX_reg(context)>=0x10000) {
600 EAX_reg(context) = MapLS((LPVOID)EAX_reg(context));
601 EDX_reg(context) = EAX_reg(context);
603 EDX_reg(context) = 0;
607 void WINAPI SUnMapLS(CONTEXT *context)
609 if (EAX_reg(context)>=0x10000)
610 UnMapLS((SEGPTR)EAX_reg(context));
614 x_SUnMapLS_IP_EBP_x(CONTEXT *context,int argoff) {
615 if (*(DWORD*)(EBP_reg(context)+argoff))
616 UnMapLS(*(DWORD*)(EBP_reg(context)+argoff));
617 *(DWORD*)(EBP_reg(context)+argoff)=0;
619 void WINAPI SUnMapLS_IP_EBP_8(CONTEXT *context) { x_SUnMapLS_IP_EBP_x(context,12); }
620 void WINAPI SUnMapLS_IP_EBP_12(CONTEXT *context) { x_SUnMapLS_IP_EBP_x(context,12); }
621 void WINAPI SUnMapLS_IP_EBP_16(CONTEXT *context) { x_SUnMapLS_IP_EBP_x(context,16); }
622 void WINAPI SUnMapLS_IP_EBP_20(CONTEXT *context) { x_SUnMapLS_IP_EBP_x(context,20); }
623 void WINAPI SUnMapLS_IP_EBP_24(CONTEXT *context) { x_SUnMapLS_IP_EBP_x(context,24); }
624 void WINAPI SUnMapLS_IP_EBP_28(CONTEXT *context) { x_SUnMapLS_IP_EBP_x(context,28); }
625 void WINAPI SUnMapLS_IP_EBP_32(CONTEXT *context) { x_SUnMapLS_IP_EBP_x(context,32); }
626 void WINAPI SUnMapLS_IP_EBP_36(CONTEXT *context) { x_SUnMapLS_IP_EBP_x(context,36); }
627 void WINAPI SUnMapLS_IP_EBP_40(CONTEXT *context) { x_SUnMapLS_IP_EBP_x(context,40); }
629 /**********************************************************************
630 * WOWGetVDMPointer (KERNEL32.55)
631 * Get linear from segmented pointer. (MSDN lib)
633 LPVOID WINAPI WOWGetVDMPointer(DWORD vp,DWORD nrofbytes,BOOL32 protected)
635 /* FIXME: add size check too */
636 fprintf(stdnimp,"WOWGetVDMPointer(%08lx,%ld,%d)\n",vp,nrofbytes,protected);
638 return PTR_SEG_TO_LIN(vp);
640 return DOSMEM_MapRealToLinear(vp);
643 /**********************************************************************
644 * GetVDMPointer32W (KERNEL.516)
646 LPVOID WINAPI GetVDMPointer32W(DWORD vp,DWORD mode)
648 return WOWGetVDMPointer(vp,0,mode);
651 /**********************************************************************
652 * WOWGetVDMPointerFix (KERNEL32.55)
653 * Dito, but fix heapsegment (MSDN lib)
655 LPVOID WINAPI WOWGetVDMPointerFix(DWORD vp,DWORD nrofbytes,BOOL32 protected)
657 /* FIXME: fix heapsegment */
658 fprintf(stdnimp,"WOWGetVDMPointerFix(%08lx,%ld,%d)\n",vp,nrofbytes,protected);
659 return WOWGetVDMPointer(vp,nrofbytes,protected);
662 /**********************************************************************
663 * WOWGetVDMPointerUnFix (KERNEL32.56)
665 void WINAPI WOWGetVDMPointerUnfix(DWORD vp)
667 fprintf(stdnimp,"WOWGetVDMPointerUnfix(%08lx), STUB\n",vp);
668 /* FIXME: unfix heapsegment */
671 /***********************************************************************
672 * UTSelectorOffsetToLinear (WIN32S16.48)
674 * rough guesswork, but seems to work (I had no "reasonable" docu)
676 LPVOID WINAPI UTSelectorOffsetToLinear(SEGPTR sptr)
678 return PTR_SEG_TO_LIN(sptr);
681 /***********************************************************************
682 * UTLinearToSelectorOffset (WIN32S16.49)
684 * FIXME: I don't know if that's the right way to do linear -> segmented
686 SEGPTR WINAPI UTLinearToSelectorOffset(LPVOID lptr)
688 fprintf( stderr, "UTLinearToSelectorOffset(%p): stub\n", lptr );