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 )
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 /* Mark selector as allocated */
35 while (size--) ldt_flags_copy[i--] |= LDT_FLAGS_ALLOCATED;
36 return ENTRY_TO_SELECTOR( i + 1 );
40 /***********************************************************************
41 * AllocSelector (KERNEL.175)
43 WORD WINAPI AllocSelector( WORD sel )
45 WORD newsel, count, i;
47 count = sel ? ((GET_SEL_LIMIT(sel) >> 16) + 1) : 1;
48 newsel = AllocSelectorArray( count );
49 dprintf_selector( stddeb, "AllocSelector(%04x): returning %04x\n",
51 if (!newsel) return 0;
52 if (!sel) return newsel; /* nothing to copy */
53 for (i = 0; i < count; i++)
56 LDT_GetEntry( SELECTOR_TO_ENTRY(sel) + i, &entry );
57 LDT_SetEntry( SELECTOR_TO_ENTRY(newsel) + i, &entry );
63 /***********************************************************************
64 * FreeSelector (KERNEL.176)
66 WORD WINAPI FreeSelector( WORD sel )
68 if (IS_SELECTOR_FREE(sel)) return sel; /* error */
69 SELECTOR_FreeBlock( sel, 1 );
74 /***********************************************************************
77 * Set the LDT entries for an array of selectors.
79 static void SELECTOR_SetEntries( WORD sel, const void *base, DWORD size,
80 enum seg_type type, BOOL32 is32bit,
86 /* The limit for the first selector is the whole */
87 /* block. The next selectors get a 64k limit. */
88 entry.base = (unsigned long)base;
90 entry.seg_32bit = is32bit;
91 entry.read_only = readonly;
92 entry.limit_in_pages = (size > 0x100000);
93 if (entry.limit_in_pages) entry.limit = ((size + 0xfff) >> 12) - 1;
94 else entry.limit = size - 1;
95 /* Make sure base and limit are not 0 together if the size is not 0 */
96 if (!base && !entry.limit && size) entry.limit = 1;
97 count = (size + 0xffff) / 0x10000;
98 for (i = 0; i < count; i++)
100 LDT_SetEntry( SELECTOR_TO_ENTRY(sel) + i, &entry );
101 entry.base += 0x10000;
102 /* Apparently the next selectors should *not* get a 64k limit. */
103 /* Can't remember where I read they should... --AJ */
104 entry.limit -= entry.limit_in_pages ? 0x10 : 0x10000;
109 /***********************************************************************
110 * SELECTOR_AllocBlock
112 * Allocate selectors for a block of linear memory.
114 WORD SELECTOR_AllocBlock( const void *base, DWORD size, enum seg_type type,
115 BOOL32 is32bit, BOOL32 readonly )
120 count = (size + 0xffff) / 0x10000;
121 sel = AllocSelectorArray( count );
122 if (sel) SELECTOR_SetEntries( sel, base, size, type, is32bit, readonly );
127 /***********************************************************************
130 * Free a block of selectors.
132 void SELECTOR_FreeBlock( WORD sel, WORD count )
138 dprintf_selector( stddeb, "SELECTOR_FreeBlock(%04x,%d)\n", sel, count );
139 sel &= ~(__AHINCR - 1); /* clear bottom bits of selector */
140 nextsel = sel + (count << __AHSHIFT);
144 /* Check if we are freeing current %fs or %gs selector */
148 __asm__("movw %%fs,%w0":"=r" (fs));
149 if ((fs >= sel) && (fs < nextsel))
151 fprintf( stderr, "SELECTOR_FreeBlock: freeing %%fs selector (%04x), not good.\n", fs );
152 __asm__("movw %w0,%%fs"::"r" (0));
154 __asm__("movw %%gs,%w0":"=r" (gs));
155 if ((gs >= sel) && (gs < nextsel))
156 __asm__("movw %w0,%%gs"::"r" (0));
158 #endif /* __i386__ */
160 memset( &entry, 0, sizeof(entry) ); /* clear the LDT entries */
161 for (i = SELECTOR_TO_ENTRY(sel); count; i++, count--)
163 LDT_SetEntry( i, &entry );
164 ldt_flags_copy[i] &= ~LDT_FLAGS_ALLOCATED;
167 /* Clear the saved 16-bit selector */
168 frame = CURRENT_STACK16;
171 if ((frame->ds >= sel) && (frame->ds < nextsel)) frame->ds = 0;
172 if ((frame->es >= sel) && (frame->es < nextsel)) frame->es = 0;
173 frame = PTR_SEG_TO_LIN( frame->saved_ss_sp );
178 /***********************************************************************
179 * SELECTOR_ReallocBlock
181 * Change the size of a block of selectors.
183 WORD SELECTOR_ReallocBlock( WORD sel, const void *base, DWORD size,
184 enum seg_type type, BOOL32 is32bit, BOOL32 readonly)
186 WORD i, oldcount, newcount;
189 oldcount = (GET_SEL_LIMIT(sel) >> 16) + 1;
190 newcount = (size + 0xffff) >> 16;
192 if (oldcount < newcount) /* We need to add selectors */
194 /* Check if the next selectors are free */
195 if (SELECTOR_TO_ENTRY(sel) + newcount > LDT_SIZE) i = oldcount;
197 for (i = oldcount; i < newcount; i++)
198 if (!IS_LDT_ENTRY_FREE(SELECTOR_TO_ENTRY(sel)+i)) break;
200 if (i < newcount) /* they are not free */
202 SELECTOR_FreeBlock( sel, oldcount );
203 sel = AllocSelectorArray( newcount );
205 else /* mark the selectors as allocated */
207 for (i = oldcount; i < newcount; i++)
208 ldt_flags_copy[SELECTOR_TO_ENTRY(sel)+i] |=LDT_FLAGS_ALLOCATED;
211 else if (oldcount > newcount) /* We need to remove selectors */
213 SELECTOR_FreeBlock( ENTRY_TO_SELECTOR(SELECTOR_TO_ENTRY(sel)+newcount),
214 oldcount - newcount );
216 if (sel) SELECTOR_SetEntries( sel, base, size, type, is32bit, readonly );
221 /***********************************************************************
222 * PrestoChangoSelector (KERNEL.177)
224 WORD WINAPI PrestoChangoSelector( WORD selSrc, WORD selDst )
227 LDT_GetEntry( SELECTOR_TO_ENTRY( selSrc ), &entry );
228 entry.type ^= SEGMENT_CODE; /* toggle the executable bit */
229 LDT_SetEntry( SELECTOR_TO_ENTRY( selDst ), &entry );
234 /***********************************************************************
235 * AllocCStoDSAlias (KERNEL.170)
237 WORD WINAPI AllocCStoDSAlias( WORD sel )
242 newsel = AllocSelectorArray( 1 );
243 dprintf_selector( stddeb, "AllocCStoDSAlias(%04x): returning %04x\n",
245 if (!newsel) return 0;
246 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
247 entry.type = SEGMENT_DATA;
248 LDT_SetEntry( SELECTOR_TO_ENTRY(newsel), &entry );
253 /***********************************************************************
254 * AllocDStoCSAlias (KERNEL.171)
256 WORD WINAPI AllocDStoCSAlias( WORD sel )
261 newsel = AllocSelectorArray( 1 );
262 dprintf_selector( stddeb, "AllocDStoCSAlias(%04x): returning %04x\n",
264 if (!newsel) return 0;
265 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
266 entry.type = SEGMENT_CODE;
267 LDT_SetEntry( SELECTOR_TO_ENTRY(newsel), &entry );
272 /***********************************************************************
273 * LongPtrAdd (KERNEL.180)
275 void WINAPI LongPtrAdd( DWORD ptr, DWORD add )
278 LDT_GetEntry( SELECTOR_TO_ENTRY(SELECTOROF(ptr)), &entry );
280 LDT_SetEntry( SELECTOR_TO_ENTRY(SELECTOROF(ptr)), &entry );
284 /***********************************************************************
285 * GetSelectorBase (KERNEL.186)
287 DWORD WINAPI GetSelectorBase( WORD sel )
289 DWORD base = GET_SEL_BASE(sel);
291 /* if base points into DOSMEM, assume we have to
292 * return pointer into physical lower 1MB */
294 return DOSMEM_MapLinearToDos( (LPVOID)base );
298 /***********************************************************************
299 * SetSelectorBase (KERNEL.187)
301 WORD WINAPI SetSelectorBase( WORD sel, DWORD base )
305 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
307 entry.base = (DWORD)DOSMEM_MapDosToLinear(base);
309 LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
314 /***********************************************************************
315 * GetSelectorLimit (KERNEL.188)
317 DWORD WINAPI GetSelectorLimit( WORD sel )
319 return GET_SEL_LIMIT(sel);
323 /***********************************************************************
324 * SetSelectorLimit (KERNEL.189)
326 WORD WINAPI SetSelectorLimit( WORD sel, DWORD limit )
329 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
330 entry.limit_in_pages = (limit >= 0x100000);
331 if (entry.limit_in_pages) entry.limit = limit >> 12;
332 else entry.limit = limit;
333 LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
338 /***********************************************************************
339 * SelectorAccessRights (KERNEL.196)
341 WORD WINAPI SelectorAccessRights( WORD sel, WORD op, WORD val )
344 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
345 if (op == 0) /* get */
347 return 0x01 | /* accessed */
348 0x10 | /* not system */
351 ((entry.read_only == 0) << 1) |
353 (entry.seg_32bit << 14) |
354 (entry.limit_in_pages << 15);
358 entry.read_only = ((val & 2) == 0);
359 entry.type = (val >> 2) & 3;
360 entry.seg_32bit = val & 0x4000;
361 entry.limit_in_pages = val & 0x8000;
362 LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
368 /***********************************************************************
369 * IsBadCodePtr16 (KERNEL.336)
371 BOOL16 WINAPI IsBadCodePtr16( SEGPTR lpfn )
376 sel = SELECTOROF(lpfn);
377 if (!sel) return TRUE;
378 if (IS_SELECTOR_FREE(sel)) return TRUE;
379 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
380 if (entry.type != SEGMENT_CODE) return TRUE;
381 if (OFFSETOF(lpfn) > entry.limit) return TRUE;
386 /***********************************************************************
387 * IsBadStringPtr16 (KERNEL.337)
389 BOOL16 WINAPI IsBadStringPtr16( SEGPTR ptr, UINT16 size )
394 sel = SELECTOROF(ptr);
395 if (!sel) return TRUE;
396 if (IS_SELECTOR_FREE(sel)) return TRUE;
397 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
398 if ((entry.type == SEGMENT_CODE) && entry.read_only) return TRUE;
399 if (strlen(PTR_SEG_TO_LIN(ptr)) < size) size = strlen(PTR_SEG_TO_LIN(ptr));
400 if (OFFSETOF(ptr) + size - 1 > entry.limit) return TRUE;
405 /***********************************************************************
406 * IsBadHugeReadPtr16 (KERNEL.346)
408 BOOL16 WINAPI IsBadHugeReadPtr16( SEGPTR ptr, DWORD size )
413 sel = SELECTOROF(ptr);
414 if (!sel) return TRUE;
415 if (IS_SELECTOR_FREE(sel)) return TRUE;
416 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
417 if ((entry.type == SEGMENT_CODE) && entry.read_only) return TRUE;
418 if (OFFSETOF(ptr) + size - 1 > entry.limit) return TRUE;
423 /***********************************************************************
424 * IsBadHugeWritePtr16 (KERNEL.347)
426 BOOL16 WINAPI IsBadHugeWritePtr16( SEGPTR ptr, DWORD size )
431 sel = SELECTOROF(ptr);
432 if (!sel) return TRUE;
433 if (IS_SELECTOR_FREE(sel)) return TRUE;
434 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
435 if ((entry.type == SEGMENT_CODE) || entry.read_only) return TRUE;
436 if (OFFSETOF(ptr) + size - 1 > entry.limit) return TRUE;
440 /***********************************************************************
441 * IsBadReadPtr16 (KERNEL.334)
443 BOOL16 WINAPI IsBadReadPtr16( SEGPTR ptr, UINT16 size )
445 return IsBadHugeReadPtr16( ptr, size );
449 /***********************************************************************
450 * IsBadWritePtr16 (KERNEL.335)
452 BOOL16 WINAPI IsBadWritePtr16( SEGPTR ptr, UINT16 size )
454 return IsBadHugeWritePtr16( ptr, size );
458 /***********************************************************************
459 * MemoryRead (TOOLHELP.78)
461 DWORD WINAPI MemoryRead( WORD sel, DWORD offset, void *buffer, DWORD count )
463 if (IS_SELECTOR_FREE(sel)) return 0;
464 if (offset > GET_SEL_LIMIT(sel)) return 0;
465 if (offset + count > GET_SEL_LIMIT(sel) + 1)
466 count = GET_SEL_LIMIT(sel) + 1 - offset;
467 memcpy( buffer, ((char *)GET_SEL_BASE(sel)) + offset, count );
472 /***********************************************************************
473 * MemoryWrite (TOOLHELP.79)
475 DWORD WINAPI MemoryWrite( WORD sel, DWORD offset, void *buffer, DWORD count )
477 if (IS_SELECTOR_FREE(sel)) return 0;
478 if (offset > GET_SEL_LIMIT(sel)) return 0;
479 if (offset + count > GET_SEL_LIMIT(sel) + 1)
480 count = GET_SEL_LIMIT(sel) + 1 - offset;
481 memcpy( ((char *)GET_SEL_BASE(sel)) + offset, buffer, count );
485 /************************************* Win95 pointer mapping functions *
487 * NOTE: MapSLFix and UnMapSLFixArray are probably needed to prevent
488 * unexpected linear address change when GlobalCompact() shuffles
492 /***********************************************************************
493 * MapSL (KERNEL32.662)
495 * Maps fixed segmented pointer to linear.
497 LPVOID WINAPI MapSL( SEGPTR sptr )
499 return (LPVOID)PTR_SEG_TO_LIN(sptr);
503 /***********************************************************************
504 * MapLS (KERNEL32.679)
506 * Maps linear pointer to segmented.
508 SEGPTR WINAPI MapLS( LPVOID ptr )
510 WORD sel = SELECTOR_AllocBlock( ptr, 0x10000, SEGMENT_DATA, FALSE, FALSE );
511 return PTR_SEG_OFF_TO_SEGPTR( sel, 0 );
515 /***********************************************************************
516 * UnMapLS (KERNEL32.680)
518 * Free mapped selector.
520 void WINAPI UnMapLS( SEGPTR sptr )
522 if (!__winelib) SELECTOR_FreeBlock( SELECTOROF(sptr), 1 );
525 /***********************************************************************
526 * GetThreadSelectorEntry (KERNEL32)
527 * FIXME: add #ifdef i386 for non x86
529 BOOL32 WINAPI GetThreadSelectorEntry( HANDLE32 hthread, DWORD sel,
534 LDT_GetEntry(SELECTOR_TO_ENTRY(sel),&ldtentry);
535 ldtent->BaseLow = ldtentry.base & 0x0000ffff;
536 ldtent->HighWord.Bits.BaseMid = (ldtentry.base & 0x00ff0000) >> 16;
537 ldtent->HighWord.Bits.BaseHi = (ldtentry.base & 0xff000000) >> 24;
538 ldtent->LimitLow = ldtentry.limit & 0x0000ffff;
539 ldtent->HighWord.Bits.LimitHi = (ldtentry.limit & 0x00ff0000) >> 16;
540 ldtent->HighWord.Bits.Dpl = 3;
541 ldtent->HighWord.Bits.Sys = 0;
542 ldtent->HighWord.Bits.Pres = 1;
543 ldtent->HighWord.Bits.Type = 0x10|(ldtentry.type << 2);
544 if (ldtentry.read_only)
545 ldtent->HighWord.Bits.Type|=0x2;
546 ldtent->HighWord.Bits.Granularity = ldtentry.limit_in_pages;
547 ldtent->HighWord.Bits.Default_Big = ldtentry.seg_32bit;
552 /**********************************************************************
554 * These functions map linear pointers at [EBP+xxx] to segmented pointers
556 * Win95 uses some kind of alias structs, which it stores in [EBP+x] to
557 * unravel them at SUnMapLS. We just store the segmented pointer there.
560 x_SMapLS_IP_EBP_x(CONTEXT *context,int argoff) {
563 val =*(DWORD*)(EBP_reg(context)+argoff);
566 *(DWORD*)(EBP_reg(context)+argoff) = 0;
568 ptr = MapLS((LPVOID)val);
569 *(DWORD*)(EBP_reg(context)+argoff) = ptr;
571 fprintf(stderr,"[EBP+%d] %08lx => %08lx\n",argoff,val,ptr);
572 EAX_reg(context) = ptr;
575 void WINAPI SMapLS_IP_EBP_8(CONTEXT *context) {x_SMapLS_IP_EBP_x(context,8);}
576 void WINAPI SMapLS_IP_EBP_12(CONTEXT *context) {x_SMapLS_IP_EBP_x(context,12);}
577 void WINAPI SMapLS_IP_EBP_16(CONTEXT *context) {x_SMapLS_IP_EBP_x(context,16);}
578 void WINAPI SMapLS_IP_EBP_20(CONTEXT *context) {x_SMapLS_IP_EBP_x(context,20);}
579 void WINAPI SMapLS_IP_EBP_24(CONTEXT *context) {x_SMapLS_IP_EBP_x(context,24);}
580 void WINAPI SMapLS_IP_EBP_28(CONTEXT *context) {x_SMapLS_IP_EBP_x(context,28);}
581 void WINAPI SMapLS_IP_EBP_32(CONTEXT *context) {x_SMapLS_IP_EBP_x(context,32);}
582 void WINAPI SMapLS_IP_EBP_36(CONTEXT *context) {x_SMapLS_IP_EBP_x(context,36);}
583 void WINAPI SMapLS_IP_EBP_40(CONTEXT *context) {x_SMapLS_IP_EBP_x(context,40);}
585 void WINAPI SMapLS(CONTEXT *context)
587 if (EAX_reg(context)>=0x10000) {
588 EAX_reg(context) = MapLS((LPVOID)EAX_reg(context));
589 EDX_reg(context) = EAX_reg(context);
591 EDX_reg(context) = 0;
595 void WINAPI SUnMapLS(CONTEXT *context)
597 if (EAX_reg(context)>=0x10000)
598 UnMapLS((SEGPTR)EAX_reg(context));
602 x_SUnMapLS_IP_EBP_x(CONTEXT *context,int argoff) {
603 if (*(DWORD*)(EBP_reg(context)+argoff))
604 UnMapLS(*(DWORD*)(EBP_reg(context)+argoff));
605 *(DWORD*)(EBP_reg(context)+argoff)=0;
607 void WINAPI SUnMapLS_IP_EBP_8(CONTEXT *context) { x_SUnMapLS_IP_EBP_x(context,12); }
608 void WINAPI SUnMapLS_IP_EBP_12(CONTEXT *context) { x_SUnMapLS_IP_EBP_x(context,12); }
609 void WINAPI SUnMapLS_IP_EBP_16(CONTEXT *context) { x_SUnMapLS_IP_EBP_x(context,16); }
610 void WINAPI SUnMapLS_IP_EBP_20(CONTEXT *context) { x_SUnMapLS_IP_EBP_x(context,20); }
611 void WINAPI SUnMapLS_IP_EBP_24(CONTEXT *context) { x_SUnMapLS_IP_EBP_x(context,24); }
612 void WINAPI SUnMapLS_IP_EBP_28(CONTEXT *context) { x_SUnMapLS_IP_EBP_x(context,28); }
613 void WINAPI SUnMapLS_IP_EBP_32(CONTEXT *context) { x_SUnMapLS_IP_EBP_x(context,32); }
614 void WINAPI SUnMapLS_IP_EBP_36(CONTEXT *context) { x_SUnMapLS_IP_EBP_x(context,36); }
615 void WINAPI SUnMapLS_IP_EBP_40(CONTEXT *context) { x_SUnMapLS_IP_EBP_x(context,40); }
617 /**********************************************************************
618 * WOWGetVDMPointer (KERNEL32.55)
619 * Get linear from segmented pointer. (MSDN lib)
621 LPVOID WINAPI WOWGetVDMPointer(DWORD vp,DWORD nrofbytes,BOOL32 protected)
623 /* FIXME: add size check too */
624 fprintf(stdnimp,"WOWGetVDMPointer(%08lx,%ld,%d)\n",vp,nrofbytes,protected);
626 return PTR_SEG_TO_LIN(vp);
628 return DOSMEM_MapRealToLinear(vp);
631 /**********************************************************************
632 * GetVDMPointer32W (KERNEL.516)
634 LPVOID WINAPI GetVDMPointer32W(DWORD vp,DWORD mode)
636 return WOWGetVDMPointer(vp,0,mode);
639 /**********************************************************************
640 * WOWGetVDMPointerFix (KERNEL32.55)
641 * Dito, but fix heapsegment (MSDN lib)
643 LPVOID WINAPI WOWGetVDMPointerFix(DWORD vp,DWORD nrofbytes,BOOL32 protected)
645 /* FIXME: fix heapsegment */
646 fprintf(stdnimp,"WOWGetVDMPointerFix(%08lx,%ld,%d)\n",vp,nrofbytes,protected);
647 return WOWGetVDMPointer(vp,nrofbytes,protected);
650 /**********************************************************************
651 * WOWGetVDMPointerUnFix (KERNEL32.56)
653 void WINAPI WOWGetVDMPointerUnfix(DWORD vp)
655 fprintf(stdnimp,"WOWGetVDMPointerUnfix(%08lx), STUB\n",vp);
656 /* FIXME: unfix heapsegment */