Release 960818
[wine/hacks.git] / memory / selector.c
blob98a6ea9babe416a29895201e25e9c49ffc31a7c7
1 /*
2 * Selector manipulation functions
4 * Copyright 1995 Alexandre Julliard
5 */
7 #include <string.h>
8 #include "windows.h"
9 #include "ldt.h"
10 #include "selectors.h"
11 #include "stackframe.h"
12 #include "stddebug.h"
13 #include "debug.h"
16 #define FIRST_LDT_ENTRY_TO_ALLOC 6
19 /***********************************************************************
20 * AllocSelectorArray (KERNEL.206)
22 WORD AllocSelectorArray( WORD count )
24 WORD i, size = 0;
26 if (!count) return 0;
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",
49 sel, newsel );
50 if (!newsel) return 0;
51 if (!sel) return newsel; /* nothing to copy */
52 for (i = 0; i < count; i++)
54 ldt_entry entry;
55 LDT_GetEntry( SELECTOR_TO_ENTRY(sel) + i, &entry );
56 LDT_SetEntry( SELECTOR_TO_ENTRY(newsel) + i, &entry );
58 return newsel;
62 /***********************************************************************
63 * FreeSelector (KERNEL.176)
65 WORD FreeSelector( WORD sel )
67 if (IS_SELECTOR_FREE(sel)) return sel; /* error */
68 SELECTOR_FreeBlock( sel, 1 );
69 return 0;
73 /***********************************************************************
74 * SELECTOR_SetEntries
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,
80 BOOL32 readonly )
82 ldt_entry entry;
83 WORD i, count;
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;
88 entry.type = type;
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 )
116 WORD sel, count;
118 if (!size) return 0;
119 count = (size + 0xffff) / 0x10000;
120 sel = AllocSelectorArray( count );
121 if (sel) SELECTOR_SetEntries( sel, base, size, type, is32bit, readonly );
122 return sel;
126 /***********************************************************************
127 * SELECTOR_FreeBlock
129 * Free a block of selectors.
131 void SELECTOR_FreeBlock( WORD sel, WORD count )
133 WORD i, nextsel;
134 ldt_entry entry;
135 STACK16FRAME *frame;
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;
149 while (frame)
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;
168 if (!size) size = 1;
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;
176 else
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 );
197 return sel;
201 /***********************************************************************
202 * PrestoChangoSelector (KERNEL.177)
204 WORD PrestoChangoSelector( WORD selSrc, WORD selDst )
206 ldt_entry entry;
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 );
210 return selDst;
214 /***********************************************************************
215 * AllocCStoDSAlias (KERNEL.170)
217 WORD AllocCStoDSAlias( WORD sel )
219 WORD newsel;
220 ldt_entry entry;
222 newsel = AllocSelectorArray( 1 );
223 dprintf_selector( stddeb, "AllocCStoDSAlias(%04x): returning %04x\n",
224 sel, newsel );
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 );
229 return newsel;
233 /***********************************************************************
234 * AllocDStoCSAlias (KERNEL.171)
236 WORD AllocDStoCSAlias( WORD sel )
238 WORD newsel;
239 ldt_entry entry;
241 newsel = AllocSelectorArray( 1 );
242 dprintf_selector( stddeb, "AllocDStoCSAlias(%04x): returning %04x\n",
243 sel, newsel );
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 );
248 return newsel;
252 /***********************************************************************
253 * LongPtrAdd (KERNEL.180)
255 void LongPtrAdd( DWORD ptr, DWORD add )
257 ldt_entry entry;
258 LDT_GetEntry( SELECTOR_TO_ENTRY(SELECTOROF(ptr)), &entry );
259 entry.base += add;
260 LDT_SetEntry( SELECTOR_TO_ENTRY(SELECTOROF(ptr)), &entry );
264 /***********************************************************************
265 * GetSelectorBase (KERNEL.186)
267 DWORD GetSelectorBase( WORD sel )
269 extern char* DOSMEM_dosmem;
270 DWORD base;
272 base = GET_SEL_BASE(sel);
274 #ifndef WINELIB
275 /* if base points into DOSMEM, assume we have to
276 * return pointer into physical lower 1MB
278 if ((base >= (DWORD)DOSMEM_dosmem) &&
279 (base < ((DWORD)DOSMEM_dosmem+0x100000)))
280 base = base - (DWORD)DOSMEM_dosmem;
281 #endif
282 return base;
286 /***********************************************************************
287 * SetSelectorBase (KERNEL.187)
289 WORD SetSelectorBase( WORD sel, DWORD base )
291 extern char* DOSMEM_dosmem;
292 ldt_entry entry;
294 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
295 #ifndef WINELIB
296 if (base < 0x100000)
298 /* Assume pointers in the lower 1MB range are
299 * in fact physical addresses into DOS memory.
300 * Translate the base to our internal representation
302 * (NETAPI.DLL of Win95 does use SetSelectorBase this way)
304 entry.base = (DWORD)(DOSMEM_dosmem+base);
306 else entry.base = base;
307 #endif
308 LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
309 return sel;
313 /***********************************************************************
314 * GetSelectorLimit (KERNEL.188)
316 DWORD GetSelectorLimit( WORD sel )
318 return GET_SEL_LIMIT(sel);
322 /***********************************************************************
323 * SetSelectorLimit (KERNEL.189)
325 WORD SetSelectorLimit( WORD sel, DWORD limit )
327 ldt_entry entry;
328 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
329 entry.limit_in_pages = (limit >= 0x100000);
330 if (entry.limit_in_pages) entry.limit = limit >> 12;
331 else entry.limit = limit;
332 LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
333 return sel;
337 /***********************************************************************
338 * SelectorAccessRights (KERNEL.196)
340 WORD SelectorAccessRights( WORD sel, WORD op, WORD val )
342 ldt_entry entry;
343 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
344 if (op == 0) /* get */
346 return 0x01 | /* accessed */
347 0x10 | /* not system */
348 0x60 | /* DPL 3 */
349 0x80 | /* present */
350 ((entry.read_only == 0) << 1) |
351 (entry.type << 2) |
352 (entry.seg_32bit << 14) |
353 (entry.limit_in_pages << 15);
355 else /* set */
357 entry.read_only = ((val & 2) == 0);
358 entry.type = (val >> 2) & 3;
359 entry.seg_32bit = val & 0x4000;
360 entry.limit_in_pages = val & 0x8000;
361 LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
362 return 0;
367 /***********************************************************************
368 * IsBadCodePtr (KERNEL.336)
370 BOOL IsBadCodePtr( SEGPTR lpfn )
372 WORD sel;
373 ldt_entry entry;
375 sel = SELECTOROF(lpfn);
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) return TRUE;
380 if (OFFSETOF(lpfn) > entry.limit) return TRUE;
381 return FALSE;
385 /***********************************************************************
386 * IsBadStringPtr (KERNEL.337)
388 BOOL IsBadStringPtr( SEGPTR ptr, WORD size )
390 WORD sel;
391 ldt_entry entry;
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 (strlen(PTR_SEG_TO_LIN(ptr)) < size) size = strlen(PTR_SEG_TO_LIN(ptr));
399 if (OFFSETOF(ptr) + size - 1 > entry.limit) return TRUE;
400 return FALSE;
404 /***********************************************************************
405 * IsBadHugeReadPtr (KERNEL.346)
407 BOOL IsBadHugeReadPtr( SEGPTR ptr, DWORD size )
409 WORD sel;
410 ldt_entry entry;
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;
418 return FALSE;
422 /***********************************************************************
423 * IsBadHugeWritePtr (KERNEL.347)
425 BOOL IsBadHugeWritePtr( SEGPTR ptr, DWORD size )
427 WORD sel;
428 ldt_entry entry;
430 sel = SELECTOROF(ptr);
431 if (!sel) return TRUE;
432 if (IS_SELECTOR_FREE(sel)) return TRUE;
433 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
434 if ((entry.type == SEGMENT_CODE) || entry.read_only) return TRUE;
435 if (OFFSETOF(ptr) + size - 1 > entry.limit) return TRUE;
436 return FALSE;
439 /***********************************************************************
440 * IsBadReadPtr (KERNEL.334)
442 BOOL IsBadReadPtr( SEGPTR ptr, WORD size )
444 return IsBadHugeReadPtr( ptr, size );
448 /***********************************************************************
449 * IsBadWritePtr (KERNEL.335)
451 BOOL IsBadWritePtr( SEGPTR ptr, WORD size )
453 return IsBadHugeWritePtr( ptr, size );
457 /***********************************************************************
458 * MemoryRead (TOOLHELP.78)
460 DWORD MemoryRead( WORD sel, DWORD offset, void *buffer, DWORD count )
462 if (IS_SELECTOR_FREE(sel)) return 0;
463 if (offset > GET_SEL_LIMIT(sel)) return 0;
464 if (offset + count > GET_SEL_LIMIT(sel) + 1)
465 count = GET_SEL_LIMIT(sel) + 1 - offset;
466 memcpy( buffer, ((char *)GET_SEL_BASE(sel)) + offset, count );
467 return count;
471 /***********************************************************************
472 * MemoryWrite (TOOLHELP.79)
474 DWORD MemoryWrite( 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( ((char *)GET_SEL_BASE(sel)) + offset, buffer, count );
481 return count;