ntdll: Avoid inter-process APCs when called for the process itself.
[wine/multimedia.git] / dlls / winedos / vxd.c
blob9a4f1cdcab556a891f9d638562b30fac91243242
1 /*
2 * VxD emulation
4 * Copyright 1995 Anand Kumria
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
22 #include "wine/port.h"
24 #include <fcntl.h>
25 #include <string.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <sys/types.h>
29 #ifdef HAVE_UNISTD_H
30 # include <unistd.h>
31 #endif
33 #define NONAMELESSUNION
34 #define NONAMELESSSTRUCT
35 #include "ntstatus.h"
36 #define WIN32_NO_STATUS
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winreg.h"
40 #include "winternl.h"
41 #include "wingdi.h"
42 #include "winuser.h"
43 #include "wine/winbase16.h"
44 #include "wine/winuser16.h"
45 #include "dosexe.h"
46 #include "wine/debug.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(vxd);
50 #define W32S_APP2WINE(addr) ((addr)? (DWORD)(addr) + W32S_offset : 0)
51 #define W32S_WINE2APP(addr) ((addr)? (DWORD)(addr) - W32S_offset : 0)
53 #define VXD_BARF(context,name) \
54 TRACE( "vxd %s: unknown/not implemented parameters:\n" \
55 "vxd %s: AX %04x, BX %04x, CX %04x, DX %04x, " \
56 "SI %04x, DI %04x, DS %04x, ES %04x\n", \
57 (name), (name), AX_reg(context), BX_reg(context), \
58 CX_reg(context), DX_reg(context), SI_reg(context), \
59 DI_reg(context), (WORD)context->SegDs, (WORD)context->SegEs )
61 UINT W32S_offset = 0;
63 static WORD VXD_WinVersion(void)
65 WORD version = LOWORD(GetVersion16());
66 return (version >> 8) | (version << 8);
69 /***********************************************************************
70 * VXD_VMM (WPROCS.401)
72 void WINAPI VXD_VMM ( CONTEXT86 *context )
74 unsigned service = AX_reg(context);
76 TRACE("[%04x] VMM\n", (UINT16)service);
78 switch(service)
80 case 0x0000: /* version */
81 SET_AX( context, VXD_WinVersion() );
82 RESET_CFLAG(context);
83 break;
85 case 0x026d: /* Get_Debug_Flag '/m' */
86 case 0x026e: /* Get_Debug_Flag '/n' */
87 SET_AL( context, 0 );
88 RESET_CFLAG(context);
89 break;
91 default:
92 VXD_BARF( context, "VMM" );
96 /***********************************************************************
97 * VXD_PageFile (WPROCS.433)
99 void WINAPI VXD_PageFile( CONTEXT86 *context )
101 unsigned service = AX_reg(context);
103 /* taken from Ralf Brown's Interrupt List */
105 TRACE("[%04x] PageFile\n", (UINT16)service );
107 switch(service)
109 case 0x00: /* get version, is this windows version? */
110 TRACE("returning version\n");
111 SET_AX( context, VXD_WinVersion() );
112 RESET_CFLAG(context);
113 break;
115 case 0x01: /* get swap file info */
116 TRACE("VxD PageFile: returning swap file info\n");
117 SET_AX( context, 0x00 ); /* paging disabled */
118 context->Ecx = 0; /* maximum size of paging file */
119 /* FIXME: do I touch DS:SI or DS:DI? */
120 RESET_CFLAG(context);
121 break;
123 case 0x02: /* delete permanent swap on exit */
124 TRACE("VxD PageFile: supposed to delete swap\n");
125 RESET_CFLAG(context);
126 break;
128 case 0x03: /* current temporary swap file size */
129 TRACE("VxD PageFile: what is current temp. swap size\n");
130 RESET_CFLAG(context);
131 break;
133 case 0x04: /* read or write?? INTERRUP.D */
134 case 0x05: /* cancel?? INTERRUP.D */
135 case 0x06: /* test I/O valid INTERRUP.D */
136 default:
137 VXD_BARF( context, "pagefile" );
138 break;
142 /***********************************************************************
143 * VXD_Reboot (WPROCS.409)
145 void WINAPI VXD_Reboot ( CONTEXT86 *context )
147 unsigned service = AX_reg(context);
149 TRACE("[%04x] Reboot\n", (UINT16)service);
151 switch(service)
153 case 0x0000: /* version */
154 SET_AX( context, VXD_WinVersion() );
155 RESET_CFLAG(context);
156 break;
158 default:
159 VXD_BARF( context, "REBOOT" );
163 /***********************************************************************
164 * VXD_VDD (WPROCS.410)
166 void WINAPI VXD_VDD ( CONTEXT86 *context )
168 unsigned service = AX_reg(context);
170 TRACE("[%04x] VDD\n", (UINT16)service);
172 switch(service)
174 case 0x0000: /* version */
175 SET_AX( context, VXD_WinVersion() );
176 RESET_CFLAG(context);
177 break;
179 default:
180 VXD_BARF( context, "VDD" );
184 /***********************************************************************
185 * VXD_VMD (WPROCS.412)
187 void WINAPI VXD_VMD ( CONTEXT86 *context )
189 unsigned service = AX_reg(context);
191 TRACE("[%04x] VMD\n", (UINT16)service);
193 switch(service)
195 case 0x0000: /* version */
196 SET_AX( context, VXD_WinVersion() );
197 RESET_CFLAG(context);
198 break;
200 default:
201 VXD_BARF( context, "VMD" );
205 /***********************************************************************
206 * VXD_VXDLoader (WPROCS.439)
208 void WINAPI VXD_VXDLoader( CONTEXT86 *context )
210 unsigned service = AX_reg(context);
212 TRACE("[%04x] VXDLoader\n", (UINT16)service);
214 switch (service)
216 case 0x0000: /* get version */
217 TRACE("returning version\n");
218 SET_AX( context, 0x0000 );
219 SET_DX( context, VXD_WinVersion() );
220 RESET_CFLAG(context);
221 break;
223 case 0x0001: /* load device */
224 FIXME("load device %04x:%04x (%s)\n",
225 context->SegDs, DX_reg(context),
226 debugstr_a(MapSL(MAKESEGPTR(context->SegDs, DX_reg(context)))));
227 SET_AX( context, 0x0000 );
228 context->SegEs = 0x0000;
229 SET_DI( context, 0x0000 );
230 RESET_CFLAG(context);
231 break;
233 case 0x0002: /* unload device */
234 FIXME("unload device (%08x)\n", context->Ebx);
235 SET_AX( context, 0x0000 );
236 RESET_CFLAG(context);
237 break;
239 default:
240 VXD_BARF( context, "VXDLDR" );
241 SET_AX( context, 0x000B ); /* invalid function number */
242 SET_CFLAG(context);
243 break;
247 /***********************************************************************
248 * VXD_Shell (WPROCS.423)
250 void WINAPI VXD_Shell( CONTEXT86 *context )
252 unsigned service = DX_reg(context);
254 TRACE("[%04x] Shell\n", (UINT16)service);
256 switch (service) /* Ralf Brown says EDX, but I use DX instead */
258 case 0x0000:
259 TRACE("returning version\n");
260 SET_AX( context, VXD_WinVersion() );
261 context->Ebx = 1; /* system VM Handle */
262 break;
264 case 0x0001:
265 case 0x0002:
266 case 0x0003:
267 /* SHELL_SYSMODAL_Message
268 ebx virtual maschine handle
269 eax message box flags
270 ecx address of message
271 edi address of caption
272 return response in eax
274 case 0x0004:
275 /* SHELL_Message
276 ebx virtual maschine handle
277 eax message box flags
278 ecx address of message
279 edi address of caption
280 esi address callback
281 edx reference data for callback
282 return response in eax
284 case 0x0005:
285 VXD_BARF( context, "shell" );
286 break;
288 case 0x0006: /* SHELL_Get_VM_State */
289 TRACE("VxD Shell: returning VM state\n");
290 /* Actually we don't, not yet. We have to return a structure
291 * and I am not to sure how to set it up and return it yet,
292 * so for now let's do nothing. I can (hopefully) get this
293 * by the next release
295 /* RESET_CFLAG(context); */
296 break;
298 case 0x0007:
299 case 0x0008:
300 case 0x0009:
301 case 0x000A:
302 case 0x000B:
303 case 0x000C:
304 case 0x000D:
305 case 0x000E:
306 case 0x000F:
307 case 0x0010:
308 case 0x0011:
309 case 0x0012:
310 case 0x0013:
311 case 0x0014:
312 case 0x0015:
313 case 0x0016:
314 VXD_BARF( context, "SHELL" );
315 break;
317 /* the new Win95 shell API */
318 case 0x0100: /* get version */
319 SET_AX( context, VXD_WinVersion() );
320 break;
322 case 0x0104: /* retrieve Hook_Properties list */
323 case 0x0105: /* call Hook_Properties callbacks */
324 VXD_BARF( context, "SHELL" );
325 break;
327 case 0x0106: /* install timeout callback */
328 TRACE("VxD Shell: ignoring shell callback (%d sec.)\n", context->Ebx);
329 SET_CFLAG(context);
330 break;
332 case 0x0107: /* get version of any VxD */
333 default:
334 VXD_BARF( context, "SHELL" );
335 break;
340 /***********************************************************************
341 * VXD_Comm (WPROCS.414)
343 void WINAPI VXD_Comm( CONTEXT86 *context )
345 unsigned service = AX_reg(context);
347 TRACE("[%04x] Comm\n", (UINT16)service);
349 switch (service)
351 case 0x0000: /* get version */
352 TRACE("returning version\n");
353 SET_AX( context, VXD_WinVersion() );
354 RESET_CFLAG(context);
355 break;
357 case 0x0001: /* set port global */
358 case 0x0002: /* get focus */
359 case 0x0003: /* virtualise port */
360 default:
361 VXD_BARF( context, "comm" );
365 /***********************************************************************
366 * VXD_Timer (WPROCS.405)
368 void WINAPI VXD_Timer( CONTEXT86 *context )
370 unsigned service = AX_reg(context);
372 TRACE("[%04x] Virtual Timer\n", (UINT16)service);
374 switch(service)
376 case 0x0000: /* version */
377 SET_AX( context, VXD_WinVersion() );
378 RESET_CFLAG(context);
379 break;
381 case 0x0100: /* clock tick time, in 840nsecs */
382 context->Eax = GetTickCount();
384 context->Edx = context->Eax >> 22;
385 context->Eax <<= 10; /* not very precise */
386 break;
388 case 0x0101: /* current Windows time, msecs */
389 case 0x0102: /* current VM time, msecs */
390 context->Eax = GetTickCount();
391 break;
393 default:
394 VXD_BARF( context, "VTD" );
399 /***********************************************************************
400 * timer_thread
402 static DWORD CALLBACK timer_thread( void *arg )
404 DWORD *system_time = arg;
406 for (;;)
408 *system_time = GetTickCount();
409 Sleep( 55 );
414 /***********************************************************************
415 * VXD_TimerAPI (WPROCS.1490)
417 void WINAPI VXD_TimerAPI ( CONTEXT86 *context )
419 static WORD System_Time_Selector;
421 unsigned service = AX_reg(context);
423 TRACE("[%04x] TimerAPI\n", (UINT16)service);
425 switch(service)
427 case 0x0000: /* version */
428 SET_AX( context, VXD_WinVersion() );
429 RESET_CFLAG(context);
430 break;
432 case 0x0009: /* get system time selector */
433 if ( !System_Time_Selector )
435 HANDLE16 handle = GlobalAlloc16( GMEM_FIXED, sizeof(DWORD) );
436 System_Time_Selector = handle | 7;
437 CloseHandle( CreateThread( NULL, 0, timer_thread, GlobalLock16(handle), 0, NULL ) );
439 SET_AX( context, System_Time_Selector );
440 RESET_CFLAG(context);
441 break;
443 default:
444 VXD_BARF( context, "VTDAPI" );
448 /***********************************************************************
449 * VXD_ConfigMG (WPROCS.451)
451 void WINAPI VXD_ConfigMG ( CONTEXT86 *context )
453 unsigned service = AX_reg(context);
455 TRACE("[%04x] ConfigMG\n", (UINT16)service);
457 switch(service)
459 case 0x0000: /* version */
460 SET_AX( context, VXD_WinVersion() );
461 RESET_CFLAG(context);
462 break;
464 default:
465 VXD_BARF( context, "CONFIGMG" );
469 /***********************************************************************
470 * VXD_Enable (WPROCS.455)
472 void WINAPI VXD_Enable ( CONTEXT86 *context )
474 unsigned service = AX_reg(context);
476 TRACE("[%04x] Enable\n", (UINT16)service);
478 switch(service)
480 case 0x0000: /* version */
481 SET_AX( context, VXD_WinVersion() );
482 RESET_CFLAG(context);
483 break;
485 default:
486 VXD_BARF( context, "ENABLE" );
490 /***********************************************************************
491 * VXD_APM (WPROCS.438)
493 void WINAPI VXD_APM ( CONTEXT86 *context )
495 unsigned service = AX_reg(context);
497 TRACE("[%04x] APM\n", (UINT16)service);
499 switch(service)
501 case 0x0000: /* version */
502 SET_AX( context, VXD_WinVersion() );
503 RESET_CFLAG(context);
504 break;
506 default:
507 VXD_BARF( context, "APM" );
511 /***********************************************************************
512 * VXD_Win32s (WPROCS.445)
514 * This is an implementation of the services of the Win32s VxD.
515 * Since official documentation of these does not seem to be available,
516 * certain arguments of some of the services remain unclear.
518 * FIXME: The following services are currently unimplemented:
519 * Exception handling (0x01, 0x1C)
520 * Debugger support (0x0C, 0x14, 0x17)
521 * Low-level memory access (0x02, 0x03, 0x0A, 0x0B)
522 * Memory Statistics (0x1B)
525 * We have a specific problem running Win32s on Linux (and probably also
526 * the other x86 unixes), since Win32s tries to allocate its main 'flat
527 * code/data segment' selectors with a base of 0xffff0000 (and limit 4GB).
528 * The rationale for this seems to be that they want one the one hand to
529 * be able to leave the Win 3.1 memory (starting with the main DOS memory)
530 * at linear address 0, but want at other hand to have offset 0 of the
531 * flat data/code segment point to an unmapped page (to catch NULL pointer
532 * accesses). Hence they allocate the flat segments with a base of 0xffff0000
533 * so that the Win 3.1 memory area at linear address zero shows up in the
534 * flat segments at offset 0x10000 (since linear addresses wrap around at
535 * 4GB). To compensate for that discrepancy between flat segment offsets
536 * and plain linear addresses, all flat pointers passed between the 32-bit
537 * and the 16-bit parts of Win32s are shifted by 0x10000 in the appropriate
538 * direction by the glue code (mainly) in W32SKRNL and WIN32S16.
540 * The problem for us is now that Linux does not allow a LDT selector with
541 * base 0xffff0000 to be created, since it would 'see' a part of the kernel
542 * address space. To address this problem we introduce *another* offset:
543 * We add 0x10000 to every linear address we get as an argument from Win32s.
544 * This means especially that the flat code/data selectors get actually
545 * allocated with base 0x0, so that flat offsets and (real) linear addresses
546 * do again agree! In fact, every call e.g. of a Win32s VxD service now
547 * has all pointer arguments (which are offsets in the flat data segement)
548 * first reduced by 0x10000 by the W32SKRNL glue code, and then again
549 * increased by 0x10000 by *our* code.
551 * Note that to keep everything consistent, this offset has to be applied by
552 * every Wine function that operates on 'linear addresses' passed to it by
553 * Win32s. Fortunately, since Win32s does not directly call any Wine 32-bit
554 * API routines, this affects only two locations: this VxD and the DPMI
555 * handler. (NOTE: Should any Win32s application pass a linear address to
556 * any routine apart from those, e.g. some other VxD handler, that code
557 * would have to take the offset into account as well!)
559 * The offset is set the first time any application calls the GetVersion()
560 * service of the Win32s VxD. (Note that the offset is never reset.)
564 void WINAPI VXD_Win32s( CONTEXT86 *context )
566 switch (AX_reg(context))
568 case 0x0000: /* Get Version */
570 * Input: None
572 * Output: EAX: LoWord: Win32s Version (1.30)
573 * HiWord: VxD Version (200)
575 * EBX: Build (172)
577 * ECX: ??? (1)
579 * EDX: Debugging Flags
581 * EDI: Error Flag
582 * 0 if OK,
583 * 1 if VMCPD VxD not found
586 TRACE("GetVersion()\n");
588 context->Eax = VXD_WinVersion() | (200 << 16);
589 context->Ebx = 0;
590 context->Ecx = 0;
591 context->Edx = 0;
592 context->Edi = 0;
595 * If this is the first time we are called for this process,
596 * hack the memory image of WIN32S16 so that it doesn't try
597 * to access the GDT directly ...
599 * The first code segment of WIN32S16 (version 1.30) contains
600 * an unexported function somewhere between the exported functions
601 * SetFS and StackLinearToSegmented that tries to find a selector
602 * in the LDT that maps to the memory image of the LDT itself.
603 * If it succeeds, it stores this selector into a global variable
604 * which will be used to speed up execution by using this selector
605 * to modify the LDT directly instead of using the DPMI calls.
607 * To perform this search of the LDT, this function uses the
608 * sgdt and sldt instructions to find the linear address of
609 * the (GDT and then) LDT. While those instructions themselves
610 * execute without problem, the linear address that sgdt returns
611 * points (at least under Linux) to the kernel address space, so
612 * that any subsequent access leads to a segfault.
614 * Fortunately, WIN32S16 still contains as a fallback option the
615 * mechanism of using DPMI calls to modify LDT selectors instead
616 * of direct writes to the LDT. Thus we can circumvent the problem
617 * by simply replacing the first byte of the offending function
618 * with an 'retf' instruction. This means that the global variable
619 * supposed to contain the LDT alias selector will remain zero,
620 * and hence WIN32S16 will fall back to using DPMI calls.
622 * The heuristic we employ to _find_ that function is as follows:
623 * We search between the addresses of the exported symbols SetFS
624 * and StackLinearToSegmented for the byte sequence '0F 01 04'
625 * (this is the opcode of 'sgdt [si]'). We then search backwards
626 * from this address for the last occurrence of 'CB' (retf) that marks
627 * the end of the preceding function. The following byte (which
628 * should now be the first byte of the function we are looking for)
629 * will be replaced by 'CB' (retf).
631 * This heuristic works for the retail as well as the debug version
632 * of Win32s version 1.30. For versions earlier than that this
633 * hack should not be necessary at all, since the whole mechanism
634 * ('PERF130') was introduced only in 1.30 to improve the overall
635 * performance of Win32s.
638 if (!W32S_offset)
640 HMODULE16 hModule = GetModuleHandle16("win32s16");
641 SEGPTR func1 = (SEGPTR)GetProcAddress16(hModule, "SetFS");
642 SEGPTR func2 = (SEGPTR)GetProcAddress16(hModule, "StackLinearToSegmented");
644 if ( hModule && func1 && func2
645 && SELECTOROF(func1) == SELECTOROF(func2))
647 BYTE *start = MapSL(func1);
648 BYTE *end = MapSL(func2);
649 BYTE *p, *retv = NULL;
650 int found = 0;
652 for (p = start; p < end; p++)
653 if (*p == 0xCB) found = 0, retv = p;
654 else if (*p == 0x0F) found = 1;
655 else if (*p == 0x01 && found == 1) found = 2;
656 else if (*p == 0x04 && found == 2) { found = 3; break; }
657 else found = 0;
659 if (found == 3 && retv)
661 TRACE("PERF130 hack: "
662 "Replacing byte %02X at offset %04X:%04X\n",
663 *(retv+1), SELECTOROF(func1),
664 OFFSETOF(func1) + retv+1-start);
666 *(retv+1) = (BYTE)0xCB;
672 * Mark process as Win32s, so that subsequent DPMI calls
673 * will perform the W32S_APP2WINE/W32S_WINE2APP address shift.
675 W32S_offset = 0x10000;
676 break;
679 case 0x0001: /* Install Exception Handling */
681 * Input: EBX: Flat address of W32SKRNL Exception Data
683 * ECX: LoWord: Flat Code Selector
684 * HiWord: Flat Data Selector
686 * EDX: Flat address of W32SKRNL Exception Handler
687 * (this is equal to W32S_BackTo32 + 0x40)
689 * ESI: SEGPTR KERNEL.HASGPHANDLER
691 * EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10)
693 * Output: EAX: 0 if OK
696 TRACE("[0001] EBX=%x ECX=%x EDX=%x ESI=%x EDI=%x\n",
697 context->Ebx, context->Ecx, context->Edx,
698 context->Esi, context->Edi);
700 /* FIXME */
702 context->Eax = 0;
703 break;
706 case 0x0002: /* Set Page Access Flags */
708 * Input: EBX: New access flags
709 * Bit 2: User Page if set, Supervisor Page if clear
710 * Bit 1: Read-Write if set, Read-Only if clear
712 * ECX: Size of memory area to change
714 * EDX: Flat start address of memory area
716 * Output: EAX: Size of area changed
719 TRACE("[0002] EBX=%x ECX=%x EDX=%x\n",
720 context->Ebx, context->Ecx, context->Edx);
722 /* FIXME */
724 context->Eax = context->Ecx;
725 break;
728 case 0x0003: /* Get Page Access Flags */
730 * Input: EDX: Flat address of page to query
732 * Output: EAX: Page access flags
733 * Bit 2: User Page if set, Supervisor Page if clear
734 * Bit 1: Read-Write if set, Read-Only if clear
737 TRACE("[0003] EDX=%x\n", context->Edx);
739 /* FIXME */
741 context->Eax = 6;
742 break;
745 case 0x0004: /* Map Module */
747 * Input: ECX: IMTE (offset in Module Table) of new module
749 * EDX: Flat address of Win32s Module Table
751 * Output: EAX: 0 if OK
754 if (!context->Edx || CX_reg(context) == 0xFFFF)
756 TRACE("MapModule: Initialization call\n");
757 context->Eax = 0;
759 else
762 * Structure of a Win32s Module Table Entry:
764 struct Win32sModule
766 DWORD flags;
767 DWORD flatBaseAddr;
768 LPCSTR moduleName;
769 LPCSTR pathName;
770 LPCSTR unknown;
771 LPBYTE baseAddr;
772 DWORD hModule;
773 DWORD relocDelta;
777 * Note: This function should set up a demand-paged memory image
778 * of the given module. Since mmap does not allow file offsets
779 * not aligned at 1024 bytes, we simply load the image fully
780 * into memory.
783 struct Win32sModule *moduleTable =
784 (struct Win32sModule *)W32S_APP2WINE(context->Edx);
785 struct Win32sModule *module = moduleTable + context->Ecx;
787 IMAGE_NT_HEADERS *nt_header = RtlImageNtHeader( (HMODULE)module->baseAddr );
788 IMAGE_SECTION_HEADER *pe_seg = (IMAGE_SECTION_HEADER*)((char *)&nt_header->OptionalHeader +
789 nt_header->FileHeader.SizeOfOptionalHeader);
792 HFILE image = _lopen(module->pathName, OF_READ);
793 BOOL error = (image == HFILE_ERROR);
794 UINT i;
796 TRACE("MapModule: Loading %s\n", module->pathName);
798 for (i = 0;
799 !error && i < nt_header->FileHeader.NumberOfSections;
800 i++, pe_seg++)
801 if(!(pe_seg->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA))
803 DWORD off = pe_seg->PointerToRawData;
804 DWORD len = pe_seg->SizeOfRawData;
805 LPBYTE addr = module->baseAddr + pe_seg->VirtualAddress;
807 TRACE("MapModule: "
808 "Section %d at %08x from %08x len %08x\n",
809 i, (DWORD)addr, off, len);
811 if ( _llseek(image, off, SEEK_SET) != off
812 || _lread(image, addr, len) != len)
813 error = TRUE;
816 _lclose(image);
818 if (error)
819 ERR("MapModule: Unable to load %s\n", module->pathName);
821 else if (module->relocDelta != 0)
823 IMAGE_DATA_DIRECTORY *dir = nt_header->OptionalHeader.DataDirectory
824 + IMAGE_DIRECTORY_ENTRY_BASERELOC;
825 IMAGE_BASE_RELOCATION *r = (IMAGE_BASE_RELOCATION *)
826 (dir->Size? module->baseAddr + dir->VirtualAddress : 0);
828 TRACE("MapModule: Reloc delta %08x\n", module->relocDelta);
830 while (r && r->VirtualAddress)
832 LPBYTE page = module->baseAddr + r->VirtualAddress;
833 WORD *TypeOffset = (WORD *)(r + 1);
834 unsigned int count = (r->SizeOfBlock - sizeof(*r)) / sizeof(*TypeOffset);
836 TRACE("MapModule: %d relocations for page %08x\n",
837 count, (DWORD)page);
839 for(i = 0; i < count; i++)
841 int offset = TypeOffset[i] & 0xFFF;
842 int type = TypeOffset[i] >> 12;
843 switch(type)
845 case IMAGE_REL_BASED_ABSOLUTE:
846 break;
847 case IMAGE_REL_BASED_HIGH:
848 *(WORD *)(page+offset) += HIWORD(module->relocDelta);
849 break;
850 case IMAGE_REL_BASED_LOW:
851 *(WORD *)(page+offset) += LOWORD(module->relocDelta);
852 break;
853 case IMAGE_REL_BASED_HIGHLOW:
854 *(DWORD*)(page+offset) += module->relocDelta;
855 break;
856 default:
857 WARN("MapModule: Unsupported fixup type\n");
858 break;
862 r = (IMAGE_BASE_RELOCATION *)((LPBYTE)r + r->SizeOfBlock);
866 context->Eax = 0;
867 RESET_CFLAG(context);
869 break;
872 case 0x0005: /* UnMap Module */
874 * Input: EDX: Flat address of module image
876 * Output: EAX: 1 if OK
879 TRACE("UnMapModule: %x\n", (DWORD)W32S_APP2WINE(context->Edx));
881 /* As we didn't map anything, there's nothing to unmap ... */
883 context->Eax = 1;
884 break;
887 case 0x0006: /* VirtualAlloc */
889 * Input: ECX: Current Process
891 * EDX: Flat address of arguments on stack
893 * DWORD *retv [out] Flat base address of allocated region
894 * LPVOID base [in] Flat address of region to reserve/commit
895 * DWORD size [in] Size of region
896 * DWORD type [in] Type of allocation
897 * DWORD prot [in] Type of access protection
899 * Output: EAX: NtStatus
902 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
903 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
904 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
905 DWORD size = stack[2];
906 DWORD type = stack[3];
907 DWORD prot = stack[4];
908 DWORD result;
910 TRACE("VirtualAlloc(%x, %x, %x, %x, %x)\n",
911 (DWORD)retv, (DWORD)base, size, type, prot);
913 if (type & 0x80000000)
915 WARN("VirtualAlloc: strange type %x\n", type);
916 type &= 0x7fffffff;
919 if (!base && (type & MEM_COMMIT) && prot == PAGE_READONLY)
921 WARN("VirtualAlloc: NLS hack, allowing write access!\n");
922 prot = PAGE_READWRITE;
925 result = (DWORD)VirtualAlloc(base, size, type, prot);
927 if (W32S_WINE2APP(result))
928 *retv = W32S_WINE2APP(result),
929 context->Eax = STATUS_SUCCESS;
930 else
931 *retv = 0,
932 context->Eax = STATUS_NO_MEMORY; /* FIXME */
934 break;
937 case 0x0007: /* VirtualFree */
939 * Input: ECX: Current Process
941 * EDX: Flat address of arguments on stack
943 * DWORD *retv [out] TRUE if success, FALSE if failure
944 * LPVOID base [in] Flat address of region
945 * DWORD size [in] Size of region
946 * DWORD type [in] Type of operation
948 * Output: EAX: NtStatus
951 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
952 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
953 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
954 DWORD size = stack[2];
955 DWORD type = stack[3];
956 DWORD result;
958 TRACE("VirtualFree(%x, %x, %x, %x)\n",
959 (DWORD)retv, (DWORD)base, size, type);
961 result = VirtualFree(base, size, type);
963 if (result)
964 *retv = TRUE,
965 context->Eax = STATUS_SUCCESS;
966 else
967 *retv = FALSE,
968 context->Eax = STATUS_NO_MEMORY; /* FIXME */
970 break;
973 case 0x0008: /* VirtualProtect */
975 * Input: ECX: Current Process
977 * EDX: Flat address of arguments on stack
979 * DWORD *retv [out] TRUE if success, FALSE if failure
980 * LPVOID base [in] Flat address of region
981 * DWORD size [in] Size of region
982 * DWORD new_prot [in] Desired access protection
983 * DWORD *old_prot [out] Previous access protection
985 * Output: EAX: NtStatus
988 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
989 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
990 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
991 DWORD size = stack[2];
992 DWORD new_prot = stack[3];
993 DWORD *old_prot = (DWORD *)W32S_APP2WINE(stack[4]);
994 DWORD result;
996 TRACE("VirtualProtect(%x, %x, %x, %x, %x)\n",
997 (DWORD)retv, (DWORD)base, size, new_prot, (DWORD)old_prot);
999 result = VirtualProtect(base, size, new_prot, old_prot);
1001 if (result)
1002 *retv = TRUE,
1003 context->Eax = STATUS_SUCCESS;
1004 else
1005 *retv = FALSE,
1006 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1008 break;
1011 case 0x0009: /* VirtualQuery */
1013 * Input: ECX: Current Process
1015 * EDX: Flat address of arguments on stack
1017 * DWORD *retv [out] Nr. bytes returned
1018 * LPVOID base [in] Flat address of region
1019 * LPMEMORY_BASIC_INFORMATION info [out] Info buffer
1020 * DWORD len [in] Size of buffer
1022 * Output: EAX: NtStatus
1025 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1026 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1027 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1028 PMEMORY_BASIC_INFORMATION info =
1029 (PMEMORY_BASIC_INFORMATION)W32S_APP2WINE(stack[2]);
1030 DWORD len = stack[3];
1031 DWORD result;
1033 TRACE("VirtualQuery(%x, %x, %x, %x)\n",
1034 (DWORD)retv, (DWORD)base, (DWORD)info, len);
1036 result = VirtualQuery(base, info, len);
1038 *retv = result;
1039 context->Eax = STATUS_SUCCESS;
1041 break;
1044 case 0x000A: /* SetVirtMemProcess */
1046 * Input: ECX: Process Handle
1048 * EDX: Flat address of region
1050 * Output: EAX: NtStatus
1053 TRACE("[000a] ECX=%x EDX=%x\n",
1054 context->Ecx, context->Edx);
1056 /* FIXME */
1058 context->Eax = STATUS_SUCCESS;
1059 break;
1062 case 0x000B: /* ??? some kind of cleanup */
1064 * Input: ECX: Process Handle
1066 * Output: EAX: NtStatus
1069 TRACE("[000b] ECX=%x\n", context->Ecx);
1071 /* FIXME */
1073 context->Eax = STATUS_SUCCESS;
1074 break;
1077 case 0x000C: /* Set Debug Flags */
1079 * Input: EDX: Debug Flags
1081 * Output: EDX: Previous Debug Flags
1084 FIXME("[000c] EDX=%x\n", context->Edx);
1086 /* FIXME */
1088 context->Edx = 0;
1089 break;
1092 case 0x000D: /* NtCreateSection */
1094 * Input: EDX: Flat address of arguments on stack
1096 * HANDLE32 *retv [out] Handle of Section created
1097 * DWORD flags1 [in] (?? unknown ??)
1098 * DWORD atom [in] Name of Section to create
1099 * LARGE_INTEGER *size [in] Size of Section
1100 * DWORD protect [in] Access protection
1101 * DWORD flags2 [in] (?? unknown ??)
1102 * HFILE32 hFile [in] Handle of file to map
1103 * DWORD psp [in] (Win32s: PSP that hFile belongs to)
1105 * Output: EAX: NtStatus
1108 DWORD *stack = (DWORD *) W32S_APP2WINE(context->Edx);
1109 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]);
1110 DWORD flags1 = stack[1];
1111 DWORD atom = stack[2];
1112 LARGE_INTEGER *size = (LARGE_INTEGER *)W32S_APP2WINE(stack[3]);
1113 DWORD protect = stack[4];
1114 DWORD flags2 = stack[5];
1115 HANDLE hFile = DosFileHandleToWin32Handle(stack[6]);
1116 DWORD psp = stack[7];
1118 HANDLE result = INVALID_HANDLE_VALUE;
1119 char name[128];
1121 TRACE("NtCreateSection(%x, %x, %x, %x, %x, %x, %x, %x)\n",
1122 (DWORD)retv, flags1, atom, (DWORD)size, protect, flags2,
1123 (DWORD)hFile, psp);
1125 if (!atom || GlobalGetAtomNameA(atom, name, sizeof(name)))
1127 TRACE("NtCreateSection: name=%s\n", atom? name : NULL);
1129 result = CreateFileMappingA(hFile, NULL, protect,
1130 size? size->u.HighPart : 0,
1131 size? size->u.LowPart : 0,
1132 atom? name : NULL);
1135 if (result == INVALID_HANDLE_VALUE)
1136 WARN("NtCreateSection: failed!\n");
1137 else
1138 TRACE("NtCreateSection: returned %x\n", (DWORD)result);
1140 if (result != INVALID_HANDLE_VALUE)
1141 *retv = result,
1142 context->Eax = STATUS_SUCCESS;
1143 else
1144 *retv = result,
1145 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1147 break;
1150 case 0x000E: /* NtOpenSection */
1152 * Input: EDX: Flat address of arguments on stack
1154 * HANDLE32 *retv [out] Handle of Section opened
1155 * DWORD protect [in] Access protection
1156 * DWORD atom [in] Name of Section to create
1158 * Output: EAX: NtStatus
1161 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1162 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]);
1163 DWORD protect = stack[1];
1164 DWORD atom = stack[2];
1166 HANDLE result = INVALID_HANDLE_VALUE;
1167 char name[128];
1169 TRACE("NtOpenSection(%x, %x, %x)\n",
1170 (DWORD)retv, protect, atom);
1172 if (atom && GlobalGetAtomNameA(atom, name, sizeof(name)))
1174 TRACE("NtOpenSection: name=%s\n", name);
1176 result = OpenFileMappingA(protect, FALSE, name);
1179 if (result == INVALID_HANDLE_VALUE)
1180 WARN("NtOpenSection: failed!\n");
1181 else
1182 TRACE("NtOpenSection: returned %x\n", (DWORD)result);
1184 if (result != INVALID_HANDLE_VALUE)
1185 *retv = result,
1186 context->Eax = STATUS_SUCCESS;
1187 else
1188 *retv = result,
1189 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1191 break;
1194 case 0x000F: /* NtCloseSection */
1196 * Input: EDX: Flat address of arguments on stack
1198 * HANDLE32 handle [in] Handle of Section to close
1199 * DWORD *id [out] Unique ID (?? unclear ??)
1201 * Output: EAX: NtStatus
1204 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1205 HANDLE handle = (HANDLE)stack[0];
1206 DWORD *id = (DWORD *)W32S_APP2WINE(stack[1]);
1208 TRACE("NtCloseSection(%x, %x)\n", (DWORD)handle, (DWORD)id);
1210 CloseHandle(handle);
1211 if (id) *id = 0; /* FIXME */
1213 context->Eax = STATUS_SUCCESS;
1215 break;
1218 case 0x0010: /* NtDupSection */
1220 * Input: EDX: Flat address of arguments on stack
1222 * HANDLE32 handle [in] Handle of Section to duplicate
1224 * Output: EAX: NtStatus
1227 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1228 HANDLE handle = (HANDLE)stack[0];
1229 HANDLE new_handle;
1231 TRACE("NtDupSection(%x)\n", (DWORD)handle);
1233 DuplicateHandle( GetCurrentProcess(), handle,
1234 GetCurrentProcess(), &new_handle,
1235 0, FALSE, DUPLICATE_SAME_ACCESS );
1236 context->Eax = STATUS_SUCCESS;
1238 break;
1241 case 0x0011: /* NtMapViewOfSection */
1243 * Input: EDX: Flat address of arguments on stack
1245 * HANDLE32 SectionHandle [in] Section to be mapped
1246 * DWORD ProcessHandle [in] Process to be mapped into
1247 * DWORD * BaseAddress [in/out] Address to be mapped at
1248 * DWORD ZeroBits [in] (?? unclear ??)
1249 * DWORD CommitSize [in] (?? unclear ??)
1250 * LARGE_INTEGER *SectionOffset [in] Offset within section
1251 * DWORD * ViewSize [in] Size of view
1252 * DWORD InheritDisposition [in] (?? unclear ??)
1253 * DWORD AllocationType [in] (?? unclear ??)
1254 * DWORD Protect [in] Access protection
1256 * Output: EAX: NtStatus
1259 DWORD * stack = (DWORD *)W32S_APP2WINE(context->Edx);
1260 HANDLE SectionHandle = (HANDLE)stack[0];
1261 DWORD ProcessHandle = stack[1]; /* ignored */
1262 DWORD * BaseAddress = (DWORD *)W32S_APP2WINE(stack[2]);
1263 DWORD ZeroBits = stack[3];
1264 DWORD CommitSize = stack[4];
1265 LARGE_INTEGER *SectionOffset = (LARGE_INTEGER *)W32S_APP2WINE(stack[5]);
1266 DWORD * ViewSize = (DWORD *)W32S_APP2WINE(stack[6]);
1267 DWORD InheritDisposition = stack[7];
1268 DWORD AllocationType = stack[8];
1269 DWORD Protect = stack[9];
1271 LPBYTE address = (LPBYTE)(BaseAddress?
1272 W32S_APP2WINE(*BaseAddress) : 0);
1273 DWORD access = 0, result;
1275 switch (Protect & ~(PAGE_GUARD|PAGE_NOCACHE))
1277 case PAGE_READONLY: access = FILE_MAP_READ; break;
1278 case PAGE_READWRITE: access = FILE_MAP_WRITE; break;
1279 case PAGE_WRITECOPY: access = FILE_MAP_COPY; break;
1281 case PAGE_EXECUTE_READ: access = FILE_MAP_READ; break;
1282 case PAGE_EXECUTE_READWRITE: access = FILE_MAP_WRITE; break;
1283 case PAGE_EXECUTE_WRITECOPY: access = FILE_MAP_COPY; break;
1286 TRACE("NtMapViewOfSection"
1287 "(%x, %x, %x, %x, %x, %x, %x, %x, %x, %x)\n",
1288 (DWORD)SectionHandle, ProcessHandle, (DWORD)BaseAddress,
1289 ZeroBits, CommitSize, (DWORD)SectionOffset, (DWORD)ViewSize,
1290 InheritDisposition, AllocationType, Protect);
1291 TRACE("NtMapViewOfSection: "
1292 "base=%x, offset=%x, size=%x, access=%x\n",
1293 (DWORD)address, SectionOffset? SectionOffset->u.LowPart : 0,
1294 ViewSize? *ViewSize : 0, access);
1296 result = (DWORD)MapViewOfFileEx(SectionHandle, access,
1297 SectionOffset? SectionOffset->u.HighPart : 0,
1298 SectionOffset? SectionOffset->u.LowPart : 0,
1299 ViewSize? *ViewSize : 0, address);
1301 TRACE("NtMapViewOfSection: result=%x\n", result);
1303 if (W32S_WINE2APP(result))
1305 if (BaseAddress) *BaseAddress = W32S_WINE2APP(result);
1306 context->Eax = STATUS_SUCCESS;
1308 else
1309 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1311 break;
1314 case 0x0012: /* NtUnmapViewOfSection */
1316 * Input: EDX: Flat address of arguments on stack
1318 * DWORD ProcessHandle [in] Process (defining address space)
1319 * LPBYTE BaseAddress [in] Base address of view to be unmapped
1321 * Output: EAX: NtStatus
1324 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1325 DWORD ProcessHandle = stack[0]; /* ignored */
1326 LPBYTE BaseAddress = (LPBYTE)W32S_APP2WINE(stack[1]);
1328 TRACE("NtUnmapViewOfSection(%x, %x)\n",
1329 ProcessHandle, (DWORD)BaseAddress);
1331 UnmapViewOfFile(BaseAddress);
1333 context->Eax = STATUS_SUCCESS;
1335 break;
1338 case 0x0013: /* NtFlushVirtualMemory */
1340 * Input: EDX: Flat address of arguments on stack
1342 * DWORD ProcessHandle [in] Process (defining address space)
1343 * LPBYTE *BaseAddress [in?] Base address of range to be flushed
1344 * DWORD *ViewSize [in?] Number of bytes to be flushed
1345 * DWORD *unknown [???] (?? unknown ??)
1347 * Output: EAX: NtStatus
1350 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1351 DWORD ProcessHandle = stack[0]; /* ignored */
1352 DWORD *BaseAddress = (DWORD *)W32S_APP2WINE(stack[1]);
1353 DWORD *ViewSize = (DWORD *)W32S_APP2WINE(stack[2]);
1354 DWORD *unknown = (DWORD *)W32S_APP2WINE(stack[3]);
1356 LPBYTE address = (LPBYTE)(BaseAddress? W32S_APP2WINE(*BaseAddress) : 0);
1357 DWORD size = ViewSize? *ViewSize : 0;
1359 TRACE("NtFlushVirtualMemory(%x, %x, %x, %x)\n",
1360 ProcessHandle, (DWORD)BaseAddress, (DWORD)ViewSize,
1361 (DWORD)unknown);
1362 TRACE("NtFlushVirtualMemory: base=%x, size=%x\n",
1363 (DWORD)address, size);
1365 FlushViewOfFile(address, size);
1367 context->Eax = STATUS_SUCCESS;
1369 break;
1372 case 0x0014: /* Get/Set Debug Registers */
1374 * Input: ECX: 0 if Get, 1 if Set
1376 * EDX: Get: Flat address of buffer to receive values of
1377 * debug registers DR0 .. DR7
1378 * Set: Flat address of buffer containing values of
1379 * debug registers DR0 .. DR7 to be set
1380 * Output: None
1383 FIXME("[0014] ECX=%x EDX=%x\n",
1384 context->Ecx, context->Edx);
1386 /* FIXME */
1387 break;
1390 case 0x0015: /* Set Coprocessor Emulation Flag */
1392 * Input: EDX: 0 to deactivate, 1 to activate coprocessor emulation
1394 * Output: None
1397 TRACE("[0015] EDX=%x\n", context->Edx);
1399 /* We don't care, as we always have a coprocessor anyway */
1400 break;
1403 case 0x0016: /* Init Win32S VxD PSP */
1405 * If called to query required PSP size:
1407 * Input: EBX: 0
1408 * Output: EDX: Required size of Win32s VxD PSP
1410 * If called to initialize allocated PSP:
1412 * Input: EBX: LoWord: Selector of Win32s VxD PSP
1413 * HiWord: Paragraph of Win32s VxD PSP (DOSMEM)
1414 * Output: None
1417 if (context->Ebx == 0)
1418 context->Edx = 0x80;
1419 else
1421 PDB16 *psp = MapSL( MAKESEGPTR( BX_reg(context), 0 ));
1422 psp->nbFiles = 32;
1423 psp->fileHandlesPtr = MAKELONG(HIWORD(context->Ebx), 0x5c);
1424 memset((LPBYTE)psp + 0x5c, '\xFF', 32);
1426 break;
1429 case 0x0017: /* Set Break Point */
1431 * Input: EBX: Offset of Break Point
1432 * CX: Selector of Break Point
1434 * Output: None
1437 FIXME("[0017] EBX=%x CX=%x\n",
1438 context->Ebx, CX_reg(context));
1440 /* FIXME */
1441 break;
1444 case 0x0018: /* VirtualLock */
1446 * Input: ECX: Current Process
1448 * EDX: Flat address of arguments on stack
1450 * DWORD *retv [out] TRUE if success, FALSE if failure
1451 * LPVOID base [in] Flat address of range to lock
1452 * DWORD size [in] Size of range
1454 * Output: EAX: NtStatus
1457 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1458 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1459 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1460 DWORD size = stack[2];
1461 DWORD result;
1463 TRACE("VirtualLock(%x, %x, %x)\n",
1464 (DWORD)retv, (DWORD)base, size);
1466 result = VirtualLock(base, size);
1468 if (result)
1469 *retv = TRUE,
1470 context->Eax = STATUS_SUCCESS;
1471 else
1472 *retv = FALSE,
1473 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1475 break;
1478 case 0x0019: /* VirtualUnlock */
1480 * Input: ECX: Current Process
1482 * EDX: Flat address of arguments on stack
1484 * DWORD *retv [out] TRUE if success, FALSE if failure
1485 * LPVOID base [in] Flat address of range to unlock
1486 * DWORD size [in] Size of range
1488 * Output: EAX: NtStatus
1491 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1492 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1493 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1494 DWORD size = stack[2];
1495 DWORD result;
1497 TRACE("VirtualUnlock(%x, %x, %x)\n",
1498 (DWORD)retv, (DWORD)base, size);
1500 result = VirtualUnlock(base, size);
1502 if (result)
1503 *retv = TRUE,
1504 context->Eax = STATUS_SUCCESS;
1505 else
1506 *retv = FALSE,
1507 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1509 break;
1512 case 0x001A: /* KGetSystemInfo */
1514 * Input: None
1516 * Output: ECX: Start of sparse memory arena
1517 * EDX: End of sparse memory arena
1520 TRACE("KGetSystemInfo()\n");
1523 * Note: Win32s reserves 0GB - 2GB for Win 3.1 and uses 2GB - 4GB as
1524 * sparse memory arena. We do it the other way around, since
1525 * we have to reserve 3GB - 4GB for Linux, and thus use
1526 * 0GB - 3GB as sparse memory arena.
1528 * FIXME: What about other OSes ?
1531 context->Ecx = W32S_WINE2APP(0x00000000);
1532 context->Edx = W32S_WINE2APP(0xbfffffff);
1533 break;
1536 case 0x001B: /* KGlobalMemStat */
1538 * Input: ESI: Flat address of buffer to receive memory info
1540 * Output: None
1543 struct Win32sMemoryInfo
1545 DWORD DIPhys_Count; /* Total physical pages */
1546 DWORD DIFree_Count; /* Free physical pages */
1547 DWORD DILin_Total_Count; /* Total virtual pages (private arena) */
1548 DWORD DILin_Total_Free; /* Free virtual pages (private arena) */
1550 DWORD SparseTotal; /* Total size of sparse arena (bytes ?) */
1551 DWORD SparseFree; /* Free size of sparse arena (bytes ?) */
1554 struct Win32sMemoryInfo *info =
1555 (struct Win32sMemoryInfo *)W32S_APP2WINE(context->Esi);
1557 FIXME("KGlobalMemStat(%x)\n", (DWORD)info);
1559 /* FIXME */
1561 break;
1564 case 0x001C: /* Enable/Disable Exceptions */
1566 * Input: ECX: 0 to disable, 1 to enable exception handling
1568 * Output: None
1571 TRACE("[001c] ECX=%x\n", context->Ecx);
1573 /* FIXME */
1574 break;
1577 case 0x001D: /* VirtualAlloc called from 16-bit code */
1579 * Input: EDX: Segmented address of arguments on stack
1581 * LPVOID base [in] Flat address of region to reserve/commit
1582 * DWORD size [in] Size of region
1583 * DWORD type [in] Type of allocation
1584 * DWORD prot [in] Type of access protection
1586 * Output: EAX: NtStatus
1587 * EDX: Flat base address of allocated region
1590 DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) ));
1591 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]);
1592 DWORD size = stack[1];
1593 DWORD type = stack[2];
1594 DWORD prot = stack[3];
1595 DWORD result;
1597 TRACE("VirtualAlloc16(%x, %x, %x, %x)\n",
1598 (DWORD)base, size, type, prot);
1600 if (type & 0x80000000)
1602 WARN("VirtualAlloc16: strange type %x\n", type);
1603 type &= 0x7fffffff;
1606 result = (DWORD)VirtualAlloc(base, size, type, prot);
1608 if (W32S_WINE2APP(result))
1609 context->Edx = W32S_WINE2APP(result),
1610 context->Eax = STATUS_SUCCESS;
1611 else
1612 context->Edx = 0,
1613 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1614 TRACE("VirtualAlloc16: returning base %x\n", context->Edx);
1616 break;
1619 case 0x001E: /* VirtualFree called from 16-bit code */
1621 * Input: EDX: Segmented address of arguments on stack
1623 * LPVOID base [in] Flat address of region
1624 * DWORD size [in] Size of region
1625 * DWORD type [in] Type of operation
1627 * Output: EAX: NtStatus
1628 * EDX: TRUE if success, FALSE if failure
1631 DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) ));
1632 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]);
1633 DWORD size = stack[1];
1634 DWORD type = stack[2];
1635 DWORD result;
1637 TRACE("VirtualFree16(%x, %x, %x)\n",
1638 (DWORD)base, size, type);
1640 result = VirtualFree(base, size, type);
1642 if (result)
1643 context->Edx = TRUE,
1644 context->Eax = STATUS_SUCCESS;
1645 else
1646 context->Edx = FALSE,
1647 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1649 break;
1652 case 0x001F: /* FWorkingSetSize */
1654 * Input: EDX: 0 if Get, 1 if Set
1656 * ECX: Get: Buffer to receive Working Set Size
1657 * Set: Buffer containing Working Set Size
1659 * Output: NtStatus
1662 DWORD *ptr = (DWORD *)W32S_APP2WINE(context->Ecx);
1663 BOOL set = context->Edx;
1665 TRACE("FWorkingSetSize(%x, %x)\n", (DWORD)ptr, (DWORD)set);
1667 if (set)
1668 /* We do it differently ... */;
1669 else
1670 *ptr = 0x100;
1672 context->Eax = STATUS_SUCCESS;
1674 break;
1677 default:
1678 VXD_BARF( context, "W32S" );