vxd.c 50.9 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3 4
/*
 * VxD emulation
 *
 * Copyright 1995 Anand Kumria
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * 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
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 <fcntl.h>
25
#include <string.h>
26
#include <stdarg.h>
27
#include <stdio.h>
28
#include <sys/types.h>
29 30 31
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
32 33 34

#define NONAMELESSUNION
#define NONAMELESSSTRUCT
35 36
#include "ntstatus.h"
#define WIN32_NO_STATUS
37
#include "windef.h"
38 39
#include "winbase.h"
#include "winreg.h"
40
#include "winternl.h"
41
#include "wingdi.h"
42 43
#include "winuser.h"
#include "wine/winbase16.h"
44
#include "dosexe.h"
45
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
46

47
WINE_DEFAULT_DEBUG_CHANNEL(vxd);
48

49 50
#define W32S_APP2WINE(addr) ((addr)? (DWORD)(addr) + W32S_offset : 0)
#define W32S_WINE2APP(addr) ((addr)? (DWORD)(addr) - W32S_offset : 0)
Alexandre Julliard's avatar
Alexandre Julliard committed
51

Alexandre Julliard's avatar
Alexandre Julliard committed
52
#define VXD_BARF(context,name) \
Diego Pettenò's avatar
Diego Pettenò committed
53
    TRACE( "vxd %s: unknown/not implemented parameters:\n" \
Alexandre Julliard's avatar
Alexandre Julliard committed
54 55 56 57
                     "vxd %s: AX %04x, BX %04x, CX %04x, DX %04x, " \
                     "SI %04x, DI %04x, DS %04x, ES %04x\n", \
             (name), (name), AX_reg(context), BX_reg(context), \
             CX_reg(context), DX_reg(context), SI_reg(context), \
58
             DI_reg(context), (WORD)context->SegDs, (WORD)context->SegEs )
Alexandre Julliard's avatar
Alexandre Julliard committed
59

60
static UINT W32S_offset;
Alexandre Julliard's avatar
Alexandre Julliard committed
61 62 63

static WORD VXD_WinVersion(void)
{
Alexandre Julliard's avatar
Alexandre Julliard committed
64
    WORD version = LOWORD(GetVersion16());
Alexandre Julliard's avatar
Alexandre Julliard committed
65 66 67
    return (version >> 8) | (version << 8);
}

Alexandre Julliard's avatar
Alexandre Julliard committed
68
/***********************************************************************
69
 *           VXD_VMM (WPROCS.401)
Alexandre Julliard's avatar
Alexandre Julliard committed
70
 */
71
void WINAPI VXD_VMM ( CONTEXT86 *context )
Alexandre Julliard's avatar
Alexandre Julliard committed
72 73 74
{
    unsigned service = AX_reg(context);

75
    TRACE("[%04x] VMM\n", (UINT16)service);
Alexandre Julliard's avatar
Alexandre Julliard committed
76 77 78 79

    switch(service)
    {
    case 0x0000: /* version */
80
        SET_AX( context, VXD_WinVersion() );
Alexandre Julliard's avatar
Alexandre Julliard committed
81 82 83
        RESET_CFLAG(context);
        break;

84 85
    case 0x026d: /* Get_Debug_Flag '/m' */
    case 0x026e: /* Get_Debug_Flag '/n' */
86
        SET_AL( context, 0 );
87 88 89
        RESET_CFLAG(context);
        break;

Alexandre Julliard's avatar
Alexandre Julliard committed
90 91 92 93 94
    default:
        VXD_BARF( context, "VMM" );
    }
}

Alexandre Julliard's avatar
Alexandre Julliard committed
95
/***********************************************************************
96
 *           VXD_PageFile (WPROCS.433)
Alexandre Julliard's avatar
Alexandre Julliard committed
97
 */
98
void WINAPI VXD_PageFile( CONTEXT86 *context )
Alexandre Julliard's avatar
Alexandre Julliard committed
99
{
Alexandre Julliard's avatar
Alexandre Julliard committed
100 101
    unsigned	service = AX_reg(context);

Alexandre Julliard's avatar
Alexandre Julliard committed
102 103
    /* taken from Ralf Brown's Interrupt List */

104
    TRACE("[%04x] PageFile\n", (UINT16)service );
Alexandre Julliard's avatar
Alexandre Julliard committed
105

Alexandre Julliard's avatar
Alexandre Julliard committed
106
    switch(service)
Alexandre Julliard's avatar
Alexandre Julliard committed
107 108
    {
    case 0x00: /* get version, is this windows version? */
109
	TRACE("returning version\n");
110
        SET_AX( context, VXD_WinVersion() );
Alexandre Julliard's avatar
Alexandre Julliard committed
111
	RESET_CFLAG(context);
Alexandre Julliard's avatar
Alexandre Julliard committed
112 113 114
	break;

    case 0x01: /* get swap file info */
115
	TRACE("VxD PageFile: returning swap file info\n");
116
	SET_AX( context, 0x00 ); /* paging disabled */
117
	context->Ecx = 0;   /* maximum size of paging file */
Alexandre Julliard's avatar
Alexandre Julliard committed
118
	/* FIXME: do I touch DS:SI or DS:DI? */
Alexandre Julliard's avatar
Alexandre Julliard committed
119
	RESET_CFLAG(context);
Alexandre Julliard's avatar
Alexandre Julliard committed
120 121 122
	break;

    case 0x02: /* delete permanent swap on exit */
123
	TRACE("VxD PageFile: supposed to delete swap\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
124
	RESET_CFLAG(context);
Alexandre Julliard's avatar
Alexandre Julliard committed
125 126 127
	break;

    case 0x03: /* current temporary swap file size */
128
	TRACE("VxD PageFile: what is current temp. swap size\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
129
	RESET_CFLAG(context);
Alexandre Julliard's avatar
Alexandre Julliard committed
130 131 132 133 134 135
	break;

    case 0x04: /* read or write?? INTERRUP.D */
    case 0x05: /* cancel?? INTERRUP.D */
    case 0x06: /* test I/O valid INTERRUP.D */
    default:
Alexandre Julliard's avatar
Alexandre Julliard committed
136
	VXD_BARF( context, "pagefile" );
Alexandre Julliard's avatar
Alexandre Julliard committed
137 138 139 140
	break;
    }
}

141
/***********************************************************************
142
 *           VXD_Reboot (WPROCS.409)
143
 */
144
void WINAPI VXD_Reboot ( CONTEXT86 *context )
145 146 147
{
    unsigned service = AX_reg(context);

148
    TRACE("[%04x] Reboot\n", (UINT16)service);
149 150 151 152

    switch(service)
    {
    case 0x0000: /* version */
153
        SET_AX( context, VXD_WinVersion() );
154 155 156 157 158 159 160 161 162
        RESET_CFLAG(context);
        break;

    default:
        VXD_BARF( context, "REBOOT" );
    }
}

/***********************************************************************
163
 *           VXD_VDD (WPROCS.410)
164
 */
165
void WINAPI VXD_VDD ( CONTEXT86 *context )
166 167 168
{
    unsigned service = AX_reg(context);

169
    TRACE("[%04x] VDD\n", (UINT16)service);
170 171 172 173

    switch(service)
    {
    case 0x0000: /* version */
174
        SET_AX( context, VXD_WinVersion() );
175 176 177 178 179 180 181
        RESET_CFLAG(context);
        break;

    default:
        VXD_BARF( context, "VDD" );
    }
}
Alexandre Julliard's avatar
Alexandre Julliard committed
182

183
/***********************************************************************
184
 *           VXD_VMD (WPROCS.412)
185
 */
186
void WINAPI VXD_VMD ( CONTEXT86 *context )
187 188 189
{
    unsigned service = AX_reg(context);

190
    TRACE("[%04x] VMD\n", (UINT16)service);
191 192 193 194

    switch(service)
    {
    case 0x0000: /* version */
195
        SET_AX( context, VXD_WinVersion() );
196 197 198 199 200 201 202 203
        RESET_CFLAG(context);
        break;

    default:
        VXD_BARF( context, "VMD" );
    }
}

204
/***********************************************************************
205
 *           VXD_VXDLoader (WPROCS.439)
206 207 208 209 210 211 212 213 214 215 216
 */
void WINAPI VXD_VXDLoader( CONTEXT86 *context )
{
    unsigned service = AX_reg(context);

    TRACE("[%04x] VXDLoader\n", (UINT16)service);

    switch (service)
    {
    case 0x0000: /* get version */
	TRACE("returning version\n");
217 218
	SET_AX( context, 0x0000 );
	SET_DX( context, VXD_WinVersion() );
219 220 221 222
	RESET_CFLAG(context);
	break;

    case 0x0001: /* load device */
223
	FIXME("load device %04x:%04x (%s)\n",
224
	      context->SegDs, DX_reg(context),
225
	      debugstr_a(MapSL(MAKESEGPTR(context->SegDs, DX_reg(context)))));
226
	SET_AX( context, 0x0000 );
227
	context->SegEs = 0x0000;
228
	SET_DI( context, 0x0000 );
229 230 231 232
	RESET_CFLAG(context);
	break;

    case 0x0002: /* unload device */
233
	FIXME("unload device (%08x)\n", context->Ebx);
234
	SET_AX( context, 0x0000 );
235 236 237 238 239
	RESET_CFLAG(context);
	break;

    default:
	VXD_BARF( context, "VXDLDR" );
240
	SET_AX( context, 0x000B ); /* invalid function number */
241 242
	SET_CFLAG(context);
	break;
243
    }
244 245
}

Alexandre Julliard's avatar
Alexandre Julliard committed
246
/***********************************************************************
247
 *           VXD_Shell (WPROCS.423)
Alexandre Julliard's avatar
Alexandre Julliard committed
248
 */
249
void WINAPI VXD_Shell( CONTEXT86 *context )
Alexandre Julliard's avatar
Alexandre Julliard committed
250
{
Alexandre Julliard's avatar
Alexandre Julliard committed
251 252
    unsigned	service = DX_reg(context);

253
    TRACE("[%04x] Shell\n", (UINT16)service);
Alexandre Julliard's avatar
Alexandre Julliard committed
254

Alexandre Julliard's avatar
Alexandre Julliard committed
255
    switch (service) /* Ralf Brown says EDX, but I use DX instead */
Alexandre Julliard's avatar
Alexandre Julliard committed
256 257
    {
    case 0x0000:
258
	TRACE("returning version\n");
259
        SET_AX( context, VXD_WinVersion() );
260
	context->Ebx = 1; /* system VM Handle */
Alexandre Julliard's avatar
Alexandre Julliard committed
261 262 263 264 265
	break;

    case 0x0001:
    case 0x0002:
    case 0x0003:
266
        /* SHELL_SYSMODAL_Message
Austin English's avatar
Austin English committed
267
	ebx virtual machine handle
268 269 270 271 272
	eax message box flags
	ecx address of message
	edi address of caption
	return response in eax
	*/
Alexandre Julliard's avatar
Alexandre Julliard committed
273
    case 0x0004:
274
	/* SHELL_Message
Austin English's avatar
Austin English committed
275
	ebx virtual machine handle
276 277 278 279 280 281 282
	eax message box flags
	ecx address of message
	edi address of caption
	esi address callback
	edx reference data for callback
	return response in eax
	*/
Alexandre Julliard's avatar
Alexandre Julliard committed
283
    case 0x0005:
Alexandre Julliard's avatar
Alexandre Julliard committed
284
	VXD_BARF( context, "shell" );
Alexandre Julliard's avatar
Alexandre Julliard committed
285 286 287
	break;

    case 0x0006: /* SHELL_Get_VM_State */
288
	TRACE("VxD Shell: returning VM state\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
289 290 291 292 293
	/* Actually we don't, not yet. We have to return a structure
         * and I am not to sure how to set it up and return it yet,
         * so for now let's do nothing. I can (hopefully) get this
         * by the next release
         */
Alexandre Julliard's avatar
Alexandre Julliard committed
294
	/* RESET_CFLAG(context); */
Alexandre Julliard's avatar
Alexandre Julliard committed
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
	break;

    case 0x0007:
    case 0x0008:
    case 0x0009:
    case 0x000A:
    case 0x000B:
    case 0x000C:
    case 0x000D:
    case 0x000E:
    case 0x000F:
    case 0x0010:
    case 0x0011:
    case 0x0012:
    case 0x0013:
    case 0x0014:
    case 0x0015:
    case 0x0016:
313 314 315 316 317
	VXD_BARF( context, "SHELL" );
	break;

    /* the new Win95 shell API */
    case 0x0100:     /* get version */
318
        SET_AX( context, VXD_WinVersion() );
319 320 321 322 323 324 325 326
	break;

    case 0x0104:   /* retrieve Hook_Properties list */
    case 0x0105:   /* call Hook_Properties callbacks */
	VXD_BARF( context, "SHELL" );
	break;

    case 0x0106:   /* install timeout callback */
327
	TRACE("VxD Shell: ignoring shell callback (%d sec.)\n", context->Ebx);
328 329 330 331
	SET_CFLAG(context);
	break;

    case 0x0107:   /* get version of any VxD */
Alexandre Julliard's avatar
Alexandre Julliard committed
332
    default:
333
	VXD_BARF( context, "SHELL" );
Alexandre Julliard's avatar
Alexandre Julliard committed
334 335 336 337 338 339
	break;
    }
}


/***********************************************************************
340
 *           VXD_Comm (WPROCS.414)
Alexandre Julliard's avatar
Alexandre Julliard committed
341
 */
342
void WINAPI VXD_Comm( CONTEXT86 *context )
Alexandre Julliard's avatar
Alexandre Julliard committed
343
{
Alexandre Julliard's avatar
Alexandre Julliard committed
344 345
    unsigned	service = AX_reg(context);

346
    TRACE("[%04x] Comm\n", (UINT16)service);
Alexandre Julliard's avatar
Alexandre Julliard committed
347

Alexandre Julliard's avatar
Alexandre Julliard committed
348
    switch (service)
Alexandre Julliard's avatar
Alexandre Julliard committed
349 350
    {
    case 0x0000: /* get version */
351
	TRACE("returning version\n");
352
        SET_AX( context, VXD_WinVersion() );
Alexandre Julliard's avatar
Alexandre Julliard committed
353
	RESET_CFLAG(context);
Alexandre Julliard's avatar
Alexandre Julliard committed
354 355 356 357 358 359
	break;

    case 0x0001: /* set port global */
    case 0x0002: /* get focus */
    case 0x0003: /* virtualise port */
    default:
Alexandre Julliard's avatar
Alexandre Julliard committed
360
        VXD_BARF( context, "comm" );
Alexandre Julliard's avatar
Alexandre Julliard committed
361 362
    }
}
Alexandre Julliard's avatar
Alexandre Julliard committed
363 364

/***********************************************************************
365
 *           VXD_Timer (WPROCS.405)
Alexandre Julliard's avatar
Alexandre Julliard committed
366
 */
367
void WINAPI VXD_Timer( CONTEXT86 *context )
Alexandre Julliard's avatar
Alexandre Julliard committed
368 369 370
{
    unsigned service = AX_reg(context);

371
    TRACE("[%04x] Virtual Timer\n", (UINT16)service);
Alexandre Julliard's avatar
Alexandre Julliard committed
372 373 374 375

    switch(service)
    {
    case 0x0000: /* version */
376
	SET_AX( context, VXD_WinVersion() );
Alexandre Julliard's avatar
Alexandre Julliard committed
377 378 379 380
	RESET_CFLAG(context);
	break;

    case 0x0100: /* clock tick time, in 840nsecs */
381
	context->Eax = GetTickCount();
Alexandre Julliard's avatar
Alexandre Julliard committed
382

383 384
	context->Edx = context->Eax >> 22;
	context->Eax <<= 10; /* not very precise */
Alexandre Julliard's avatar
Alexandre Julliard committed
385 386 387 388
	break;

    case 0x0101: /* current Windows time, msecs */
    case 0x0102: /* current VM time, msecs */
389
	context->Eax = GetTickCount();
Alexandre Julliard's avatar
Alexandre Julliard committed
390 391 392 393 394 395 396
	break;

    default:
	VXD_BARF( context, "VTD" );
    }
}

397 398 399 400 401 402 403 404 405 406 407 408 409

/***********************************************************************
 *           timer_thread
 */
static DWORD CALLBACK timer_thread( void *arg )
{
    DWORD *system_time = arg;

    for (;;)
    {
        *system_time = GetTickCount();
        Sleep( 55 );
    }
410 411

    return 0;
412 413 414
}


Alexandre Julliard's avatar
Alexandre Julliard committed
415
/***********************************************************************
416
 *           VXD_TimerAPI (WPROCS.1490)
Alexandre Julliard's avatar
Alexandre Julliard committed
417
 */
418
void WINAPI VXD_TimerAPI ( CONTEXT86 *context )
Alexandre Julliard's avatar
Alexandre Julliard committed
419
{
420 421
    static WORD System_Time_Selector;

Alexandre Julliard's avatar
Alexandre Julliard committed
422 423
    unsigned service = AX_reg(context);

424
    TRACE("[%04x] TimerAPI\n", (UINT16)service);
Alexandre Julliard's avatar
Alexandre Julliard committed
425 426 427 428

    switch(service)
    {
    case 0x0000: /* version */
429
        SET_AX( context, VXD_WinVersion() );
Alexandre Julliard's avatar
Alexandre Julliard committed
430 431 432 433
        RESET_CFLAG(context);
        break;

    case 0x0009: /* get system time selector */
434 435
        if ( !System_Time_Selector )
        {
436 437 438
            HANDLE16 handle = GlobalAlloc16( GMEM_FIXED, sizeof(DWORD) );
            System_Time_Selector = handle | 7;
            CloseHandle( CreateThread( NULL, 0, timer_thread, GlobalLock16(handle), 0, NULL ) );
439
        }
440
        SET_AX( context, System_Time_Selector );
Alexandre Julliard's avatar
Alexandre Julliard committed
441 442 443 444 445 446 447 448 449
        RESET_CFLAG(context);
        break;

    default:
        VXD_BARF( context, "VTDAPI" );
    }
}

/***********************************************************************
450
 *           VXD_ConfigMG (WPROCS.451)
Alexandre Julliard's avatar
Alexandre Julliard committed
451
 */
452
void WINAPI VXD_ConfigMG ( CONTEXT86 *context )
Alexandre Julliard's avatar
Alexandre Julliard committed
453 454 455
{
    unsigned service = AX_reg(context);

456
    TRACE("[%04x] ConfigMG\n", (UINT16)service);
Alexandre Julliard's avatar
Alexandre Julliard committed
457 458 459 460

    switch(service)
    {
    case 0x0000: /* version */
461
        SET_AX( context, VXD_WinVersion() );
Alexandre Julliard's avatar
Alexandre Julliard committed
462 463 464 465 466 467 468 469
        RESET_CFLAG(context);
        break;

    default:
        VXD_BARF( context, "CONFIGMG" );
    }
}

470
/***********************************************************************
471
 *           VXD_Enable (WPROCS.455)
472
 */
473
void WINAPI VXD_Enable ( CONTEXT86 *context )
474 475 476
{
    unsigned service = AX_reg(context);

477
    TRACE("[%04x] Enable\n", (UINT16)service);
478 479 480 481

    switch(service)
    {
    case 0x0000: /* version */
482
        SET_AX( context, VXD_WinVersion() );
483 484 485 486 487 488 489 490 491
        RESET_CFLAG(context);
        break;

    default:
        VXD_BARF( context, "ENABLE" );
    }
}

/***********************************************************************
492
 *           VXD_APM (WPROCS.438)
493
 */
494
void WINAPI VXD_APM ( CONTEXT86 *context )
495 496 497
{
    unsigned service = AX_reg(context);

498
    TRACE("[%04x] APM\n", (UINT16)service);
499 500 501 502

    switch(service)
    {
    case 0x0000: /* version */
503
        SET_AX( context, VXD_WinVersion() );
504 505 506 507 508 509 510 511
        RESET_CFLAG(context);
        break;

    default:
        VXD_BARF( context, "APM" );
    }
}

Alexandre Julliard's avatar
Alexandre Julliard committed
512
/***********************************************************************
513
 *           VXD_Win32s (WPROCS.445)
Alexandre Julliard's avatar
Alexandre Julliard committed
514 515 516
 *
 * This is an implementation of the services of the Win32s VxD.
 * Since official documentation of these does not seem to be available,
517
 * certain arguments of some of the services remain unclear.
Alexandre Julliard's avatar
Alexandre Julliard committed
518
 *
519
 * FIXME: The following services are currently unimplemented:
Alexandre Julliard's avatar
Alexandre Julliard committed
520 521 522 523
 *        Exception handling      (0x01, 0x1C)
 *        Debugger support        (0x0C, 0x14, 0x17)
 *        Low-level memory access (0x02, 0x03, 0x0A, 0x0B)
 *        Memory Statistics       (0x1B)
524
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
525 526 527 528
 *
 * We have a specific problem running Win32s on Linux (and probably also
 * the other x86 unixes), since Win32s tries to allocate its main 'flat
 * code/data segment' selectors with a base of 0xffff0000 (and limit 4GB).
529 530
 * The rationale for this seems to be that they want one the one hand to
 * be able to leave the Win 3.1 memory (starting with the main DOS memory)
Alexandre Julliard's avatar
Alexandre Julliard committed
531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547
 * at linear address 0, but want at other hand to have offset 0 of the
 * flat data/code segment point to an unmapped page (to catch NULL pointer
 * accesses). Hence they allocate the flat segments with a base of 0xffff0000
 * so that the Win 3.1 memory area at linear address zero shows up in the
 * flat segments at offset 0x10000 (since linear addresses wrap around at
 * 4GB). To compensate for that discrepancy between flat segment offsets
 * and plain linear addresses, all flat pointers passed between the 32-bit
 * and the 16-bit parts of Win32s are shifted by 0x10000 in the appropriate
 * direction by the glue code (mainly) in W32SKRNL and WIN32S16.
 *
 * The problem for us is now that Linux does not allow a LDT selector with
 * base 0xffff0000 to be created, since it would 'see' a part of the kernel
 * address space. To address this problem we introduce *another* offset:
 * We add 0x10000 to every linear address we get as an argument from Win32s.
 * This means especially that the flat code/data selectors get actually
 * allocated with base 0x0, so that flat offsets and (real) linear addresses
 * do again agree!  In fact, every call e.g. of a Win32s VxD service now
Austin English's avatar
Austin English committed
548
 * has all pointer arguments (which are offsets in the flat data segment)
Alexandre Julliard's avatar
Alexandre Julliard committed
549 550 551 552 553 554 555 556 557 558 559
 * first reduced by 0x10000 by the W32SKRNL glue code, and then again
 * increased by 0x10000 by *our* code.
 *
 * Note that to keep everything consistent, this offset has to be applied by
 * every Wine function that operates on 'linear addresses' passed to it by
 * Win32s. Fortunately, since Win32s does not directly call any Wine 32-bit
 * API routines, this affects only two locations: this VxD and the DPMI
 * handler. (NOTE: Should any Win32s application pass a linear address to
 * any routine apart from those, e.g. some other VxD handler, that code
 * would have to take the offset into account as well!)
 *
560 561
 * The offset is set the first time any application calls the GetVersion()
 * service of the Win32s VxD. (Note that the offset is never reset.)
562
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
563 564
 */

565
void WINAPI VXD_Win32s( CONTEXT86 *context )
Alexandre Julliard's avatar
Alexandre Julliard committed
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581
{
    switch (AX_reg(context))
    {
    case 0x0000: /* Get Version */
        /*
         * Input:   None
         *
         * Output:  EAX: LoWord: Win32s Version (1.30)
         *               HiWord: VxD Version (200)
         *
         *          EBX: Build (172)
         *
         *          ECX: ???   (1)
         *
         *          EDX: Debugging Flags
         *
582
         *          EDI: Error Flag
Alexandre Julliard's avatar
Alexandre Julliard committed
583 584 585 586
         *               0 if OK,
         *               1 if VMCPD VxD not found
         */

587
        TRACE("GetVersion()\n");
588

589 590 591 592 593
	context->Eax = VXD_WinVersion() | (200 << 16);
        context->Ebx = 0;
        context->Ecx = 0;
        context->Edx = 0;
        context->Edi = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
594

595
        /*
Alexandre Julliard's avatar
Alexandre Julliard committed
596 597 598 599
         * If this is the first time we are called for this process,
         * hack the memory image of WIN32S16 so that it doesn't try
         * to access the GDT directly ...
         *
600
         * The first code segment of WIN32S16 (version 1.30) contains
Alexandre Julliard's avatar
Alexandre Julliard committed
601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626
         * an unexported function somewhere between the exported functions
         * SetFS and StackLinearToSegmented that tries to find a selector
         * in the LDT that maps to the memory image of the LDT itself.
         * If it succeeds, it stores this selector into a global variable
         * which will be used to speed up execution by using this selector
         * to modify the LDT directly instead of using the DPMI calls.
         *
         * To perform this search of the LDT, this function uses the
         * sgdt and sldt instructions to find the linear address of
         * the (GDT and then) LDT. While those instructions themselves
         * execute without problem, the linear address that sgdt returns
         * points (at least under Linux) to the kernel address space, so
         * that any subsequent access leads to a segfault.
         *
         * Fortunately, WIN32S16 still contains as a fallback option the
         * mechanism of using DPMI calls to modify LDT selectors instead
         * of direct writes to the LDT. Thus we can circumvent the problem
         * by simply replacing the first byte of the offending function
         * with an 'retf' instruction. This means that the global variable
         * supposed to contain the LDT alias selector will remain zero,
         * and hence WIN32S16 will fall back to using DPMI calls.
         *
         * The heuristic we employ to _find_ that function is as follows:
         * We search between the addresses of the exported symbols SetFS
         * and StackLinearToSegmented for the byte sequence '0F 01 04'
         * (this is the opcode of 'sgdt [si]'). We then search backwards
Andreas Mohr's avatar
Andreas Mohr committed
627
         * from this address for the last occurrence of 'CB' (retf) that marks
628
         * the end of the preceding function. The following byte (which
Alexandre Julliard's avatar
Alexandre Julliard committed
629 630 631 632 633 634 635 636 637 638
         * should now be the first byte of the function we are looking for)
         * will be replaced by 'CB' (retf).
         *
         * This heuristic works for the retail as well as the debug version
         * of Win32s version 1.30. For versions earlier than that this
         * hack should not be necessary at all, since the whole mechanism
         * ('PERF130') was introduced only in 1.30 to improve the overall
         * performance of Win32s.
         */

639
        if (!W32S_offset)
Alexandre Julliard's avatar
Alexandre Julliard committed
640 641
        {
            HMODULE16 hModule = GetModuleHandle16("win32s16");
642 643
            SEGPTR func1 = (SEGPTR)GetProcAddress16(hModule, "SetFS");
            SEGPTR func2 = (SEGPTR)GetProcAddress16(hModule, "StackLinearToSegmented");
Alexandre Julliard's avatar
Alexandre Julliard committed
644

645
            if (   hModule && func1 && func2
Alexandre Julliard's avatar
Alexandre Julliard committed
646 647
                && SELECTOROF(func1) == SELECTOROF(func2))
            {
648 649
                BYTE *start = MapSL(func1);
                BYTE *end   = MapSL(func2);
Alexandre Julliard's avatar
Alexandre Julliard committed
650 651 652 653 654 655 656 657 658 659 660 661
                BYTE *p, *retv = NULL;
                int found = 0;

                for (p = start; p < end; p++)
                    if (*p == 0xCB) found = 0, retv = p;
                    else if (*p == 0x0F) found = 1;
                    else if (*p == 0x01 && found == 1) found = 2;
                    else if (*p == 0x04 && found == 2) { found = 3; break; }
                    else found = 0;

                if (found == 3 && retv)
                {
662
                    TRACE("PERF130 hack: "
Alexandre Julliard's avatar
Alexandre Julliard committed
663
                               "Replacing byte %02X at offset %04X:%04X\n",
664
                               *(retv+1), SELECTOROF(func1),
Alexandre Julliard's avatar
Alexandre Julliard committed
665 666 667 668 669 670 671
                                          OFFSETOF(func1) + retv+1-start);

                    *(retv+1) = (BYTE)0xCB;
                }
            }
        }

672
        /*
Alexandre Julliard's avatar
Alexandre Julliard committed
673
         * Mark process as Win32s, so that subsequent DPMI calls
674
         * will perform the W32S_APP2WINE/W32S_WINE2APP address shift.
Alexandre Julliard's avatar
Alexandre Julliard committed
675
         */
676 677
        W32S_offset = 0x10000;
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
678 679 680 681 682 683 684 685 686


    case 0x0001: /* Install Exception Handling */
        /*
         * Input:   EBX: Flat address of W32SKRNL Exception Data
         *
         *          ECX: LoWord: Flat Code Selector
         *               HiWord: Flat Data Selector
         *
687
         *          EDX: Flat address of W32SKRNL Exception Handler
Alexandre Julliard's avatar
Alexandre Julliard committed
688 689 690 691 692 693 694 695 696
         *               (this is equal to W32S_BackTo32 + 0x40)
         *
         *          ESI: SEGPTR KERNEL.HASGPHANDLER
         *
         *          EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10)
         *
         * Output:  EAX: 0 if OK
         */

697
        TRACE("[0001] EBX=%x ECX=%x EDX=%x ESI=%x EDI=%x\n",
698 699
                   context->Ebx, context->Ecx, context->Edx,
                   context->Esi, context->Edi);
Alexandre Julliard's avatar
Alexandre Julliard committed
700 701 702

        /* FIXME */

703
        context->Eax = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719
        break;


    case 0x0002: /* Set Page Access Flags */
        /*
         * Input:   EBX: New access flags
         *               Bit 2: User Page if set, Supervisor Page if clear
         *               Bit 1: Read-Write if set, Read-Only if clear
         *
         *          ECX: Size of memory area to change
         *
         *          EDX: Flat start address of memory area
         *
         * Output:  EAX: Size of area changed
         */

720
        TRACE("[0002] EBX=%x ECX=%x EDX=%x\n",
721
                   context->Ebx, context->Ecx, context->Edx);
Alexandre Julliard's avatar
Alexandre Julliard committed
722 723 724

        /* FIXME */

725
        context->Eax = context->Ecx;
Alexandre Julliard's avatar
Alexandre Julliard committed
726 727 728 729 730 731 732 733 734 735 736 737
        break;


    case 0x0003: /* Get Page Access Flags */
        /*
         * Input:   EDX: Flat address of page to query
         *
         * Output:  EAX: Page access flags
         *               Bit 2: User Page if set, Supervisor Page if clear
         *               Bit 1: Read-Write if set, Read-Only if clear
         */

738
        TRACE("[0003] EDX=%x\n", context->Edx);
Alexandre Julliard's avatar
Alexandre Julliard committed
739 740 741

        /* FIXME */

742
        context->Eax = 6;
Alexandre Julliard's avatar
Alexandre Julliard committed
743 744 745 746 747 748 749 750 751 752 753 754
        break;


    case 0x0004: /* Map Module */
        /*
         * Input:   ECX: IMTE (offset in Module Table) of new module
         *
         *          EDX: Flat address of Win32s Module Table
         *
         * Output:  EAX: 0 if OK
         */

755
    if (!context->Edx || CX_reg(context) == 0xFFFF)
Alexandre Julliard's avatar
Alexandre Julliard committed
756
    {
757
        TRACE("MapModule: Initialization call\n");
758
        context->Eax = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776
    }
    else
    {
        /*
         * Structure of a Win32s Module Table Entry:
         */
        struct Win32sModule
        {
            DWORD  flags;
            DWORD  flatBaseAddr;
            LPCSTR moduleName;
            LPCSTR pathName;
            LPCSTR unknown;
            LPBYTE baseAddr;
            DWORD  hModule;
            DWORD  relocDelta;
        };

777 778
        /*
         * Note: This function should set up a demand-paged memory image
Alexandre Julliard's avatar
Alexandre Julliard committed
779 780 781 782 783
         *       of the given module. Since mmap does not allow file offsets
         *       not aligned at 1024 bytes, we simply load the image fully
         *       into memory.
         */

784
        struct Win32sModule *moduleTable =
785
                            (struct Win32sModule *)W32S_APP2WINE(context->Edx);
786
        struct Win32sModule *module = moduleTable + context->Ecx;
Alexandre Julliard's avatar
Alexandre Julliard committed
787

788 789 790 791
        IMAGE_NT_HEADERS *nt_header = RtlImageNtHeader( (HMODULE)module->baseAddr );
        IMAGE_SECTION_HEADER *pe_seg = (IMAGE_SECTION_HEADER*)((char *)&nt_header->OptionalHeader +
                                                         nt_header->FileHeader.SizeOfOptionalHeader);

Alexandre Julliard's avatar
Alexandre Julliard committed
792

793
        HFILE image = _lopen(module->pathName, OF_READ);
794
        BOOL error = (image == HFILE_ERROR);
795
        UINT i;
Alexandre Julliard's avatar
Alexandre Julliard committed
796

797
        TRACE("MapModule: Loading %s\n", module->pathName);
Alexandre Julliard's avatar
Alexandre Julliard committed
798

799 800
        for (i = 0;
             !error && i < nt_header->FileHeader.NumberOfSections;
Alexandre Julliard's avatar
Alexandre Julliard committed
801 802 803 804 805 806 807
             i++, pe_seg++)
            if(!(pe_seg->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA))
            {
                DWORD  off  = pe_seg->PointerToRawData;
                DWORD  len  = pe_seg->SizeOfRawData;
                LPBYTE addr = module->baseAddr + pe_seg->VirtualAddress;

808
                TRACE("MapModule: "
809
                           "Section %d at %08x from %08x len %08x\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
810 811
                           i, (DWORD)addr, off, len);

812 813
                if (   _llseek(image, off, SEEK_SET) != off
                    || _lread(image, addr, len) != len)
Alexandre Julliard's avatar
Alexandre Julliard committed
814 815
                    error = TRUE;
            }
816

817
        _lclose(image);
Alexandre Julliard's avatar
Alexandre Julliard committed
818 819

        if (error)
820
            ERR("MapModule: Unable to load %s\n", module->pathName);
Alexandre Julliard's avatar
Alexandre Julliard committed
821 822 823 824 825 826 827 828

        else if (module->relocDelta != 0)
        {
            IMAGE_DATA_DIRECTORY *dir = nt_header->OptionalHeader.DataDirectory
                                      + IMAGE_DIRECTORY_ENTRY_BASERELOC;
            IMAGE_BASE_RELOCATION *r = (IMAGE_BASE_RELOCATION *)
                (dir->Size? module->baseAddr + dir->VirtualAddress : 0);

829
            TRACE("MapModule: Reloc delta %08x\n", module->relocDelta);
Alexandre Julliard's avatar
Alexandre Julliard committed
830 831 832 833

            while (r && r->VirtualAddress)
            {
                LPBYTE page  = module->baseAddr + r->VirtualAddress;
834
                WORD *TypeOffset = (WORD *)(r + 1);
835
                unsigned int count = (r->SizeOfBlock - sizeof(*r)) / sizeof(*TypeOffset);
Alexandre Julliard's avatar
Alexandre Julliard committed
836

837
                TRACE("MapModule: %d relocations for page %08x\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
838 839 840 841
                           count, (DWORD)page);

                for(i = 0; i < count; i++)
                {
842 843
                    int offset = TypeOffset[i] & 0xFFF;
                    int type   = TypeOffset[i] >> 12;
Alexandre Julliard's avatar
Alexandre Julliard committed
844 845
                    switch(type)
                    {
846
                    case IMAGE_REL_BASED_ABSOLUTE:
Alexandre Julliard's avatar
Alexandre Julliard committed
847 848 849 850 851 852 853 854 855 856 857
                        break;
                    case IMAGE_REL_BASED_HIGH:
                        *(WORD *)(page+offset) += HIWORD(module->relocDelta);
                        break;
                    case IMAGE_REL_BASED_LOW:
                        *(WORD *)(page+offset) += LOWORD(module->relocDelta);
                        break;
                    case IMAGE_REL_BASED_HIGHLOW:
                        *(DWORD*)(page+offset) += module->relocDelta;
                        break;
                    default:
858
                        WARN("MapModule: Unsupported fixup type\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
859 860 861 862 863 864 865 866
                        break;
                    }
                }

                r = (IMAGE_BASE_RELOCATION *)((LPBYTE)r + r->SizeOfBlock);
            }
        }

867
        context->Eax = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
868 869 870 871 872 873 874
        RESET_CFLAG(context);
    }
    break;


    case 0x0005: /* UnMap Module */
        /*
875
         * Input:   EDX: Flat address of module image
Alexandre Julliard's avatar
Alexandre Julliard committed
876 877 878
         *
         * Output:  EAX: 1 if OK
         */
879

880
        TRACE("UnMapModule: %x\n", W32S_APP2WINE(context->Edx));
Alexandre Julliard's avatar
Alexandre Julliard committed
881 882 883

        /* As we didn't map anything, there's nothing to unmap ... */

884
        context->Eax = 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
885 886 887 888
        break;


    case 0x0006: /* VirtualAlloc */
889
        /*
Alexandre Julliard's avatar
Alexandre Julliard committed
890 891 892
         * Input:   ECX: Current Process
         *
         *          EDX: Flat address of arguments on stack
893
         *
Alexandre Julliard's avatar
Alexandre Julliard committed
894 895 896 897 898 899 900 901 902
         *   DWORD *retv     [out] Flat base address of allocated region
         *   LPVOID base     [in]  Flat address of region to reserve/commit
         *   DWORD  size     [in]  Size of region
         *   DWORD  type     [in]  Type of allocation
         *   DWORD  prot     [in]  Type of access protection
         *
         * Output:  EAX: NtStatus
         */
    {
903 904 905
        DWORD *stack  = (DWORD *)W32S_APP2WINE(context->Edx);
        DWORD *retv   = (DWORD *)W32S_APP2WINE(stack[0]);
        LPVOID base   = (LPVOID) W32S_APP2WINE(stack[1]);
Alexandre Julliard's avatar
Alexandre Julliard committed
906 907 908 909 910
        DWORD  size   = stack[2];
        DWORD  type   = stack[3];
        DWORD  prot   = stack[4];
        DWORD  result;

911
        TRACE("VirtualAlloc(%x, %x, %x, %x, %x)\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
912 913 914 915
                   (DWORD)retv, (DWORD)base, size, type, prot);

        if (type & 0x80000000)
        {
916
            WARN("VirtualAlloc: strange type %x\n", type);
Alexandre Julliard's avatar
Alexandre Julliard committed
917 918 919 920 921
            type &= 0x7fffffff;
        }

        if (!base && (type & MEM_COMMIT) && prot == PAGE_READONLY)
        {
922
            WARN("VirtualAlloc: NLS hack, allowing write access!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
923 924 925 926 927
            prot = PAGE_READWRITE;
        }

        result = (DWORD)VirtualAlloc(base, size, type, prot);

928 929
        if (W32S_WINE2APP(result))
            *retv            = W32S_WINE2APP(result),
930
            context->Eax = STATUS_SUCCESS;
Alexandre Julliard's avatar
Alexandre Julliard committed
931 932
        else
            *retv            = 0,
933
            context->Eax = STATUS_NO_MEMORY;  /* FIXME */
Alexandre Julliard's avatar
Alexandre Julliard committed
934 935 936 937 938
    }
    break;


    case 0x0007: /* VirtualFree */
939
        /*
Alexandre Julliard's avatar
Alexandre Julliard committed
940 941 942
         * Input:   ECX: Current Process
         *
         *          EDX: Flat address of arguments on stack
943
         *
Alexandre Julliard's avatar
Alexandre Julliard committed
944 945 946 947 948 949 950 951
         *   DWORD *retv     [out] TRUE if success, FALSE if failure
         *   LPVOID base     [in]  Flat address of region
         *   DWORD  size     [in]  Size of region
         *   DWORD  type     [in]  Type of operation
         *
         * Output:  EAX: NtStatus
         */
    {
952 953 954
        DWORD *stack  = (DWORD *)W32S_APP2WINE(context->Edx);
        DWORD *retv   = (DWORD *)W32S_APP2WINE(stack[0]);
        LPVOID base   = (LPVOID) W32S_APP2WINE(stack[1]);
Alexandre Julliard's avatar
Alexandre Julliard committed
955 956 957 958
        DWORD  size   = stack[2];
        DWORD  type   = stack[3];
        DWORD  result;

959
        TRACE("VirtualFree(%x, %x, %x, %x)\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
960 961 962 963 964 965
                   (DWORD)retv, (DWORD)base, size, type);

        result = VirtualFree(base, size, type);

        if (result)
            *retv            = TRUE,
966
            context->Eax = STATUS_SUCCESS;
Alexandre Julliard's avatar
Alexandre Julliard committed
967 968
        else
            *retv            = FALSE,
969
            context->Eax = STATUS_NO_MEMORY;  /* FIXME */
Alexandre Julliard's avatar
Alexandre Julliard committed
970 971 972 973 974
    }
    break;


    case 0x0008: /* VirtualProtect */
975
        /*
Alexandre Julliard's avatar
Alexandre Julliard committed
976 977 978
         * Input:   ECX: Current Process
         *
         *          EDX: Flat address of arguments on stack
979
         *
Alexandre Julliard's avatar
Alexandre Julliard committed
980 981 982 983 984 985 986 987 988
         *   DWORD *retv     [out] TRUE if success, FALSE if failure
         *   LPVOID base     [in]  Flat address of region
         *   DWORD  size     [in]  Size of region
         *   DWORD  new_prot [in]  Desired access protection
         *   DWORD *old_prot [out] Previous access protection
         *
         * Output:  EAX: NtStatus
         */
    {
989 990 991
        DWORD *stack    = (DWORD *)W32S_APP2WINE(context->Edx);
        DWORD *retv     = (DWORD *)W32S_APP2WINE(stack[0]);
        LPVOID base     = (LPVOID) W32S_APP2WINE(stack[1]);
Alexandre Julliard's avatar
Alexandre Julliard committed
992 993
        DWORD  size     = stack[2];
        DWORD  new_prot = stack[3];
994
        DWORD *old_prot = (DWORD *)W32S_APP2WINE(stack[4]);
Alexandre Julliard's avatar
Alexandre Julliard committed
995 996
        DWORD  result;

997
        TRACE("VirtualProtect(%x, %x, %x, %x, %x)\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
998 999 1000 1001 1002 1003
                   (DWORD)retv, (DWORD)base, size, new_prot, (DWORD)old_prot);

        result = VirtualProtect(base, size, new_prot, old_prot);

        if (result)
            *retv            = TRUE,
1004
            context->Eax = STATUS_SUCCESS;
Alexandre Julliard's avatar
Alexandre Julliard committed
1005 1006
        else
            *retv            = FALSE,
1007
            context->Eax = STATUS_NO_MEMORY;  /* FIXME */
Alexandre Julliard's avatar
Alexandre Julliard committed
1008 1009 1010 1011 1012
    }
    break;


    case 0x0009: /* VirtualQuery */
1013
        /*
Alexandre Julliard's avatar
Alexandre Julliard committed
1014 1015 1016
         * Input:   ECX: Current Process
         *
         *          EDX: Flat address of arguments on stack
1017
         *
Alexandre Julliard's avatar
Alexandre Julliard committed
1018 1019 1020 1021 1022 1023 1024 1025
         *   DWORD *retv                     [out] Nr. bytes returned
         *   LPVOID base                     [in]  Flat address of region
         *   LPMEMORY_BASIC_INFORMATION info [out] Info buffer
         *   DWORD  len                      [in]  Size of buffer
         *
         * Output:  EAX: NtStatus
         */
    {
1026 1027 1028
        DWORD *stack  = (DWORD *)W32S_APP2WINE(context->Edx);
        DWORD *retv   = (DWORD *)W32S_APP2WINE(stack[0]);
        LPVOID base   = (LPVOID) W32S_APP2WINE(stack[1]);
1029 1030
        PMEMORY_BASIC_INFORMATION info =
                        (PMEMORY_BASIC_INFORMATION)W32S_APP2WINE(stack[2]);
Alexandre Julliard's avatar
Alexandre Julliard committed
1031 1032 1033
        DWORD  len    = stack[3];
        DWORD  result;

1034
        TRACE("VirtualQuery(%x, %x, %x, %x)\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
1035 1036 1037 1038 1039
                   (DWORD)retv, (DWORD)base, (DWORD)info, len);

        result = VirtualQuery(base, info, len);

        *retv            = result;
1040
        context->Eax = STATUS_SUCCESS;
Alexandre Julliard's avatar
Alexandre Julliard committed
1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053
    }
    break;


    case 0x000A: /* SetVirtMemProcess */
        /*
         * Input:   ECX: Process Handle
         *
         *          EDX: Flat address of region
         *
         * Output:  EAX: NtStatus
         */

1054
        TRACE("[000a] ECX=%x EDX=%x\n",
1055
                   context->Ecx, context->Edx);
Alexandre Julliard's avatar
Alexandre Julliard committed
1056 1057 1058

        /* FIXME */

1059
        context->Eax = STATUS_SUCCESS;
Alexandre Julliard's avatar
Alexandre Julliard committed
1060 1061 1062 1063 1064 1065 1066 1067 1068 1069
        break;


    case 0x000B: /* ??? some kind of cleanup */
        /*
         * Input:   ECX: Process Handle
         *
         * Output:  EAX: NtStatus
         */

1070
        TRACE("[000b] ECX=%x\n", context->Ecx);
Alexandre Julliard's avatar
Alexandre Julliard committed
1071 1072 1073

        /* FIXME */

1074
        context->Eax = STATUS_SUCCESS;
Alexandre Julliard's avatar
Alexandre Julliard committed
1075 1076 1077 1078 1079 1080 1081 1082 1083 1084
        break;


    case 0x000C: /* Set Debug Flags */
        /*
         * Input:   EDX: Debug Flags
         *
         * Output:  EDX: Previous Debug Flags
         */

1085
        FIXME("[000c] EDX=%x\n", context->Edx);
Alexandre Julliard's avatar
Alexandre Julliard committed
1086 1087 1088

        /* FIXME */

1089
        context->Edx = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1090 1091 1092 1093
        break;


    case 0x000D: /* NtCreateSection */
1094
        /*
Alexandre Julliard's avatar
Alexandre Julliard committed
1095
         * Input:   EDX: Flat address of arguments on stack
1096
         *
Alexandre Julliard's avatar
Alexandre Julliard committed
1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108
         *   HANDLE32 *retv      [out] Handle of Section created
         *   DWORD  flags1       [in]  (?? unknown ??)
         *   DWORD  atom         [in]  Name of Section to create
         *   LARGE_INTEGER *size [in]  Size of Section
         *   DWORD  protect      [in]  Access protection
         *   DWORD  flags2       [in]  (?? unknown ??)
         *   HFILE32 hFile       [in]  Handle of file to map
         *   DWORD  psp          [in]  (Win32s: PSP that hFile belongs to)
         *
         * Output:  EAX: NtStatus
         */
    {
1109 1110
        DWORD *stack    = (DWORD *)   W32S_APP2WINE(context->Edx);
        HANDLE *retv  = (HANDLE *)W32S_APP2WINE(stack[0]);
Alexandre Julliard's avatar
Alexandre Julliard committed
1111 1112
        DWORD  flags1   = stack[1];
        DWORD  atom     = stack[2];
1113
        LARGE_INTEGER *size = (LARGE_INTEGER *)W32S_APP2WINE(stack[3]);
Alexandre Julliard's avatar
Alexandre Julliard committed
1114 1115
        DWORD  protect  = stack[4];
        DWORD  flags2   = stack[5];
1116
        HANDLE hFile    = DosFileHandleToWin32Handle(stack[6]);
Alexandre Julliard's avatar
Alexandre Julliard committed
1117 1118
        DWORD  psp      = stack[7];

1119
        HANDLE result = INVALID_HANDLE_VALUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1120 1121
        char name[128];

1122
        TRACE("NtCreateSection(%x, %x, %x, %x, %x, %x, %x, %x)\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
1123 1124 1125
                   (DWORD)retv, flags1, atom, (DWORD)size, protect, flags2,
                   (DWORD)hFile, psp);

1126
        if (!atom || GlobalGetAtomNameA(atom, name, sizeof(name)))
Alexandre Julliard's avatar
Alexandre Julliard committed
1127
        {
1128
            TRACE("NtCreateSection: name=%s\n", atom? name : NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
1129

1130
            result = CreateFileMappingA(hFile, NULL, protect,
1131 1132
                                          size? size->u.HighPart : 0,
                                          size? size->u.LowPart  : 0,
Alexandre Julliard's avatar
Alexandre Julliard committed
1133 1134 1135
                                          atom? name : NULL);
        }

1136
        if (result == INVALID_HANDLE_VALUE)
1137
            WARN("NtCreateSection: failed!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1138
        else
1139
            TRACE("NtCreateSection: returned %x\n", (DWORD)result);
Alexandre Julliard's avatar
Alexandre Julliard committed
1140

1141
        if (result != INVALID_HANDLE_VALUE)
Alexandre Julliard's avatar
Alexandre Julliard committed
1142
            *retv            = result,
1143
            context->Eax = STATUS_SUCCESS;
Alexandre Julliard's avatar
Alexandre Julliard committed
1144 1145
        else
            *retv            = result,
1146
            context->Eax = STATUS_NO_MEMORY;   /* FIXME */
Alexandre Julliard's avatar
Alexandre Julliard committed
1147 1148 1149 1150 1151
    }
    break;


    case 0x000E: /* NtOpenSection */
1152
        /*
Alexandre Julliard's avatar
Alexandre Julliard committed
1153
         * Input:   EDX: Flat address of arguments on stack
1154
         *
Alexandre Julliard's avatar
Alexandre Julliard committed
1155 1156 1157 1158 1159 1160 1161
         *   HANDLE32 *retv  [out] Handle of Section opened
         *   DWORD  protect  [in]  Access protection
         *   DWORD  atom     [in]  Name of Section to create
         *
         * Output:  EAX: NtStatus
         */
    {
1162 1163
        DWORD *stack    = (DWORD *)W32S_APP2WINE(context->Edx);
        HANDLE *retv  = (HANDLE *)W32S_APP2WINE(stack[0]);
Alexandre Julliard's avatar
Alexandre Julliard committed
1164 1165 1166
        DWORD  protect  = stack[1];
        DWORD  atom     = stack[2];

1167
        HANDLE result = INVALID_HANDLE_VALUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1168 1169
        char name[128];

1170
        TRACE("NtOpenSection(%x, %x, %x)\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
1171 1172
                   (DWORD)retv, protect, atom);

1173
        if (atom && GlobalGetAtomNameA(atom, name, sizeof(name)))
Alexandre Julliard's avatar
Alexandre Julliard committed
1174
        {
1175
            TRACE("NtOpenSection: name=%s\n", name);
Alexandre Julliard's avatar
Alexandre Julliard committed
1176

1177
            result = OpenFileMappingA(protect, FALSE, name);
Alexandre Julliard's avatar
Alexandre Julliard committed
1178 1179
        }

1180
        if (result == INVALID_HANDLE_VALUE)
1181
            WARN("NtOpenSection: failed!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1182
        else
1183
            TRACE("NtOpenSection: returned %x\n", (DWORD)result);
Alexandre Julliard's avatar
Alexandre Julliard committed
1184

1185
        if (result != INVALID_HANDLE_VALUE)
Alexandre Julliard's avatar
Alexandre Julliard committed
1186
            *retv            = result,
1187
            context->Eax = STATUS_SUCCESS;
Alexandre Julliard's avatar
Alexandre Julliard committed
1188 1189
        else
            *retv            = result,
1190
            context->Eax = STATUS_NO_MEMORY;   /* FIXME */
Alexandre Julliard's avatar
Alexandre Julliard committed
1191 1192 1193 1194 1195
    }
    break;


    case 0x000F: /* NtCloseSection */
1196
        /*
Alexandre Julliard's avatar
Alexandre Julliard committed
1197
         * Input:   EDX: Flat address of arguments on stack
1198
         *
Alexandre Julliard's avatar
Alexandre Julliard committed
1199 1200 1201 1202 1203 1204
         *   HANDLE32 handle  [in]  Handle of Section to close
         *   DWORD *id        [out] Unique ID  (?? unclear ??)
         *
         * Output:  EAX: NtStatus
         */
    {
1205
        DWORD *stack    = (DWORD *)W32S_APP2WINE(context->Edx);
1206
        HANDLE handle   = (HANDLE)stack[0];
1207
        DWORD *id       = (DWORD *)W32S_APP2WINE(stack[1]);
Alexandre Julliard's avatar
Alexandre Julliard committed
1208

1209
        TRACE("NtCloseSection(%x, %x)\n", (DWORD)handle, (DWORD)id);
Alexandre Julliard's avatar
Alexandre Julliard committed
1210 1211 1212 1213

        CloseHandle(handle);
        if (id) *id = 0; /* FIXME */

1214
        context->Eax = STATUS_SUCCESS;
Alexandre Julliard's avatar
Alexandre Julliard committed
1215 1216 1217 1218 1219
    }
    break;


    case 0x0010: /* NtDupSection */
1220
        /*
Alexandre Julliard's avatar
Alexandre Julliard committed
1221
         * Input:   EDX: Flat address of arguments on stack
1222
         *
Alexandre Julliard's avatar
Alexandre Julliard committed
1223 1224 1225 1226 1227
         *   HANDLE32 handle  [in]  Handle of Section to duplicate
         *
         * Output:  EAX: NtStatus
         */
    {
1228
        DWORD *stack    = (DWORD *)W32S_APP2WINE(context->Edx);
1229
        HANDLE handle   = (HANDLE)stack[0];
1230
        HANDLE new_handle;
Alexandre Julliard's avatar
Alexandre Julliard committed
1231

1232
        TRACE("NtDupSection(%x)\n", (DWORD)handle);
1233

1234 1235 1236
        DuplicateHandle( GetCurrentProcess(), handle,
                         GetCurrentProcess(), &new_handle,
                         0, FALSE, DUPLICATE_SAME_ACCESS );
1237
        context->Eax = STATUS_SUCCESS;
Alexandre Julliard's avatar
Alexandre Julliard committed
1238 1239 1240 1241 1242
    }
    break;


    case 0x0011: /* NtMapViewOfSection */
1243
        /*
Alexandre Julliard's avatar
Alexandre Julliard committed
1244
         * Input:   EDX: Flat address of arguments on stack
1245
         *
Alexandre Julliard's avatar
Alexandre Julliard committed
1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259
         *   HANDLE32 SectionHandle       [in]     Section to be mapped
         *   DWORD    ProcessHandle       [in]     Process to be mapped into
         *   DWORD *  BaseAddress         [in/out] Address to be mapped at
         *   DWORD    ZeroBits            [in]     (?? unclear ??)
         *   DWORD    CommitSize          [in]     (?? unclear ??)
         *   LARGE_INTEGER *SectionOffset [in]     Offset within section
         *   DWORD *  ViewSize            [in]     Size of view
         *   DWORD    InheritDisposition  [in]     (?? unclear ??)
         *   DWORD    AllocationType      [in]     (?? unclear ??)
         *   DWORD    Protect             [in]     Access protection
         *
         * Output:  EAX: NtStatus
         */
    {
1260
        DWORD *  stack          = (DWORD *)W32S_APP2WINE(context->Edx);
1261
        HANDLE   SectionHandle  = (HANDLE)stack[0];
Alexandre Julliard's avatar
Alexandre Julliard committed
1262
        DWORD    ProcessHandle  = stack[1]; /* ignored */
1263
        DWORD *  BaseAddress    = (DWORD *)W32S_APP2WINE(stack[2]);
Alexandre Julliard's avatar
Alexandre Julliard committed
1264 1265
        DWORD    ZeroBits       = stack[3];
        DWORD    CommitSize     = stack[4];
1266 1267
        LARGE_INTEGER *SectionOffset = (LARGE_INTEGER *)W32S_APP2WINE(stack[5]);
        DWORD *  ViewSize       = (DWORD *)W32S_APP2WINE(stack[6]);
Alexandre Julliard's avatar
Alexandre Julliard committed
1268 1269 1270 1271
        DWORD    InheritDisposition = stack[7];
        DWORD    AllocationType = stack[8];
        DWORD    Protect        = stack[9];

1272
        LPBYTE address = (LPBYTE)(BaseAddress?
1273
			W32S_APP2WINE(*BaseAddress) : 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286
        DWORD  access = 0, result;

        switch (Protect & ~(PAGE_GUARD|PAGE_NOCACHE))
        {
            case PAGE_READONLY:           access = FILE_MAP_READ;  break;
            case PAGE_READWRITE:          access = FILE_MAP_WRITE; break;
            case PAGE_WRITECOPY:          access = FILE_MAP_COPY;  break;

            case PAGE_EXECUTE_READ:       access = FILE_MAP_READ;  break;
            case PAGE_EXECUTE_READWRITE:  access = FILE_MAP_WRITE; break;
            case PAGE_EXECUTE_WRITECOPY:  access = FILE_MAP_COPY;  break;
        }

1287
        TRACE("NtMapViewOfSection"
1288
                   "(%x, %x, %x, %x, %x, %x, %x, %x, %x, %x)\n",
1289
                   (DWORD)SectionHandle, ProcessHandle, (DWORD)BaseAddress,
Alexandre Julliard's avatar
Alexandre Julliard committed
1290 1291
                   ZeroBits, CommitSize, (DWORD)SectionOffset, (DWORD)ViewSize,
                   InheritDisposition, AllocationType, Protect);
1292
        TRACE("NtMapViewOfSection: "
1293
                   "base=%x, offset=%x, size=%x, access=%x\n",
1294
                   (DWORD)address, SectionOffset? SectionOffset->u.LowPart : 0,
Alexandre Julliard's avatar
Alexandre Julliard committed
1295 1296
                   ViewSize? *ViewSize : 0, access);

1297
        result = (DWORD)MapViewOfFileEx(SectionHandle, access,
1298 1299
                            SectionOffset? SectionOffset->u.HighPart : 0,
                            SectionOffset? SectionOffset->u.LowPart  : 0,
Alexandre Julliard's avatar
Alexandre Julliard committed
1300 1301
                            ViewSize? *ViewSize : 0, address);

1302
        TRACE("NtMapViewOfSection: result=%x\n", result);
Alexandre Julliard's avatar
Alexandre Julliard committed
1303

1304
        if (W32S_WINE2APP(result))
Alexandre Julliard's avatar
Alexandre Julliard committed
1305
        {
1306
            if (BaseAddress) *BaseAddress = W32S_WINE2APP(result);
1307
            context->Eax = STATUS_SUCCESS;
Alexandre Julliard's avatar
Alexandre Julliard committed
1308 1309
        }
        else
1310
            context->Eax = STATUS_NO_MEMORY; /* FIXME */
Alexandre Julliard's avatar
Alexandre Julliard committed
1311 1312 1313 1314 1315
    }
    break;


    case 0x0012: /* NtUnmapViewOfSection */
1316
        /*
Alexandre Julliard's avatar
Alexandre Julliard committed
1317
         * Input:   EDX: Flat address of arguments on stack
1318
         *
Alexandre Julliard's avatar
Alexandre Julliard committed
1319 1320 1321 1322 1323 1324
         *   DWORD  ProcessHandle  [in]  Process (defining address space)
         *   LPBYTE BaseAddress    [in]  Base address of view to be unmapped
         *
         * Output:  EAX: NtStatus
         */
    {
1325
        DWORD *stack          = (DWORD *)W32S_APP2WINE(context->Edx);
Alexandre Julliard's avatar
Alexandre Julliard committed
1326
        DWORD  ProcessHandle  = stack[0]; /* ignored */
1327
        LPBYTE BaseAddress    = (LPBYTE)W32S_APP2WINE(stack[1]);
Alexandre Julliard's avatar
Alexandre Julliard committed
1328

1329
        TRACE("NtUnmapViewOfSection(%x, %x)\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
1330 1331 1332 1333
                   ProcessHandle, (DWORD)BaseAddress);

        UnmapViewOfFile(BaseAddress);

1334
        context->Eax = STATUS_SUCCESS;
Alexandre Julliard's avatar
Alexandre Julliard committed
1335 1336 1337 1338 1339
    }
    break;


    case 0x0013: /* NtFlushVirtualMemory */
1340
        /*
Alexandre Julliard's avatar
Alexandre Julliard committed
1341
         * Input:   EDX: Flat address of arguments on stack
1342
         *
Alexandre Julliard's avatar
Alexandre Julliard committed
1343 1344 1345 1346 1347 1348 1349 1350
         *   DWORD   ProcessHandle  [in]  Process (defining address space)
         *   LPBYTE *BaseAddress    [in?] Base address of range to be flushed
         *   DWORD  *ViewSize       [in?] Number of bytes to be flushed
         *   DWORD  *unknown        [???] (?? unknown ??)
         *
         * Output:  EAX: NtStatus
         */
    {
1351
        DWORD *stack          = (DWORD *)W32S_APP2WINE(context->Edx);
Alexandre Julliard's avatar
Alexandre Julliard committed
1352
        DWORD  ProcessHandle  = stack[0]; /* ignored */
1353 1354 1355
        DWORD *BaseAddress    = (DWORD *)W32S_APP2WINE(stack[1]);
        DWORD *ViewSize       = (DWORD *)W32S_APP2WINE(stack[2]);
        DWORD *unknown        = (DWORD *)W32S_APP2WINE(stack[3]);
1356

1357
        LPBYTE address = (LPBYTE)(BaseAddress? W32S_APP2WINE(*BaseAddress) : 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
1358 1359
        DWORD  size    = ViewSize? *ViewSize : 0;

1360
        TRACE("NtFlushVirtualMemory(%x, %x, %x, %x)\n",
1361
                   ProcessHandle, (DWORD)BaseAddress, (DWORD)ViewSize,
Alexandre Julliard's avatar
Alexandre Julliard committed
1362
                   (DWORD)unknown);
1363
        TRACE("NtFlushVirtualMemory: base=%x, size=%x\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
1364 1365 1366 1367
                   (DWORD)address, size);

        FlushViewOfFile(address, size);

1368
        context->Eax = STATUS_SUCCESS;
Alexandre Julliard's avatar
Alexandre Julliard committed
1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383
    }
    break;


    case 0x0014: /* Get/Set Debug Registers */
        /*
         * Input:   ECX: 0 if Get, 1 if Set
         *
         *          EDX: Get: Flat address of buffer to receive values of
         *                    debug registers DR0 .. DR7
         *               Set: Flat address of buffer containing values of
         *                    debug registers DR0 .. DR7 to be set
         * Output:  None
         */

1384
        FIXME("[0014] ECX=%x EDX=%x\n",
1385
                   context->Ecx, context->Edx);
Alexandre Julliard's avatar
Alexandre Julliard committed
1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397

        /* FIXME */
        break;


    case 0x0015: /* Set Coprocessor Emulation Flag */
        /*
         * Input:   EDX: 0 to deactivate, 1 to activate coprocessor emulation
         *
         * Output:  None
         */

1398
        TRACE("[0015] EDX=%x\n", context->Edx);
Alexandre Julliard's avatar
Alexandre Julliard committed
1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416

        /* We don't care, as we always have a coprocessor anyway */
        break;


    case 0x0016: /* Init Win32S VxD PSP */
        /*
         * If called to query required PSP size:
         *
         *     Input:  EBX: 0
         *     Output: EDX: Required size of Win32s VxD PSP
         *
         * If called to initialize allocated PSP:
         *
         *     Input:  EBX: LoWord: Selector of Win32s VxD PSP
         *                  HiWord: Paragraph of Win32s VxD PSP (DOSMEM)
         *     Output: None
         */
1417

1418 1419
        if (context->Ebx == 0)
            context->Edx = 0x80;
Alexandre Julliard's avatar
Alexandre Julliard committed
1420 1421
        else
        {
1422
            PDB16 *psp = MapSL( MAKESEGPTR( BX_reg(context), 0 ));
Alexandre Julliard's avatar
Alexandre Julliard committed
1423
            psp->nbFiles = 32;
1424
            psp->fileHandlesPtr = MAKELONG(HIWORD(context->Ebx), 0x5c);
Alexandre Julliard's avatar
Alexandre Julliard committed
1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437
            memset((LPBYTE)psp + 0x5c, '\xFF', 32);
        }
        break;


    case 0x0017: /* Set Break Point */
        /*
         * Input:   EBX: Offset of Break Point
         *          CX:  Selector of Break Point
         *
         * Output:  None
         */

1438
        FIXME("[0017] EBX=%x CX=%x\n",
1439
                   context->Ebx, CX_reg(context));
Alexandre Julliard's avatar
Alexandre Julliard committed
1440 1441 1442 1443 1444 1445

        /* FIXME */
        break;


    case 0x0018: /* VirtualLock */
1446
        /*
Alexandre Julliard's avatar
Alexandre Julliard committed
1447 1448 1449
         * Input:   ECX: Current Process
         *
         *          EDX: Flat address of arguments on stack
1450
         *
Alexandre Julliard's avatar
Alexandre Julliard committed
1451 1452 1453 1454 1455 1456 1457
         *   DWORD *retv     [out] TRUE if success, FALSE if failure
         *   LPVOID base     [in]  Flat address of range to lock
         *   DWORD  size     [in]  Size of range
         *
         * Output:  EAX: NtStatus
         */
    {
1458 1459 1460
        DWORD *stack  = (DWORD *)W32S_APP2WINE(context->Edx);
        DWORD *retv   = (DWORD *)W32S_APP2WINE(stack[0]);
        LPVOID base   = (LPVOID) W32S_APP2WINE(stack[1]);
Alexandre Julliard's avatar
Alexandre Julliard committed
1461 1462 1463
        DWORD  size   = stack[2];
        DWORD  result;

1464
        TRACE("VirtualLock(%x, %x, %x)\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
1465 1466 1467 1468 1469 1470
                   (DWORD)retv, (DWORD)base, size);

        result = VirtualLock(base, size);

        if (result)
            *retv            = TRUE,
1471
            context->Eax = STATUS_SUCCESS;
Alexandre Julliard's avatar
Alexandre Julliard committed
1472 1473
        else
            *retv            = FALSE,
1474
            context->Eax = STATUS_NO_MEMORY;  /* FIXME */
Alexandre Julliard's avatar
Alexandre Julliard committed
1475 1476 1477 1478 1479
    }
    break;


    case 0x0019: /* VirtualUnlock */
1480
        /*
Alexandre Julliard's avatar
Alexandre Julliard committed
1481 1482 1483
         * Input:   ECX: Current Process
         *
         *          EDX: Flat address of arguments on stack
1484
         *
Alexandre Julliard's avatar
Alexandre Julliard committed
1485 1486 1487 1488 1489 1490 1491
         *   DWORD *retv     [out] TRUE if success, FALSE if failure
         *   LPVOID base     [in]  Flat address of range to unlock
         *   DWORD  size     [in]  Size of range
         *
         * Output:  EAX: NtStatus
         */
    {
1492 1493 1494
        DWORD *stack  = (DWORD *)W32S_APP2WINE(context->Edx);
        DWORD *retv   = (DWORD *)W32S_APP2WINE(stack[0]);
        LPVOID base   = (LPVOID) W32S_APP2WINE(stack[1]);
Alexandre Julliard's avatar
Alexandre Julliard committed
1495 1496 1497
        DWORD  size   = stack[2];
        DWORD  result;

1498
        TRACE("VirtualUnlock(%x, %x, %x)\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
1499 1500 1501 1502 1503 1504
                   (DWORD)retv, (DWORD)base, size);

        result = VirtualUnlock(base, size);

        if (result)
            *retv            = TRUE,
1505
            context->Eax = STATUS_SUCCESS;
Alexandre Julliard's avatar
Alexandre Julliard committed
1506 1507
        else
            *retv            = FALSE,
1508
            context->Eax = STATUS_NO_MEMORY;  /* FIXME */
Alexandre Julliard's avatar
Alexandre Julliard committed
1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520
    }
    break;


    case 0x001A: /* KGetSystemInfo */
        /*
         * Input:   None
         *
         * Output:  ECX:  Start of sparse memory arena
         *          EDX:  End of sparse memory arena
         */

1521
        TRACE("KGetSystemInfo()\n");
1522

Alexandre Julliard's avatar
Alexandre Julliard committed
1523
        /*
1524 1525
         * Note: Win32s reserves 0GB - 2GB for Win 3.1 and uses 2GB - 4GB as
         *       sparse memory arena. We do it the other way around, since
Alexandre Julliard's avatar
Alexandre Julliard committed
1526 1527 1528 1529 1530 1531
         *       we have to reserve 3GB - 4GB for Linux, and thus use
         *       0GB - 3GB as sparse memory arena.
         *
         *       FIXME: What about other OSes ?
         */

1532 1533
        context->Ecx = W32S_WINE2APP(0x00000000);
        context->Edx = W32S_WINE2APP(0xbfffffff);
Alexandre Julliard's avatar
Alexandre Julliard committed
1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554
        break;


    case 0x001B: /* KGlobalMemStat */
        /*
         * Input:   ESI: Flat address of buffer to receive memory info
         *
         * Output:  None
         */
    {
        struct Win32sMemoryInfo
        {
            DWORD DIPhys_Count;       /* Total physical pages */
            DWORD DIFree_Count;       /* Free physical pages */
            DWORD DILin_Total_Count;  /* Total virtual pages (private arena) */
            DWORD DILin_Total_Free;   /* Free virtual pages (private arena) */

            DWORD SparseTotal;        /* Total size of sparse arena (bytes ?) */
            DWORD SparseFree;         /* Free size of sparse arena (bytes ?) */
        };

1555
        struct Win32sMemoryInfo *info =
1556
                       (struct Win32sMemoryInfo *)W32S_APP2WINE(context->Esi);
Alexandre Julliard's avatar
Alexandre Julliard committed
1557

1558
        FIXME("KGlobalMemStat(%x)\n", (DWORD)info);
Alexandre Julliard's avatar
Alexandre Julliard committed
1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571

        /* FIXME */
    }
    break;


    case 0x001C: /* Enable/Disable Exceptions */
        /*
         * Input:   ECX: 0 to disable, 1 to enable exception handling
         *
         * Output:  None
         */

1572
        TRACE("[001c] ECX=%x\n", context->Ecx);
Alexandre Julliard's avatar
Alexandre Julliard committed
1573 1574 1575 1576 1577 1578

        /* FIXME */
        break;


    case 0x001D: /* VirtualAlloc called from 16-bit code */
1579
        /*
Alexandre Julliard's avatar
Alexandre Julliard committed
1580
         * Input:   EDX: Segmented address of arguments on stack
1581
         *
Alexandre Julliard's avatar
Alexandre Julliard committed
1582 1583 1584 1585 1586 1587 1588 1589 1590
         *   LPVOID base     [in]  Flat address of region to reserve/commit
         *   DWORD  size     [in]  Size of region
         *   DWORD  type     [in]  Type of allocation
         *   DWORD  prot     [in]  Type of access protection
         *
         * Output:  EAX: NtStatus
         *          EDX: Flat base address of allocated region
         */
    {
1591
        DWORD *stack  = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) ));
1592
        LPVOID base   = (LPVOID)W32S_APP2WINE(stack[0]);
Alexandre Julliard's avatar
Alexandre Julliard committed
1593 1594 1595 1596 1597
        DWORD  size   = stack[1];
        DWORD  type   = stack[2];
        DWORD  prot   = stack[3];
        DWORD  result;

1598
        TRACE("VirtualAlloc16(%x, %x, %x, %x)\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
1599 1600 1601 1602
                   (DWORD)base, size, type, prot);

        if (type & 0x80000000)
        {
1603
            WARN("VirtualAlloc16: strange type %x\n", type);
Alexandre Julliard's avatar
Alexandre Julliard committed
1604 1605 1606 1607 1608
            type &= 0x7fffffff;
        }

        result = (DWORD)VirtualAlloc(base, size, type, prot);

1609 1610
        if (W32S_WINE2APP(result))
            context->Edx = W32S_WINE2APP(result),
1611
            context->Eax = STATUS_SUCCESS;
Alexandre Julliard's avatar
Alexandre Julliard committed
1612
        else
1613 1614
            context->Edx = 0,
            context->Eax = STATUS_NO_MEMORY;  /* FIXME */
1615
	TRACE("VirtualAlloc16: returning base %x\n", context->Edx);
Alexandre Julliard's avatar
Alexandre Julliard committed
1616 1617 1618 1619 1620
    }
    break;


    case 0x001E: /* VirtualFree called from 16-bit code */
1621
        /*
Alexandre Julliard's avatar
Alexandre Julliard committed
1622
         * Input:   EDX: Segmented address of arguments on stack
1623
         *
Alexandre Julliard's avatar
Alexandre Julliard committed
1624 1625 1626 1627 1628 1629 1630 1631
         *   LPVOID base     [in]  Flat address of region
         *   DWORD  size     [in]  Size of region
         *   DWORD  type     [in]  Type of operation
         *
         * Output:  EAX: NtStatus
         *          EDX: TRUE if success, FALSE if failure
         */
    {
1632
        DWORD *stack  = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) ));
1633
        LPVOID base   = (LPVOID)W32S_APP2WINE(stack[0]);
Alexandre Julliard's avatar
Alexandre Julliard committed
1634 1635 1636 1637
        DWORD  size   = stack[1];
        DWORD  type   = stack[2];
        DWORD  result;

1638
        TRACE("VirtualFree16(%x, %x, %x)\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
1639 1640 1641 1642 1643
                   (DWORD)base, size, type);

        result = VirtualFree(base, size, type);

        if (result)
1644 1645
            context->Edx = TRUE,
            context->Eax = STATUS_SUCCESS;
Alexandre Julliard's avatar
Alexandre Julliard committed
1646
        else
1647 1648
            context->Edx = FALSE,
            context->Eax = STATUS_NO_MEMORY;  /* FIXME */
Alexandre Julliard's avatar
Alexandre Julliard committed
1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662
    }
    break;


    case 0x001F: /* FWorkingSetSize */
        /*
         * Input:   EDX: 0 if Get, 1 if Set
         *
         *          ECX: Get: Buffer to receive Working Set Size
         *               Set: Buffer containing Working Set Size
         *
         * Output:  NtStatus
         */
    {
1663
        DWORD *ptr = (DWORD *)W32S_APP2WINE(context->Ecx);
1664
        BOOL set = context->Edx;
1665

1666
        TRACE("FWorkingSetSize(%x, %x)\n", (DWORD)ptr, (DWORD)set);
Alexandre Julliard's avatar
Alexandre Julliard committed
1667 1668 1669 1670 1671 1672

        if (set)
            /* We do it differently ... */;
        else
            *ptr = 0x100;

1673
        context->Eax = STATUS_SUCCESS;
Alexandre Julliard's avatar
Alexandre Julliard committed
1674 1675 1676 1677 1678 1679 1680 1681 1682
    }
    break;


    default:
	VXD_BARF( context, "W32S" );
    }

}