Release 950727
[wine/multimedia.git] / memory / selector.c
blob1959c712c31651af8148436d9574dd2fa26a3d39
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;
70 dprintf_selector( stddeb, "FreeSelector(%04x)\n", sel );
71 if (IS_SELECTOR_FREE(sel)) return sel; /* error */
72 count = (GET_SEL_LIMIT(sel) >> 16) + 1;
73 memset( &entry, 0, sizeof(entry) ); /* clear the LDT entries */
74 /* FIXME: is it correct to free the whole array? */
75 for (i = SELECTOR_TO_ENTRY(sel); count; i++, count--)
77 LDT_SetEntry( i, &entry );
78 ldt_flags_copy[i] &= ~LDT_FLAGS_ALLOCATED;
81 /* Clear the saved 16-bit selector */
82 #ifndef WINELIB
83 if (CURRENT_STACK16)
85 /* FIXME: maybe we ought to walk up the stack and fix all frames */
86 if (CURRENT_STACK16->ds == sel) CURRENT_STACK16->ds = 0;
87 if (CURRENT_STACK16->es == sel) CURRENT_STACK16->es = 0;
89 #endif
90 return 0;
94 /***********************************************************************
95 * SELECTOR_SetEntries
97 * Set the LDT entries for an array of selectors.
99 static void SELECTOR_SetEntries( WORD sel, void *base, DWORD size,
100 enum seg_type type, BOOL is32bit,
101 BOOL readonly )
103 ldt_entry entry;
104 WORD i, count;
106 /* The limit for the first selector is the whole */
107 /* block. The next selectors get a 64k limit. */
108 entry.base = (unsigned long)base;
109 entry.type = type;
110 entry.seg_32bit = is32bit;
111 entry.read_only = readonly;
112 entry.limit_in_pages = (size > 0x100000);
113 if (entry.limit_in_pages) entry.limit = ((size + 0xfff) >> 12) - 1;
114 else entry.limit = size - 1;
115 count = (size + 0xffff) / 0x10000;
116 for (i = 0; i < count; i++)
118 LDT_SetEntry( SELECTOR_TO_ENTRY(sel) + i, &entry );
119 entry.base += 0x10000;
120 size -= 0x10000;
121 entry.limit = (size > 0x10000) ? 0xffff : size-1;
122 entry.limit_in_pages = 0;
127 /***********************************************************************
128 * SELECTOR_AllocBlock
130 * Allocate selectors for a block of linear memory.
132 WORD SELECTOR_AllocBlock( void *base, DWORD size, enum seg_type type,
133 BOOL is32bit, BOOL readonly )
135 WORD sel, count;
137 if (!size) return 0;
138 count = (size + 0xffff) / 0x10000;
139 sel = AllocSelectorArray( count );
140 if (sel) SELECTOR_SetEntries( sel, base, size, type, is32bit, readonly );
141 return sel;
145 /***********************************************************************
146 * SELECTOR_ReallocBlock
148 * Change the size of a block of selectors.
150 WORD SELECTOR_ReallocBlock( WORD sel, void *base, DWORD size,
151 enum seg_type type, BOOL is32bit, BOOL readonly )
153 WORD i, oldcount, newcount;
154 ldt_entry entry;
156 if (!size) size = 1;
157 oldcount = (GET_SEL_LIMIT(sel) >> 16) + 1;
158 newcount = (size + 0xffff) >> 16;
160 if (oldcount < newcount) /* We need to add selectors */
162 /* Check if the next selectors are free */
163 if (SELECTOR_TO_ENTRY(sel) + newcount > LDT_SIZE) i = oldcount;
164 else
165 for (i = oldcount; i < newcount; i++)
166 if (!IS_LDT_ENTRY_FREE(SELECTOR_TO_ENTRY(sel)+i)) break;
168 if (i < newcount) /* they are not free */
170 FreeSelector( sel );
171 sel = AllocSelectorArray( newcount );
173 else /* mark the selectors as allocated */
175 for (i = oldcount; i < newcount; i++)
176 ldt_flags_copy[SELECTOR_TO_ENTRY(sel)+i] |=LDT_FLAGS_ALLOCATED;
179 else if (oldcount > newcount) /* We need to remove selectors */
181 memset( &entry, 0, sizeof(entry) ); /* clear the LDT entries */
182 for (i = oldcount; i < newcount; i++)
184 LDT_SetEntry( SELECTOR_TO_ENTRY(sel) + i, &entry );
185 ldt_flags_copy[SELECTOR_TO_ENTRY(sel) + i] &= ~LDT_FLAGS_ALLOCATED;
188 if (sel) SELECTOR_SetEntries( sel, base, size, type, is32bit, readonly );
189 return sel;
193 /***********************************************************************
194 * PrestoChangoSelector (KERNEL.177)
196 WORD PrestoChangoSelector( WORD selSrc, WORD selDst )
198 ldt_entry entry;
199 LDT_GetEntry( SELECTOR_TO_ENTRY( selSrc ), &entry );
200 entry.type ^= SEGMENT_CODE; /* toggle the executable bit */
201 LDT_SetEntry( SELECTOR_TO_ENTRY( selDst ), &entry );
202 return selDst;
206 /***********************************************************************
207 * AllocCStoDSAlias (KERNEL.170)
209 WORD AllocCStoDSAlias( WORD sel )
211 WORD newsel;
212 ldt_entry entry;
214 newsel = AllocSelectorArray( 1 );
215 dprintf_selector( stddeb, "AllocCStoDSAlias(%04x): returning %04x\n",
216 sel, newsel );
217 if (!newsel) return 0;
218 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
219 entry.type = SEGMENT_DATA;
220 LDT_SetEntry( SELECTOR_TO_ENTRY(newsel), &entry );
221 return newsel;
225 /***********************************************************************
226 * AllocDStoCSAlias (KERNEL.171)
228 WORD AllocDStoCSAlias( WORD sel )
230 WORD newsel;
231 ldt_entry entry;
233 newsel = AllocSelectorArray( 1 );
234 dprintf_selector( stddeb, "AllocDStoCSAlias(%04x): returning %04x\n",
235 sel, newsel );
236 if (!newsel) return 0;
237 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
238 entry.type = SEGMENT_CODE;
239 LDT_SetEntry( SELECTOR_TO_ENTRY(newsel), &entry );
240 return newsel;
244 /***********************************************************************
245 * LongPtrAdd (KERNEL.180)
247 void LongPtrAdd( DWORD ptr, DWORD add )
249 ldt_entry entry;
250 LDT_GetEntry( SELECTOR_TO_ENTRY(SELECTOROF(ptr)), &entry );
251 entry.base += add;
252 LDT_SetEntry( SELECTOR_TO_ENTRY(SELECTOROF(ptr)), &entry );
256 /***********************************************************************
257 * GetSelectorBase (KERNEL.186)
259 DWORD GetSelectorBase( WORD sel )
261 return GET_SEL_BASE(sel);
265 /***********************************************************************
266 * SetSelectorBase (KERNEL.187)
268 WORD SetSelectorBase( WORD sel, DWORD base )
270 ldt_entry entry;
271 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
272 entry.base = base;
273 LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
274 return sel;
278 /***********************************************************************
279 * GetSelectorLimit (KERNEL.188)
281 DWORD GetSelectorLimit( WORD sel )
283 return GET_SEL_LIMIT(sel);
287 /***********************************************************************
288 * SetSelectorLimit (KERNEL.189)
290 WORD SetSelectorLimit( WORD sel, DWORD limit )
292 ldt_entry entry;
293 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
294 entry.limit = limit;
295 LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
296 return sel;
300 /***********************************************************************
301 * SelectorAccessRights (KERNEL.196)
303 WORD SelectorAccessRights( WORD sel, WORD op, WORD val )
305 ldt_entry entry;
306 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
307 if (op == 0) /* get */
309 return 1 /* accessed */ |
310 (entry.read_only << 1) |
311 (entry.type << 2) |
312 (entry.seg_32bit << 14) |
313 (entry.limit_in_pages << 15);
315 else /* set */
317 entry.read_only = val & 2;
318 entry.type = (val >> 2) & 3;
319 entry.seg_32bit = val & 0x4000;
320 entry.limit_in_pages = val & 0x8000;
321 LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
322 return 0;
327 /***********************************************************************
328 * IsBadCodePtr (KERNEL.336)
330 BOOL IsBadCodePtr( SEGPTR lpfn )
332 WORD sel;
333 ldt_entry entry;
335 sel = SELECTOROF(lpfn);
336 if (!sel) return TRUE;
337 if (IS_SELECTOR_FREE(sel)) return TRUE;
338 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
339 if (entry.type != SEGMENT_CODE) return TRUE;
340 if (OFFSETOF(lpfn) > entry.limit) return TRUE;
341 return FALSE;
345 /***********************************************************************
346 * IsBadStringPtr (KERNEL.337)
348 BOOL IsBadStringPtr( SEGPTR ptr, WORD size )
350 WORD sel;
351 ldt_entry entry;
353 sel = SELECTOROF(ptr);
354 if (!sel) return TRUE;
355 if (IS_SELECTOR_FREE(sel)) return TRUE;
356 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
357 if ((entry.type == SEGMENT_CODE) && entry.read_only) return TRUE;
358 if (strlen(PTR_SEG_TO_LIN(ptr)) < size) size = strlen(PTR_SEG_TO_LIN(ptr));
359 if (OFFSETOF(ptr) + size > entry.limit) return TRUE;
360 return FALSE;
364 /***********************************************************************
365 * IsBadHugeReadPtr (KERNEL.346)
367 BOOL IsBadHugeReadPtr( SEGPTR ptr, DWORD size )
369 WORD sel;
370 ldt_entry entry;
372 sel = SELECTOROF(ptr);
373 if (!sel) return TRUE;
374 if (IS_SELECTOR_FREE(sel)) return TRUE;
375 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
376 if ((entry.type == SEGMENT_CODE) && entry.read_only) return TRUE;
377 if (OFFSETOF(ptr) + size > entry.limit) return TRUE;
378 return FALSE;
382 /***********************************************************************
383 * IsBadHugeWritePtr (KERNEL.347)
385 BOOL IsBadHugeWritePtr( SEGPTR ptr, DWORD size )
387 WORD sel;
388 ldt_entry entry;
390 sel = SELECTOROF(ptr);
391 if (!sel) return TRUE;
392 if (IS_SELECTOR_FREE(sel)) return TRUE;
393 LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
394 if ((entry.type == SEGMENT_CODE) || entry.read_only) return TRUE;
395 if (OFFSETOF(ptr) + size > entry.limit) return TRUE;
396 return FALSE;
399 /***********************************************************************
400 * IsBadReadPtr (KERNEL.334)
402 BOOL IsBadReadPtr( SEGPTR ptr, WORD size )
404 return IsBadHugeReadPtr( ptr, size );
408 /***********************************************************************
409 * IsBadWritePtr (KERNEL.335)
411 BOOL IsBadWritePtr( SEGPTR ptr, WORD size )
413 return IsBadHugeWritePtr( ptr, size );
417 /***********************************************************************
418 * MemoryRead (TOOLHELP.78)
420 DWORD MemoryRead( WORD sel, DWORD offset, void *buffer, DWORD count )
422 if (IS_SELECTOR_FREE(sel)) return 0;
423 if (offset > GET_SEL_LIMIT(sel)) return 0;
424 if (offset + count > GET_SEL_LIMIT(sel) + 1)
425 count = GET_SEL_LIMIT(sel) + 1 - offset;
426 memcpy( buffer, ((char *)GET_SEL_BASE(sel)) + offset, count );
427 return count;
431 /***********************************************************************
432 * MemoryWrite (TOOLHELP.79)
434 DWORD MemoryWrite( WORD sel, DWORD offset, void *buffer, DWORD count )
436 if (IS_SELECTOR_FREE(sel)) return 0;
437 if (offset > GET_SEL_LIMIT(sel)) return 0;
438 if (offset + count > GET_SEL_LIMIT(sel) + 1)
439 count = GET_SEL_LIMIT(sel) + 1 - offset;
440 memcpy( ((char *)GET_SEL_BASE(sel)) + offset, buffer, count );
441 return count;