Release 960728
[wine/multimedia.git] / memory / selector.c
blobecf7df432fa54b54485fad313dfcce0d18003a2d
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, nextsel;
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 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 */
85 frame = CURRENT_STACK16;
86 while (frame)
88 if ((frame->ds >= sel) && (frame->ds < nextsel)) frame->ds = 0;
89 if ((frame->es >= sel) && (frame->es < nextsel)) frame->es = 0;
90 frame = PTR_SEG_OFF_TO_LIN(frame->saved_ss, frame->saved_sp);
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, BOOL32 is32bit,
103 BOOL32 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 /* Make sure base and limit are not 0 together if the size is not 0 */
118 if (!base && !entry.limit && size) entry.limit = 1;
119 count = (size + 0xffff) / 0x10000;
120 for (i = 0; i < count; i++)
122 LDT_SetEntry( SELECTOR_TO_ENTRY(sel) + i, &entry );
123 entry.base += 0x10000;
124 /* Apparently the next selectors should *not* get a 64k limit. */
125 /* Can't remember where I read they should... --AJ */
126 entry.limit -= entry.limit_in_pages ? 0x10 : 0x10000;
131 /***********************************************************************
132 * SELECTOR_AllocBlock
134 * Allocate selectors for a block of linear memory.
136 WORD SELECTOR_AllocBlock( const void *base, DWORD size, enum seg_type type,
137 BOOL32 is32bit, BOOL32 readonly )
139 WORD sel, count;
141 if (!size) return 0;
142 count = (size + 0xffff) / 0x10000;
143 sel = AllocSelectorArray( count );
144 if (sel) SELECTOR_SetEntries( sel, base, size, type, is32bit, readonly );
145 return sel;
149 /***********************************************************************
150 * SELECTOR_ReallocBlock
152 * Change the size of a block of selectors.
154 WORD SELECTOR_ReallocBlock( WORD sel, const void *base, DWORD size,
155 enum seg_type type, BOOL32 is32bit, BOOL32 readonly)
157 WORD i, oldcount, newcount;
158 ldt_entry entry;
160 if (!size) size = 1;
161 oldcount = (GET_SEL_LIMIT(sel) >> 16) + 1;
162 newcount = (size + 0xffff) >> 16;
164 if (oldcount < newcount) /* We need to add selectors */
166 /* Check if the next selectors are free */
167 if (SELECTOR_TO_ENTRY(sel) + newcount > LDT_SIZE) i = oldcount;
168 else
169 for (i = oldcount; i < newcount; i++)
170 if (!IS_LDT_ENTRY_FREE(SELECTOR_TO_ENTRY(sel)+i)) break;
172 if (i < newcount) /* they are not free */
174 FreeSelector( sel );
175 sel = AllocSelectorArray( newcount );
177 else /* mark the selectors as allocated */
179 for (i = oldcount; i < newcount; i++)
180 ldt_flags_copy[SELECTOR_TO_ENTRY(sel)+i] |=LDT_FLAGS_ALLOCATED;
183 else if (oldcount > newcount) /* We need to remove selectors */
185 memset( &entry, 0, sizeof(entry) ); /* clear the LDT entries */
186 for (i = oldcount; i < newcount; i++)
188 LDT_SetEntry( SELECTOR_TO_ENTRY(sel) + i, &entry );
189 ldt_flags_copy[SELECTOR_TO_ENTRY(sel) + i] &= ~LDT_FLAGS_ALLOCATED;
192 if (sel) SELECTOR_SetEntries( sel, base, size, type, is32bit, readonly );
193 return sel;
197 /***********************************************************************
198 * PrestoChangoSelector (KERNEL.177)
200 WORD PrestoChangoSelector( WORD selSrc, WORD selDst )
202 ldt_entry entry;
203 LDT_GetEntry( SELECTOR_TO_ENTRY( selSrc ), &entry );
204 entry.type ^= SEGMENT_CODE; /* toggle the executable bit */
205 LDT_SetEntry( SELECTOR_TO_ENTRY( selDst ), &entry );
206 return selDst;
210 /***********************************************************************
211 * AllocCStoDSAlias (KERNEL.170)
213 WORD AllocCStoDSAlias( WORD sel )
215 WORD newsel;
216 ldt_entry entry;
218 newsel = AllocSelectorArray( 1 );
219 dprintf_selector( stddeb, "AllocCStoDSAlias(%04x): returning %04x\n",
220 sel, newsel );
221 if (!newsel) return 0;
222 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
223 entry.type = SEGMENT_DATA;
224 LDT_SetEntry( SELECTOR_TO_ENTRY(newsel), &entry );
225 return newsel;
229 /***********************************************************************
230 * AllocDStoCSAlias (KERNEL.171)
232 WORD AllocDStoCSAlias( WORD sel )
234 WORD newsel;
235 ldt_entry entry;
237 newsel = AllocSelectorArray( 1 );
238 dprintf_selector( stddeb, "AllocDStoCSAlias(%04x): returning %04x\n",
239 sel, newsel );
240 if (!newsel) return 0;
241 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
242 entry.type = SEGMENT_CODE;
243 LDT_SetEntry( SELECTOR_TO_ENTRY(newsel), &entry );
244 return newsel;
248 /***********************************************************************
249 * LongPtrAdd (KERNEL.180)
251 void LongPtrAdd( DWORD ptr, DWORD add )
253 ldt_entry entry;
254 LDT_GetEntry( SELECTOR_TO_ENTRY(SELECTOROF(ptr)), &entry );
255 entry.base += add;
256 LDT_SetEntry( SELECTOR_TO_ENTRY(SELECTOROF(ptr)), &entry );
260 /***********************************************************************
261 * GetSelectorBase (KERNEL.186)
263 DWORD GetSelectorBase( WORD sel )
265 extern char* DOSMEM_dosmem;
266 DWORD base;
268 base = GET_SEL_BASE(sel);
270 #ifndef WINELIB
271 /* if base points into DOSMEM, assume we have to
272 * return pointer into physical lower 1MB
274 if ((base >= (DWORD)DOSMEM_dosmem) &&
275 (base < ((DWORD)DOSMEM_dosmem+0x100000)))
276 base = base - (DWORD)DOSMEM_dosmem;
277 #endif
278 return base;
282 /***********************************************************************
283 * SetSelectorBase (KERNEL.187)
285 WORD SetSelectorBase( WORD sel, DWORD base )
287 extern char* DOSMEM_dosmem;
288 ldt_entry entry;
290 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
291 #ifndef WINELIB
292 if (base < 0x100000)
294 /* Assume pointers in the lower 1MB range are
295 * in fact physical addresses into DOS memory.
296 * Translate the base to our internal representation
298 * (NETAPI.DLL of Win95 does use SetSelectorBase this way)
300 entry.base = (DWORD)(DOSMEM_dosmem+base);
302 else entry.base = base;
303 #endif
304 LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
305 return sel;
309 /***********************************************************************
310 * GetSelectorLimit (KERNEL.188)
312 DWORD GetSelectorLimit( WORD sel )
314 return GET_SEL_LIMIT(sel);
318 /***********************************************************************
319 * SetSelectorLimit (KERNEL.189)
321 WORD SetSelectorLimit( WORD sel, DWORD limit )
323 ldt_entry entry;
324 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
325 entry.limit_in_pages = (limit >= 0x100000);
326 if (entry.limit_in_pages) entry.limit = limit >> 12;
327 else entry.limit = limit;
328 LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
329 return sel;
333 /***********************************************************************
334 * SelectorAccessRights (KERNEL.196)
336 WORD SelectorAccessRights( WORD sel, WORD op, WORD val )
338 ldt_entry entry;
339 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
340 if (op == 0) /* get */
342 return 0x01 | /* accessed */
343 0x10 | /* not system */
344 0x60 | /* DPL 3 */
345 0x80 | /* present */
346 ((entry.read_only == 0) << 1) |
347 (entry.type << 2) |
348 (entry.seg_32bit << 14) |
349 (entry.limit_in_pages << 15);
351 else /* set */
353 entry.read_only = ((val & 2) == 0);
354 entry.type = (val >> 2) & 3;
355 entry.seg_32bit = val & 0x4000;
356 entry.limit_in_pages = val & 0x8000;
357 LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
358 return 0;
363 /***********************************************************************
364 * IsBadCodePtr (KERNEL.336)
366 BOOL IsBadCodePtr( SEGPTR lpfn )
368 WORD sel;
369 ldt_entry entry;
371 sel = SELECTOROF(lpfn);
372 if (!sel) return TRUE;
373 if (IS_SELECTOR_FREE(sel)) return TRUE;
374 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
375 if (entry.type != SEGMENT_CODE) return TRUE;
376 if (OFFSETOF(lpfn) > entry.limit) return TRUE;
377 return FALSE;
381 /***********************************************************************
382 * IsBadStringPtr (KERNEL.337)
384 BOOL IsBadStringPtr( SEGPTR ptr, WORD size )
386 WORD sel;
387 ldt_entry entry;
389 sel = SELECTOROF(ptr);
390 if (!sel) return TRUE;
391 if (IS_SELECTOR_FREE(sel)) return TRUE;
392 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
393 if ((entry.type == SEGMENT_CODE) && entry.read_only) return TRUE;
394 if (strlen(PTR_SEG_TO_LIN(ptr)) < size) size = strlen(PTR_SEG_TO_LIN(ptr));
395 if (OFFSETOF(ptr) + size - 1 > entry.limit) return TRUE;
396 return FALSE;
400 /***********************************************************************
401 * IsBadHugeReadPtr (KERNEL.346)
403 BOOL IsBadHugeReadPtr( SEGPTR ptr, DWORD size )
405 WORD sel;
406 ldt_entry entry;
408 sel = SELECTOROF(ptr);
409 if (!sel) return TRUE;
410 if (IS_SELECTOR_FREE(sel)) return TRUE;
411 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
412 if ((entry.type == SEGMENT_CODE) && entry.read_only) return TRUE;
413 if (OFFSETOF(ptr) + size - 1 > entry.limit) return TRUE;
414 return FALSE;
418 /***********************************************************************
419 * IsBadHugeWritePtr (KERNEL.347)
421 BOOL IsBadHugeWritePtr( SEGPTR ptr, DWORD size )
423 WORD sel;
424 ldt_entry entry;
426 sel = SELECTOROF(ptr);
427 if (!sel) return TRUE;
428 if (IS_SELECTOR_FREE(sel)) return TRUE;
429 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
430 if ((entry.type == SEGMENT_CODE) || entry.read_only) return TRUE;
431 if (OFFSETOF(ptr) + size - 1 > entry.limit) return TRUE;
432 return FALSE;
435 /***********************************************************************
436 * IsBadReadPtr (KERNEL.334)
438 BOOL IsBadReadPtr( SEGPTR ptr, WORD size )
440 return IsBadHugeReadPtr( ptr, size );
444 /***********************************************************************
445 * IsBadWritePtr (KERNEL.335)
447 BOOL IsBadWritePtr( SEGPTR ptr, WORD size )
449 return IsBadHugeWritePtr( ptr, size );
453 /***********************************************************************
454 * MemoryRead (TOOLHELP.78)
456 DWORD MemoryRead( 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( buffer, ((char *)GET_SEL_BASE(sel)) + offset, count );
463 return count;
467 /***********************************************************************
468 * MemoryWrite (TOOLHELP.79)
470 DWORD MemoryWrite( WORD sel, DWORD offset, void *buffer, DWORD count )
472 if (IS_SELECTOR_FREE(sel)) return 0;
473 if (offset > GET_SEL_LIMIT(sel)) return 0;
474 if (offset + count > GET_SEL_LIMIT(sel) + 1)
475 count = GET_SEL_LIMIT(sel) + 1 - offset;
476 memcpy( ((char *)GET_SEL_BASE(sel)) + offset, buffer, count );
477 return count;
480 #ifndef WINELIB
481 SEGPTR MAKE_SEGPTR(void * ptr)
484 SEGPTR result;
485 int entry;
487 if (!ptr)
488 return ptr;
489 if (!((unsigned)ptr & 0xffff0000)) {
490 fprintf(stderr, "Invalid pointer %p has been passed to MAKE_SEGPTR. This was\n", ptr);
491 fprintf(stderr, "probably caused by an unnecessary call to PTR_SEG_TO_LIN.\n");
492 fprintf(stderr, "Forcing call to debugger\n");
493 ptr = *(void **)0;
495 result = (SEGPTR) (IF1632_Stack32_base) +
496 ((DWORD)(ptr) - (DWORD) PTR_SEG_TO_LIN(IF1632_Stack32_base));
497 if (PTR_SEG_TO_LIN(result) == ptr)
498 return result;
500 for (entry = 0; entry < LDT_SIZE; entry++) {
501 if (ldt_copy[entry].base &&
502 (ldt_copy[entry].limit < 0x10000) &&
503 ((unsigned) ptr >= ldt_copy[entry].base) &&
504 ((unsigned) ptr < (ldt_copy[entry].base + ldt_copy[entry].limit))) {
505 return ((ENTRY_TO_SELECTOR(entry) << 16) |
506 ((unsigned) ptr - ldt_copy[entry].base));
509 entry = SELECTOR_AllocBlock((void *)((unsigned)ptr & 0xffff0000), 0x10000, SEGMENT_DATA, 0, 0);
510 return ((entry << 16) | ((unsigned) ptr & 0xffff));
512 #endif