2 * Selector manipulation functions
4 * Copyright 1995 Alexandre Julliard
10 #include "selectors.h"
11 #include "stackframe.h"
16 #define FIRST_LDT_ENTRY_TO_ALLOC 6
19 /***********************************************************************
20 * AllocSelectorArray (KERNEL.206)
22 WORD
AllocSelectorArray( WORD count
)
27 for (i
= FIRST_LDT_ENTRY_TO_ALLOC
; i
< LDT_SIZE
; i
++)
29 if (!IS_LDT_ENTRY_FREE(i
)) size
= 0;
30 else if (++size
>= count
) break;
32 if (i
== LDT_SIZE
) return 0;
33 /* Mark selector as allocated */
34 while (size
--) ldt_flags_copy
[i
--] |= LDT_FLAGS_ALLOCATED
;
35 return ENTRY_TO_SELECTOR( i
+ 1 );
39 /***********************************************************************
40 * AllocSelector (KERNEL.175)
42 WORD
AllocSelector( WORD sel
)
44 WORD newsel
, count
, i
;
46 count
= sel
? ((GET_SEL_LIMIT(sel
) >> 16) + 1) : 1;
47 newsel
= AllocSelectorArray( count
);
48 dprintf_selector( stddeb
, "AllocSelector(%04x): returning %04x\n",
50 if (!newsel
) return 0;
51 if (!sel
) return newsel
; /* nothing to copy */
52 for (i
= 0; i
< count
; i
++)
55 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
) + i
, &entry
);
56 LDT_SetEntry( SELECTOR_TO_ENTRY(newsel
) + i
, &entry
);
62 /***********************************************************************
63 * FreeSelector (KERNEL.176)
65 WORD
FreeSelector( WORD sel
)
67 WORD i
, count
, nextsel
;
71 dprintf_selector( stddeb
, "FreeSelector(%04x)\n", sel
);
72 if (IS_SELECTOR_FREE(sel
)) return sel
; /* error */
73 count
= (GET_SEL_LIMIT(sel
) >> 16) + 1;
74 sel
&= ~(__AHINCR
- 1); /* clear bottom bits of selector */
75 nextsel
= sel
+ (count
<< __AHSHIFT
);
76 memset( &entry
, 0, sizeof(entry
) ); /* clear the LDT entries */
77 /* FIXME: is it correct to free the whole array? */
78 for (i
= SELECTOR_TO_ENTRY(sel
); count
; i
++, count
--)
80 LDT_SetEntry( i
, &entry
);
81 ldt_flags_copy
[i
] &= ~LDT_FLAGS_ALLOCATED
;
84 /* Clear the saved 16-bit selector */
86 frame
= CURRENT_STACK16
;
89 if ((frame
->ds
>= sel
) && (frame
->ds
< nextsel
)) frame
->ds
= 0;
90 if ((frame
->es
>= sel
) && (frame
->es
< nextsel
)) frame
->es
= 0;
91 frame
= PTR_SEG_OFF_TO_LIN(frame
->saved_ss
, frame
->saved_sp
);
98 /***********************************************************************
101 * Set the LDT entries for an array of selectors.
103 static void SELECTOR_SetEntries( WORD sel
, const void *base
, DWORD size
,
104 enum seg_type type
, BOOL is32bit
,
110 /* The limit for the first selector is the whole */
111 /* block. The next selectors get a 64k limit. */
112 entry
.base
= (unsigned long)base
;
114 entry
.seg_32bit
= is32bit
;
115 entry
.read_only
= readonly
;
116 entry
.limit_in_pages
= (size
> 0x100000);
117 if (entry
.limit_in_pages
) entry
.limit
= ((size
+ 0xfff) >> 12) - 1;
118 else entry
.limit
= size
- 1;
119 /* Make sure base and limit are not 0 together if the size is not 0 */
120 if (!base
&& !entry
.limit
&& size
) entry
.limit
= 1;
121 count
= (size
+ 0xffff) / 0x10000;
122 for (i
= 0; i
< count
; i
++)
124 LDT_SetEntry( SELECTOR_TO_ENTRY(sel
) + i
, &entry
);
125 entry
.base
+= 0x10000;
126 /* Apparently the next selectors should *not* get a 64k limit. */
127 /* Can't remember where I read they should... --AJ */
128 entry
.limit
-= entry
.limit_in_pages
? 0x10 : 0x10000;
133 /***********************************************************************
134 * SELECTOR_AllocBlock
136 * Allocate selectors for a block of linear memory.
138 WORD
SELECTOR_AllocBlock( const void *base
, DWORD size
, enum seg_type type
,
139 BOOL is32bit
, BOOL readonly
)
144 count
= (size
+ 0xffff) / 0x10000;
145 sel
= AllocSelectorArray( count
);
146 if (sel
) SELECTOR_SetEntries( sel
, base
, size
, type
, is32bit
, readonly
);
151 /***********************************************************************
152 * SELECTOR_ReallocBlock
154 * Change the size of a block of selectors.
156 WORD
SELECTOR_ReallocBlock( WORD sel
, const void *base
, DWORD size
,
157 enum seg_type type
, BOOL is32bit
, BOOL readonly
)
159 WORD i
, oldcount
, newcount
;
163 oldcount
= (GET_SEL_LIMIT(sel
) >> 16) + 1;
164 newcount
= (size
+ 0xffff) >> 16;
166 if (oldcount
< newcount
) /* We need to add selectors */
168 /* Check if the next selectors are free */
169 if (SELECTOR_TO_ENTRY(sel
) + newcount
> LDT_SIZE
) i
= oldcount
;
171 for (i
= oldcount
; i
< newcount
; i
++)
172 if (!IS_LDT_ENTRY_FREE(SELECTOR_TO_ENTRY(sel
)+i
)) break;
174 if (i
< newcount
) /* they are not free */
177 sel
= AllocSelectorArray( newcount
);
179 else /* mark the selectors as allocated */
181 for (i
= oldcount
; i
< newcount
; i
++)
182 ldt_flags_copy
[SELECTOR_TO_ENTRY(sel
)+i
] |=LDT_FLAGS_ALLOCATED
;
185 else if (oldcount
> newcount
) /* We need to remove selectors */
187 memset( &entry
, 0, sizeof(entry
) ); /* clear the LDT entries */
188 for (i
= oldcount
; i
< newcount
; i
++)
190 LDT_SetEntry( SELECTOR_TO_ENTRY(sel
) + i
, &entry
);
191 ldt_flags_copy
[SELECTOR_TO_ENTRY(sel
) + i
] &= ~LDT_FLAGS_ALLOCATED
;
194 if (sel
) SELECTOR_SetEntries( sel
, base
, size
, type
, is32bit
, readonly
);
199 /***********************************************************************
200 * PrestoChangoSelector (KERNEL.177)
202 WORD
PrestoChangoSelector( WORD selSrc
, WORD selDst
)
205 LDT_GetEntry( SELECTOR_TO_ENTRY( selSrc
), &entry
);
206 entry
.type
^= SEGMENT_CODE
; /* toggle the executable bit */
207 LDT_SetEntry( SELECTOR_TO_ENTRY( selDst
), &entry
);
212 /***********************************************************************
213 * AllocCStoDSAlias (KERNEL.170)
215 WORD
AllocCStoDSAlias( WORD sel
)
220 newsel
= AllocSelectorArray( 1 );
221 dprintf_selector( stddeb
, "AllocCStoDSAlias(%04x): returning %04x\n",
223 if (!newsel
) return 0;
224 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
225 entry
.type
= SEGMENT_DATA
;
226 LDT_SetEntry( SELECTOR_TO_ENTRY(newsel
), &entry
);
231 /***********************************************************************
232 * AllocDStoCSAlias (KERNEL.171)
234 WORD
AllocDStoCSAlias( WORD sel
)
239 newsel
= AllocSelectorArray( 1 );
240 dprintf_selector( stddeb
, "AllocDStoCSAlias(%04x): returning %04x\n",
242 if (!newsel
) return 0;
243 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
244 entry
.type
= SEGMENT_CODE
;
245 LDT_SetEntry( SELECTOR_TO_ENTRY(newsel
), &entry
);
250 /***********************************************************************
251 * LongPtrAdd (KERNEL.180)
253 void LongPtrAdd( DWORD ptr
, DWORD add
)
256 LDT_GetEntry( SELECTOR_TO_ENTRY(SELECTOROF(ptr
)), &entry
);
258 LDT_SetEntry( SELECTOR_TO_ENTRY(SELECTOROF(ptr
)), &entry
);
262 /***********************************************************************
263 * GetSelectorBase (KERNEL.186)
265 DWORD
GetSelectorBase( WORD sel
)
267 return GET_SEL_BASE(sel
);
271 /***********************************************************************
272 * SetSelectorBase (KERNEL.187)
274 WORD
SetSelectorBase( WORD sel
, DWORD base
)
277 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
279 LDT_SetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
284 /***********************************************************************
285 * GetSelectorLimit (KERNEL.188)
287 DWORD
GetSelectorLimit( WORD sel
)
289 return GET_SEL_LIMIT(sel
);
293 /***********************************************************************
294 * SetSelectorLimit (KERNEL.189)
296 WORD
SetSelectorLimit( WORD sel
, DWORD limit
)
299 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
301 LDT_SetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
306 /***********************************************************************
307 * SelectorAccessRights (KERNEL.196)
309 WORD
SelectorAccessRights( WORD sel
, WORD op
, WORD val
)
312 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
313 if (op
== 0) /* get */
315 return 0x01 | /* accessed */
316 0x10 | /* not system */
319 ((entry
.read_only
== 0) << 1) |
321 (entry
.seg_32bit
<< 14) |
322 (entry
.limit_in_pages
<< 15);
326 entry
.read_only
= ((val
& 2) == 0);
327 entry
.type
= (val
>> 2) & 3;
328 entry
.seg_32bit
= val
& 0x4000;
329 entry
.limit_in_pages
= val
& 0x8000;
330 LDT_SetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
336 /***********************************************************************
337 * IsBadCodePtr (KERNEL.336)
339 BOOL
IsBadCodePtr( SEGPTR lpfn
)
344 sel
= SELECTOROF(lpfn
);
345 if (!sel
) return TRUE
;
346 if (IS_SELECTOR_FREE(sel
)) return TRUE
;
347 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
348 if (entry
.type
!= SEGMENT_CODE
) return TRUE
;
349 if (OFFSETOF(lpfn
) > entry
.limit
) return TRUE
;
354 /***********************************************************************
355 * IsBadStringPtr (KERNEL.337)
357 BOOL
IsBadStringPtr( SEGPTR ptr
, WORD size
)
362 sel
= SELECTOROF(ptr
);
363 if (!sel
) return TRUE
;
364 if (IS_SELECTOR_FREE(sel
)) return TRUE
;
365 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
366 if ((entry
.type
== SEGMENT_CODE
) && entry
.read_only
) return TRUE
;
367 if (strlen(PTR_SEG_TO_LIN(ptr
)) < size
) size
= strlen(PTR_SEG_TO_LIN(ptr
));
368 if (OFFSETOF(ptr
) + size
- 1 > entry
.limit
) return TRUE
;
373 /***********************************************************************
374 * IsBadHugeReadPtr (KERNEL.346)
376 BOOL
IsBadHugeReadPtr( SEGPTR ptr
, DWORD size
)
381 sel
= SELECTOROF(ptr
);
382 if (!sel
) return TRUE
;
383 if (IS_SELECTOR_FREE(sel
)) return TRUE
;
384 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
385 if ((entry
.type
== SEGMENT_CODE
) && entry
.read_only
) return TRUE
;
386 if (OFFSETOF(ptr
) + size
- 1 > entry
.limit
) return TRUE
;
391 /***********************************************************************
392 * IsBadHugeWritePtr (KERNEL.347)
394 BOOL
IsBadHugeWritePtr( SEGPTR ptr
, DWORD size
)
399 sel
= SELECTOROF(ptr
);
400 if (!sel
) return TRUE
;
401 if (IS_SELECTOR_FREE(sel
)) return TRUE
;
402 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
403 if ((entry
.type
== SEGMENT_CODE
) || entry
.read_only
) return TRUE
;
404 if (OFFSETOF(ptr
) + size
- 1 > entry
.limit
) return TRUE
;
408 /***********************************************************************
409 * IsBadReadPtr (KERNEL.334)
411 BOOL
IsBadReadPtr( SEGPTR ptr
, WORD size
)
413 return IsBadHugeReadPtr( ptr
, size
);
417 /***********************************************************************
418 * IsBadWritePtr (KERNEL.335)
420 BOOL
IsBadWritePtr( SEGPTR ptr
, WORD size
)
422 return IsBadHugeWritePtr( ptr
, size
);
426 /***********************************************************************
427 * MemoryRead (TOOLHELP.78)
429 DWORD
MemoryRead( WORD sel
, DWORD offset
, void *buffer
, DWORD count
)
431 if (IS_SELECTOR_FREE(sel
)) return 0;
432 if (offset
> GET_SEL_LIMIT(sel
)) return 0;
433 if (offset
+ count
> GET_SEL_LIMIT(sel
) + 1)
434 count
= GET_SEL_LIMIT(sel
) + 1 - offset
;
435 memcpy( buffer
, ((char *)GET_SEL_BASE(sel
)) + offset
, count
);
440 /***********************************************************************
441 * MemoryWrite (TOOLHELP.79)
443 DWORD
MemoryWrite( WORD sel
, DWORD offset
, void *buffer
, DWORD count
)
445 if (IS_SELECTOR_FREE(sel
)) return 0;
446 if (offset
> GET_SEL_LIMIT(sel
)) return 0;
447 if (offset
+ count
> GET_SEL_LIMIT(sel
) + 1)
448 count
= GET_SEL_LIMIT(sel
) + 1 - offset
;
449 memcpy( ((char *)GET_SEL_BASE(sel
)) + offset
, buffer
, count
);
454 SEGPTR
MAKE_SEGPTR(void * ptr
)
462 if (!((unsigned)ptr
& 0xffff0000)) {
463 fprintf(stderr
, "Invalid pointer %p has been passed to MAKE_SEGPTR. This was\n", ptr
);
464 fprintf(stderr
, "probably caused by an unnecessary call to PTR_SEG_TO_LIN.\n");
465 fprintf(stderr
, "Forcing call to debugger\n");
468 result
= (SEGPTR
) (IF1632_Stack32_base
) +
469 ((DWORD
)(ptr
) - (DWORD
) PTR_SEG_TO_LIN(IF1632_Stack32_base
));
470 if (PTR_SEG_TO_LIN(result
) == ptr
)
473 for (entry
= 0; entry
< LDT_SIZE
; entry
++) {
474 if (ldt_copy
[entry
].base
&&
475 (ldt_copy
[entry
].limit
< 0x10000) &&
476 ((unsigned) ptr
>= ldt_copy
[entry
].base
) &&
477 ((unsigned) ptr
< (ldt_copy
[entry
].base
+ ldt_copy
[entry
].limit
))) {
478 return ((ENTRY_TO_SELECTOR(entry
) << 16) |
479 ((unsigned) ptr
- ldt_copy
[entry
].base
));
482 entry
= SELECTOR_AllocBlock((void *)((unsigned)ptr
& 0xffff0000), 0x10000, SEGMENT_DATA
, 0, 0);
483 return ((entry
<< 16) | ((unsigned) ptr
& 0xffff));