push acf9cae24af5f4234e2e98ec9986d6b14607ba2a
[wine/hacks.git] / dlls / winedos / vxd.c
bloba719c30e108e4b1e86ea1db6824ae823696030ca
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 "dosexe.h"
45 #include "wine/debug.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(vxd);
49 #define W32S_APP2WINE(addr) ((addr)? (DWORD)(addr) + W32S_offset : 0)
50 #define W32S_WINE2APP(addr) ((addr)? (DWORD)(addr) - W32S_offset : 0)
52 #define VXD_BARF(context,name) \
53 TRACE( "vxd %s: unknown/not implemented parameters:\n" \
54 "vxd %s: AX %04x, BX %04x, CX %04x, DX %04x, " \
55 "SI %04x, DI %04x, DS %04x, ES %04x\n", \
56 (name), (name), AX_reg(context), BX_reg(context), \
57 CX_reg(context), DX_reg(context), SI_reg(context), \
58 DI_reg(context), (WORD)context->SegDs, (WORD)context->SegEs )
60 static UINT W32S_offset;
62 static WORD VXD_WinVersion(void)
64 WORD version = LOWORD(GetVersion16());
65 return (version >> 8) | (version << 8);
68 /***********************************************************************
69 * VXD_VMM (WPROCS.401)
71 void WINAPI VXD_VMM ( CONTEXT86 *context )
73 unsigned service = AX_reg(context);
75 TRACE("[%04x] VMM\n", (UINT16)service);
77 switch(service)
79 case 0x0000: /* version */
80 SET_AX( context, VXD_WinVersion() );
81 RESET_CFLAG(context);
82 break;
84 case 0x026d: /* Get_Debug_Flag '/m' */
85 case 0x026e: /* Get_Debug_Flag '/n' */
86 SET_AL( context, 0 );
87 RESET_CFLAG(context);
88 break;
90 default:
91 VXD_BARF( context, "VMM" );
95 /***********************************************************************
96 * VXD_PageFile (WPROCS.433)
98 void WINAPI VXD_PageFile( CONTEXT86 *context )
100 unsigned service = AX_reg(context);
102 /* taken from Ralf Brown's Interrupt List */
104 TRACE("[%04x] PageFile\n", (UINT16)service );
106 switch(service)
108 case 0x00: /* get version, is this windows version? */
109 TRACE("returning version\n");
110 SET_AX( context, VXD_WinVersion() );
111 RESET_CFLAG(context);
112 break;
114 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 */
118 /* FIXME: do I touch DS:SI or DS:DI? */
119 RESET_CFLAG(context);
120 break;
122 case 0x02: /* delete permanent swap on exit */
123 TRACE("VxD PageFile: supposed to delete swap\n");
124 RESET_CFLAG(context);
125 break;
127 case 0x03: /* current temporary swap file size */
128 TRACE("VxD PageFile: what is current temp. swap size\n");
129 RESET_CFLAG(context);
130 break;
132 case 0x04: /* read or write?? INTERRUP.D */
133 case 0x05: /* cancel?? INTERRUP.D */
134 case 0x06: /* test I/O valid INTERRUP.D */
135 default:
136 VXD_BARF( context, "pagefile" );
137 break;
141 /***********************************************************************
142 * VXD_Reboot (WPROCS.409)
144 void WINAPI VXD_Reboot ( CONTEXT86 *context )
146 unsigned service = AX_reg(context);
148 TRACE("[%04x] Reboot\n", (UINT16)service);
150 switch(service)
152 case 0x0000: /* version */
153 SET_AX( context, VXD_WinVersion() );
154 RESET_CFLAG(context);
155 break;
157 default:
158 VXD_BARF( context, "REBOOT" );
162 /***********************************************************************
163 * VXD_VDD (WPROCS.410)
165 void WINAPI VXD_VDD ( CONTEXT86 *context )
167 unsigned service = AX_reg(context);
169 TRACE("[%04x] VDD\n", (UINT16)service);
171 switch(service)
173 case 0x0000: /* version */
174 SET_AX( context, VXD_WinVersion() );
175 RESET_CFLAG(context);
176 break;
178 default:
179 VXD_BARF( context, "VDD" );
183 /***********************************************************************
184 * VXD_VMD (WPROCS.412)
186 void WINAPI VXD_VMD ( CONTEXT86 *context )
188 unsigned service = AX_reg(context);
190 TRACE("[%04x] VMD\n", (UINT16)service);
192 switch(service)
194 case 0x0000: /* version */
195 SET_AX( context, VXD_WinVersion() );
196 RESET_CFLAG(context);
197 break;
199 default:
200 VXD_BARF( context, "VMD" );
204 /***********************************************************************
205 * VXD_VXDLoader (WPROCS.439)
207 void WINAPI VXD_VXDLoader( CONTEXT86 *context )
209 unsigned service = AX_reg(context);
211 TRACE("[%04x] VXDLoader\n", (UINT16)service);
213 switch (service)
215 case 0x0000: /* get version */
216 TRACE("returning version\n");
217 SET_AX( context, 0x0000 );
218 SET_DX( context, VXD_WinVersion() );
219 RESET_CFLAG(context);
220 break;
222 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 RESET_CFLAG(context);
230 break;
232 case 0x0002: /* unload device */
233 FIXME("unload device (%08x)\n", context->Ebx);
234 SET_AX( context, 0x0000 );
235 RESET_CFLAG(context);
236 break;
238 default:
239 VXD_BARF( context, "VXDLDR" );
240 SET_AX( context, 0x000B ); /* invalid function number */
241 SET_CFLAG(context);
242 break;
246 /***********************************************************************
247 * VXD_Shell (WPROCS.423)
249 void WINAPI VXD_Shell( CONTEXT86 *context )
251 unsigned service = DX_reg(context);
253 TRACE("[%04x] Shell\n", (UINT16)service);
255 switch (service) /* Ralf Brown says EDX, but I use DX instead */
257 case 0x0000:
258 TRACE("returning version\n");
259 SET_AX( context, VXD_WinVersion() );
260 context->Ebx = 1; /* system VM Handle */
261 break;
263 case 0x0001:
264 case 0x0002:
265 case 0x0003:
266 /* SHELL_SYSMODAL_Message
267 ebx virtual machine handle
268 eax message box flags
269 ecx address of message
270 edi address of caption
271 return response in eax
273 case 0x0004:
274 /* SHELL_Message
275 ebx virtual machine handle
276 eax message box flags
277 ecx address of message
278 edi address of caption
279 esi address callback
280 edx reference data for callback
281 return response in eax
283 case 0x0005:
284 VXD_BARF( context, "shell" );
285 break;
287 case 0x0006: /* SHELL_Get_VM_State */
288 TRACE("VxD Shell: returning VM state\n");
289 /* Actually we don't, not yet. We have to return a structure
290 * and I am not to sure how to set it up and return it yet,
291 * so for now let's do nothing. I can (hopefully) get this
292 * by the next release
294 /* RESET_CFLAG(context); */
295 break;
297 case 0x0007:
298 case 0x0008:
299 case 0x0009:
300 case 0x000A:
301 case 0x000B:
302 case 0x000C:
303 case 0x000D:
304 case 0x000E:
305 case 0x000F:
306 case 0x0010:
307 case 0x0011:
308 case 0x0012:
309 case 0x0013:
310 case 0x0014:
311 case 0x0015:
312 case 0x0016:
313 VXD_BARF( context, "SHELL" );
314 break;
316 /* the new Win95 shell API */
317 case 0x0100: /* get version */
318 SET_AX( context, VXD_WinVersion() );
319 break;
321 case 0x0104: /* retrieve Hook_Properties list */
322 case 0x0105: /* call Hook_Properties callbacks */
323 VXD_BARF( context, "SHELL" );
324 break;
326 case 0x0106: /* install timeout callback */
327 TRACE("VxD Shell: ignoring shell callback (%d sec.)\n", context->Ebx);
328 SET_CFLAG(context);
329 break;
331 case 0x0107: /* get version of any VxD */
332 default:
333 VXD_BARF( context, "SHELL" );
334 break;
339 /***********************************************************************
340 * VXD_Comm (WPROCS.414)
342 void WINAPI VXD_Comm( CONTEXT86 *context )
344 unsigned service = AX_reg(context);
346 TRACE("[%04x] Comm\n", (UINT16)service);
348 switch (service)
350 case 0x0000: /* get version */
351 TRACE("returning version\n");
352 SET_AX( context, VXD_WinVersion() );
353 RESET_CFLAG(context);
354 break;
356 case 0x0001: /* set port global */
357 case 0x0002: /* get focus */
358 case 0x0003: /* virtualise port */
359 default:
360 VXD_BARF( context, "comm" );
364 /***********************************************************************
365 * VXD_Timer (WPROCS.405)
367 void WINAPI VXD_Timer( CONTEXT86 *context )
369 unsigned service = AX_reg(context);
371 TRACE("[%04x] Virtual Timer\n", (UINT16)service);
373 switch(service)
375 case 0x0000: /* version */
376 SET_AX( context, VXD_WinVersion() );
377 RESET_CFLAG(context);
378 break;
380 case 0x0100: /* clock tick time, in 840nsecs */
381 context->Eax = GetTickCount();
383 context->Edx = context->Eax >> 22;
384 context->Eax <<= 10; /* not very precise */
385 break;
387 case 0x0101: /* current Windows time, msecs */
388 case 0x0102: /* current VM time, msecs */
389 context->Eax = GetTickCount();
390 break;
392 default:
393 VXD_BARF( context, "VTD" );
398 /***********************************************************************
399 * timer_thread
401 static DWORD CALLBACK timer_thread( void *arg )
403 DWORD *system_time = arg;
405 for (;;)
407 *system_time = GetTickCount();
408 Sleep( 55 );
411 return 0;
415 /***********************************************************************
416 * VXD_TimerAPI (WPROCS.1490)
418 void WINAPI VXD_TimerAPI ( CONTEXT86 *context )
420 static WORD System_Time_Selector;
422 unsigned service = AX_reg(context);
424 TRACE("[%04x] TimerAPI\n", (UINT16)service);
426 switch(service)
428 case 0x0000: /* version */
429 SET_AX( context, VXD_WinVersion() );
430 RESET_CFLAG(context);
431 break;
433 case 0x0009: /* get system time selector */
434 if ( !System_Time_Selector )
436 HANDLE16 handle = GlobalAlloc16( GMEM_FIXED, sizeof(DWORD) );
437 System_Time_Selector = handle | 7;
438 CloseHandle( CreateThread( NULL, 0, timer_thread, GlobalLock16(handle), 0, NULL ) );
440 SET_AX( context, System_Time_Selector );
441 RESET_CFLAG(context);
442 break;
444 default:
445 VXD_BARF( context, "VTDAPI" );
449 /***********************************************************************
450 * VXD_ConfigMG (WPROCS.451)
452 void WINAPI VXD_ConfigMG ( CONTEXT86 *context )
454 unsigned service = AX_reg(context);
456 TRACE("[%04x] ConfigMG\n", (UINT16)service);
458 switch(service)
460 case 0x0000: /* version */
461 SET_AX( context, VXD_WinVersion() );
462 RESET_CFLAG(context);
463 break;
465 default:
466 VXD_BARF( context, "CONFIGMG" );
470 /***********************************************************************
471 * VXD_Enable (WPROCS.455)
473 void WINAPI VXD_Enable ( CONTEXT86 *context )
475 unsigned service = AX_reg(context);
477 TRACE("[%04x] Enable\n", (UINT16)service);
479 switch(service)
481 case 0x0000: /* version */
482 SET_AX( context, VXD_WinVersion() );
483 RESET_CFLAG(context);
484 break;
486 default:
487 VXD_BARF( context, "ENABLE" );
491 /***********************************************************************
492 * VXD_APM (WPROCS.438)
494 void WINAPI VXD_APM ( CONTEXT86 *context )
496 unsigned service = AX_reg(context);
498 TRACE("[%04x] APM\n", (UINT16)service);
500 switch(service)
502 case 0x0000: /* version */
503 SET_AX( context, VXD_WinVersion() );
504 RESET_CFLAG(context);
505 break;
507 default:
508 VXD_BARF( context, "APM" );
512 /***********************************************************************
513 * VXD_Win32s (WPROCS.445)
515 * This is an implementation of the services of the Win32s VxD.
516 * Since official documentation of these does not seem to be available,
517 * certain arguments of some of the services remain unclear.
519 * FIXME: The following services are currently unimplemented:
520 * Exception handling (0x01, 0x1C)
521 * Debugger support (0x0C, 0x14, 0x17)
522 * Low-level memory access (0x02, 0x03, 0x0A, 0x0B)
523 * Memory Statistics (0x1B)
526 * We have a specific problem running Win32s on Linux (and probably also
527 * the other x86 unixes), since Win32s tries to allocate its main 'flat
528 * code/data segment' selectors with a base of 0xffff0000 (and limit 4GB).
529 * The rationale for this seems to be that they want one the one hand to
530 * be able to leave the Win 3.1 memory (starting with the main DOS memory)
531 * at linear address 0, but want at other hand to have offset 0 of the
532 * flat data/code segment point to an unmapped page (to catch NULL pointer
533 * accesses). Hence they allocate the flat segments with a base of 0xffff0000
534 * so that the Win 3.1 memory area at linear address zero shows up in the
535 * flat segments at offset 0x10000 (since linear addresses wrap around at
536 * 4GB). To compensate for that discrepancy between flat segment offsets
537 * and plain linear addresses, all flat pointers passed between the 32-bit
538 * and the 16-bit parts of Win32s are shifted by 0x10000 in the appropriate
539 * direction by the glue code (mainly) in W32SKRNL and WIN32S16.
541 * The problem for us is now that Linux does not allow a LDT selector with
542 * base 0xffff0000 to be created, since it would 'see' a part of the kernel
543 * address space. To address this problem we introduce *another* offset:
544 * We add 0x10000 to every linear address we get as an argument from Win32s.
545 * This means especially that the flat code/data selectors get actually
546 * allocated with base 0x0, so that flat offsets and (real) linear addresses
547 * do again agree! In fact, every call e.g. of a Win32s VxD service now
548 * has all pointer arguments (which are offsets in the flat data segment)
549 * first reduced by 0x10000 by the W32SKRNL glue code, and then again
550 * increased by 0x10000 by *our* code.
552 * Note that to keep everything consistent, this offset has to be applied by
553 * every Wine function that operates on 'linear addresses' passed to it by
554 * Win32s. Fortunately, since Win32s does not directly call any Wine 32-bit
555 * API routines, this affects only two locations: this VxD and the DPMI
556 * handler. (NOTE: Should any Win32s application pass a linear address to
557 * any routine apart from those, e.g. some other VxD handler, that code
558 * would have to take the offset into account as well!)
560 * The offset is set the first time any application calls the GetVersion()
561 * service of the Win32s VxD. (Note that the offset is never reset.)
565 void WINAPI VXD_Win32s( CONTEXT86 *context )
567 switch (AX_reg(context))
569 case 0x0000: /* Get Version */
571 * Input: None
573 * Output: EAX: LoWord: Win32s Version (1.30)
574 * HiWord: VxD Version (200)
576 * EBX: Build (172)
578 * ECX: ??? (1)
580 * EDX: Debugging Flags
582 * EDI: Error Flag
583 * 0 if OK,
584 * 1 if VMCPD VxD not found
587 TRACE("GetVersion()\n");
589 context->Eax = VXD_WinVersion() | (200 << 16);
590 context->Ebx = 0;
591 context->Ecx = 0;
592 context->Edx = 0;
593 context->Edi = 0;
596 * If this is the first time we are called for this process,
597 * hack the memory image of WIN32S16 so that it doesn't try
598 * to access the GDT directly ...
600 * The first code segment of WIN32S16 (version 1.30) contains
601 * an unexported function somewhere between the exported functions
602 * SetFS and StackLinearToSegmented that tries to find a selector
603 * in the LDT that maps to the memory image of the LDT itself.
604 * If it succeeds, it stores this selector into a global variable
605 * which will be used to speed up execution by using this selector
606 * to modify the LDT directly instead of using the DPMI calls.
608 * To perform this search of the LDT, this function uses the
609 * sgdt and sldt instructions to find the linear address of
610 * the (GDT and then) LDT. While those instructions themselves
611 * execute without problem, the linear address that sgdt returns
612 * points (at least under Linux) to the kernel address space, so
613 * that any subsequent access leads to a segfault.
615 * Fortunately, WIN32S16 still contains as a fallback option the
616 * mechanism of using DPMI calls to modify LDT selectors instead
617 * of direct writes to the LDT. Thus we can circumvent the problem
618 * by simply replacing the first byte of the offending function
619 * with an 'retf' instruction. This means that the global variable
620 * supposed to contain the LDT alias selector will remain zero,
621 * and hence WIN32S16 will fall back to using DPMI calls.
623 * The heuristic we employ to _find_ that function is as follows:
624 * We search between the addresses of the exported symbols SetFS
625 * and StackLinearToSegmented for the byte sequence '0F 01 04'
626 * (this is the opcode of 'sgdt [si]'). We then search backwards
627 * from this address for the last occurrence of 'CB' (retf) that marks
628 * the end of the preceding function. The following byte (which
629 * should now be the first byte of the function we are looking for)
630 * will be replaced by 'CB' (retf).
632 * This heuristic works for the retail as well as the debug version
633 * of Win32s version 1.30. For versions earlier than that this
634 * hack should not be necessary at all, since the whole mechanism
635 * ('PERF130') was introduced only in 1.30 to improve the overall
636 * performance of Win32s.
639 if (!W32S_offset)
641 HMODULE16 hModule = GetModuleHandle16("win32s16");
642 SEGPTR func1 = (SEGPTR)GetProcAddress16(hModule, "SetFS");
643 SEGPTR func2 = (SEGPTR)GetProcAddress16(hModule, "StackLinearToSegmented");
645 if ( hModule && func1 && func2
646 && SELECTOROF(func1) == SELECTOROF(func2))
648 BYTE *start = MapSL(func1);
649 BYTE *end = MapSL(func2);
650 BYTE *p, *retv = NULL;
651 int found = 0;
653 for (p = start; p < end; p++)
654 if (*p == 0xCB) found = 0, retv = p;
655 else if (*p == 0x0F) found = 1;
656 else if (*p == 0x01 && found == 1) found = 2;
657 else if (*p == 0x04 && found == 2) { found = 3; break; }
658 else found = 0;
660 if (found == 3 && retv)
662 TRACE("PERF130 hack: "
663 "Replacing byte %02X at offset %04X:%04X\n",
664 *(retv+1), SELECTOROF(func1),
665 OFFSETOF(func1) + retv+1-start);
667 *(retv+1) = (BYTE)0xCB;
673 * Mark process as Win32s, so that subsequent DPMI calls
674 * will perform the W32S_APP2WINE/W32S_WINE2APP address shift.
676 W32S_offset = 0x10000;
677 break;
680 case 0x0001: /* Install Exception Handling */
682 * Input: EBX: Flat address of W32SKRNL Exception Data
684 * ECX: LoWord: Flat Code Selector
685 * HiWord: Flat Data Selector
687 * EDX: Flat address of W32SKRNL Exception Handler
688 * (this is equal to W32S_BackTo32 + 0x40)
690 * ESI: SEGPTR KERNEL.HASGPHANDLER
692 * EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10)
694 * Output: EAX: 0 if OK
697 TRACE("[0001] EBX=%x ECX=%x EDX=%x ESI=%x EDI=%x\n",
698 context->Ebx, context->Ecx, context->Edx,
699 context->Esi, context->Edi);
701 /* FIXME */
703 context->Eax = 0;
704 break;
707 case 0x0002: /* Set Page Access Flags */
709 * Input: EBX: New access flags
710 * Bit 2: User Page if set, Supervisor Page if clear
711 * Bit 1: Read-Write if set, Read-Only if clear
713 * ECX: Size of memory area to change
715 * EDX: Flat start address of memory area
717 * Output: EAX: Size of area changed
720 TRACE("[0002] EBX=%x ECX=%x EDX=%x\n",
721 context->Ebx, context->Ecx, context->Edx);
723 /* FIXME */
725 context->Eax = context->Ecx;
726 break;
729 case 0x0003: /* Get Page Access Flags */
731 * Input: EDX: Flat address of page to query
733 * Output: EAX: Page access flags
734 * Bit 2: User Page if set, Supervisor Page if clear
735 * Bit 1: Read-Write if set, Read-Only if clear
738 TRACE("[0003] EDX=%x\n", context->Edx);
740 /* FIXME */
742 context->Eax = 6;
743 break;
746 case 0x0004: /* Map Module */
748 * Input: ECX: IMTE (offset in Module Table) of new module
750 * EDX: Flat address of Win32s Module Table
752 * Output: EAX: 0 if OK
755 if (!context->Edx || CX_reg(context) == 0xFFFF)
757 TRACE("MapModule: Initialization call\n");
758 context->Eax = 0;
760 else
763 * Structure of a Win32s Module Table Entry:
765 struct Win32sModule
767 DWORD flags;
768 DWORD flatBaseAddr;
769 LPCSTR moduleName;
770 LPCSTR pathName;
771 LPCSTR unknown;
772 LPBYTE baseAddr;
773 DWORD hModule;
774 DWORD relocDelta;
778 * Note: This function should set up a demand-paged memory image
779 * of the given module. Since mmap does not allow file offsets
780 * not aligned at 1024 bytes, we simply load the image fully
781 * into memory.
784 struct Win32sModule *moduleTable =
785 (struct Win32sModule *)W32S_APP2WINE(context->Edx);
786 struct Win32sModule *module = moduleTable + context->Ecx;
788 IMAGE_NT_HEADERS *nt_header = RtlImageNtHeader( (HMODULE)module->baseAddr );
789 IMAGE_SECTION_HEADER *pe_seg = (IMAGE_SECTION_HEADER*)((char *)&nt_header->OptionalHeader +
790 nt_header->FileHeader.SizeOfOptionalHeader);
793 HFILE image = _lopen(module->pathName, OF_READ);
794 BOOL error = (image == HFILE_ERROR);
795 UINT i;
797 TRACE("MapModule: Loading %s\n", module->pathName);
799 for (i = 0;
800 !error && i < nt_header->FileHeader.NumberOfSections;
801 i++, pe_seg++)
802 if(!(pe_seg->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA))
804 DWORD off = pe_seg->PointerToRawData;
805 DWORD len = pe_seg->SizeOfRawData;
806 LPBYTE addr = module->baseAddr + pe_seg->VirtualAddress;
808 TRACE("MapModule: "
809 "Section %d at %08x from %08x len %08x\n",
810 i, (DWORD)addr, off, len);
812 if ( _llseek(image, off, SEEK_SET) != off
813 || _lread(image, addr, len) != len)
814 error = TRUE;
817 _lclose(image);
819 if (error)
820 ERR("MapModule: Unable to load %s\n", module->pathName);
822 else if (module->relocDelta != 0)
824 IMAGE_DATA_DIRECTORY *dir = nt_header->OptionalHeader.DataDirectory
825 + IMAGE_DIRECTORY_ENTRY_BASERELOC;
826 IMAGE_BASE_RELOCATION *r = (IMAGE_BASE_RELOCATION *)
827 (dir->Size? module->baseAddr + dir->VirtualAddress : 0);
829 TRACE("MapModule: Reloc delta %08x\n", module->relocDelta);
831 while (r && r->VirtualAddress)
833 LPBYTE page = module->baseAddr + r->VirtualAddress;
834 WORD *TypeOffset = (WORD *)(r + 1);
835 unsigned int count = (r->SizeOfBlock - sizeof(*r)) / sizeof(*TypeOffset);
837 TRACE("MapModule: %d relocations for page %08x\n",
838 count, (DWORD)page);
840 for(i = 0; i < count; i++)
842 int offset = TypeOffset[i] & 0xFFF;
843 int type = TypeOffset[i] >> 12;
844 switch(type)
846 case IMAGE_REL_BASED_ABSOLUTE:
847 break;
848 case IMAGE_REL_BASED_HIGH:
849 *(WORD *)(page+offset) += HIWORD(module->relocDelta);
850 break;
851 case IMAGE_REL_BASED_LOW:
852 *(WORD *)(page+offset) += LOWORD(module->relocDelta);
853 break;
854 case IMAGE_REL_BASED_HIGHLOW:
855 *(DWORD*)(page+offset) += module->relocDelta;
856 break;
857 default:
858 WARN("MapModule: Unsupported fixup type\n");
859 break;
863 r = (IMAGE_BASE_RELOCATION *)((LPBYTE)r + r->SizeOfBlock);
867 context->Eax = 0;
868 RESET_CFLAG(context);
870 break;
873 case 0x0005: /* UnMap Module */
875 * Input: EDX: Flat address of module image
877 * Output: EAX: 1 if OK
880 TRACE("UnMapModule: %x\n", W32S_APP2WINE(context->Edx));
882 /* As we didn't map anything, there's nothing to unmap ... */
884 context->Eax = 1;
885 break;
888 case 0x0006: /* VirtualAlloc */
890 * Input: ECX: Current Process
892 * EDX: Flat address of arguments on stack
894 * DWORD *retv [out] Flat base address of allocated region
895 * LPVOID base [in] Flat address of region to reserve/commit
896 * DWORD size [in] Size of region
897 * DWORD type [in] Type of allocation
898 * DWORD prot [in] Type of access protection
900 * Output: EAX: NtStatus
903 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
904 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
905 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
906 DWORD size = stack[2];
907 DWORD type = stack[3];
908 DWORD prot = stack[4];
909 DWORD result;
911 TRACE("VirtualAlloc(%x, %x, %x, %x, %x)\n",
912 (DWORD)retv, (DWORD)base, size, type, prot);
914 if (type & 0x80000000)
916 WARN("VirtualAlloc: strange type %x\n", type);
917 type &= 0x7fffffff;
920 if (!base && (type & MEM_COMMIT) && prot == PAGE_READONLY)
922 WARN("VirtualAlloc: NLS hack, allowing write access!\n");
923 prot = PAGE_READWRITE;
926 result = (DWORD)VirtualAlloc(base, size, type, prot);
928 if (W32S_WINE2APP(result))
929 *retv = W32S_WINE2APP(result),
930 context->Eax = STATUS_SUCCESS;
931 else
932 *retv = 0,
933 context->Eax = STATUS_NO_MEMORY; /* FIXME */
935 break;
938 case 0x0007: /* VirtualFree */
940 * Input: ECX: Current Process
942 * EDX: Flat address of arguments on stack
944 * DWORD *retv [out] TRUE if success, FALSE if failure
945 * LPVOID base [in] Flat address of region
946 * DWORD size [in] Size of region
947 * DWORD type [in] Type of operation
949 * Output: EAX: NtStatus
952 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
953 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
954 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
955 DWORD size = stack[2];
956 DWORD type = stack[3];
957 DWORD result;
959 TRACE("VirtualFree(%x, %x, %x, %x)\n",
960 (DWORD)retv, (DWORD)base, size, type);
962 result = VirtualFree(base, size, type);
964 if (result)
965 *retv = TRUE,
966 context->Eax = STATUS_SUCCESS;
967 else
968 *retv = FALSE,
969 context->Eax = STATUS_NO_MEMORY; /* FIXME */
971 break;
974 case 0x0008: /* VirtualProtect */
976 * Input: ECX: Current Process
978 * EDX: Flat address of arguments on stack
980 * DWORD *retv [out] TRUE if success, FALSE if failure
981 * LPVOID base [in] Flat address of region
982 * DWORD size [in] Size of region
983 * DWORD new_prot [in] Desired access protection
984 * DWORD *old_prot [out] Previous access protection
986 * Output: EAX: NtStatus
989 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
990 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
991 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
992 DWORD size = stack[2];
993 DWORD new_prot = stack[3];
994 DWORD *old_prot = (DWORD *)W32S_APP2WINE(stack[4]);
995 DWORD result;
997 TRACE("VirtualProtect(%x, %x, %x, %x, %x)\n",
998 (DWORD)retv, (DWORD)base, size, new_prot, (DWORD)old_prot);
1000 result = VirtualProtect(base, size, new_prot, old_prot);
1002 if (result)
1003 *retv = TRUE,
1004 context->Eax = STATUS_SUCCESS;
1005 else
1006 *retv = FALSE,
1007 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1009 break;
1012 case 0x0009: /* VirtualQuery */
1014 * Input: ECX: Current Process
1016 * EDX: Flat address of arguments on stack
1018 * DWORD *retv [out] Nr. bytes returned
1019 * LPVOID base [in] Flat address of region
1020 * LPMEMORY_BASIC_INFORMATION info [out] Info buffer
1021 * DWORD len [in] Size of buffer
1023 * Output: EAX: NtStatus
1026 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1027 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1028 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1029 PMEMORY_BASIC_INFORMATION info =
1030 (PMEMORY_BASIC_INFORMATION)W32S_APP2WINE(stack[2]);
1031 DWORD len = stack[3];
1032 DWORD result;
1034 TRACE("VirtualQuery(%x, %x, %x, %x)\n",
1035 (DWORD)retv, (DWORD)base, (DWORD)info, len);
1037 result = VirtualQuery(base, info, len);
1039 *retv = result;
1040 context->Eax = STATUS_SUCCESS;
1042 break;
1045 case 0x000A: /* SetVirtMemProcess */
1047 * Input: ECX: Process Handle
1049 * EDX: Flat address of region
1051 * Output: EAX: NtStatus
1054 TRACE("[000a] ECX=%x EDX=%x\n",
1055 context->Ecx, context->Edx);
1057 /* FIXME */
1059 context->Eax = STATUS_SUCCESS;
1060 break;
1063 case 0x000B: /* ??? some kind of cleanup */
1065 * Input: ECX: Process Handle
1067 * Output: EAX: NtStatus
1070 TRACE("[000b] ECX=%x\n", context->Ecx);
1072 /* FIXME */
1074 context->Eax = STATUS_SUCCESS;
1075 break;
1078 case 0x000C: /* Set Debug Flags */
1080 * Input: EDX: Debug Flags
1082 * Output: EDX: Previous Debug Flags
1085 FIXME("[000c] EDX=%x\n", context->Edx);
1087 /* FIXME */
1089 context->Edx = 0;
1090 break;
1093 case 0x000D: /* NtCreateSection */
1095 * Input: EDX: Flat address of arguments on stack
1097 * HANDLE32 *retv [out] Handle of Section created
1098 * DWORD flags1 [in] (?? unknown ??)
1099 * DWORD atom [in] Name of Section to create
1100 * LARGE_INTEGER *size [in] Size of Section
1101 * DWORD protect [in] Access protection
1102 * DWORD flags2 [in] (?? unknown ??)
1103 * HFILE32 hFile [in] Handle of file to map
1104 * DWORD psp [in] (Win32s: PSP that hFile belongs to)
1106 * Output: EAX: NtStatus
1109 DWORD *stack = (DWORD *) W32S_APP2WINE(context->Edx);
1110 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]);
1111 DWORD flags1 = stack[1];
1112 DWORD atom = stack[2];
1113 LARGE_INTEGER *size = (LARGE_INTEGER *)W32S_APP2WINE(stack[3]);
1114 DWORD protect = stack[4];
1115 DWORD flags2 = stack[5];
1116 HANDLE hFile = DosFileHandleToWin32Handle(stack[6]);
1117 DWORD psp = stack[7];
1119 HANDLE result = INVALID_HANDLE_VALUE;
1120 char name[128];
1122 TRACE("NtCreateSection(%x, %x, %x, %x, %x, %x, %x, %x)\n",
1123 (DWORD)retv, flags1, atom, (DWORD)size, protect, flags2,
1124 (DWORD)hFile, psp);
1126 if (!atom || GlobalGetAtomNameA(atom, name, sizeof(name)))
1128 TRACE("NtCreateSection: name=%s\n", atom? name : NULL);
1130 result = CreateFileMappingA(hFile, NULL, protect,
1131 size? size->u.HighPart : 0,
1132 size? size->u.LowPart : 0,
1133 atom? name : NULL);
1136 if (result == INVALID_HANDLE_VALUE)
1137 WARN("NtCreateSection: failed!\n");
1138 else
1139 TRACE("NtCreateSection: returned %x\n", (DWORD)result);
1141 if (result != INVALID_HANDLE_VALUE)
1142 *retv = result,
1143 context->Eax = STATUS_SUCCESS;
1144 else
1145 *retv = result,
1146 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1148 break;
1151 case 0x000E: /* NtOpenSection */
1153 * Input: EDX: Flat address of arguments on stack
1155 * HANDLE32 *retv [out] Handle of Section opened
1156 * DWORD protect [in] Access protection
1157 * DWORD atom [in] Name of Section to create
1159 * Output: EAX: NtStatus
1162 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1163 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]);
1164 DWORD protect = stack[1];
1165 DWORD atom = stack[2];
1167 HANDLE result = INVALID_HANDLE_VALUE;
1168 char name[128];
1170 TRACE("NtOpenSection(%x, %x, %x)\n",
1171 (DWORD)retv, protect, atom);
1173 if (atom && GlobalGetAtomNameA(atom, name, sizeof(name)))
1175 TRACE("NtOpenSection: name=%s\n", name);
1177 result = OpenFileMappingA(protect, FALSE, name);
1180 if (result == INVALID_HANDLE_VALUE)
1181 WARN("NtOpenSection: failed!\n");
1182 else
1183 TRACE("NtOpenSection: returned %x\n", (DWORD)result);
1185 if (result != INVALID_HANDLE_VALUE)
1186 *retv = result,
1187 context->Eax = STATUS_SUCCESS;
1188 else
1189 *retv = result,
1190 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1192 break;
1195 case 0x000F: /* NtCloseSection */
1197 * Input: EDX: Flat address of arguments on stack
1199 * HANDLE32 handle [in] Handle of Section to close
1200 * DWORD *id [out] Unique ID (?? unclear ??)
1202 * 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]);
1209 TRACE("NtCloseSection(%x, %x)\n", (DWORD)handle, (DWORD)id);
1211 CloseHandle(handle);
1212 if (id) *id = 0; /* FIXME */
1214 context->Eax = STATUS_SUCCESS;
1216 break;
1219 case 0x0010: /* NtDupSection */
1221 * Input: EDX: Flat address of arguments on stack
1223 * HANDLE32 handle [in] Handle of Section to duplicate
1225 * Output: EAX: NtStatus
1228 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1229 HANDLE handle = (HANDLE)stack[0];
1230 HANDLE new_handle;
1232 TRACE("NtDupSection(%x)\n", (DWORD)handle);
1234 DuplicateHandle( GetCurrentProcess(), handle,
1235 GetCurrentProcess(), &new_handle,
1236 0, FALSE, DUPLICATE_SAME_ACCESS );
1237 context->Eax = STATUS_SUCCESS;
1239 break;
1242 case 0x0011: /* NtMapViewOfSection */
1244 * Input: EDX: Flat address of arguments on stack
1246 * HANDLE32 SectionHandle [in] Section to be mapped
1247 * DWORD ProcessHandle [in] Process to be mapped into
1248 * DWORD * BaseAddress [in/out] Address to be mapped at
1249 * DWORD ZeroBits [in] (?? unclear ??)
1250 * DWORD CommitSize [in] (?? unclear ??)
1251 * LARGE_INTEGER *SectionOffset [in] Offset within section
1252 * DWORD * ViewSize [in] Size of view
1253 * DWORD InheritDisposition [in] (?? unclear ??)
1254 * DWORD AllocationType [in] (?? unclear ??)
1255 * DWORD Protect [in] Access protection
1257 * Output: EAX: NtStatus
1260 DWORD * stack = (DWORD *)W32S_APP2WINE(context->Edx);
1261 HANDLE SectionHandle = (HANDLE)stack[0];
1262 DWORD ProcessHandle = stack[1]; /* ignored */
1263 DWORD * BaseAddress = (DWORD *)W32S_APP2WINE(stack[2]);
1264 DWORD ZeroBits = stack[3];
1265 DWORD CommitSize = stack[4];
1266 LARGE_INTEGER *SectionOffset = (LARGE_INTEGER *)W32S_APP2WINE(stack[5]);
1267 DWORD * ViewSize = (DWORD *)W32S_APP2WINE(stack[6]);
1268 DWORD InheritDisposition = stack[7];
1269 DWORD AllocationType = stack[8];
1270 DWORD Protect = stack[9];
1272 LPBYTE address = (LPBYTE)(BaseAddress?
1273 W32S_APP2WINE(*BaseAddress) : 0);
1274 DWORD access = 0, result;
1276 switch (Protect & ~(PAGE_GUARD|PAGE_NOCACHE))
1278 case PAGE_READONLY: access = FILE_MAP_READ; break;
1279 case PAGE_READWRITE: access = FILE_MAP_WRITE; break;
1280 case PAGE_WRITECOPY: access = FILE_MAP_COPY; break;
1282 case PAGE_EXECUTE_READ: access = FILE_MAP_READ; break;
1283 case PAGE_EXECUTE_READWRITE: access = FILE_MAP_WRITE; break;
1284 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,
1290 ZeroBits, CommitSize, (DWORD)SectionOffset, (DWORD)ViewSize,
1291 InheritDisposition, AllocationType, Protect);
1292 TRACE("NtMapViewOfSection: "
1293 "base=%x, offset=%x, size=%x, access=%x\n",
1294 (DWORD)address, SectionOffset? SectionOffset->u.LowPart : 0,
1295 ViewSize? *ViewSize : 0, access);
1297 result = (DWORD)MapViewOfFileEx(SectionHandle, access,
1298 SectionOffset? SectionOffset->u.HighPart : 0,
1299 SectionOffset? SectionOffset->u.LowPart : 0,
1300 ViewSize? *ViewSize : 0, address);
1302 TRACE("NtMapViewOfSection: result=%x\n", result);
1304 if (W32S_WINE2APP(result))
1306 if (BaseAddress) *BaseAddress = W32S_WINE2APP(result);
1307 context->Eax = STATUS_SUCCESS;
1309 else
1310 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1312 break;
1315 case 0x0012: /* NtUnmapViewOfSection */
1317 * Input: EDX: Flat address of arguments on stack
1319 * DWORD ProcessHandle [in] Process (defining address space)
1320 * LPBYTE BaseAddress [in] Base address of view to be unmapped
1322 * Output: EAX: NtStatus
1325 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1326 DWORD ProcessHandle = stack[0]; /* ignored */
1327 LPBYTE BaseAddress = (LPBYTE)W32S_APP2WINE(stack[1]);
1329 TRACE("NtUnmapViewOfSection(%x, %x)\n",
1330 ProcessHandle, (DWORD)BaseAddress);
1332 UnmapViewOfFile(BaseAddress);
1334 context->Eax = STATUS_SUCCESS;
1336 break;
1339 case 0x0013: /* NtFlushVirtualMemory */
1341 * Input: EDX: Flat address of arguments on stack
1343 * DWORD ProcessHandle [in] Process (defining address space)
1344 * LPBYTE *BaseAddress [in?] Base address of range to be flushed
1345 * DWORD *ViewSize [in?] Number of bytes to be flushed
1346 * DWORD *unknown [???] (?? unknown ??)
1348 * Output: EAX: NtStatus
1351 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1352 DWORD ProcessHandle = stack[0]; /* ignored */
1353 DWORD *BaseAddress = (DWORD *)W32S_APP2WINE(stack[1]);
1354 DWORD *ViewSize = (DWORD *)W32S_APP2WINE(stack[2]);
1355 DWORD *unknown = (DWORD *)W32S_APP2WINE(stack[3]);
1357 LPBYTE address = (LPBYTE)(BaseAddress? W32S_APP2WINE(*BaseAddress) : 0);
1358 DWORD size = ViewSize? *ViewSize : 0;
1360 TRACE("NtFlushVirtualMemory(%x, %x, %x, %x)\n",
1361 ProcessHandle, (DWORD)BaseAddress, (DWORD)ViewSize,
1362 (DWORD)unknown);
1363 TRACE("NtFlushVirtualMemory: base=%x, size=%x\n",
1364 (DWORD)address, size);
1366 FlushViewOfFile(address, size);
1368 context->Eax = STATUS_SUCCESS;
1370 break;
1373 case 0x0014: /* Get/Set Debug Registers */
1375 * Input: ECX: 0 if Get, 1 if Set
1377 * EDX: Get: Flat address of buffer to receive values of
1378 * debug registers DR0 .. DR7
1379 * Set: Flat address of buffer containing values of
1380 * debug registers DR0 .. DR7 to be set
1381 * Output: None
1384 FIXME("[0014] ECX=%x EDX=%x\n",
1385 context->Ecx, context->Edx);
1387 /* FIXME */
1388 break;
1391 case 0x0015: /* Set Coprocessor Emulation Flag */
1393 * Input: EDX: 0 to deactivate, 1 to activate coprocessor emulation
1395 * Output: None
1398 TRACE("[0015] EDX=%x\n", context->Edx);
1400 /* We don't care, as we always have a coprocessor anyway */
1401 break;
1404 case 0x0016: /* Init Win32S VxD PSP */
1406 * If called to query required PSP size:
1408 * Input: EBX: 0
1409 * Output: EDX: Required size of Win32s VxD PSP
1411 * If called to initialize allocated PSP:
1413 * Input: EBX: LoWord: Selector of Win32s VxD PSP
1414 * HiWord: Paragraph of Win32s VxD PSP (DOSMEM)
1415 * Output: None
1418 if (context->Ebx == 0)
1419 context->Edx = 0x80;
1420 else
1422 PDB16 *psp = MapSL( MAKESEGPTR( BX_reg(context), 0 ));
1423 psp->nbFiles = 32;
1424 psp->fileHandlesPtr = MAKELONG(HIWORD(context->Ebx), 0x5c);
1425 memset((LPBYTE)psp + 0x5c, '\xFF', 32);
1427 break;
1430 case 0x0017: /* Set Break Point */
1432 * Input: EBX: Offset of Break Point
1433 * CX: Selector of Break Point
1435 * Output: None
1438 FIXME("[0017] EBX=%x CX=%x\n",
1439 context->Ebx, CX_reg(context));
1441 /* FIXME */
1442 break;
1445 case 0x0018: /* VirtualLock */
1447 * Input: ECX: Current Process
1449 * EDX: Flat address of arguments on stack
1451 * DWORD *retv [out] TRUE if success, FALSE if failure
1452 * LPVOID base [in] Flat address of range to lock
1453 * DWORD size [in] Size of range
1455 * Output: EAX: NtStatus
1458 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1459 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1460 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1461 DWORD size = stack[2];
1462 DWORD result;
1464 TRACE("VirtualLock(%x, %x, %x)\n",
1465 (DWORD)retv, (DWORD)base, size);
1467 result = VirtualLock(base, size);
1469 if (result)
1470 *retv = TRUE,
1471 context->Eax = STATUS_SUCCESS;
1472 else
1473 *retv = FALSE,
1474 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1476 break;
1479 case 0x0019: /* VirtualUnlock */
1481 * Input: ECX: Current Process
1483 * EDX: Flat address of arguments on stack
1485 * DWORD *retv [out] TRUE if success, FALSE if failure
1486 * LPVOID base [in] Flat address of range to unlock
1487 * DWORD size [in] Size of range
1489 * Output: EAX: NtStatus
1492 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1493 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1494 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1495 DWORD size = stack[2];
1496 DWORD result;
1498 TRACE("VirtualUnlock(%x, %x, %x)\n",
1499 (DWORD)retv, (DWORD)base, size);
1501 result = VirtualUnlock(base, size);
1503 if (result)
1504 *retv = TRUE,
1505 context->Eax = STATUS_SUCCESS;
1506 else
1507 *retv = FALSE,
1508 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1510 break;
1513 case 0x001A: /* KGetSystemInfo */
1515 * Input: None
1517 * Output: ECX: Start of sparse memory arena
1518 * EDX: End of sparse memory arena
1521 TRACE("KGetSystemInfo()\n");
1524 * Note: Win32s reserves 0GB - 2GB for Win 3.1 and uses 2GB - 4GB as
1525 * sparse memory arena. We do it the other way around, since
1526 * we have to reserve 3GB - 4GB for Linux, and thus use
1527 * 0GB - 3GB as sparse memory arena.
1529 * FIXME: What about other OSes ?
1532 context->Ecx = W32S_WINE2APP(0x00000000);
1533 context->Edx = W32S_WINE2APP(0xbfffffff);
1534 break;
1537 case 0x001B: /* KGlobalMemStat */
1539 * Input: ESI: Flat address of buffer to receive memory info
1541 * Output: None
1544 struct Win32sMemoryInfo
1546 DWORD DIPhys_Count; /* Total physical pages */
1547 DWORD DIFree_Count; /* Free physical pages */
1548 DWORD DILin_Total_Count; /* Total virtual pages (private arena) */
1549 DWORD DILin_Total_Free; /* Free virtual pages (private arena) */
1551 DWORD SparseTotal; /* Total size of sparse arena (bytes ?) */
1552 DWORD SparseFree; /* Free size of sparse arena (bytes ?) */
1555 struct Win32sMemoryInfo *info =
1556 (struct Win32sMemoryInfo *)W32S_APP2WINE(context->Esi);
1558 FIXME("KGlobalMemStat(%x)\n", (DWORD)info);
1560 /* FIXME */
1562 break;
1565 case 0x001C: /* Enable/Disable Exceptions */
1567 * Input: ECX: 0 to disable, 1 to enable exception handling
1569 * Output: None
1572 TRACE("[001c] ECX=%x\n", context->Ecx);
1574 /* FIXME */
1575 break;
1578 case 0x001D: /* VirtualAlloc called from 16-bit code */
1580 * Input: EDX: Segmented address of arguments on stack
1582 * LPVOID base [in] Flat address of region to reserve/commit
1583 * DWORD size [in] Size of region
1584 * DWORD type [in] Type of allocation
1585 * DWORD prot [in] Type of access protection
1587 * Output: EAX: NtStatus
1588 * 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]);
1593 DWORD size = stack[1];
1594 DWORD type = stack[2];
1595 DWORD prot = stack[3];
1596 DWORD result;
1598 TRACE("VirtualAlloc16(%x, %x, %x, %x)\n",
1599 (DWORD)base, size, type, prot);
1601 if (type & 0x80000000)
1603 WARN("VirtualAlloc16: strange type %x\n", type);
1604 type &= 0x7fffffff;
1607 result = (DWORD)VirtualAlloc(base, size, type, prot);
1609 if (W32S_WINE2APP(result))
1610 context->Edx = W32S_WINE2APP(result),
1611 context->Eax = STATUS_SUCCESS;
1612 else
1613 context->Edx = 0,
1614 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1615 TRACE("VirtualAlloc16: returning base %x\n", context->Edx);
1617 break;
1620 case 0x001E: /* VirtualFree called from 16-bit code */
1622 * Input: EDX: Segmented address of arguments on stack
1624 * LPVOID base [in] Flat address of region
1625 * DWORD size [in] Size of region
1626 * DWORD type [in] Type of operation
1628 * Output: EAX: NtStatus
1629 * 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]);
1634 DWORD size = stack[1];
1635 DWORD type = stack[2];
1636 DWORD result;
1638 TRACE("VirtualFree16(%x, %x, %x)\n",
1639 (DWORD)base, size, type);
1641 result = VirtualFree(base, size, type);
1643 if (result)
1644 context->Edx = TRUE,
1645 context->Eax = STATUS_SUCCESS;
1646 else
1647 context->Edx = FALSE,
1648 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1650 break;
1653 case 0x001F: /* FWorkingSetSize */
1655 * Input: EDX: 0 if Get, 1 if Set
1657 * ECX: Get: Buffer to receive Working Set Size
1658 * Set: Buffer containing Working Set Size
1660 * Output: NtStatus
1663 DWORD *ptr = (DWORD *)W32S_APP2WINE(context->Ecx);
1664 BOOL set = context->Edx;
1666 TRACE("FWorkingSetSize(%x, %x)\n", (DWORD)ptr, (DWORD)set);
1668 if (set)
1669 /* We do it differently ... */;
1670 else
1671 *ptr = 0x100;
1673 context->Eax = STATUS_SUCCESS;
1675 break;
1678 default:
1679 VXD_BARF( context, "W32S" );