Release 960131
[wine/multimedia.git] / memory / selector.c
blobbbf2e441349125790d5cf0d1edaef7d3a6de7c4c
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 WORD i, count;
68 ldt_entry entry;
69 STACK16FRAME *frame;
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 memset( &entry, 0, sizeof(entry) ); /* clear the LDT entries */
75 /* FIXME: is it correct to free the whole array? */
76 for (i = SELECTOR_TO_ENTRY(sel); count; i++, count--)
78 LDT_SetEntry( i, &entry );
79 ldt_flags_copy[i] &= ~LDT_FLAGS_ALLOCATED;
82 /* Clear the saved 16-bit selector */
83 #ifndef WINELIB
84 frame = CURRENT_STACK16;
85 while (frame)
87 if (frame->ds == sel) frame->ds = 0;
88 if (frame->es == sel) frame->es = 0;
89 frame = PTR_SEG_OFF_TO_LIN(frame->saved_ss, frame->saved_sp);
91 #endif
92 return 0;
96 /***********************************************************************
97 * SELECTOR_SetEntries
99 * Set the LDT entries for an array of selectors.
101 static void SELECTOR_SetEntries( WORD sel, const void *base, DWORD size,
102 enum seg_type type, BOOL is32bit,
103 BOOL readonly )
105 ldt_entry entry;
106 WORD i, count;
108 /* The limit for the first selector is the whole */
109 /* block. The next selectors get a 64k limit. */
110 entry.base = (unsigned long)base;
111 entry.type = type;
112 entry.seg_32bit = is32bit;
113 entry.read_only = readonly;
114 entry.limit_in_pages = (size > 0x100000);
115 if (entry.limit_in_pages) entry.limit = ((size + 0xfff) >> 12) - 1;
116 else entry.limit = size - 1;
117 count = (size + 0xffff) / 0x10000;
118 for (i = 0; i < count; i++)
120 LDT_SetEntry( SELECTOR_TO_ENTRY(sel) + i, &entry );
121 entry.base += 0x10000;
122 size -= 0x10000;
123 entry.limit = (size > 0x10000) ? 0xffff : size-1;
124 entry.limit_in_pages = 0;
129 /***********************************************************************
130 * SELECTOR_AllocBlock
132 * Allocate selectors for a block of linear memory.
134 WORD SELECTOR_AllocBlock( const void *base, DWORD size, enum seg_type type,
135 BOOL is32bit, BOOL readonly )
137 WORD sel, count;
139 if (!size) return 0;
140 count = (size + 0xffff) / 0x10000;
141 sel = AllocSelectorArray( count );
142 if (sel) SELECTOR_SetEntries( sel, base, size, type, is32bit, readonly );
143 return sel;
147 /***********************************************************************
148 * SELECTOR_ReallocBlock
150 * Change the size of a block of selectors.
152 WORD SELECTOR_ReallocBlock( WORD sel, const void *base, DWORD size,
153 enum seg_type type, BOOL is32bit, BOOL readonly )
155 WORD i, oldcount, newcount;
156 ldt_entry entry;
158 if (!size) size = 1;
159 oldcount = (GET_SEL_LIMIT(sel) >> 16) + 1;
160 newcount = (size + 0xffff) >> 16;
162 if (oldcount < newcount) /* We need to add selectors */
164 /* Check if the next selectors are free */
165 if (SELECTOR_TO_ENTRY(sel) + newcount > LDT_SIZE) i = oldcount;
166 else
167 for (i = oldcount; i < newcount; i++)
168 if (!IS_LDT_ENTRY_FREE(SELECTOR_TO_ENTRY(sel)+i)) break;
170 if (i < newcount) /* they are not free */
172 FreeSelector( sel );
173 sel = AllocSelectorArray( newcount );
175 else /* mark the selectors as allocated */
177 for (i = oldcount; i < newcount; i++)
178 ldt_flags_copy[SELECTOR_TO_ENTRY(sel)+i] |=LDT_FLAGS_ALLOCATED;
181 else if (oldcount > newcount) /* We need to remove selectors */
183 memset( &entry, 0, sizeof(entry) ); /* clear the LDT entries */
184 for (i = oldcount; i < newcount; i++)
186 LDT_SetEntry( SELECTOR_TO_ENTRY(sel) + i, &entry );
187 ldt_flags_copy[SELECTOR_TO_ENTRY(sel) + i] &= ~LDT_FLAGS_ALLOCATED;
190 if (sel) SELECTOR_SetEntries( sel, base, size, type, is32bit, readonly );
191 return sel;
195 /***********************************************************************
196 * PrestoChangoSelector (KERNEL.177)
198 WORD PrestoChangoSelector( WORD selSrc, WORD selDst )
200 ldt_entry entry;
201 LDT_GetEntry( SELECTOR_TO_ENTRY( selSrc ), &entry );
202 entry.type ^= SEGMENT_CODE; /* toggle the executable bit */
203 LDT_SetEntry( SELECTOR_TO_ENTRY( selDst ), &entry );
204 return selDst;
208 /***********************************************************************
209 * AllocCStoDSAlias (KERNEL.170)
211 WORD AllocCStoDSAlias( WORD sel )
213 WORD newsel;
214 ldt_entry entry;
216 newsel = AllocSelectorArray( 1 );
217 dprintf_selector( stddeb, "AllocCStoDSAlias(%04x): returning %04x\n",
218 sel, newsel );
219 if (!newsel) return 0;
220 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
221 entry.type = SEGMENT_DATA;
222 LDT_SetEntry( SELECTOR_TO_ENTRY(newsel), &entry );
223 return newsel;
227 /***********************************************************************
228 * AllocDStoCSAlias (KERNEL.171)
230 WORD AllocDStoCSAlias( WORD sel )
232 WORD newsel;
233 ldt_entry entry;
235 newsel = AllocSelectorArray( 1 );
236 dprintf_selector( stddeb, "AllocDStoCSAlias(%04x): returning %04x\n",
237 sel, newsel );
238 if (!newsel) return 0;
239 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
240 entry.type = SEGMENT_CODE;
241 LDT_SetEntry( SELECTOR_TO_ENTRY(newsel), &entry );
242 return newsel;
246 /***********************************************************************
247 * LongPtrAdd (KERNEL.180)
249 void LongPtrAdd( DWORD ptr, DWORD add )
251 ldt_entry entry;
252 LDT_GetEntry( SELECTOR_TO_ENTRY(SELECTOROF(ptr)), &entry );
253 entry.base += add;
254 LDT_SetEntry( SELECTOR_TO_ENTRY(SELECTOROF(ptr)), &entry );
258 /***********************************************************************
259 * GetSelectorBase (KERNEL.186)
261 DWORD GetSelectorBase( WORD sel )
263 return GET_SEL_BASE(sel);
267 /***********************************************************************
268 * SetSelectorBase (KERNEL.187)
270 WORD SetSelectorBase( WORD sel, DWORD base )
272 ldt_entry entry;
273 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
274 entry.base = base;
275 LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
276 return sel;
280 /***********************************************************************
281 * GetSelectorLimit (KERNEL.188)
283 DWORD GetSelectorLimit( WORD sel )
285 return GET_SEL_LIMIT(sel);
289 /***********************************************************************
290 * SetSelectorLimit (KERNEL.189)
292 WORD SetSelectorLimit( WORD sel, DWORD limit )
294 ldt_entry entry;
295 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
296 entry.limit = limit;
297 LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
298 return sel;
302 /***********************************************************************
303 * SelectorAccessRights (KERNEL.196)
305 WORD SelectorAccessRights( WORD sel, WORD op, WORD val )
307 ldt_entry entry;
308 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
309 if (op == 0) /* get */
311 return 1 /* accessed */ |
312 ((entry.read_only == 0) << 1) |
313 (entry.type << 2) |
314 (entry.seg_32bit << 14) |
315 (entry.limit_in_pages << 15);
317 else /* set */
319 entry.read_only = ((val & 2) == 0);
320 entry.type = (val >> 2) & 3;
321 entry.seg_32bit = val & 0x4000;
322 entry.limit_in_pages = val & 0x8000;
323 LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
324 return 0;
329 /***********************************************************************
330 * IsBadCodePtr (KERNEL.336)
332 BOOL IsBadCodePtr( SEGPTR lpfn )
334 WORD sel;
335 ldt_entry entry;
337 sel = SELECTOROF(lpfn);
338 if (!sel) return TRUE;
339 if (IS_SELECTOR_FREE(sel)) return TRUE;
340 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
341 if (entry.type != SEGMENT_CODE) return TRUE;
342 if (OFFSETOF(lpfn) > entry.limit) return TRUE;
343 return FALSE;
347 /***********************************************************************
348 * IsBadStringPtr (KERNEL.337)
350 BOOL IsBadStringPtr( SEGPTR ptr, WORD size )
352 WORD sel;
353 ldt_entry entry;
355 sel = SELECTOROF(ptr);
356 if (!sel) return TRUE;
357 if (IS_SELECTOR_FREE(sel)) return TRUE;
358 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
359 if ((entry.type == SEGMENT_CODE) && entry.read_only) return TRUE;
360 if (strlen(PTR_SEG_TO_LIN(ptr)) < size) size = strlen(PTR_SEG_TO_LIN(ptr));
361 if (OFFSETOF(ptr) + size - 1 > entry.limit) return TRUE;
362 return FALSE;
366 /***********************************************************************
367 * IsBadHugeReadPtr (KERNEL.346)
369 BOOL IsBadHugeReadPtr( SEGPTR ptr, DWORD size )
371 WORD sel;
372 ldt_entry entry;
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 (OFFSETOF(ptr) + size - 1 > entry.limit) return TRUE;
380 return FALSE;
384 /***********************************************************************
385 * IsBadHugeWritePtr (KERNEL.347)
387 BOOL IsBadHugeWritePtr( SEGPTR ptr, DWORD size )
389 WORD sel;
390 ldt_entry entry;
392 sel = SELECTOROF(ptr);
393 if (!sel) return TRUE;
394 if (IS_SELECTOR_FREE(sel)) return TRUE;
395 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
396 if ((entry.type == SEGMENT_CODE) || entry.read_only) return TRUE;
397 if (OFFSETOF(ptr) + size - 1 > entry.limit) return TRUE;
398 return FALSE;
401 /***********************************************************************
402 * IsBadReadPtr (KERNEL.334)
404 BOOL IsBadReadPtr( SEGPTR ptr, WORD size )
406 return IsBadHugeReadPtr( ptr, size );
410 /***********************************************************************
411 * IsBadWritePtr (KERNEL.335)
413 BOOL IsBadWritePtr( SEGPTR ptr, WORD size )
415 return IsBadHugeWritePtr( ptr, size );
419 /***********************************************************************
420 * MemoryRead (TOOLHELP.78)
422 DWORD MemoryRead( WORD sel, DWORD offset, void *buffer, DWORD count )
424 if (IS_SELECTOR_FREE(sel)) return 0;
425 if (offset > GET_SEL_LIMIT(sel)) return 0;
426 if (offset + count > GET_SEL_LIMIT(sel) + 1)
427 count = GET_SEL_LIMIT(sel) + 1 - offset;
428 memcpy( buffer, ((char *)GET_SEL_BASE(sel)) + offset, count );
429 return count;
433 /***********************************************************************
434 * MemoryWrite (TOOLHELP.79)
436 DWORD MemoryWrite( WORD sel, DWORD offset, void *buffer, DWORD count )
438 if (IS_SELECTOR_FREE(sel)) return 0;
439 if (offset > GET_SEL_LIMIT(sel)) return 0;
440 if (offset + count > GET_SEL_LIMIT(sel) + 1)
441 count = GET_SEL_LIMIT(sel) + 1 - offset;
442 memcpy( ((char *)GET_SEL_BASE(sel)) + offset, buffer, count );
443 return count;
446 #ifndef WINELIB
447 SEGPTR MAKE_SEGPTR(void * ptr)
450 SEGPTR result;
451 int entry;
453 if (!ptr)
454 return ptr;
455 if (!((unsigned)ptr & 0xffff0000)) {
456 fprintf(stderr, "Invalid pointer %08x has been passed to MAKE_SEGPTR. This was\n", ptr);
457 fprintf(stderr, "probably caused by an unnecessary call to PTR_SEG_TO_LIN.\n");
458 fprintf(stderr, "Forcing call to debugger\n");
459 ptr = *(void **)0;
461 result = (SEGPTR) (IF1632_Stack32_base) +
462 ((DWORD)(ptr) - (DWORD) PTR_SEG_TO_LIN(IF1632_Stack32_base));
463 if (PTR_SEG_TO_LIN(result) == ptr)
464 return result;
466 for (entry = 0; entry < LDT_SIZE; entry++) {
467 if (ldt_copy[entry].base &&
468 (ldt_copy[entry].limit < 0x10000) &&
469 ((unsigned) ptr >= ldt_copy[entry].base) &&
470 ((unsigned) ptr < (ldt_copy[entry].base + ldt_copy[entry].limit))) {
471 return ((ENTRY_TO_SELECTOR(entry) << 16) |
472 ((unsigned) ptr - ldt_copy[entry].base));
475 entry = SELECTOR_AllocBlock((void *)((unsigned)ptr & 0xffff0000), 0x10000, SEGMENT_DATA, 0, 0);
476 return ((entry << 16) | ((unsigned) ptr & 0xffff));
478 #endif