selector.c 23.2 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3 4
/*
 * Selector manipulation functions
 *
 * Copyright 1995 Alexandre Julliard
5 6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Alexandre Julliard's avatar
Alexandre Julliard committed
19 20
 */

21
#include "config.h"
22
#include "wine/port.h"
23

Alexandre Julliard's avatar
Alexandre Julliard committed
24
#include <string.h>
25

26
#include "winerror.h"
27
#include "wine/winbase16.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
28
#include "miscemu.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
29
#include "selectors.h"
30
#include "wine/server.h"
31
#include "wine/debug.h"
Patrik Stridvall's avatar
Patrik Stridvall committed
32
#include "toolhelp.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
33

34
WINE_DEFAULT_DEBUG_CHANNEL(selector);
35

36 37 38 39 40 41 42
#define LDT_SIZE 8192

/* get the number of selectors needed to cover up to the selector limit */
inline static WORD get_sel_count( WORD sel )
{
    return (wine_ldt_copy.limit[sel >> __AHSHIFT] >> 16) + 1;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
43

44 45 46 47 48 49

/***********************************************************************
 *           AllocSelectorArray   (KERNEL.206)
 */
WORD WINAPI AllocSelectorArray16( WORD count )
{
50
    WORD i, sel = wine_ldt_alloc_entries( count );
51 52

    if (sel)
Alexandre Julliard's avatar
Alexandre Julliard committed
53
    {
54 55 56 57 58
        LDT_ENTRY entry;
        wine_ldt_set_base( &entry, 0 );
        wine_ldt_set_limit( &entry, 1 ); /* avoid 0 base and limit */
        wine_ldt_set_flags( &entry, WINE_LDT_FLAGS_DATA );
        for (i = 0; i < count; i++) wine_ldt_set_entry( sel + (i << __AHSHIFT), &entry );
Alexandre Julliard's avatar
Alexandre Julliard committed
59
    }
60
    return sel;
Alexandre Julliard's avatar
Alexandre Julliard committed
61 62 63 64 65 66
}


/***********************************************************************
 *           AllocSelector   (KERNEL.175)
 */
67
WORD WINAPI AllocSelector16( WORD sel )
Alexandre Julliard's avatar
Alexandre Julliard committed
68 69 70
{
    WORD newsel, count, i;

71
    count = sel ? get_sel_count(sel) : 1;
72
    newsel = wine_ldt_alloc_entries( count );
73
    TRACE("(%04x): returning %04x\n", sel, newsel );
Alexandre Julliard's avatar
Alexandre Julliard committed
74 75 76 77
    if (!newsel) return 0;
    if (!sel) return newsel;  /* nothing to copy */
    for (i = 0; i < count; i++)
    {
78 79 80
        LDT_ENTRY entry;
        wine_ldt_get_entry( sel + (i << __AHSHIFT), &entry );
        wine_ldt_set_entry( newsel + (i << __AHSHIFT), &entry );
Alexandre Julliard's avatar
Alexandre Julliard committed
81 82 83 84 85 86 87 88
    }
    return newsel;
}


/***********************************************************************
 *           FreeSelector   (KERNEL.176)
 */
89
WORD WINAPI FreeSelector16( WORD sel )
Alexandre Julliard's avatar
Alexandre Julliard committed
90
{
91
    LDT_ENTRY entry;
92

93 94
    wine_ldt_get_entry( sel, &entry );
    if (wine_ldt_is_empty( &entry )) return sel;  /* error */
95
#ifdef __i386__
96
    /* Check if we are freeing current %fs selector */
97
    if (!((wine_get_fs() ^ sel) & ~3))
98
        WARN("Freeing %%fs selector (%04x), not good.\n", wine_get_fs() );
99
#endif  /* __i386__ */
100
    wine_ldt_free_entries( sel, 1 );
Alexandre Julliard's avatar
Alexandre Julliard committed
101 102 103 104 105 106 107 108 109
    return 0;
}


/***********************************************************************
 *           SELECTOR_SetEntries
 *
 * Set the LDT entries for an array of selectors.
 */
110
static void SELECTOR_SetEntries( WORD sel, const void *base, DWORD size, unsigned char flags )
Alexandre Julliard's avatar
Alexandre Julliard committed
111
{
112
    LDT_ENTRY entry;
Alexandre Julliard's avatar
Alexandre Julliard committed
113 114
    WORD i, count;

115
    wine_ldt_set_base( &entry, base );
116
    wine_ldt_set_limit( &entry, size - 1 );
117
    wine_ldt_set_flags( &entry, flags );
Alexandre Julliard's avatar
Alexandre Julliard committed
118 119 120
    count = (size + 0xffff) / 0x10000;
    for (i = 0; i < count; i++)
    {
121
        wine_ldt_set_entry( sel + (i << __AHSHIFT), &entry );
122
        wine_ldt_set_base( &entry, (char*)wine_ldt_get_base(&entry) + 0x10000);
123
        /* yep, Windows sets limit like that, not 64K sel units */
124
        wine_ldt_set_limit( &entry, wine_ldt_get_limit(&entry) - 0x10000 );
Alexandre Julliard's avatar
Alexandre Julliard committed
125 126 127 128 129 130 131 132 133
    }
}


/***********************************************************************
 *           SELECTOR_AllocBlock
 *
 * Allocate selectors for a block of linear memory.
 */
134
WORD SELECTOR_AllocBlock( const void *base, DWORD size, unsigned char flags )
Alexandre Julliard's avatar
Alexandre Julliard committed
135 136 137 138 139
{
    WORD sel, count;

    if (!size) return 0;
    count = (size + 0xffff) / 0x10000;
140
    sel = wine_ldt_alloc_entries( count );
141
    if (sel) SELECTOR_SetEntries( sel, base, size, flags );
Alexandre Julliard's avatar
Alexandre Julliard committed
142 143 144 145
    return sel;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
146 147 148 149 150
/***********************************************************************
 *           SELECTOR_FreeBlock
 *
 * Free a block of selectors.
 */
151
void SELECTOR_FreeBlock( WORD sel )
Alexandre Julliard's avatar
Alexandre Julliard committed
152
{
153
    WORD i, count = get_sel_count( sel );
Alexandre Julliard's avatar
Alexandre Julliard committed
154

155
    TRACE("(%04x,%d)\n", sel, count );
156
    for (i = 0; i < count; i++) FreeSelector16( sel + (i << __AHSHIFT) );
Alexandre Julliard's avatar
Alexandre Julliard committed
157 158 159
}


Alexandre Julliard's avatar
Alexandre Julliard committed
160 161 162 163 164
/***********************************************************************
 *           SELECTOR_ReallocBlock
 *
 * Change the size of a block of selectors.
 */
165
WORD SELECTOR_ReallocBlock( WORD sel, const void *base, DWORD size )
Alexandre Julliard's avatar
Alexandre Julliard committed
166
{
167
    LDT_ENTRY entry;
168
    int oldcount, newcount;
Alexandre Julliard's avatar
Alexandre Julliard committed
169

Alexandre Julliard's avatar
Alexandre Julliard committed
170
    if (!size) size = 1;
171
    wine_ldt_get_entry( sel, &entry );
172 173
    oldcount = (wine_ldt_get_limit(&entry) >> 16) + 1;
    newcount = (size + 0xffff) >> 16;
Alexandre Julliard's avatar
Alexandre Julliard committed
174

175
    sel = wine_ldt_realloc_entries( sel, oldcount, newcount );
176
    if (sel) SELECTOR_SetEntries( sel, base, size, wine_ldt_get_flags(&entry) );
Alexandre Julliard's avatar
Alexandre Julliard committed
177 178 179 180 181 182 183
    return sel;
}


/***********************************************************************
 *           PrestoChangoSelector   (KERNEL.177)
 */
184
WORD WINAPI PrestoChangoSelector16( WORD selSrc, WORD selDst )
Alexandre Julliard's avatar
Alexandre Julliard committed
185
{
186 187 188 189 190
    LDT_ENTRY entry;
    wine_ldt_get_entry( selSrc, &entry );
    /* toggle the executable bit */
    entry.HighWord.Bits.Type ^= (WINE_LDT_FLAGS_CODE ^ WINE_LDT_FLAGS_DATA);
    wine_ldt_set_entry( selDst, &entry );
Alexandre Julliard's avatar
Alexandre Julliard committed
191 192 193 194 195
    return selDst;
}


/***********************************************************************
196
 *           AllocCStoDSAlias   (KERNEL.170)
Patrik Stridvall's avatar
Patrik Stridvall committed
197
 *           AllocAlias         (KERNEL.172)
Alexandre Julliard's avatar
Alexandre Julliard committed
198
 */
199
WORD WINAPI AllocCStoDSAlias16( WORD sel )
Alexandre Julliard's avatar
Alexandre Julliard committed
200 201
{
    WORD newsel;
202
    LDT_ENTRY entry;
Alexandre Julliard's avatar
Alexandre Julliard committed
203

204
    newsel = wine_ldt_alloc_entries( 1 );
205
    TRACE("(%04x): returning %04x\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
206 207
                      sel, newsel );
    if (!newsel) return 0;
208 209 210
    wine_ldt_get_entry( sel, &entry );
    entry.HighWord.Bits.Type = WINE_LDT_FLAGS_DATA;
    wine_ldt_set_entry( newsel, &entry );
Alexandre Julliard's avatar
Alexandre Julliard committed
211 212 213 214 215 216 217
    return newsel;
}


/***********************************************************************
 *           AllocDStoCSAlias   (KERNEL.171)
 */
218
WORD WINAPI AllocDStoCSAlias16( WORD sel )
Alexandre Julliard's avatar
Alexandre Julliard committed
219 220
{
    WORD newsel;
221
    LDT_ENTRY entry;
Alexandre Julliard's avatar
Alexandre Julliard committed
222

223
    newsel = wine_ldt_alloc_entries( 1 );
224
    TRACE("(%04x): returning %04x\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
225 226
                      sel, newsel );
    if (!newsel) return 0;
227 228 229
    wine_ldt_get_entry( sel, &entry );
    entry.HighWord.Bits.Type = WINE_LDT_FLAGS_CODE;
    wine_ldt_set_entry( newsel, &entry );
Alexandre Julliard's avatar
Alexandre Julliard committed
230 231 232 233 234 235 236
    return newsel;
}


/***********************************************************************
 *           LongPtrAdd   (KERNEL.180)
 */
237
void WINAPI LongPtrAdd16( DWORD ptr, DWORD add )
Alexandre Julliard's avatar
Alexandre Julliard committed
238
{
239 240 241 242
    LDT_ENTRY entry;
    wine_ldt_get_entry( SELECTOROF(ptr), &entry );
    wine_ldt_set_base( &entry, (char *)wine_ldt_get_base(&entry) + add );
    wine_ldt_set_entry( SELECTOROF(ptr), &entry );
Alexandre Julliard's avatar
Alexandre Julliard committed
243 244 245 246
}


/***********************************************************************
247
 *             GetSelectorBase   (KERNEL.186)
248
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
249
DWORD WINAPI GetSelectorBase( WORD sel )
Alexandre Julliard's avatar
Alexandre Julliard committed
250
{
251
    void *base = wine_ldt_copy.base[sel >> __AHSHIFT];
Alexandre Julliard's avatar
Alexandre Julliard committed
252 253

    /* if base points into DOSMEM, assume we have to
Alexandre Julliard's avatar
Alexandre Julliard committed
254 255
     * return pointer into physical lower 1MB */

256
    return DOSMEM_MapLinearToDos( base );
Alexandre Julliard's avatar
Alexandre Julliard committed
257 258 259 260
}


/***********************************************************************
261
 *             SetSelectorBase   (KERNEL.187)
262
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
263
WORD WINAPI SetSelectorBase( WORD sel, DWORD base )
Alexandre Julliard's avatar
Alexandre Julliard committed
264
{
265 266 267 268
    LDT_ENTRY entry;
    wine_ldt_get_entry( sel, &entry );
    wine_ldt_set_base( &entry, DOSMEM_MapDosToLinear(base) );
    wine_ldt_set_entry( sel, &entry );
Alexandre Julliard's avatar
Alexandre Julliard committed
269 270 271 272 273 274 275
    return sel;
}


/***********************************************************************
 *           GetSelectorLimit   (KERNEL.188)
 */
276
DWORD WINAPI GetSelectorLimit16( WORD sel )
Alexandre Julliard's avatar
Alexandre Julliard committed
277
{
278
    return wine_ldt_copy.limit[sel >> __AHSHIFT];
Alexandre Julliard's avatar
Alexandre Julliard committed
279 280 281 282 283 284
}


/***********************************************************************
 *           SetSelectorLimit   (KERNEL.189)
 */
285
WORD WINAPI SetSelectorLimit16( WORD sel, DWORD limit )
Alexandre Julliard's avatar
Alexandre Julliard committed
286
{
287 288 289 290
    LDT_ENTRY entry;
    wine_ldt_get_entry( sel, &entry );
    wine_ldt_set_limit( &entry, limit );
    wine_ldt_set_entry( sel, &entry );
Alexandre Julliard's avatar
Alexandre Julliard committed
291 292 293 294 295 296 297
    return sel;
}


/***********************************************************************
 *           SelectorAccessRights   (KERNEL.196)
 */
298
WORD WINAPI SelectorAccessRights16( WORD sel, WORD op, WORD val )
Alexandre Julliard's avatar
Alexandre Julliard committed
299
{
300 301 302
    LDT_ENTRY entry;
    wine_ldt_get_entry( sel, &entry );

Alexandre Julliard's avatar
Alexandre Julliard committed
303 304
    if (op == 0)  /* get */
    {
305
        return entry.HighWord.Bytes.Flags1 | ((entry.HighWord.Bytes.Flags2 << 8) & 0xf0);
Alexandre Julliard's avatar
Alexandre Julliard committed
306 307 308
    }
    else  /* set */
    {
309 310 311
        entry.HighWord.Bytes.Flags1 = LOBYTE(val) | 0xf0;
        entry.HighWord.Bytes.Flags2 = (entry.HighWord.Bytes.Flags2 & 0x0f) | (HIBYTE(val) & 0xf0);
        wine_ldt_set_entry( sel, &entry );
Alexandre Julliard's avatar
Alexandre Julliard committed
312 313 314 315 316 317
        return 0;
    }
}


/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
318
 *           IsBadCodePtr   (KERNEL.336)
Alexandre Julliard's avatar
Alexandre Julliard committed
319
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
320
BOOL16 WINAPI IsBadCodePtr16( SEGPTR lpfn )
Alexandre Julliard's avatar
Alexandre Julliard committed
321 322
{
    WORD sel;
323
    LDT_ENTRY entry;
Alexandre Julliard's avatar
Alexandre Julliard committed
324 325

    sel = SELECTOROF(lpfn);
Alexandre Julliard's avatar
Alexandre Julliard committed
326
    if (!sel) return TRUE;
327
    wine_ldt_get_entry( sel, &entry );
328
    if (wine_ldt_is_empty( &entry )) return TRUE;
329 330 331
    /* check for code segment, ignoring conforming, read-only and accessed bits */
    if ((entry.HighWord.Bits.Type ^ WINE_LDT_FLAGS_CODE) & 0x18) return TRUE;
    if (OFFSETOF(lpfn) > wine_ldt_get_limit(&entry)) return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
332
    return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
333 334 335 336
}


/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
337
 *           IsBadStringPtr   (KERNEL.337)
Alexandre Julliard's avatar
Alexandre Julliard committed
338
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
339
BOOL16 WINAPI IsBadStringPtr16( SEGPTR ptr, UINT16 size )
Alexandre Julliard's avatar
Alexandre Julliard committed
340 341
{
    WORD sel;
342
    LDT_ENTRY entry;
Alexandre Julliard's avatar
Alexandre Julliard committed
343 344

    sel = SELECTOROF(ptr);
Alexandre Julliard's avatar
Alexandre Julliard committed
345
    if (!sel) return TRUE;
346
    wine_ldt_get_entry( sel, &entry );
347
    if (wine_ldt_is_empty( &entry )) return TRUE;
348 349 350
    /* check for data or readable code segment */
    if (!(entry.HighWord.Bits.Type & 0x10)) return TRUE;  /* system descriptor */
    if ((entry.HighWord.Bits.Type & 0x0a) == 0x08) return TRUE;  /* non-readable code segment */
351
    if (strlen(MapSL(ptr)) < size) size = strlen(MapSL(ptr)) + 1;
352
    if (size && (OFFSETOF(ptr) + size - 1 > wine_ldt_get_limit(&entry))) return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
353
    return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
354 355 356 357
}


/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
358
 *           IsBadHugeReadPtr   (KERNEL.346)
Alexandre Julliard's avatar
Alexandre Julliard committed
359
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
360
BOOL16 WINAPI IsBadHugeReadPtr16( SEGPTR ptr, DWORD size )
Alexandre Julliard's avatar
Alexandre Julliard committed
361 362
{
    WORD sel;
363
    LDT_ENTRY entry;
Alexandre Julliard's avatar
Alexandre Julliard committed
364 365

    sel = SELECTOROF(ptr);
Alexandre Julliard's avatar
Alexandre Julliard committed
366
    if (!sel) return TRUE;
367
    wine_ldt_get_entry( sel, &entry );
368
    if (wine_ldt_is_empty( &entry )) return TRUE;
369 370 371 372
    /* check for data or readable code segment */
    if (!(entry.HighWord.Bits.Type & 0x10)) return TRUE;  /* system descriptor */
    if ((entry.HighWord.Bits.Type & 0x0a) == 0x08) return TRUE;  /* non-readable code segment */
    if (size && (OFFSETOF(ptr) + size - 1 > wine_ldt_get_limit( &entry ))) return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
373
    return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
374 375 376 377
}


/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
378
 *           IsBadHugeWritePtr   (KERNEL.347)
Alexandre Julliard's avatar
Alexandre Julliard committed
379
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
380
BOOL16 WINAPI IsBadHugeWritePtr16( SEGPTR ptr, DWORD size )
Alexandre Julliard's avatar
Alexandre Julliard committed
381 382
{
    WORD sel;
383
    LDT_ENTRY entry;
Alexandre Julliard's avatar
Alexandre Julliard committed
384 385

    sel = SELECTOROF(ptr);
Alexandre Julliard's avatar
Alexandre Julliard committed
386
    if (!sel) return TRUE;
387
    wine_ldt_get_entry( sel, &entry );
388
    if (wine_ldt_is_empty( &entry )) return TRUE;
389 390 391
    /* check for writeable data segment, ignoring expand-down and accessed flags */
    if ((entry.HighWord.Bits.Type ^ WINE_LDT_FLAGS_DATA) & ~5) return TRUE;
    if (size && (OFFSETOF(ptr) + size - 1 > wine_ldt_get_limit( &entry ))) return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
392
    return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
393 394 395
}

/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
396
 *           IsBadReadPtr   (KERNEL.334)
Alexandre Julliard's avatar
Alexandre Julliard committed
397
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
398
BOOL16 WINAPI IsBadReadPtr16( SEGPTR ptr, UINT16 size )
Alexandre Julliard's avatar
Alexandre Julliard committed
399
{
Alexandre Julliard's avatar
Alexandre Julliard committed
400
    return IsBadHugeReadPtr16( ptr, size );
Alexandre Julliard's avatar
Alexandre Julliard committed
401 402 403 404
}


/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
405
 *           IsBadWritePtr   (KERNEL.335)
Alexandre Julliard's avatar
Alexandre Julliard committed
406
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
407
BOOL16 WINAPI IsBadWritePtr16( SEGPTR ptr, UINT16 size )
Alexandre Julliard's avatar
Alexandre Julliard committed
408
{
Alexandre Julliard's avatar
Alexandre Julliard committed
409
    return IsBadHugeWritePtr16( ptr, size );
Alexandre Julliard's avatar
Alexandre Julliard committed
410 411 412
}


413
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
414
 *           IsBadFlatReadWritePtr   (KERNEL.627)
415 416 417 418 419 420 421 422
 */
BOOL16 WINAPI IsBadFlatReadWritePtr16( SEGPTR ptr, DWORD size, BOOL16 bWrite )
{
    return bWrite? IsBadHugeWritePtr16( ptr, size )
                 : IsBadHugeReadPtr16( ptr, size );
}


Alexandre Julliard's avatar
Alexandre Julliard committed
423 424 425
/***********************************************************************
 *           MemoryRead   (TOOLHELP.78)
 */
426
DWORD WINAPI MemoryRead16( WORD sel, DWORD offset, void *buffer, DWORD count )
Alexandre Julliard's avatar
Alexandre Julliard committed
427
{
428 429
    LDT_ENTRY entry;
    DWORD limit;
430

431 432 433 434 435 436
    wine_ldt_get_entry( sel, &entry );
    if (wine_ldt_is_empty( &entry )) return 0;
    limit = wine_ldt_get_limit( &entry );
    if (offset > limit) return 0;
    if (offset + count > limit + 1) count = limit + 1 - offset;
    memcpy( buffer, (char *)wine_ldt_get_base(&entry) + offset, count );
Alexandre Julliard's avatar
Alexandre Julliard committed
437 438 439 440 441 442 443
    return count;
}


/***********************************************************************
 *           MemoryWrite   (TOOLHELP.79)
 */
444
DWORD WINAPI MemoryWrite16( WORD sel, DWORD offset, void *buffer, DWORD count )
Alexandre Julliard's avatar
Alexandre Julliard committed
445
{
446 447
    LDT_ENTRY entry;
    DWORD limit;
448

449 450 451 452 453 454
    wine_ldt_get_entry( sel, &entry );
    if (wine_ldt_is_empty( &entry )) return 0;
    limit = wine_ldt_get_limit( &entry );
    if (offset > limit) return 0;
    if (offset + count > limit) count = limit + 1 - offset;
    memcpy( (char *)wine_ldt_get_base(&entry) + offset, buffer, count );
Alexandre Julliard's avatar
Alexandre Julliard committed
455 456
    return count;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
457 458 459 460 461

/************************************* Win95 pointer mapping functions *
 *
 */

462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539
struct mapls_entry
{
    struct mapls_entry *next;
    void               *addr;   /* linear address */
    int                 count;  /* ref count */
    WORD                sel;    /* selector */
};

static struct mapls_entry *first_entry;


/***********************************************************************
 *           MapLS   (KERNEL32.@)
 *           MapLS   (KERNEL.358)
 *
 * Maps linear pointer to segmented.
 */
SEGPTR WINAPI MapLS( LPCVOID ptr )
{
    struct mapls_entry *entry, *free = NULL;
    void *base;
    SEGPTR ret = 0;

    if (!HIWORD(ptr)) return (SEGPTR)ptr;

    base = (char *)ptr - ((unsigned int)ptr & 0x7fff);
    HeapLock( GetProcessHeap() );
    for (entry = first_entry; entry; entry = entry->next)
    {
        if (entry->addr == base) break;
        if (!entry->count) free = entry;
    }

    if (!entry)
    {
        if (!free)  /* no free entry found, create a new one */
        {
            if (!(free = HeapAlloc( GetProcessHeap(), 0, sizeof(*free) ))) goto done;
            if (!(free->sel = SELECTOR_AllocBlock( base, 0x10000, WINE_LDT_FLAGS_DATA )))
            {
                HeapFree( GetProcessHeap(), 0, free );
                goto done;
            }
            free->count = 0;
            free->next = first_entry;
            first_entry = free;
        }
        SetSelectorBase( free->sel, (DWORD)base );
        free->addr = base;
        entry = free;
    }
    entry->count++;
    ret = MAKESEGPTR( entry->sel, (char *)ptr - (char *)entry->addr );
 done:
    HeapUnlock( GetProcessHeap() );
    return ret;
}

/***********************************************************************
 *           UnMapLS   (KERNEL32.@)
 *           UnMapLS   (KERNEL.359)
 *
 * Free mapped selector.
 */
void WINAPI UnMapLS( SEGPTR sptr )
{
    struct mapls_entry *entry;
    WORD sel = SELECTOROF(sptr);

    if (sel)
    {
        HeapLock( GetProcessHeap() );
        for (entry = first_entry; entry; entry = entry->next) if (entry->sel == sel) break;
        if (entry && entry->count > 0) entry->count--;
        HeapUnlock( GetProcessHeap() );
    }
}

Alexandre Julliard's avatar
Alexandre Julliard committed
540
/***********************************************************************
541
 *           MapSL   (KERNEL32.@)
Patrik Stridvall's avatar
Patrik Stridvall committed
542
 *           MapSL   (KERNEL.357)
Alexandre Julliard's avatar
Alexandre Julliard committed
543 544 545
 *
 * Maps fixed segmented pointer to linear.
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
546
LPVOID WINAPI MapSL( SEGPTR sptr )
Alexandre Julliard's avatar
Alexandre Julliard committed
547
{
548
    return (char *)wine_ldt_copy.base[SELECTOROF(sptr) >> __AHSHIFT] + OFFSETOF(sptr);
Alexandre Julliard's avatar
Alexandre Julliard committed
549 550
}

Alexandre Julliard's avatar
Alexandre Julliard committed
551
/***********************************************************************
552
 *           MapSLFix   (KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
553 554 555 556 557 558 559 560
 *
 * FIXME: MapSLFix and UnMapSLFixArray should probably prevent
 * unexpected linear address change when GlobalCompact() shuffles
 * moveable blocks.
 */

LPVOID WINAPI MapSLFix( SEGPTR sptr )
{
561
    return MapSL(sptr);
Alexandre Julliard's avatar
Alexandre Julliard committed
562 563 564
}

/***********************************************************************
565
 *           UnMapSLFixArray   (KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
566 567
 */

568
void WINAPI UnMapSLFixArray( SEGPTR sptr[], INT length, CONTEXT86 *context )
Alexandre Julliard's avatar
Alexandre Julliard committed
569
{
570
    /* Must not change EAX, hence defined as 'register' function */
Alexandre Julliard's avatar
Alexandre Julliard committed
571
}
Alexandre Julliard's avatar
Alexandre Julliard committed
572

Alexandre Julliard's avatar
Alexandre Julliard committed
573
/***********************************************************************
574
 *           GetThreadSelectorEntry   (KERNEL32.@)
575 576 577 578
 */
BOOL WINAPI GetThreadSelectorEntry( HANDLE hthread, DWORD sel, LPLDT_ENTRY ldtent)
{
#ifdef __i386__
579
    BOOL ret;
580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600

    if (!(sel & 4))  /* GDT selector */
    {
        sel &= ~3;  /* ignore RPL */
        if (!sel)  /* null selector */
        {
            memset( ldtent, 0, sizeof(*ldtent) );
            return TRUE;
        }
        ldtent->BaseLow                   = 0;
        ldtent->HighWord.Bits.BaseMid     = 0;
        ldtent->HighWord.Bits.BaseHi      = 0;
        ldtent->LimitLow                  = 0xffff;
        ldtent->HighWord.Bits.LimitHi     = 0xf;
        ldtent->HighWord.Bits.Dpl         = 3;
        ldtent->HighWord.Bits.Sys         = 0;
        ldtent->HighWord.Bits.Pres        = 1;
        ldtent->HighWord.Bits.Granularity = 1;
        ldtent->HighWord.Bits.Default_Big = 1;
        ldtent->HighWord.Bits.Type        = 0x12;
        /* it has to be one of the system GDT selectors */
601 602 603
        if (sel == (wine_get_ds() & ~3)) return TRUE;
        if (sel == (wine_get_ss() & ~3)) return TRUE;
        if (sel == (wine_get_cs() & ~3))
604 605 606 607 608 609 610 611
        {
            ldtent->HighWord.Bits.Type |= 8;  /* code segment */
            return TRUE;
        }
        SetLastError( ERROR_NOACCESS );
        return FALSE;
    }

612
    SERVER_START_REQ( get_selector_entry )
613
    {
614 615
        req->handle = hthread;
        req->entry = sel >> __AHSHIFT;
616
        if ((ret = !wine_server_call_err( req )))
617
        {
618
            if (!(reply->flags & WINE_LDT_FLAGS_ALLOCATED))
619 620 621 622 623 624
            {
                SetLastError( ERROR_MR_MID_NOT_FOUND );  /* sic */
                ret = FALSE;
            }
            else
            {
625 626 627
                wine_ldt_set_base( ldtent, (void *)reply->base );
                wine_ldt_set_limit( ldtent, reply->limit );
                wine_ldt_set_flags( ldtent, reply->flags );
628 629
            }
        }
630
    }
631 632
    SERVER_END_REQ;
    return ret;
633
#else
634
    SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
635 636
    return FALSE;
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
637 638 639 640 641 642 643 644 645 646 647
}


/**********************************************************************
 * 		SMapLS*		(KERNEL32)
 * These functions map linear pointers at [EBP+xxx] to segmented pointers
 * and return them.
 * Win95 uses some kind of alias structs, which it stores in [EBP+x] to
 * unravel them at SUnMapLS. We just store the segmented pointer there.
 */
static void
648
x_SMapLS_IP_EBP_x(CONTEXT86 *context,int argoff) {
649
    DWORD	val,ptr;
Alexandre Julliard's avatar
Alexandre Julliard committed
650

651
    val =*(DWORD*)(context->Ebp + argoff);
Alexandre Julliard's avatar
Alexandre Julliard committed
652 653
    if (val<0x10000) {
	ptr=val;
654
        *(DWORD*)(context->Ebp + argoff) = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
655 656
    } else {
    	ptr = MapLS((LPVOID)val);
657
        *(DWORD*)(context->Ebp + argoff) = ptr;
Alexandre Julliard's avatar
Alexandre Julliard committed
658
    }
659
    context->Eax = ptr;
Alexandre Julliard's avatar
Alexandre Julliard committed
660 661
}

662
/***********************************************************************
663
 *		SMapLS_IP_EBP_8 (KERNEL32.@)
664
 */
665
void WINAPI SMapLS_IP_EBP_8 (CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context, 8);}
666 667

/***********************************************************************
668
 *		SMapLS_IP_EBP_12 (KERNEL32.@)
669
 */
670
void WINAPI SMapLS_IP_EBP_12(CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context,12);}
671 672

/***********************************************************************
673
 *		SMapLS_IP_EBP_16 (KERNEL32.@)
674
 */
675
void WINAPI SMapLS_IP_EBP_16(CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context,16);}
676 677

/***********************************************************************
678
 *		SMapLS_IP_EBP_20 (KERNEL32.@)
679
 */
680
void WINAPI SMapLS_IP_EBP_20(CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context,20);}
681 682

/***********************************************************************
683
 *		SMapLS_IP_EBP_24 (KERNEL32.@)
684
 */
685
void WINAPI SMapLS_IP_EBP_24(CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context,24);}
686 687

/***********************************************************************
688
 *		SMapLS_IP_EBP_28 (KERNEL32.@)
689
 */
690
void WINAPI SMapLS_IP_EBP_28(CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context,28);}
691 692

/***********************************************************************
693
 *		SMapLS_IP_EBP_32 (KERNEL32.@)
694
 */
695
void WINAPI SMapLS_IP_EBP_32(CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context,32);}
696 697

/***********************************************************************
698
 *		SMapLS_IP_EBP_36 (KERNEL32.@)
699
 */
700
void WINAPI SMapLS_IP_EBP_36(CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context,36);}
701 702

/***********************************************************************
703
 *		SMapLS_IP_EBP_40 (KERNEL32.@)
704
 */
705
void WINAPI SMapLS_IP_EBP_40(CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context,40);}
Alexandre Julliard's avatar
Alexandre Julliard committed
706

707
/***********************************************************************
708
 *		SMapLS (KERNEL32.@)
709
 */
710
void WINAPI SMapLS( CONTEXT86 *context )
Alexandre Julliard's avatar
Alexandre Julliard committed
711
{
712 713 714 715
    if (HIWORD(context->Eax))
    {
        context->Eax = MapLS( (LPVOID)context->Eax );
        context->Edx = context->Eax;
Alexandre Julliard's avatar
Alexandre Julliard committed
716
    } else {
717
        context->Edx = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
718 719 720
    }
}

721
/***********************************************************************
722
 *		SUnMapLS (KERNEL32.@)
723 724
 */

725
void WINAPI SUnMapLS( CONTEXT86 *context )
Alexandre Julliard's avatar
Alexandre Julliard committed
726
{
727
    if (HIWORD(context->Eax)) UnMapLS( (SEGPTR)context->Eax );
Alexandre Julliard's avatar
Alexandre Julliard committed
728 729
}

730 731 732 733 734 735 736 737
inline static void x_SUnMapLS_IP_EBP_x(CONTEXT86 *context,int argoff)
{
    SEGPTR *ptr = (SEGPTR *)(context->Ebp + argoff);
    if (*ptr)
    {
        UnMapLS( *ptr );
        *ptr = 0;
    }
738
}
739 740

/***********************************************************************
741
 *		SUnMapLS_IP_EBP_8 (KERNEL32.@)
742
 */
743
void WINAPI SUnMapLS_IP_EBP_8 (CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context, 8); }
744 745

/***********************************************************************
746
 *		SUnMapLS_IP_EBP_12 (KERNEL32.@)
747
 */
748
void WINAPI SUnMapLS_IP_EBP_12(CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context,12); }
749 750

/***********************************************************************
751
 *		SUnMapLS_IP_EBP_16 (KERNEL32.@)
752
 */
753
void WINAPI SUnMapLS_IP_EBP_16(CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context,16); }
754 755

/***********************************************************************
756
 *		SUnMapLS_IP_EBP_20 (KERNEL32.@)
757
 */
758
void WINAPI SUnMapLS_IP_EBP_20(CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context,20); }
759 760

/***********************************************************************
761
 *		SUnMapLS_IP_EBP_24 (KERNEL32.@)
762
 */
763
void WINAPI SUnMapLS_IP_EBP_24(CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context,24); }
764 765

/***********************************************************************
766
 *		SUnMapLS_IP_EBP_28 (KERNEL32.@)
767
 */
768
void WINAPI SUnMapLS_IP_EBP_28(CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context,28); }
769 770

/***********************************************************************
771
 *		SUnMapLS_IP_EBP_32 (KERNEL32.@)
772
 */
773
void WINAPI SUnMapLS_IP_EBP_32(CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context,32); }
774 775

/***********************************************************************
776
 *		SUnMapLS_IP_EBP_36 (KERNEL32.@)
777
 */
778
void WINAPI SUnMapLS_IP_EBP_36(CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context,36); }
779 780

/***********************************************************************
781
 *		SUnMapLS_IP_EBP_40 (KERNEL32.@)
782
 */
783
void WINAPI SUnMapLS_IP_EBP_40(CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context,40); }