mshtml: Added IHTMLWindow2::get_length implementation.
[wine] / dlls / kernel32 / selector.c
1 /*
2  * Selector manipulation functions
3  *
4  * Copyright 1995 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <string.h>
25
26 #include "wine/winbase16.h"
27 #include "wine/server.h"
28 #include "wine/debug.h"
29 #include "kernel16_private.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(selector);
32
33 #define LDT_SIZE 8192
34
35 /* get the number of selectors needed to cover up to the selector limit */
36 static inline WORD get_sel_count( WORD sel )
37 {
38     return (wine_ldt_copy.limit[sel >> __AHSHIFT] >> 16) + 1;
39 }
40
41
42 /***********************************************************************
43  *           AllocSelectorArray   (KERNEL.206)
44  */
45 WORD WINAPI AllocSelectorArray16( WORD count )
46 {
47     WORD i, sel = wine_ldt_alloc_entries( count );
48
49     if (sel)
50     {
51         LDT_ENTRY entry;
52         wine_ldt_set_base( &entry, 0 );
53         wine_ldt_set_limit( &entry, 1 ); /* avoid 0 base and limit */
54         wine_ldt_set_flags( &entry, WINE_LDT_FLAGS_DATA );
55         for (i = 0; i < count; i++) wine_ldt_set_entry( sel + (i << __AHSHIFT), &entry );
56     }
57     return sel;
58 }
59
60
61 /***********************************************************************
62  *           AllocSelector   (KERNEL.175)
63  */
64 WORD WINAPI AllocSelector16( WORD sel )
65 {
66     WORD newsel, count, i;
67
68     count = sel ? get_sel_count(sel) : 1;
69     newsel = wine_ldt_alloc_entries( count );
70     TRACE("(%04x): returning %04x\n", sel, newsel );
71     if (!newsel) return 0;
72     if (!sel) return newsel;  /* nothing to copy */
73     for (i = 0; i < count; i++)
74     {
75         LDT_ENTRY entry;
76         wine_ldt_get_entry( sel + (i << __AHSHIFT), &entry );
77         wine_ldt_set_entry( newsel + (i << __AHSHIFT), &entry );
78     }
79     return newsel;
80 }
81
82
83 /***********************************************************************
84  *           FreeSelector   (KERNEL.176)
85  */
86 WORD WINAPI FreeSelector16( WORD sel )
87 {
88     LDT_ENTRY entry;
89
90     wine_ldt_get_entry( sel, &entry );
91     if (wine_ldt_is_empty( &entry )) return sel;  /* error */
92 #ifdef __i386__
93     /* Check if we are freeing current %fs selector */
94     if (!((wine_get_fs() ^ sel) & ~3))
95         WARN("Freeing %%fs selector (%04x), not good.\n", wine_get_fs() );
96 #endif  /* __i386__ */
97     wine_ldt_free_entries( sel, 1 );
98     return 0;
99 }
100
101
102 /***********************************************************************
103  *           SELECTOR_SetEntries
104  *
105  * Set the LDT entries for an array of selectors.
106  */
107 static void SELECTOR_SetEntries( WORD sel, const void *base, DWORD size, unsigned char flags )
108 {
109     LDT_ENTRY entry;
110     WORD i, count;
111
112     wine_ldt_set_base( &entry, base );
113     wine_ldt_set_limit( &entry, size - 1 );
114     wine_ldt_set_flags( &entry, flags );
115     count = (size + 0xffff) / 0x10000;
116     for (i = 0; i < count; i++)
117     {
118         wine_ldt_set_entry( sel + (i << __AHSHIFT), &entry );
119         wine_ldt_set_base( &entry, (char*)wine_ldt_get_base(&entry) + 0x10000);
120         /* yep, Windows sets limit like that, not 64K sel units */
121         wine_ldt_set_limit( &entry, wine_ldt_get_limit(&entry) - 0x10000 );
122     }
123 }
124
125
126 /***********************************************************************
127  *           SELECTOR_AllocBlock
128  *
129  * Allocate selectors for a block of linear memory.
130  */
131 WORD SELECTOR_AllocBlock( const void *base, DWORD size, unsigned char flags )
132 {
133     WORD sel, count;
134
135     if (!size) return 0;
136     count = (size + 0xffff) / 0x10000;
137     sel = wine_ldt_alloc_entries( count );
138     if (sel) SELECTOR_SetEntries( sel, base, size, flags );
139     return sel;
140 }
141
142
143 /***********************************************************************
144  *           SELECTOR_FreeBlock
145  *
146  * Free a block of selectors.
147  */
148 void SELECTOR_FreeBlock( WORD sel )
149 {
150     WORD i, count = get_sel_count( sel );
151
152     TRACE("(%04x,%d)\n", sel, count );
153     for (i = 0; i < count; i++) FreeSelector16( sel + (i << __AHSHIFT) );
154 }
155
156
157 /***********************************************************************
158  *           SELECTOR_ReallocBlock
159  *
160  * Change the size of a block of selectors.
161  */
162 WORD SELECTOR_ReallocBlock( WORD sel, const void *base, DWORD size )
163 {
164     LDT_ENTRY entry;
165     int oldcount, newcount;
166
167     if (!size) size = 1;
168     wine_ldt_get_entry( sel, &entry );
169     oldcount = (wine_ldt_get_limit(&entry) >> 16) + 1;
170     newcount = (size + 0xffff) >> 16;
171
172     sel = wine_ldt_realloc_entries( sel, oldcount, newcount );
173     if (sel) SELECTOR_SetEntries( sel, base, size, wine_ldt_get_flags(&entry) );
174     return sel;
175 }
176
177
178 /***********************************************************************
179  *           PrestoChangoSelector   (KERNEL.177)
180  */
181 WORD WINAPI PrestoChangoSelector16( WORD selSrc, WORD selDst )
182 {
183     LDT_ENTRY entry;
184     wine_ldt_get_entry( selSrc, &entry );
185     /* toggle the executable bit */
186     entry.HighWord.Bits.Type ^= (WINE_LDT_FLAGS_CODE ^ WINE_LDT_FLAGS_DATA);
187     wine_ldt_set_entry( selDst, &entry );
188     return selDst;
189 }
190
191
192 /***********************************************************************
193  *           AllocCStoDSAlias   (KERNEL.170)
194  *           AllocAlias         (KERNEL.172)
195  */
196 WORD WINAPI AllocCStoDSAlias16( WORD sel )
197 {
198     WORD newsel;
199     LDT_ENTRY entry;
200
201     newsel = wine_ldt_alloc_entries( 1 );
202     TRACE("(%04x): returning %04x\n",
203                       sel, newsel );
204     if (!newsel) return 0;
205     wine_ldt_get_entry( sel, &entry );
206     entry.HighWord.Bits.Type = WINE_LDT_FLAGS_DATA;
207     wine_ldt_set_entry( newsel, &entry );
208     return newsel;
209 }
210
211
212 /***********************************************************************
213  *           AllocDStoCSAlias   (KERNEL.171)
214  */
215 WORD WINAPI AllocDStoCSAlias16( WORD sel )
216 {
217     WORD newsel;
218     LDT_ENTRY entry;
219
220     newsel = wine_ldt_alloc_entries( 1 );
221     TRACE("(%04x): returning %04x\n",
222                       sel, newsel );
223     if (!newsel) return 0;
224     wine_ldt_get_entry( sel, &entry );
225     entry.HighWord.Bits.Type = WINE_LDT_FLAGS_CODE;
226     wine_ldt_set_entry( newsel, &entry );
227     return newsel;
228 }
229
230
231 /***********************************************************************
232  *           LongPtrAdd   (KERNEL.180)
233  */
234 void WINAPI LongPtrAdd16( DWORD ptr, DWORD add )
235 {
236     LDT_ENTRY entry;
237     wine_ldt_get_entry( SELECTOROF(ptr), &entry );
238     wine_ldt_set_base( &entry, (char *)wine_ldt_get_base(&entry) + add );
239     wine_ldt_set_entry( SELECTOROF(ptr), &entry );
240 }
241
242
243 /***********************************************************************
244  *             GetSelectorBase   (KERNEL.186)
245  */
246 DWORD WINAPI GetSelectorBase( WORD sel )
247 {
248     void *base = wine_ldt_copy.base[sel >> __AHSHIFT];
249
250     /* if base points into DOSMEM, assume we have to
251      * return pointer into physical lower 1MB */
252
253     return DOSMEM_MapLinearToDos( base );
254 }
255
256
257 /***********************************************************************
258  *             SetSelectorBase   (KERNEL.187)
259  */
260 WORD WINAPI SetSelectorBase( WORD sel, DWORD base )
261 {
262     LDT_ENTRY entry;
263     wine_ldt_get_entry( sel, &entry );
264     wine_ldt_set_base( &entry, DOSMEM_MapDosToLinear(base) );
265     wine_ldt_set_entry( sel, &entry );
266     return sel;
267 }
268
269
270 /***********************************************************************
271  *           GetSelectorLimit   (KERNEL.188)
272  */
273 DWORD WINAPI GetSelectorLimit16( WORD sel )
274 {
275     return wine_ldt_copy.limit[sel >> __AHSHIFT];
276 }
277
278
279 /***********************************************************************
280  *           SetSelectorLimit   (KERNEL.189)
281  */
282 WORD WINAPI SetSelectorLimit16( WORD sel, DWORD limit )
283 {
284     LDT_ENTRY entry;
285     wine_ldt_get_entry( sel, &entry );
286     wine_ldt_set_limit( &entry, limit );
287     wine_ldt_set_entry( sel, &entry );
288     return sel;
289 }
290
291
292 /***********************************************************************
293  *           SelectorAccessRights   (KERNEL.196)
294  */
295 WORD WINAPI SelectorAccessRights16( WORD sel, WORD op, WORD val )
296 {
297     LDT_ENTRY entry;
298     wine_ldt_get_entry( sel, &entry );
299
300     if (op == 0)  /* get */
301     {
302         return entry.HighWord.Bytes.Flags1 | ((entry.HighWord.Bytes.Flags2 << 8) & 0xf0);
303     }
304     else  /* set */
305     {
306         entry.HighWord.Bytes.Flags1 = LOBYTE(val) | 0xf0;
307         entry.HighWord.Bytes.Flags2 = (entry.HighWord.Bytes.Flags2 & 0x0f) | (HIBYTE(val) & 0xf0);
308         wine_ldt_set_entry( sel, &entry );
309         return 0;
310     }
311 }
312
313
314 /***********************************************************************
315  *           IsBadCodePtr   (KERNEL.336)
316  */
317 BOOL16 WINAPI IsBadCodePtr16( SEGPTR lpfn )
318 {
319     WORD sel;
320     LDT_ENTRY entry;
321
322     sel = SELECTOROF(lpfn);
323     if (!sel) return TRUE;
324     wine_ldt_get_entry( sel, &entry );
325     if (wine_ldt_is_empty( &entry )) return TRUE;
326     /* check for code segment, ignoring conforming, read-only and accessed bits */
327     if ((entry.HighWord.Bits.Type ^ WINE_LDT_FLAGS_CODE) & 0x18) return TRUE;
328     if (OFFSETOF(lpfn) > wine_ldt_get_limit(&entry)) return TRUE;
329     return FALSE;
330 }
331
332
333 /***********************************************************************
334  *           IsBadStringPtr   (KERNEL.337)
335  */
336 BOOL16 WINAPI IsBadStringPtr16( SEGPTR ptr, UINT16 size )
337 {
338     WORD sel;
339     LDT_ENTRY entry;
340
341     sel = SELECTOROF(ptr);
342     if (!sel) return TRUE;
343     wine_ldt_get_entry( sel, &entry );
344     if (wine_ldt_is_empty( &entry )) return TRUE;
345     /* check for data or readable code segment */
346     if (!(entry.HighWord.Bits.Type & 0x10)) return TRUE;  /* system descriptor */
347     if ((entry.HighWord.Bits.Type & 0x0a) == 0x08) return TRUE;  /* non-readable code segment */
348     if (strlen(MapSL(ptr)) < size) size = strlen(MapSL(ptr)) + 1;
349     if (size && (OFFSETOF(ptr) + size - 1 > wine_ldt_get_limit(&entry))) return TRUE;
350     return FALSE;
351 }
352
353
354 /***********************************************************************
355  *           IsBadHugeReadPtr   (KERNEL.346)
356  */
357 BOOL16 WINAPI IsBadHugeReadPtr16( SEGPTR ptr, DWORD size )
358 {
359     WORD sel;
360     LDT_ENTRY entry;
361
362     sel = SELECTOROF(ptr);
363     if (!sel) return TRUE;
364     wine_ldt_get_entry( sel, &entry );
365     if (wine_ldt_is_empty( &entry )) return TRUE;
366     /* check for data or readable code segment */
367     if (!(entry.HighWord.Bits.Type & 0x10)) return TRUE;  /* system descriptor */
368     if ((entry.HighWord.Bits.Type & 0x0a) == 0x08) return TRUE;  /* non-readable code segment */
369     if (size && (OFFSETOF(ptr) + size - 1 > wine_ldt_get_limit( &entry ))) return TRUE;
370     return FALSE;
371 }
372
373
374 /***********************************************************************
375  *           IsBadHugeWritePtr   (KERNEL.347)
376  */
377 BOOL16 WINAPI IsBadHugeWritePtr16( SEGPTR ptr, DWORD size )
378 {
379     WORD sel;
380     LDT_ENTRY entry;
381
382     sel = SELECTOROF(ptr);
383     if (!sel) return TRUE;
384     wine_ldt_get_entry( sel, &entry );
385     if (wine_ldt_is_empty( &entry )) return TRUE;
386     /* check for writable data segment, ignoring expand-down and accessed flags */
387     if ((entry.HighWord.Bits.Type ^ WINE_LDT_FLAGS_DATA) & ~5) return TRUE;
388     if (size && (OFFSETOF(ptr) + size - 1 > wine_ldt_get_limit( &entry ))) return TRUE;
389     return FALSE;
390 }
391
392 /***********************************************************************
393  *           IsBadReadPtr   (KERNEL.334)
394  */
395 BOOL16 WINAPI IsBadReadPtr16( SEGPTR ptr, UINT16 size )
396 {
397     return IsBadHugeReadPtr16( ptr, size );
398 }
399
400
401 /***********************************************************************
402  *           IsBadWritePtr   (KERNEL.335)
403  */
404 BOOL16 WINAPI IsBadWritePtr16( SEGPTR ptr, UINT16 size )
405 {
406     return IsBadHugeWritePtr16( ptr, size );
407 }
408
409
410 /***********************************************************************
411  *           IsBadFlatReadWritePtr   (KERNEL.627)
412  */
413 BOOL16 WINAPI IsBadFlatReadWritePtr16( SEGPTR ptr, DWORD size, BOOL16 bWrite )
414 {
415     return bWrite? IsBadHugeWritePtr16( ptr, size )
416                  : IsBadHugeReadPtr16( ptr, size );
417 }
418
419
420 /************************************* Win95 pointer mapping functions *
421  *
422  */
423
424 struct mapls_entry
425 {
426     struct mapls_entry *next;
427     void               *addr;   /* linear address */
428     int                 count;  /* ref count */
429     WORD                sel;    /* selector */
430 };
431
432 static struct mapls_entry *first_entry;
433
434
435 /***********************************************************************
436  *           MapLS   (KERNEL32.@)
437  *           MapLS   (KERNEL.358)
438  *
439  * Maps linear pointer to segmented.
440  */
441 SEGPTR WINAPI MapLS( LPCVOID ptr )
442 {
443     struct mapls_entry *entry, *free = NULL;
444     const void *base;
445     SEGPTR ret = 0;
446
447     if (!HIWORD(ptr)) return (SEGPTR)LOWORD(ptr);
448
449     base = (const char *)ptr - ((ULONG_PTR)ptr & 0x7fff);
450     HeapLock( GetProcessHeap() );
451     for (entry = first_entry; entry; entry = entry->next)
452     {
453         if (entry->addr == base) break;
454         if (!entry->count) free = entry;
455     }
456
457     if (!entry)
458     {
459         if (!free)  /* no free entry found, create a new one */
460         {
461             if (!(free = HeapAlloc( GetProcessHeap(), 0, sizeof(*free) ))) goto done;
462             if (!(free->sel = SELECTOR_AllocBlock( base, 0x10000, WINE_LDT_FLAGS_DATA )))
463             {
464                 HeapFree( GetProcessHeap(), 0, free );
465                 goto done;
466             }
467             free->count = 0;
468             free->next = first_entry;
469             first_entry = free;
470         }
471         SetSelectorBase( free->sel, (DWORD)base );
472         free->addr = (void*)base;
473         entry = free;
474     }
475     entry->count++;
476     ret = MAKESEGPTR( entry->sel, (const char *)ptr - (char *)entry->addr );
477  done:
478     HeapUnlock( GetProcessHeap() );
479     return ret;
480 }
481
482 /***********************************************************************
483  *           UnMapLS   (KERNEL32.@)
484  *           UnMapLS   (KERNEL.359)
485  *
486  * Free mapped selector.
487  */
488 void WINAPI UnMapLS( SEGPTR sptr )
489 {
490     struct mapls_entry *entry;
491     WORD sel = SELECTOROF(sptr);
492
493     if (sel)
494     {
495         HeapLock( GetProcessHeap() );
496         for (entry = first_entry; entry; entry = entry->next) if (entry->sel == sel) break;
497         if (entry && entry->count > 0) entry->count--;
498         HeapUnlock( GetProcessHeap() );
499     }
500 }
501
502 /***********************************************************************
503  *           MapSL   (KERNEL32.@)
504  *           MapSL   (KERNEL.357)
505  *
506  * Maps fixed segmented pointer to linear.
507  */
508 LPVOID WINAPI MapSL( SEGPTR sptr )
509 {
510     return (char *)wine_ldt_copy.base[SELECTOROF(sptr) >> __AHSHIFT] + OFFSETOF(sptr);
511 }
512
513 /***********************************************************************
514  *           MapSLFix   (KERNEL32.@)
515  *
516  * FIXME: MapSLFix and UnMapSLFixArray should probably prevent
517  * unexpected linear address change when GlobalCompact() shuffles
518  * moveable blocks.
519  */
520
521 LPVOID WINAPI MapSLFix( SEGPTR sptr )
522 {
523     return MapSL(sptr);
524 }
525
526 #ifdef __i386__
527
528 /***********************************************************************
529  *           UnMapSLFixArray   (KERNEL32.@)
530  *
531  * Must not change EAX, hence defined as asm function.
532  */
533 __ASM_STDCALL_FUNC( UnMapSLFixArray, 8, "ret $8" )
534
535 /***********************************************************************
536  *              SMapLS (KERNEL32.@)
537  */
538 __ASM_STDCALL_FUNC( SMapLS, 0,
539                    "xor %edx,%edx\n\t"
540                    "testl $0xffff0000,%eax\n\t"
541                    "jz 1f\n\t"
542                    "pushl %eax\n\t"
543                    "call " __ASM_NAME("MapLS") __ASM_STDCALL(4) "\n\t"
544                    "movl %eax,%edx\n"
545                    "1:\tret" )
546
547 /***********************************************************************
548  *              SUnMapLS (KERNEL32.@)
549  */
550 __ASM_STDCALL_FUNC( SUnMapLS, 0,
551                    "pushl %eax\n\t"  /* preserve eax */
552                    "pushl %eax\n\t"
553                    "call " __ASM_NAME("UnMapLS") __ASM_STDCALL(4) "\n\t"
554                    "popl %eax\n\t"
555                    "ret" )
556
557 /***********************************************************************
558  *              SMapLS_IP_EBP_8 (KERNEL32.@)
559  *              SMapLS_IP_EBP_12 (KERNEL32.@)
560  *              SMapLS_IP_EBP_16 (KERNEL32.@)
561  *              SMapLS_IP_EBP_20 (KERNEL32.@)
562  *              SMapLS_IP_EBP_24 (KERNEL32.@)
563  *              SMapLS_IP_EBP_28 (KERNEL32.@)
564  *              SMapLS_IP_EBP_32 (KERNEL32.@)
565  *              SMapLS_IP_EBP_36 (KERNEL32.@)
566  *              SMapLS_IP_EBP_40 (KERNEL32.@)
567  *
568  * These functions map linear pointers at [EBP+xxx] to segmented pointers
569  * and return them.
570  * Win95 uses some kind of alias structs, which it stores in [EBP+x] to
571  * unravel them at SUnMapLS. We just store the segmented pointer there.
572  */
573 #define DEFINE_SMapLS(n) \
574   __ASM_STDCALL_FUNC( SMapLS_IP_EBP_ ## n, 0, \
575                      "movl " #n "(%ebp),%eax\n\t" \
576                      "call " __ASM_NAME("SMapLS") __ASM_STDCALL(4) "\n\t" \
577                      "movl %edx," #n "(%ebp)\n\t" \
578                      "ret" )
579
580 DEFINE_SMapLS(8)
581 DEFINE_SMapLS(12)
582 DEFINE_SMapLS(16)
583 DEFINE_SMapLS(20)
584 DEFINE_SMapLS(24)
585 DEFINE_SMapLS(28)
586 DEFINE_SMapLS(32)
587 DEFINE_SMapLS(36)
588 DEFINE_SMapLS(40)
589
590
591 /***********************************************************************
592  *              SUnMapLS_IP_EBP_8 (KERNEL32.@)
593  *              SUnMapLS_IP_EBP_12 (KERNEL32.@)
594  *              SUnMapLS_IP_EBP_16 (KERNEL32.@)
595  *              SUnMapLS_IP_EBP_20 (KERNEL32.@)
596  *              SUnMapLS_IP_EBP_24 (KERNEL32.@)
597  *              SUnMapLS_IP_EBP_28 (KERNEL32.@)
598  *              SUnMapLS_IP_EBP_32 (KERNEL32.@)
599  *              SUnMapLS_IP_EBP_36 (KERNEL32.@)
600  *              SUnMapLS_IP_EBP_40 (KERNEL32.@)
601  */
602
603 #define DEFINE_SUnMapLS(n) \
604   __ASM_STDCALL_FUNC( SUnMapLS_IP_EBP_ ## n, 0, \
605                      "pushl %eax\n\t"  /* preserve eax */ \
606                      "pushl " #n "(%ebp)\n\t" \
607                      "call " __ASM_NAME("UnMapLS") __ASM_STDCALL(4) "\n\t" \
608                      "movl $0," #n "(%ebp)\n\t" \
609                      "popl %eax\n\t" \
610                      "ret" )
611
612 DEFINE_SUnMapLS(8)
613 DEFINE_SUnMapLS(12)
614 DEFINE_SUnMapLS(16)
615 DEFINE_SUnMapLS(20)
616 DEFINE_SUnMapLS(24)
617 DEFINE_SUnMapLS(28)
618 DEFINE_SUnMapLS(32)
619 DEFINE_SUnMapLS(36)
620 DEFINE_SUnMapLS(40)
621
622 #endif  /* __i386__ */