Release 960712
[wine] / memory / selector.c
1 /*
2  * Selector manipulation functions
3  *
4  * Copyright 1995 Alexandre Julliard
5  */
6
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"
14
15
16 #define FIRST_LDT_ENTRY_TO_ALLOC  6
17
18
19 /***********************************************************************
20  *           AllocSelectorArray   (KERNEL.206)
21  */
22 WORD AllocSelectorArray( WORD count )
23 {
24     WORD i, size = 0;
25
26     if (!count) return 0;
27     for (i = FIRST_LDT_ENTRY_TO_ALLOC; i < LDT_SIZE; i++)
28     {
29         if (!IS_LDT_ENTRY_FREE(i)) size = 0;
30         else if (++size >= count) break;
31     }
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 );
36 }
37
38
39 /***********************************************************************
40  *           AllocSelector   (KERNEL.175)
41  */
42 WORD AllocSelector( WORD sel )
43 {
44     WORD newsel, count, i;
45
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++)
53     {
54         ldt_entry entry;
55         LDT_GetEntry( SELECTOR_TO_ENTRY(sel) + i, &entry );
56         LDT_SetEntry( SELECTOR_TO_ENTRY(newsel) + i, &entry );
57     }
58     return newsel;
59 }
60
61
62 /***********************************************************************
63  *           FreeSelector   (KERNEL.176)
64  */
65 WORD FreeSelector( WORD sel )
66 {
67     WORD i, count, nextsel;
68     ldt_entry entry;
69     STACK16FRAME *frame;
70
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--)
79     {
80         LDT_SetEntry( i, &entry );
81         ldt_flags_copy[i] &= ~LDT_FLAGS_ALLOCATED;
82     }
83
84     /* Clear the saved 16-bit selector */
85 #ifndef WINELIB
86     frame = CURRENT_STACK16;
87     while (frame)
88     {
89         if ((frame->ds >= sel) && (frame->ds < nextsel)) frame->ds = 0;
90         if ((frame->es >= sel) && (frame->es < nextsel)) frame->es = 0;
91         frame = PTR_SEG_OFF_TO_LIN(frame->saved_ss, frame->saved_sp);
92     }
93 #endif
94     return 0;
95 }
96
97
98 /***********************************************************************
99  *           SELECTOR_SetEntries
100  *
101  * Set the LDT entries for an array of selectors.
102  */
103 static void SELECTOR_SetEntries( WORD sel, const void *base, DWORD size,
104                                  enum seg_type type, BOOL32 is32bit,
105                                  BOOL32 readonly )
106 {
107     ldt_entry entry;
108     WORD i, count;
109
110     /* The limit for the first selector is the whole */
111     /* block. The next selectors get a 64k limit.    */
112     entry.base           = (unsigned long)base;
113     entry.type           = type;
114     entry.seg_32bit      = is32bit;
115     entry.read_only      = readonly;
116     entry.limit_in_pages = (size > 0x100000);
117     if (entry.limit_in_pages) entry.limit = ((size + 0xfff) >> 12) - 1;
118     else entry.limit = size - 1;
119     /* Make sure base and limit are not 0 together if the size is not 0 */
120     if (!base && !entry.limit && size) entry.limit = 1;
121     count = (size + 0xffff) / 0x10000;
122     for (i = 0; i < count; i++)
123     {
124         LDT_SetEntry( SELECTOR_TO_ENTRY(sel) + i, &entry );
125         entry.base += 0x10000;
126         /* Apparently the next selectors should *not* get a 64k limit. */
127         /* Can't remember where I read they should... --AJ */
128         entry.limit -= entry.limit_in_pages ? 0x10 : 0x10000;
129     }
130 }
131
132
133 /***********************************************************************
134  *           SELECTOR_AllocBlock
135  *
136  * Allocate selectors for a block of linear memory.
137  */
138 WORD SELECTOR_AllocBlock( const void *base, DWORD size, enum seg_type type,
139                           BOOL32 is32bit, BOOL32 readonly )
140 {
141     WORD sel, count;
142
143     if (!size) return 0;
144     count = (size + 0xffff) / 0x10000;
145     sel = AllocSelectorArray( count );
146     if (sel) SELECTOR_SetEntries( sel, base, size, type, is32bit, readonly );
147     return sel;
148 }
149
150
151 /***********************************************************************
152  *           SELECTOR_ReallocBlock
153  *
154  * Change the size of a block of selectors.
155  */
156 WORD SELECTOR_ReallocBlock( WORD sel, const void *base, DWORD size,
157                            enum seg_type type, BOOL32 is32bit, BOOL32 readonly)
158 {
159     WORD i, oldcount, newcount;
160     ldt_entry entry;
161
162     if (!size) size = 1;
163     oldcount = (GET_SEL_LIMIT(sel) >> 16) + 1;
164     newcount = (size + 0xffff) >> 16;
165
166     if (oldcount < newcount)  /* We need to add selectors */
167     {
168           /* Check if the next selectors are free */
169         if (SELECTOR_TO_ENTRY(sel) + newcount > LDT_SIZE) i = oldcount;
170         else
171             for (i = oldcount; i < newcount; i++)
172                 if (!IS_LDT_ENTRY_FREE(SELECTOR_TO_ENTRY(sel)+i)) break;
173
174         if (i < newcount)  /* they are not free */
175         {
176             FreeSelector( sel );
177             sel = AllocSelectorArray( newcount );
178         }
179         else  /* mark the selectors as allocated */
180         {
181             for (i = oldcount; i < newcount; i++)
182                 ldt_flags_copy[SELECTOR_TO_ENTRY(sel)+i] |=LDT_FLAGS_ALLOCATED;
183         }
184     }
185     else if (oldcount > newcount) /* We need to remove selectors */
186     {
187         memset( &entry, 0, sizeof(entry) );  /* clear the LDT entries */
188         for (i = oldcount; i < newcount; i++)
189         {
190             LDT_SetEntry( SELECTOR_TO_ENTRY(sel) + i, &entry );
191             ldt_flags_copy[SELECTOR_TO_ENTRY(sel) + i] &= ~LDT_FLAGS_ALLOCATED;
192         }
193     }
194     if (sel) SELECTOR_SetEntries( sel, base, size, type, is32bit, readonly );
195     return sel;
196 }
197
198
199 /***********************************************************************
200  *           PrestoChangoSelector   (KERNEL.177)
201  */
202 WORD PrestoChangoSelector( WORD selSrc, WORD selDst )
203 {
204     ldt_entry entry;
205     LDT_GetEntry( SELECTOR_TO_ENTRY( selSrc ), &entry );
206     entry.type ^= SEGMENT_CODE;  /* toggle the executable bit */
207     LDT_SetEntry( SELECTOR_TO_ENTRY( selDst ), &entry );
208     return selDst;
209 }
210
211
212 /***********************************************************************
213  *           AllocCStoDSAlias   (KERNEL.170)
214  */
215 WORD AllocCStoDSAlias( WORD sel )
216 {
217     WORD newsel;
218     ldt_entry entry;
219
220     newsel = AllocSelectorArray( 1 );
221     dprintf_selector( stddeb, "AllocCStoDSAlias(%04x): returning %04x\n",
222                       sel, newsel );
223     if (!newsel) return 0;
224     LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
225     entry.type = SEGMENT_DATA;
226     LDT_SetEntry( SELECTOR_TO_ENTRY(newsel), &entry );
227     return newsel;
228 }
229
230
231 /***********************************************************************
232  *           AllocDStoCSAlias   (KERNEL.171)
233  */
234 WORD AllocDStoCSAlias( WORD sel )
235 {
236     WORD newsel;
237     ldt_entry entry;
238
239     newsel = AllocSelectorArray( 1 );
240     dprintf_selector( stddeb, "AllocDStoCSAlias(%04x): returning %04x\n",
241                       sel, newsel );
242     if (!newsel) return 0;
243     LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
244     entry.type = SEGMENT_CODE;
245     LDT_SetEntry( SELECTOR_TO_ENTRY(newsel), &entry );
246     return newsel;
247 }
248
249
250 /***********************************************************************
251  *           LongPtrAdd   (KERNEL.180)
252  */
253 void LongPtrAdd( DWORD ptr, DWORD add )
254 {
255     ldt_entry entry;
256     LDT_GetEntry( SELECTOR_TO_ENTRY(SELECTOROF(ptr)), &entry );
257     entry.base += add;
258     LDT_SetEntry( SELECTOR_TO_ENTRY(SELECTOROF(ptr)), &entry );
259 }
260
261
262 /***********************************************************************
263  *           GetSelectorBase   (KERNEL.186)
264  */
265 DWORD GetSelectorBase( WORD sel )
266 {
267     return GET_SEL_BASE(sel);
268 }
269
270
271 /***********************************************************************
272  *           SetSelectorBase   (KERNEL.187)
273  */
274 WORD SetSelectorBase( WORD sel, DWORD base )
275 {
276     ldt_entry entry;
277     LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
278     entry.base = base;
279     LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
280     return sel;
281 }
282
283
284 /***********************************************************************
285  *           GetSelectorLimit   (KERNEL.188)
286  */
287 DWORD GetSelectorLimit( WORD sel )
288 {
289     return GET_SEL_LIMIT(sel);
290 }
291
292
293 /***********************************************************************
294  *           SetSelectorLimit   (KERNEL.189)
295  */
296 WORD SetSelectorLimit( WORD sel, DWORD limit )
297 {
298     ldt_entry entry;
299     LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
300     entry.limit = limit;
301     LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
302     return sel;
303 }
304
305
306 /***********************************************************************
307  *           SelectorAccessRights   (KERNEL.196)
308  */
309 WORD SelectorAccessRights( WORD sel, WORD op, WORD val )
310 {
311     ldt_entry entry;
312     LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
313     if (op == 0)  /* get */
314     {
315         return 0x01 | /* accessed */
316                0x10 | /* not system */
317                0x60 | /* DPL 3 */
318                0x80 | /* present */
319                ((entry.read_only == 0) << 1) |
320                (entry.type << 2) |
321                (entry.seg_32bit << 14) |
322                (entry.limit_in_pages << 15);
323     }
324     else  /* set */
325     {
326         entry.read_only = ((val & 2) == 0);
327         entry.type = (val >> 2) & 3;
328         entry.seg_32bit = val & 0x4000;
329         entry.limit_in_pages = val & 0x8000;
330         LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
331         return 0;
332     }
333 }
334
335
336 /***********************************************************************
337  *           IsBadCodePtr   (KERNEL.336)
338  */
339 BOOL IsBadCodePtr( SEGPTR lpfn )
340 {
341     WORD sel;
342     ldt_entry entry;
343
344     sel = SELECTOROF(lpfn);
345     if (!sel) return TRUE;
346     if (IS_SELECTOR_FREE(sel)) return TRUE;
347     LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
348     if (entry.type != SEGMENT_CODE) return TRUE;
349     if (OFFSETOF(lpfn) > entry.limit) return TRUE;
350     return FALSE;
351 }
352
353
354 /***********************************************************************
355  *           IsBadStringPtr   (KERNEL.337)
356  */
357 BOOL IsBadStringPtr( SEGPTR ptr, WORD size )
358 {
359     WORD sel;
360     ldt_entry entry;
361
362     sel = SELECTOROF(ptr);
363     if (!sel) return TRUE;
364     if (IS_SELECTOR_FREE(sel)) return TRUE;
365     LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
366     if ((entry.type == SEGMENT_CODE) && entry.read_only) return TRUE;
367     if (strlen(PTR_SEG_TO_LIN(ptr)) < size) size = strlen(PTR_SEG_TO_LIN(ptr));
368     if (OFFSETOF(ptr) + size - 1 > entry.limit) return TRUE;
369     return FALSE;
370 }
371
372
373 /***********************************************************************
374  *           IsBadHugeReadPtr   (KERNEL.346)
375  */
376 BOOL IsBadHugeReadPtr( SEGPTR ptr, DWORD size )
377 {
378     WORD sel;
379     ldt_entry entry;
380
381     sel = SELECTOROF(ptr);
382     if (!sel) return TRUE;
383     if (IS_SELECTOR_FREE(sel)) return TRUE;
384     LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
385     if ((entry.type == SEGMENT_CODE) && entry.read_only) return TRUE;
386     if (OFFSETOF(ptr) + size - 1 > entry.limit) return TRUE;
387     return FALSE;
388 }
389
390
391 /***********************************************************************
392  *           IsBadHugeWritePtr   (KERNEL.347)
393  */
394 BOOL IsBadHugeWritePtr( SEGPTR ptr, DWORD size )
395 {
396     WORD sel;
397     ldt_entry entry;
398
399     sel = SELECTOROF(ptr);
400     if (!sel) return TRUE;
401     if (IS_SELECTOR_FREE(sel)) return TRUE;
402     LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
403     if ((entry.type == SEGMENT_CODE) || entry.read_only) return TRUE;
404     if (OFFSETOF(ptr) + size - 1 > entry.limit) return TRUE;
405     return FALSE;
406 }
407
408 /***********************************************************************
409  *           IsBadReadPtr   (KERNEL.334)
410  */
411 BOOL IsBadReadPtr( SEGPTR ptr, WORD size )
412 {
413     return IsBadHugeReadPtr( ptr, size );
414 }
415
416
417 /***********************************************************************
418  *           IsBadWritePtr   (KERNEL.335)
419  */
420 BOOL IsBadWritePtr( SEGPTR ptr, WORD size )
421 {
422     return IsBadHugeWritePtr( ptr, size );
423 }
424
425
426 /***********************************************************************
427  *           MemoryRead   (TOOLHELP.78)
428  */
429 DWORD MemoryRead( WORD sel, DWORD offset, void *buffer, DWORD count )
430 {
431     if (IS_SELECTOR_FREE(sel)) return 0;
432     if (offset > GET_SEL_LIMIT(sel)) return 0;
433     if (offset + count > GET_SEL_LIMIT(sel) + 1)
434         count = GET_SEL_LIMIT(sel) + 1 - offset;
435     memcpy( buffer, ((char *)GET_SEL_BASE(sel)) + offset, count );
436     return count;
437 }
438
439
440 /***********************************************************************
441  *           MemoryWrite   (TOOLHELP.79)
442  */
443 DWORD MemoryWrite( WORD sel, DWORD offset, void *buffer, DWORD count )
444 {
445     if (IS_SELECTOR_FREE(sel)) return 0;
446     if (offset > GET_SEL_LIMIT(sel)) return 0;
447     if (offset + count > GET_SEL_LIMIT(sel) + 1)
448         count = GET_SEL_LIMIT(sel) + 1 - offset;
449     memcpy( ((char *)GET_SEL_BASE(sel)) + offset, buffer, count );
450     return count;
451 }
452
453 #ifndef WINELIB
454 SEGPTR MAKE_SEGPTR(void * ptr)
455
456 {
457     SEGPTR result;
458     int entry;
459
460     if (!ptr)
461         return ptr;
462     if (!((unsigned)ptr & 0xffff0000)) {
463         fprintf(stderr, "Invalid pointer %p has been passed to MAKE_SEGPTR. This was\n", ptr);
464         fprintf(stderr, "probably caused by an unnecessary call to PTR_SEG_TO_LIN.\n");
465         fprintf(stderr, "Forcing call to debugger\n");
466         ptr = *(void **)0;
467     }
468     result = (SEGPTR) (IF1632_Stack32_base) +
469              ((DWORD)(ptr) - (DWORD) PTR_SEG_TO_LIN(IF1632_Stack32_base));
470     if (PTR_SEG_TO_LIN(result) == ptr)
471         return result;
472     
473     for (entry = 0; entry < LDT_SIZE; entry++) {
474         if (ldt_copy[entry].base && 
475             (ldt_copy[entry].limit < 0x10000) &&
476             ((unsigned) ptr >= ldt_copy[entry].base) &&
477             ((unsigned) ptr < (ldt_copy[entry].base + ldt_copy[entry].limit))) {
478                 return ((ENTRY_TO_SELECTOR(entry) << 16) | 
479                        ((unsigned) ptr - ldt_copy[entry].base));
480         }
481     }
482     entry = SELECTOR_AllocBlock((void *)((unsigned)ptr & 0xffff0000), 0x10000, SEGMENT_DATA, 0, 0);
483     return ((entry << 16) | ((unsigned) ptr & 0xffff));
484 }
485 #endif