Release 950522
[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 "stddebug.h"
12 #include "debug.h"
13
14 ldt_copy_entry ldt_copy[LDT_SIZE] = { {0,0}, };
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     return ENTRY_TO_SELECTOR( i - size + 1 );
34 }
35
36
37 /***********************************************************************
38  *           AllocSelector   (KERNEL.175)
39  */
40 WORD AllocSelector( WORD sel )
41 {
42     WORD newsel, count, i;
43
44     count = sel ? ((GET_SEL_LIMIT(sel) >> 16) + 1) : 1;
45     newsel = AllocSelectorArray( count );
46     dprintf_selector( stddeb, "AllocSelector(%04x): returning %04x\n",
47                       sel, newsel );
48     if (!newsel) return 0;
49     if (!sel) return newsel;  /* nothing to copy */
50     for (i = 0; i < count; i++)
51     {
52         ldt_entry entry;
53         LDT_GetEntry( SELECTOR_TO_ENTRY(sel) + i, &entry );
54         LDT_SetEntry( SELECTOR_TO_ENTRY(newsel) + i, &entry );
55     }
56     return newsel;
57 }
58
59
60 /***********************************************************************
61  *           FreeSelector   (KERNEL.176)
62  */
63 WORD FreeSelector( WORD sel )
64 {
65     WORD i, count;
66     ldt_entry entry;
67
68     dprintf_selector( stddeb, "FreeSelector(%04x)\n", sel );
69     if (IS_SELECTOR_FREE(sel)) return sel;  /* error */
70     count = (GET_SEL_LIMIT(sel) >> 16) + 1;
71     memset( &entry, 0, sizeof(entry) );  /* clear the LDT entries */
72     for (i = 0; i < count; i++)
73         LDT_SetEntry( SELECTOR_TO_ENTRY(sel) + i, &entry );
74     return 0;
75 }
76
77
78 /***********************************************************************
79  *           SELECTOR_SetEntries
80  *
81  * Set the LDT entries for an array of selectors.
82  */
83 static void SELECTOR_SetEntries( WORD sel, void *base, DWORD size,
84                                  enum seg_type type, BOOL is32bit,
85                                  BOOL readonly )
86 {
87     ldt_entry entry;
88     WORD i, count;
89
90       /* The limit for the first selector is the whole */
91       /* block. The next selectors get a 64k limit.    */
92     entry.base           = (unsigned long)base;
93     entry.type           = type;
94     entry.seg_32bit      = is32bit;
95     entry.read_only      = readonly;
96     entry.limit_in_pages = (size > 0x100000);
97     if (entry.limit_in_pages) entry.limit = ((size + 0xfff) >> 12) - 1;
98     else entry.limit = size - 1;
99     count = (size + 0xffff) / 0x10000;
100     for (i = 0; i < count; i++)
101     {
102         LDT_SetEntry( SELECTOR_TO_ENTRY(sel) + i, &entry );
103         entry.base += 0x10000;
104         size -= 0x10000;
105         entry.limit = (size > 0x10000) ? 0xffff : size-1;
106         entry.limit_in_pages = 0;
107     }
108 }
109
110
111 /***********************************************************************
112  *           SELECTOR_ReallocArray
113  *
114  * Change the size of an allocated selector array.
115  */
116 static WORD SELECTOR_ReallocArray( WORD sel, WORD newcount )
117 {
118     WORD i, oldcount;
119     ldt_entry entry;
120
121     oldcount = (GET_SEL_LIMIT(sel) >> 16) + 1;
122     if (oldcount < newcount)  /* We need to add selectors */
123     {
124           /* Check if the next selectors are free */
125         for (i = oldcount; i < newcount; i++)
126             if (!IS_SELECTOR_FREE(sel+i)) break;
127         if (i < newcount)
128         {
129             FreeSelector( sel );
130             sel = AllocSelectorArray( newcount );
131         }
132     }
133     else if (oldcount > newcount) /* We need to remove selectors */
134     {
135         memset( &entry, 0, sizeof(entry) );  /* clear the LDT entries */
136         for (i = oldcount; i < newcount; i++)
137             LDT_SetEntry( SELECTOR_TO_ENTRY(sel) + i, &entry );
138     }
139     return sel;
140 }
141
142
143 /***********************************************************************
144  *           SELECTOR_AllocBlock
145  *
146  * Allocate selectors for a block of linear memory.
147  */
148 WORD SELECTOR_AllocBlock( void *base, DWORD size, enum seg_type type,
149                           BOOL is32bit, BOOL readonly )
150 {
151     WORD sel, count;
152
153     if (!size) return 0;
154     count = (size + 0xffff) / 0x10000;
155     sel = AllocSelectorArray( count );
156     if (sel) SELECTOR_SetEntries( sel, base, size, type, is32bit, readonly );
157     return sel;
158 }
159
160
161 /***********************************************************************
162  *           SELECTOR_ReallocBlock
163  *
164  * Change the size of a block of selectors.
165  */
166 WORD SELECTOR_ReallocBlock( WORD sel, void *base, DWORD size,
167                             enum seg_type type, BOOL is32bit, BOOL readonly )
168 {
169     WORD count;
170
171     if (!size)
172     {
173         FreeSelector( sel );
174         return 0;
175     }
176     count = (size + 0xffff) / 0x10000;
177     sel = SELECTOR_ReallocArray( sel, count );
178     if (sel) SELECTOR_SetEntries( sel, base, size, type, is32bit, readonly );
179     return sel;
180 }
181
182
183 /***********************************************************************
184  *           PrestoChangoSelector   (KERNEL.177)
185  */
186 WORD PrestoChangoSelector( WORD selSrc, WORD selDst )
187 {
188     ldt_entry entry;
189     LDT_GetEntry( SELECTOR_TO_ENTRY( selSrc ), &entry );
190     entry.type ^= SEGMENT_CODE;  /* toggle the executable bit */
191     LDT_SetEntry( SELECTOR_TO_ENTRY( selDst ), &entry );
192     return selDst;
193 }
194
195
196 /***********************************************************************
197  *           AllocCStoDSAlias   (KERNEL.170)
198  */
199 WORD AllocCStoDSAlias( WORD sel )
200 {
201     WORD newsel;
202     ldt_entry entry;
203
204     newsel = AllocSelectorArray( 1 );
205     dprintf_selector( stddeb, "AllocCStoDSAlias(%04x): returning %04x\n",
206                       sel, newsel );
207     if (!newsel) return 0;
208     LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
209     entry.type = SEGMENT_DATA;
210     LDT_SetEntry( SELECTOR_TO_ENTRY(newsel), &entry );
211     return newsel;
212 }
213
214
215 /***********************************************************************
216  *           AllocDStoCSAlias   (KERNEL.171)
217  */
218 WORD AllocDStoCSAlias( WORD sel )
219 {
220     WORD newsel;
221     ldt_entry entry;
222
223     newsel = AllocSelectorArray( 1 );
224     dprintf_selector( stddeb, "AllocDStoCSAlias(%04x): returning %04x\n",
225                       sel, newsel );
226     if (!newsel) return 0;
227     LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
228     entry.type = SEGMENT_CODE;
229     LDT_SetEntry( SELECTOR_TO_ENTRY(newsel), &entry );
230     return newsel;
231 }
232
233
234 /***********************************************************************
235  *           LongPtrAdd   (KERNEL.180)
236  */
237 void LongPtrAdd( DWORD ptr, DWORD add )
238 {
239     ldt_entry entry;
240     LDT_GetEntry( SELECTOR_TO_ENTRY(SELECTOROF(ptr)), &entry );
241     entry.base += add;
242     LDT_SetEntry( SELECTOR_TO_ENTRY(SELECTOROF(ptr)), &entry );
243 }
244
245
246 /***********************************************************************
247  *           GetSelectorBase   (KERNEL.186)
248  */
249 DWORD GetSelectorBase( WORD sel )
250 {
251     return GET_SEL_BASE(sel);
252 }
253
254
255 /***********************************************************************
256  *           SetSelectorBase   (KERNEL.187)
257  */
258 WORD SetSelectorBase( WORD sel, DWORD base )
259 {
260     ldt_entry entry;
261     LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
262     entry.base = base;
263     LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
264     return sel;
265 }
266
267
268 /***********************************************************************
269  *           GetSelectorLimit   (KERNEL.188)
270  */
271 DWORD GetSelectorLimit( WORD sel )
272 {
273     return GET_SEL_LIMIT(sel);
274 }
275
276
277 /***********************************************************************
278  *           SetSelectorLimit   (KERNEL.189)
279  */
280 WORD SetSelectorLimit( WORD sel, DWORD limit )
281 {
282     ldt_entry entry;
283     LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
284     entry.limit = limit;
285     LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
286     return sel;
287 }
288
289
290 /***********************************************************************
291  *           SelectorAccessRights   (KERNEL.196)
292  */
293 WORD SelectorAccessRights( WORD sel, WORD op, WORD val )
294 {
295     ldt_entry entry;
296     LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
297     if (op == 0)  /* get */
298     {
299         return 1 /* accessed */ |
300                (entry.read_only << 1) |
301                (entry.type << 2) |
302                (entry.seg_32bit << 14) |
303                (entry.limit_in_pages << 15);
304     }
305     else  /* set */
306     {
307         entry.read_only = val & 2;
308         entry.type = (val >> 2) & 3;
309         entry.seg_32bit = val & 0x4000;
310         entry.limit_in_pages = val & 0x8000;
311         LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
312         return 0;
313     }
314 }
315
316
317 /***********************************************************************
318  *           IsBadCodePtr   (KERNEL.336)
319  */
320 BOOL IsBadCodePtr( SEGPTR lpfn )
321 {
322     WORD sel;
323     ldt_entry entry;
324
325     sel = SELECTOROF(lpfn);
326     if (!sel) return FALSE;
327     if (IS_SELECTOR_FREE(sel)) return FALSE;
328     LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
329     if (entry.type != SEGMENT_CODE) return FALSE;
330     if (OFFSETOF(lpfn) > entry.limit) return FALSE;
331     return TRUE;
332 }
333
334
335 /***********************************************************************
336  *           IsBadStringPtr   (KERNEL.337)
337  */
338 BOOL IsBadStringPtr( SEGPTR ptr, WORD size )
339 {
340     WORD sel;
341     ldt_entry entry;
342
343     sel = SELECTOROF(ptr);
344     if (!sel) return FALSE;
345     if (IS_SELECTOR_FREE(sel)) return FALSE;
346     LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
347     if ((entry.type == SEGMENT_CODE) && entry.read_only) return FALSE;
348     if (strlen(PTR_SEG_TO_LIN(ptr)) < size) size = strlen(PTR_SEG_TO_LIN(ptr));
349     if (OFFSETOF(ptr) + size > entry.limit) return FALSE;
350     return TRUE;
351 }
352
353
354 /***********************************************************************
355  *           IsBadHugeReadPtr   (KERNEL.346)
356  */
357 BOOL IsBadHugeReadPtr( SEGPTR ptr, DWORD size )
358 {
359     WORD sel;
360     ldt_entry entry;
361
362     sel = SELECTOROF(ptr);
363     if (!sel) return FALSE;
364     if (IS_SELECTOR_FREE(sel)) return FALSE;
365     LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
366     if ((entry.type == SEGMENT_CODE) && entry.read_only) return FALSE;
367     if (OFFSETOF(ptr) + size > entry.limit) return FALSE;
368     return TRUE;
369 }
370
371
372 /***********************************************************************
373  *           IsBadHugeWritePtr   (KERNEL.347)
374  */
375 BOOL IsBadHugeWritePtr( SEGPTR ptr, DWORD size )
376 {
377     WORD sel;
378     ldt_entry entry;
379
380     sel = SELECTOROF(ptr);
381     if (!sel) return FALSE;
382     if (IS_SELECTOR_FREE(sel)) return FALSE;
383     LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
384     if ((entry.type == SEGMENT_CODE) || entry.read_only) return FALSE;
385     if (OFFSETOF(ptr) + size > entry.limit) return FALSE;
386     return TRUE;
387 }
388
389 /***********************************************************************
390  *           IsBadReadPtr   (KERNEL.334)
391  */
392 BOOL IsBadReadPtr( SEGPTR ptr, WORD size )
393 {
394     return IsBadHugeReadPtr( ptr, size );
395 }
396
397
398 /***********************************************************************
399  *           IsBadWritePtr   (KERNEL.335)
400  */
401 BOOL IsBadWritePtr( SEGPTR ptr, WORD size )
402 {
403     return IsBadHugeWritePtr( ptr, size );
404 }
405
406
407 /***********************************************************************
408  *           MemoryRead   (TOOLHELP.78)
409  */
410 DWORD MemoryRead( WORD sel, DWORD offset, void *buffer, DWORD count )
411 {
412     if (IS_SELECTOR_FREE(sel)) return 0;
413     if (offset > GET_SEL_LIMIT(sel)) return 0;
414     if (offset + count > GET_SEL_LIMIT(sel) + 1)
415         count = GET_SEL_LIMIT(sel) + 1 - offset;
416     memcpy( buffer, ((char *)GET_SEL_BASE(sel)) + offset, count );
417     return count;
418 }
419
420
421 /***********************************************************************
422  *           MemoryWrite   (TOOLHELP.79)
423  */
424 DWORD MemoryWrite( WORD sel, DWORD offset, void *buffer, DWORD count )
425 {
426     if (IS_SELECTOR_FREE(sel)) return 0;
427     if (offset > GET_SEL_LIMIT(sel)) return 0;
428     if (offset + count > GET_SEL_LIMIT(sel) + 1)
429         count = GET_SEL_LIMIT(sel) + 1 - offset;
430     memcpy( ((char *)GET_SEL_BASE(sel)) + offset, buffer, count );
431     return count;
432 }