2 * Selector manipulation functions
4 * Copyright 1995 Alexandre Julliard
10 #include "selectors.h"
11 #include "stackframe.h"
16 #define FIRST_LDT_ENTRY_TO_ALLOC 17
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 if (IS_SELECTOR_FREE(sel
)) return sel
; /* error */
68 SELECTOR_FreeBlock( sel
, 1 );
73 /***********************************************************************
76 * Set the LDT entries for an array of selectors.
78 static void SELECTOR_SetEntries( WORD sel
, const void *base
, DWORD size
,
79 enum seg_type type
, BOOL32 is32bit
,
85 /* The limit for the first selector is the whole */
86 /* block. The next selectors get a 64k limit. */
87 entry
.base
= (unsigned long)base
;
89 entry
.seg_32bit
= is32bit
;
90 entry
.read_only
= readonly
;
91 entry
.limit_in_pages
= (size
> 0x100000);
92 if (entry
.limit_in_pages
) entry
.limit
= ((size
+ 0xfff) >> 12) - 1;
93 else entry
.limit
= size
- 1;
94 /* Make sure base and limit are not 0 together if the size is not 0 */
95 if (!base
&& !entry
.limit
&& size
) entry
.limit
= 1;
96 count
= (size
+ 0xffff) / 0x10000;
97 for (i
= 0; i
< count
; i
++)
99 LDT_SetEntry( SELECTOR_TO_ENTRY(sel
) + i
, &entry
);
100 entry
.base
+= 0x10000;
101 /* Apparently the next selectors should *not* get a 64k limit. */
102 /* Can't remember where I read they should... --AJ */
103 entry
.limit
-= entry
.limit_in_pages
? 0x10 : 0x10000;
108 /***********************************************************************
109 * SELECTOR_AllocBlock
111 * Allocate selectors for a block of linear memory.
113 WORD
SELECTOR_AllocBlock( const void *base
, DWORD size
, enum seg_type type
,
114 BOOL32 is32bit
, BOOL32 readonly
)
119 count
= (size
+ 0xffff) / 0x10000;
120 sel
= AllocSelectorArray( count
);
121 if (sel
) SELECTOR_SetEntries( sel
, base
, size
, type
, is32bit
, readonly
);
126 /***********************************************************************
129 * Free a block of selectors.
131 void SELECTOR_FreeBlock( WORD sel
, WORD count
)
137 dprintf_selector( stddeb
, "SELECTOR_FreeBlock(%04x,%d)\n", sel
, count
);
138 sel
&= ~(__AHINCR
- 1); /* clear bottom bits of selector */
139 nextsel
= sel
+ (count
<< __AHSHIFT
);
140 memset( &entry
, 0, sizeof(entry
) ); /* clear the LDT entries */
141 for (i
= SELECTOR_TO_ENTRY(sel
); count
; i
++, count
--)
143 LDT_SetEntry( i
, &entry
);
144 ldt_flags_copy
[i
] &= ~LDT_FLAGS_ALLOCATED
;
147 /* Clear the saved 16-bit selector */
148 frame
= CURRENT_STACK16
;
151 if ((frame
->ds
>= sel
) && (frame
->ds
< nextsel
)) frame
->ds
= 0;
152 if ((frame
->es
>= sel
) && (frame
->es
< nextsel
)) frame
->es
= 0;
153 frame
= PTR_SEG_OFF_TO_LIN(frame
->saved_ss
, frame
->saved_sp
);
158 /***********************************************************************
159 * SELECTOR_ReallocBlock
161 * Change the size of a block of selectors.
163 WORD
SELECTOR_ReallocBlock( WORD sel
, const void *base
, DWORD size
,
164 enum seg_type type
, BOOL32 is32bit
, BOOL32 readonly
)
166 WORD i
, oldcount
, newcount
;
169 oldcount
= (GET_SEL_LIMIT(sel
) >> 16) + 1;
170 newcount
= (size
+ 0xffff) >> 16;
172 if (oldcount
< newcount
) /* We need to add selectors */
174 /* Check if the next selectors are free */
175 if (SELECTOR_TO_ENTRY(sel
) + newcount
> LDT_SIZE
) i
= oldcount
;
177 for (i
= oldcount
; i
< newcount
; i
++)
178 if (!IS_LDT_ENTRY_FREE(SELECTOR_TO_ENTRY(sel
)+i
)) break;
180 if (i
< newcount
) /* they are not free */
182 SELECTOR_FreeBlock( sel
, oldcount
);
183 sel
= AllocSelectorArray( newcount
);
185 else /* mark the selectors as allocated */
187 for (i
= oldcount
; i
< newcount
; i
++)
188 ldt_flags_copy
[SELECTOR_TO_ENTRY(sel
)+i
] |=LDT_FLAGS_ALLOCATED
;
191 else if (oldcount
> newcount
) /* We need to remove selectors */
193 SELECTOR_FreeBlock( ENTRY_TO_SELECTOR(SELECTOR_TO_ENTRY(sel
)+newcount
),
194 oldcount
- newcount
);
196 if (sel
) SELECTOR_SetEntries( sel
, base
, size
, type
, is32bit
, readonly
);
201 /***********************************************************************
202 * PrestoChangoSelector (KERNEL.177)
204 WORD
PrestoChangoSelector( WORD selSrc
, WORD selDst
)
207 LDT_GetEntry( SELECTOR_TO_ENTRY( selSrc
), &entry
);
208 entry
.type
^= SEGMENT_CODE
; /* toggle the executable bit */
209 LDT_SetEntry( SELECTOR_TO_ENTRY( selDst
), &entry
);
214 /***********************************************************************
215 * AllocCStoDSAlias (KERNEL.170)
217 WORD
AllocCStoDSAlias( WORD sel
)
222 newsel
= AllocSelectorArray( 1 );
223 dprintf_selector( stddeb
, "AllocCStoDSAlias(%04x): returning %04x\n",
225 if (!newsel
) return 0;
226 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
227 entry
.type
= SEGMENT_DATA
;
228 LDT_SetEntry( SELECTOR_TO_ENTRY(newsel
), &entry
);
233 /***********************************************************************
234 * AllocDStoCSAlias (KERNEL.171)
236 WORD
AllocDStoCSAlias( WORD sel
)
241 newsel
= AllocSelectorArray( 1 );
242 dprintf_selector( stddeb
, "AllocDStoCSAlias(%04x): returning %04x\n",
244 if (!newsel
) return 0;
245 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
246 entry
.type
= SEGMENT_CODE
;
247 LDT_SetEntry( SELECTOR_TO_ENTRY(newsel
), &entry
);
252 /***********************************************************************
253 * LongPtrAdd (KERNEL.180)
255 void LongPtrAdd( DWORD ptr
, DWORD add
)
258 LDT_GetEntry( SELECTOR_TO_ENTRY(SELECTOROF(ptr
)), &entry
);
260 LDT_SetEntry( SELECTOR_TO_ENTRY(SELECTOROF(ptr
)), &entry
);
264 /***********************************************************************
265 * GetSelectorBase (KERNEL.186)
267 DWORD
GetSelectorBase( WORD sel
)
269 DWORD base
= GET_SEL_BASE(sel
);
271 /* if base points into DOSMEM, assume we have to
272 * return pointer into physical lower 1MB */
274 return DOSMEM_MapLinearToDos( (LPVOID
)base
);
278 /***********************************************************************
279 * SetSelectorBase (KERNEL.187)
281 WORD
SetSelectorBase( WORD sel
, DWORD base
)
285 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
287 entry
.base
= (DWORD
)DOSMEM_MapDosToLinear(base
);
289 LDT_SetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
294 /***********************************************************************
295 * GetSelectorLimit (KERNEL.188)
297 DWORD
GetSelectorLimit( WORD sel
)
299 return GET_SEL_LIMIT(sel
);
303 /***********************************************************************
304 * SetSelectorLimit (KERNEL.189)
306 WORD
SetSelectorLimit( WORD sel
, DWORD limit
)
309 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
310 entry
.limit_in_pages
= (limit
>= 0x100000);
311 if (entry
.limit_in_pages
) entry
.limit
= limit
>> 12;
312 else entry
.limit
= limit
;
313 LDT_SetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
318 /***********************************************************************
319 * SelectorAccessRights (KERNEL.196)
321 WORD
SelectorAccessRights( WORD sel
, WORD op
, WORD val
)
324 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
325 if (op
== 0) /* get */
327 return 0x01 | /* accessed */
328 0x10 | /* not system */
331 ((entry
.read_only
== 0) << 1) |
333 (entry
.seg_32bit
<< 14) |
334 (entry
.limit_in_pages
<< 15);
338 entry
.read_only
= ((val
& 2) == 0);
339 entry
.type
= (val
>> 2) & 3;
340 entry
.seg_32bit
= val
& 0x4000;
341 entry
.limit_in_pages
= val
& 0x8000;
342 LDT_SetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
348 /***********************************************************************
349 * IsBadCodePtr16 (KERNEL.336)
351 BOOL16
IsBadCodePtr16( SEGPTR lpfn
)
356 sel
= SELECTOROF(lpfn
);
357 if (!sel
) return TRUE
;
358 if (IS_SELECTOR_FREE(sel
)) return TRUE
;
359 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
360 if (entry
.type
!= SEGMENT_CODE
) return TRUE
;
361 if (OFFSETOF(lpfn
) > entry
.limit
) return TRUE
;
366 /***********************************************************************
367 * IsBadStringPtr16 (KERNEL.337)
369 BOOL16
IsBadStringPtr16( SEGPTR ptr
, UINT16 size
)
374 sel
= SELECTOROF(ptr
);
375 if (!sel
) return TRUE
;
376 if (IS_SELECTOR_FREE(sel
)) return TRUE
;
377 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
378 if ((entry
.type
== SEGMENT_CODE
) && entry
.read_only
) return TRUE
;
379 if (strlen(PTR_SEG_TO_LIN(ptr
)) < size
) size
= strlen(PTR_SEG_TO_LIN(ptr
));
380 if (OFFSETOF(ptr
) + size
- 1 > entry
.limit
) return TRUE
;
385 /***********************************************************************
386 * IsBadHugeReadPtr16 (KERNEL.346)
388 BOOL16
IsBadHugeReadPtr16( SEGPTR ptr
, DWORD size
)
393 sel
= SELECTOROF(ptr
);
394 if (!sel
) return TRUE
;
395 if (IS_SELECTOR_FREE(sel
)) return TRUE
;
396 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
397 if ((entry
.type
== SEGMENT_CODE
) && entry
.read_only
) return TRUE
;
398 if (OFFSETOF(ptr
) + size
- 1 > entry
.limit
) return TRUE
;
403 /***********************************************************************
404 * IsBadHugeWritePtr16 (KERNEL.347)
406 BOOL16
IsBadHugeWritePtr16( SEGPTR ptr
, DWORD size
)
411 sel
= SELECTOROF(ptr
);
412 if (!sel
) return TRUE
;
413 if (IS_SELECTOR_FREE(sel
)) return TRUE
;
414 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
415 if ((entry
.type
== SEGMENT_CODE
) || entry
.read_only
) return TRUE
;
416 if (OFFSETOF(ptr
) + size
- 1 > entry
.limit
) return TRUE
;
420 /***********************************************************************
421 * IsBadReadPtr16 (KERNEL.334)
423 BOOL16
IsBadReadPtr16( SEGPTR ptr
, UINT16 size
)
425 return IsBadHugeReadPtr16( ptr
, size
);
429 /***********************************************************************
430 * IsBadWritePtr16 (KERNEL.335)
432 BOOL16
IsBadWritePtr16( SEGPTR ptr
, UINT16 size
)
434 return IsBadHugeWritePtr16( ptr
, size
);
438 /***********************************************************************
439 * MemoryRead (TOOLHELP.78)
441 DWORD
MemoryRead( WORD sel
, DWORD offset
, void *buffer
, DWORD count
)
443 if (IS_SELECTOR_FREE(sel
)) return 0;
444 if (offset
> GET_SEL_LIMIT(sel
)) return 0;
445 if (offset
+ count
> GET_SEL_LIMIT(sel
) + 1)
446 count
= GET_SEL_LIMIT(sel
) + 1 - offset
;
447 memcpy( buffer
, ((char *)GET_SEL_BASE(sel
)) + offset
, count
);
452 /***********************************************************************
453 * MemoryWrite (TOOLHELP.79)
455 DWORD
MemoryWrite( WORD sel
, DWORD offset
, void *buffer
, DWORD count
)
457 if (IS_SELECTOR_FREE(sel
)) return 0;
458 if (offset
> GET_SEL_LIMIT(sel
)) return 0;
459 if (offset
+ count
> GET_SEL_LIMIT(sel
) + 1)
460 count
= GET_SEL_LIMIT(sel
) + 1 - offset
;
461 memcpy( ((char *)GET_SEL_BASE(sel
)) + offset
, buffer
, count
);