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
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
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
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
);
141 memset( &entry
, 0, sizeof(entry
) ); /* clear the LDT entries */
142 for (i
= SELECTOR_TO_ENTRY(sel
); count
; i
++, count
--)
144 LDT_SetEntry( i
, &entry
);
145 ldt_flags_copy
[i
] &= ~LDT_FLAGS_ALLOCATED
;
148 /* Clear the saved 16-bit selector */
149 frame
= CURRENT_STACK16
;
152 if ((frame
->ds
>= sel
) && (frame
->ds
< nextsel
)) frame
->ds
= 0;
153 if ((frame
->es
>= sel
) && (frame
->es
< nextsel
)) frame
->es
= 0;
154 frame
= PTR_SEG_TO_LIN( frame
->saved_ss_sp
);
159 /***********************************************************************
160 * SELECTOR_ReallocBlock
162 * Change the size of a block of selectors.
164 WORD
SELECTOR_ReallocBlock( WORD sel
, const void *base
, DWORD size
,
165 enum seg_type type
, BOOL32 is32bit
, BOOL32 readonly
)
167 WORD i
, oldcount
, newcount
;
170 oldcount
= (GET_SEL_LIMIT(sel
) >> 16) + 1;
171 newcount
= (size
+ 0xffff) >> 16;
173 if (oldcount
< newcount
) /* We need to add selectors */
175 /* Check if the next selectors are free */
176 if (SELECTOR_TO_ENTRY(sel
) + newcount
> LDT_SIZE
) i
= oldcount
;
178 for (i
= oldcount
; i
< newcount
; i
++)
179 if (!IS_LDT_ENTRY_FREE(SELECTOR_TO_ENTRY(sel
)+i
)) break;
181 if (i
< newcount
) /* they are not free */
183 SELECTOR_FreeBlock( sel
, oldcount
);
184 sel
= AllocSelectorArray( newcount
);
186 else /* mark the selectors as allocated */
188 for (i
= oldcount
; i
< newcount
; i
++)
189 ldt_flags_copy
[SELECTOR_TO_ENTRY(sel
)+i
] |=LDT_FLAGS_ALLOCATED
;
192 else if (oldcount
> newcount
) /* We need to remove selectors */
194 SELECTOR_FreeBlock( ENTRY_TO_SELECTOR(SELECTOR_TO_ENTRY(sel
)+newcount
),
195 oldcount
- newcount
);
197 if (sel
) SELECTOR_SetEntries( sel
, base
, size
, type
, is32bit
, readonly
);
202 /***********************************************************************
203 * PrestoChangoSelector (KERNEL.177)
205 WORD
PrestoChangoSelector( WORD selSrc
, WORD selDst
)
208 LDT_GetEntry( SELECTOR_TO_ENTRY( selSrc
), &entry
);
209 entry
.type
^= SEGMENT_CODE
; /* toggle the executable bit */
210 LDT_SetEntry( SELECTOR_TO_ENTRY( selDst
), &entry
);
215 /***********************************************************************
216 * AllocCStoDSAlias (KERNEL.170)
218 WORD
AllocCStoDSAlias( WORD sel
)
223 newsel
= AllocSelectorArray( 1 );
224 dprintf_selector( stddeb
, "AllocCStoDSAlias(%04x): returning %04x\n",
226 if (!newsel
) return 0;
227 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
228 entry
.type
= SEGMENT_DATA
;
229 LDT_SetEntry( SELECTOR_TO_ENTRY(newsel
), &entry
);
234 /***********************************************************************
235 * AllocDStoCSAlias (KERNEL.171)
237 WORD
AllocDStoCSAlias( WORD sel
)
242 newsel
= AllocSelectorArray( 1 );
243 dprintf_selector( stddeb
, "AllocDStoCSAlias(%04x): returning %04x\n",
245 if (!newsel
) return 0;
246 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
247 entry
.type
= SEGMENT_CODE
;
248 LDT_SetEntry( SELECTOR_TO_ENTRY(newsel
), &entry
);
253 /***********************************************************************
254 * LongPtrAdd (KERNEL.180)
256 void LongPtrAdd( DWORD ptr
, DWORD add
)
259 LDT_GetEntry( SELECTOR_TO_ENTRY(SELECTOROF(ptr
)), &entry
);
261 LDT_SetEntry( SELECTOR_TO_ENTRY(SELECTOROF(ptr
)), &entry
);
265 /***********************************************************************
266 * GetSelectorBase (KERNEL.186)
268 DWORD
GetSelectorBase( WORD sel
)
270 DWORD base
= GET_SEL_BASE(sel
);
272 /* if base points into DOSMEM, assume we have to
273 * return pointer into physical lower 1MB */
275 return DOSMEM_MapLinearToDos( (LPVOID
)base
);
279 /***********************************************************************
280 * SetSelectorBase (KERNEL.187)
282 WORD
SetSelectorBase( WORD sel
, DWORD base
)
286 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
288 entry
.base
= (DWORD
)DOSMEM_MapDosToLinear(base
);
290 LDT_SetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
295 /***********************************************************************
296 * GetSelectorLimit (KERNEL.188)
298 DWORD
GetSelectorLimit( WORD sel
)
300 return GET_SEL_LIMIT(sel
);
304 /***********************************************************************
305 * SetSelectorLimit (KERNEL.189)
307 WORD
SetSelectorLimit( WORD sel
, DWORD limit
)
310 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
311 entry
.limit_in_pages
= (limit
>= 0x100000);
312 if (entry
.limit_in_pages
) entry
.limit
= limit
>> 12;
313 else entry
.limit
= limit
;
314 LDT_SetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
319 /***********************************************************************
320 * SelectorAccessRights (KERNEL.196)
322 WORD
SelectorAccessRights( WORD sel
, WORD op
, WORD val
)
325 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
326 if (op
== 0) /* get */
328 return 0x01 | /* accessed */
329 0x10 | /* not system */
332 ((entry
.read_only
== 0) << 1) |
334 (entry
.seg_32bit
<< 14) |
335 (entry
.limit_in_pages
<< 15);
339 entry
.read_only
= ((val
& 2) == 0);
340 entry
.type
= (val
>> 2) & 3;
341 entry
.seg_32bit
= val
& 0x4000;
342 entry
.limit_in_pages
= val
& 0x8000;
343 LDT_SetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
349 /***********************************************************************
350 * IsBadCodePtr16 (KERNEL.336)
352 BOOL16
IsBadCodePtr16( SEGPTR lpfn
)
357 sel
= SELECTOROF(lpfn
);
358 if (!sel
) return TRUE
;
359 if (IS_SELECTOR_FREE(sel
)) return TRUE
;
360 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
361 if (entry
.type
!= SEGMENT_CODE
) return TRUE
;
362 if (OFFSETOF(lpfn
) > entry
.limit
) return TRUE
;
367 /***********************************************************************
368 * IsBadStringPtr16 (KERNEL.337)
370 BOOL16
IsBadStringPtr16( SEGPTR ptr
, UINT16 size
)
375 sel
= SELECTOROF(ptr
);
376 if (!sel
) return TRUE
;
377 if (IS_SELECTOR_FREE(sel
)) return TRUE
;
378 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
379 if ((entry
.type
== SEGMENT_CODE
) && entry
.read_only
) return TRUE
;
380 if (strlen(PTR_SEG_TO_LIN(ptr
)) < size
) size
= strlen(PTR_SEG_TO_LIN(ptr
));
381 if (OFFSETOF(ptr
) + size
- 1 > entry
.limit
) return TRUE
;
386 /***********************************************************************
387 * IsBadHugeReadPtr16 (KERNEL.346)
389 BOOL16
IsBadHugeReadPtr16( SEGPTR ptr
, DWORD 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 (OFFSETOF(ptr
) + size
- 1 > entry
.limit
) return TRUE
;
404 /***********************************************************************
405 * IsBadHugeWritePtr16 (KERNEL.347)
407 BOOL16
IsBadHugeWritePtr16( SEGPTR ptr
, DWORD size
)
412 sel
= SELECTOROF(ptr
);
413 if (!sel
) return TRUE
;
414 if (IS_SELECTOR_FREE(sel
)) return TRUE
;
415 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
416 if ((entry
.type
== SEGMENT_CODE
) || entry
.read_only
) return TRUE
;
417 if (OFFSETOF(ptr
) + size
- 1 > entry
.limit
) return TRUE
;
421 /***********************************************************************
422 * IsBadReadPtr16 (KERNEL.334)
424 BOOL16
IsBadReadPtr16( SEGPTR ptr
, UINT16 size
)
426 return IsBadHugeReadPtr16( ptr
, size
);
430 /***********************************************************************
431 * IsBadWritePtr16 (KERNEL.335)
433 BOOL16
IsBadWritePtr16( SEGPTR ptr
, UINT16 size
)
435 return IsBadHugeWritePtr16( ptr
, size
);
439 /***********************************************************************
440 * MemoryRead (TOOLHELP.78)
442 DWORD
MemoryRead( WORD sel
, DWORD offset
, void *buffer
, DWORD count
)
444 if (IS_SELECTOR_FREE(sel
)) return 0;
445 if (offset
> GET_SEL_LIMIT(sel
)) return 0;
446 if (offset
+ count
> GET_SEL_LIMIT(sel
) + 1)
447 count
= GET_SEL_LIMIT(sel
) + 1 - offset
;
448 memcpy( buffer
, ((char *)GET_SEL_BASE(sel
)) + offset
, count
);
453 /***********************************************************************
454 * MemoryWrite (TOOLHELP.79)
456 DWORD
MemoryWrite( WORD sel
, DWORD offset
, void *buffer
, DWORD count
)
458 if (IS_SELECTOR_FREE(sel
)) return 0;
459 if (offset
> GET_SEL_LIMIT(sel
)) return 0;
460 if (offset
+ count
> GET_SEL_LIMIT(sel
) + 1)
461 count
= GET_SEL_LIMIT(sel
) + 1 - offset
;
462 memcpy( ((char *)GET_SEL_BASE(sel
)) + offset
, buffer
, count
);
466 /************************************* Win95 pointer mapping functions *
468 * NOTE: MapSLFix and UnMapSLFixArray are probably needed to prevent
469 * unexpected linear address change when GlobalCompact() shuffles
473 /***********************************************************************
474 * MapSL (KERNEL32.662)
476 * Maps fixed segmented pointer to linear.
478 LPVOID
MapSL( SEGPTR sptr
)
480 return (LPVOID
)PTR_SEG_TO_LIN(sptr
);
484 /***********************************************************************
485 * MapLS (KERNEL32.679)
487 * Maps linear pointer to segmented.
489 SEGPTR
MapLS( LPVOID ptr
)
491 WORD sel
= SELECTOR_AllocBlock( ptr
, 0x10000, SEGMENT_DATA
, FALSE
, FALSE
);
492 return PTR_SEG_OFF_TO_SEGPTR( sel
, 0 );
496 /***********************************************************************
497 * UnMapLS (KERNEL32.680)
499 * Free mapped selector.
501 void UnMapLS( SEGPTR sptr
)
503 if (!__winelib
) SELECTOR_FreeBlock( SELECTOROF(sptr
), 1 );