Implemented GetModuleBaseName(AW), GetModuleFileNameEx(AW) and
[wine/multimedia.git] / msdos / vxd.c
blobb6801430c5f13bf44455b39b340cb043c3879ad1
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "config.h"
22 #include "wine/port.h"
24 #include <fcntl.h>
25 #include <memory.h>
26 #include <stdio.h>
27 #include <sys/types.h>
28 #ifdef HAVE_UNISTD_H
29 # include <unistd.h>
30 #endif
32 #define NONAMELESSUNION
33 #define NONAMELESSSTRUCT
34 #include "winbase.h"
35 #include "windef.h"
36 #include "winternl.h"
37 #include "wingdi.h"
38 #include "winuser.h"
39 #include "wine/winbase16.h"
40 #include "wine/winuser16.h"
41 #include "msdos.h"
42 #include "miscemu.h"
43 #include "module.h"
44 #include "selectors.h"
45 #include "task.h"
46 #include "file.h"
47 #include "wine/debug.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(vxd);
51 #define W32S_APP2WINE(addr) ((addr)? (DWORD)(addr) + W32S_offset : 0)
52 #define W32S_WINE2APP(addr) ((addr)? (DWORD)(addr) - W32S_offset : 0)
54 #define VXD_BARF(context,name) \
55 DPRINTF( "vxd %s: unknown/not implemented parameters:\n" \
56 "vxd %s: AX %04x, BX %04x, CX %04x, DX %04x, " \
57 "SI %04x, DI %04x, DS %04x, ES %04x\n", \
58 (name), (name), AX_reg(context), BX_reg(context), \
59 CX_reg(context), DX_reg(context), SI_reg(context), \
60 DI_reg(context), (WORD)context->SegDs, (WORD)context->SegEs )
62 UINT W32S_offset = 0;
64 static WORD VXD_WinVersion(void)
66 WORD version = LOWORD(GetVersion16());
67 return (version >> 8) | (version << 8);
70 /***********************************************************************
71 * VXD_VMM (WPROCS.401)
73 void WINAPI VXD_VMM ( CONTEXT86 *context )
75 unsigned service = AX_reg(context);
77 TRACE("[%04x] VMM\n", (UINT16)service);
79 switch(service)
81 case 0x0000: /* version */
82 SET_AX( context, VXD_WinVersion() );
83 RESET_CFLAG(context);
84 break;
86 case 0x026d: /* Get_Debug_Flag '/m' */
87 case 0x026e: /* Get_Debug_Flag '/n' */
88 SET_AL( context, 0 );
89 RESET_CFLAG(context);
90 break;
92 default:
93 VXD_BARF( context, "VMM" );
97 /***********************************************************************
98 * VXD_PageFile (WPROCS.433)
100 void WINAPI VXD_PageFile( CONTEXT86 *context )
102 unsigned service = AX_reg(context);
104 /* taken from Ralf Brown's Interrupt List */
106 TRACE("[%04x] PageFile\n", (UINT16)service );
108 switch(service)
110 case 0x00: /* get version, is this windows version? */
111 TRACE("returning version\n");
112 SET_AX( context, VXD_WinVersion() );
113 RESET_CFLAG(context);
114 break;
116 case 0x01: /* get swap file info */
117 TRACE("VxD PageFile: returning swap file info\n");
118 SET_AX( context, 0x00 ); /* paging disabled */
119 context->Ecx = 0; /* maximum size of paging file */
120 /* FIXME: do I touch DS:SI or DS:DI? */
121 RESET_CFLAG(context);
122 break;
124 case 0x02: /* delete permanent swap on exit */
125 TRACE("VxD PageFile: supposed to delete swap\n");
126 RESET_CFLAG(context);
127 break;
129 case 0x03: /* current temporary swap file size */
130 TRACE("VxD PageFile: what is current temp. swap size\n");
131 RESET_CFLAG(context);
132 break;
134 case 0x04: /* read or write?? INTERRUP.D */
135 case 0x05: /* cancel?? INTERRUP.D */
136 case 0x06: /* test I/O valid INTERRUP.D */
137 default:
138 VXD_BARF( context, "pagefile" );
139 break;
143 /***********************************************************************
144 * VXD_Reboot (WPROCS.409)
146 void WINAPI VXD_Reboot ( CONTEXT86 *context )
148 unsigned service = AX_reg(context);
150 TRACE("[%04x] Reboot\n", (UINT16)service);
152 switch(service)
154 case 0x0000: /* version */
155 SET_AX( context, VXD_WinVersion() );
156 RESET_CFLAG(context);
157 break;
159 default:
160 VXD_BARF( context, "REBOOT" );
164 /***********************************************************************
165 * VXD_VDD (WPROCS.410)
167 void WINAPI VXD_VDD ( CONTEXT86 *context )
169 unsigned service = AX_reg(context);
171 TRACE("[%04x] VDD\n", (UINT16)service);
173 switch(service)
175 case 0x0000: /* version */
176 SET_AX( context, VXD_WinVersion() );
177 RESET_CFLAG(context);
178 break;
180 default:
181 VXD_BARF( context, "VDD" );
185 /***********************************************************************
186 * VXD_VMD (WPROCS.412)
188 void WINAPI VXD_VMD ( CONTEXT86 *context )
190 unsigned service = AX_reg(context);
192 TRACE("[%04x] VMD\n", (UINT16)service);
194 switch(service)
196 case 0x0000: /* version */
197 SET_AX( context, VXD_WinVersion() );
198 RESET_CFLAG(context);
199 break;
201 default:
202 VXD_BARF( context, "VMD" );
206 /***********************************************************************
207 * VXD_VXDLoader (WPROCS.439)
209 void WINAPI VXD_VXDLoader( CONTEXT86 *context )
211 unsigned service = AX_reg(context);
213 TRACE("[%04x] VXDLoader\n", (UINT16)service);
215 switch (service)
217 case 0x0000: /* get version */
218 TRACE("returning version\n");
219 SET_AX( context, 0x0000 );
220 SET_DX( context, VXD_WinVersion() );
221 RESET_CFLAG(context);
222 break;
224 case 0x0001: /* load device */
225 FIXME("load device %04lx:%04x (%s)\n",
226 context->SegDs, DX_reg(context),
227 debugstr_a(MapSL(MAKESEGPTR(context->SegDs, DX_reg(context)))));
228 SET_AX( context, 0x0000 );
229 context->SegEs = 0x0000;
230 SET_DI( context, 0x0000 );
231 RESET_CFLAG(context);
232 break;
234 case 0x0002: /* unload device */
235 FIXME("unload device (%08lx)\n", context->Ebx);
236 SET_AX( context, 0x0000 );
237 RESET_CFLAG(context);
238 break;
240 default:
241 VXD_BARF( context, "VXDLDR" );
242 SET_AX( context, 0x000B ); /* invalid function number */
243 SET_CFLAG(context);
244 break;
248 /***********************************************************************
249 * VXD_Shell (WPROCS.423)
251 void WINAPI VXD_Shell( CONTEXT86 *context )
253 unsigned service = DX_reg(context);
255 TRACE("[%04x] Shell\n", (UINT16)service);
257 switch (service) /* Ralf Brown says EDX, but I use DX instead */
259 case 0x0000:
260 TRACE("returning version\n");
261 SET_AX( context, VXD_WinVersion() );
262 context->Ebx = 1; /* system VM Handle */
263 break;
265 case 0x0001:
266 case 0x0002:
267 case 0x0003:
268 /* SHELL_SYSMODAL_Message
269 ebx virtual maschine handle
270 eax message box flags
271 ecx address of message
272 edi address of caption
273 return response in eax
275 case 0x0004:
276 /* SHELL_Message
277 ebx virtual maschine handle
278 eax message box flags
279 ecx address of message
280 edi address of caption
281 esi address callback
282 edx reference data for callback
283 return response in eax
285 case 0x0005:
286 VXD_BARF( context, "shell" );
287 break;
289 case 0x0006: /* SHELL_Get_VM_State */
290 TRACE("VxD Shell: returning VM state\n");
291 /* Actually we don't, not yet. We have to return a structure
292 * and I am not to sure how to set it up and return it yet,
293 * so for now let's do nothing. I can (hopefully) get this
294 * by the next release
296 /* RESET_CFLAG(context); */
297 break;
299 case 0x0007:
300 case 0x0008:
301 case 0x0009:
302 case 0x000A:
303 case 0x000B:
304 case 0x000C:
305 case 0x000D:
306 case 0x000E:
307 case 0x000F:
308 case 0x0010:
309 case 0x0011:
310 case 0x0012:
311 case 0x0013:
312 case 0x0014:
313 case 0x0015:
314 case 0x0016:
315 VXD_BARF( context, "SHELL" );
316 break;
318 /* the new Win95 shell API */
319 case 0x0100: /* get version */
320 SET_AX( context, VXD_WinVersion() );
321 break;
323 case 0x0104: /* retrieve Hook_Properties list */
324 case 0x0105: /* call Hook_Properties callbacks */
325 VXD_BARF( context, "SHELL" );
326 break;
328 case 0x0106: /* install timeout callback */
329 TRACE("VxD Shell: ignoring shell callback (%ld sec.)\n", context->Ebx);
330 SET_CFLAG(context);
331 break;
333 case 0x0107: /* get version of any VxD */
334 default:
335 VXD_BARF( context, "SHELL" );
336 break;
341 /***********************************************************************
342 * VXD_Comm (WPROCS.414)
344 void WINAPI VXD_Comm( CONTEXT86 *context )
346 unsigned service = AX_reg(context);
348 TRACE("[%04x] Comm\n", (UINT16)service);
350 switch (service)
352 case 0x0000: /* get version */
353 TRACE("returning version\n");
354 SET_AX( context, VXD_WinVersion() );
355 RESET_CFLAG(context);
356 break;
358 case 0x0001: /* set port global */
359 case 0x0002: /* get focus */
360 case 0x0003: /* virtualise port */
361 default:
362 VXD_BARF( context, "comm" );
366 /***********************************************************************
367 * VXD_Timer (WPROCS.405)
369 void WINAPI VXD_Timer( CONTEXT86 *context )
371 unsigned service = AX_reg(context);
373 TRACE("[%04x] Virtual Timer\n", (UINT16)service);
375 switch(service)
377 case 0x0000: /* version */
378 SET_AX( context, VXD_WinVersion() );
379 RESET_CFLAG(context);
380 break;
382 case 0x0100: /* clock tick time, in 840nsecs */
383 context->Eax = GetTickCount();
385 context->Edx = context->Eax >> 22;
386 context->Eax <<= 10; /* not very precise */
387 break;
389 case 0x0101: /* current Windows time, msecs */
390 case 0x0102: /* current VM time, msecs */
391 context->Eax = GetTickCount();
392 break;
394 default:
395 VXD_BARF( context, "VTD" );
399 /***********************************************************************
400 * VXD_TimerAPI (WPROCS.1490)
402 static DWORD System_Time = 0;
403 static WORD System_Time_Selector = 0;
404 static void System_Time_Tick( WORD timer ) { System_Time += 55; }
405 void WINAPI VXD_TimerAPI ( CONTEXT86 *context )
407 unsigned service = AX_reg(context);
409 TRACE("[%04x] TimerAPI\n", (UINT16)service);
411 switch(service)
413 case 0x0000: /* version */
414 SET_AX( context, VXD_WinVersion() );
415 RESET_CFLAG(context);
416 break;
418 case 0x0009: /* get system time selector */
419 if ( !System_Time_Selector )
421 System_Time_Selector = SELECTOR_AllocBlock( &System_Time, sizeof(DWORD), WINE_LDT_FLAGS_DATA );
422 CreateSystemTimer( 55, System_Time_Tick );
425 SET_AX( context, System_Time_Selector );
426 RESET_CFLAG(context);
427 break;
429 default:
430 VXD_BARF( context, "VTDAPI" );
434 /***********************************************************************
435 * VXD_ConfigMG (WPROCS.451)
437 void WINAPI VXD_ConfigMG ( CONTEXT86 *context )
439 unsigned service = AX_reg(context);
441 TRACE("[%04x] ConfigMG\n", (UINT16)service);
443 switch(service)
445 case 0x0000: /* version */
446 SET_AX( context, VXD_WinVersion() );
447 RESET_CFLAG(context);
448 break;
450 default:
451 VXD_BARF( context, "CONFIGMG" );
455 /***********************************************************************
456 * VXD_Enable (WPROCS.455)
458 void WINAPI VXD_Enable ( CONTEXT86 *context )
460 unsigned service = AX_reg(context);
462 TRACE("[%04x] Enable\n", (UINT16)service);
464 switch(service)
466 case 0x0000: /* version */
467 SET_AX( context, VXD_WinVersion() );
468 RESET_CFLAG(context);
469 break;
471 default:
472 VXD_BARF( context, "ENABLE" );
476 /***********************************************************************
477 * VXD_APM (WPROCS.438)
479 void WINAPI VXD_APM ( CONTEXT86 *context )
481 unsigned service = AX_reg(context);
483 TRACE("[%04x] APM\n", (UINT16)service);
485 switch(service)
487 case 0x0000: /* version */
488 SET_AX( context, VXD_WinVersion() );
489 RESET_CFLAG(context);
490 break;
492 default:
493 VXD_BARF( context, "APM" );
497 /***********************************************************************
498 * VXD_Win32s (WPROCS.445)
500 * This is an implementation of the services of the Win32s VxD.
501 * Since official documentation of these does not seem to be available,
502 * certain arguments of some of the services remain unclear.
504 * FIXME: The following services are currently unimplemented:
505 * Exception handling (0x01, 0x1C)
506 * Debugger support (0x0C, 0x14, 0x17)
507 * Low-level memory access (0x02, 0x03, 0x0A, 0x0B)
508 * Memory Statistics (0x1B)
511 * We have a specific problem running Win32s on Linux (and probably also
512 * the other x86 unixes), since Win32s tries to allocate its main 'flat
513 * code/data segment' selectors with a base of 0xffff0000 (and limit 4GB).
514 * The rationale for this seems to be that they want one the one hand to
515 * be able to leave the Win 3.1 memory (starting with the main DOS memory)
516 * at linear address 0, but want at other hand to have offset 0 of the
517 * flat data/code segment point to an unmapped page (to catch NULL pointer
518 * accesses). Hence they allocate the flat segments with a base of 0xffff0000
519 * so that the Win 3.1 memory area at linear address zero shows up in the
520 * flat segments at offset 0x10000 (since linear addresses wrap around at
521 * 4GB). To compensate for that discrepancy between flat segment offsets
522 * and plain linear addresses, all flat pointers passed between the 32-bit
523 * and the 16-bit parts of Win32s are shifted by 0x10000 in the appropriate
524 * direction by the glue code (mainly) in W32SKRNL and WIN32S16.
526 * The problem for us is now that Linux does not allow a LDT selector with
527 * base 0xffff0000 to be created, since it would 'see' a part of the kernel
528 * address space. To address this problem we introduce *another* offset:
529 * We add 0x10000 to every linear address we get as an argument from Win32s.
530 * This means especially that the flat code/data selectors get actually
531 * allocated with base 0x0, so that flat offsets and (real) linear addresses
532 * do again agree! In fact, every call e.g. of a Win32s VxD service now
533 * has all pointer arguments (which are offsets in the flat data segement)
534 * first reduced by 0x10000 by the W32SKRNL glue code, and then again
535 * increased by 0x10000 by *our* code.
537 * Note that to keep everything consistent, this offset has to be applied by
538 * every Wine function that operates on 'linear addresses' passed to it by
539 * Win32s. Fortunately, since Win32s does not directly call any Wine 32-bit
540 * API routines, this affects only two locations: this VxD and the DPMI
541 * handler. (NOTE: Should any Win32s application pass a linear address to
542 * any routine apart from those, e.g. some other VxD handler, that code
543 * would have to take the offset into account as well!)
545 * The offset is set the first time any application calls the GetVersion()
546 * service of the Win32s VxD. (Note that the offset is never reset.)
550 void WINAPI VXD_Win32s( CONTEXT86 *context )
552 switch (AX_reg(context))
554 case 0x0000: /* Get Version */
556 * Input: None
558 * Output: EAX: LoWord: Win32s Version (1.30)
559 * HiWord: VxD Version (200)
561 * EBX: Build (172)
563 * ECX: ??? (1)
565 * EDX: Debugging Flags
567 * EDI: Error Flag
568 * 0 if OK,
569 * 1 if VMCPD VxD not found
572 TRACE("GetVersion()\n");
574 context->Eax = VXD_WinVersion() | (200 << 16);
575 context->Ebx = 0;
576 context->Ecx = 0;
577 context->Edx = 0;
578 context->Edi = 0;
581 * If this is the first time we are called for this process,
582 * hack the memory image of WIN32S16 so that it doesn't try
583 * to access the GDT directly ...
585 * The first code segment of WIN32S16 (version 1.30) contains
586 * an unexported function somewhere between the exported functions
587 * SetFS and StackLinearToSegmented that tries to find a selector
588 * in the LDT that maps to the memory image of the LDT itself.
589 * If it succeeds, it stores this selector into a global variable
590 * which will be used to speed up execution by using this selector
591 * to modify the LDT directly instead of using the DPMI calls.
593 * To perform this search of the LDT, this function uses the
594 * sgdt and sldt instructions to find the linear address of
595 * the (GDT and then) LDT. While those instructions themselves
596 * execute without problem, the linear address that sgdt returns
597 * points (at least under Linux) to the kernel address space, so
598 * that any subsequent access leads to a segfault.
600 * Fortunately, WIN32S16 still contains as a fallback option the
601 * mechanism of using DPMI calls to modify LDT selectors instead
602 * of direct writes to the LDT. Thus we can circumvent the problem
603 * by simply replacing the first byte of the offending function
604 * with an 'retf' instruction. This means that the global variable
605 * supposed to contain the LDT alias selector will remain zero,
606 * and hence WIN32S16 will fall back to using DPMI calls.
608 * The heuristic we employ to _find_ that function is as follows:
609 * We search between the addresses of the exported symbols SetFS
610 * and StackLinearToSegmented for the byte sequence '0F 01 04'
611 * (this is the opcode of 'sgdt [si]'). We then search backwards
612 * from this address for the last occurrence of 'CB' (retf) that marks
613 * the end of the preceeding function. The following byte (which
614 * should now be the first byte of the function we are looking for)
615 * will be replaced by 'CB' (retf).
617 * This heuristic works for the retail as well as the debug version
618 * of Win32s version 1.30. For versions earlier than that this
619 * hack should not be necessary at all, since the whole mechanism
620 * ('PERF130') was introduced only in 1.30 to improve the overall
621 * performance of Win32s.
624 if (!W32S_offset)
626 HMODULE16 hModule = GetModuleHandle16("win32s16");
627 SEGPTR func1 = (SEGPTR)GetProcAddress16(hModule, "SetFS");
628 SEGPTR func2 = (SEGPTR)GetProcAddress16(hModule, "StackLinearToSegmented");
630 if ( hModule && func1 && func2
631 && SELECTOROF(func1) == SELECTOROF(func2))
633 BYTE *start = MapSL(func1);
634 BYTE *end = MapSL(func2);
635 BYTE *p, *retv = NULL;
636 int found = 0;
638 for (p = start; p < end; p++)
639 if (*p == 0xCB) found = 0, retv = p;
640 else if (*p == 0x0F) found = 1;
641 else if (*p == 0x01 && found == 1) found = 2;
642 else if (*p == 0x04 && found == 2) { found = 3; break; }
643 else found = 0;
645 if (found == 3 && retv)
647 TRACE("PERF130 hack: "
648 "Replacing byte %02X at offset %04X:%04X\n",
649 *(retv+1), SELECTOROF(func1),
650 OFFSETOF(func1) + retv+1-start);
652 *(retv+1) = (BYTE)0xCB;
658 * Mark process as Win32s, so that subsequent DPMI calls
659 * will perform the W32S_APP2WINE/W32S_WINE2APP address shift.
661 W32S_offset = 0x10000;
662 break;
665 case 0x0001: /* Install Exception Handling */
667 * Input: EBX: Flat address of W32SKRNL Exception Data
669 * ECX: LoWord: Flat Code Selector
670 * HiWord: Flat Data Selector
672 * EDX: Flat address of W32SKRNL Exception Handler
673 * (this is equal to W32S_BackTo32 + 0x40)
675 * ESI: SEGPTR KERNEL.HASGPHANDLER
677 * EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10)
679 * Output: EAX: 0 if OK
682 TRACE("[0001] EBX=%lx ECX=%lx EDX=%lx ESI=%lx EDI=%lx\n",
683 context->Ebx, context->Ecx, context->Edx,
684 context->Esi, context->Edi);
686 /* FIXME */
688 context->Eax = 0;
689 break;
692 case 0x0002: /* Set Page Access Flags */
694 * Input: EBX: New access flags
695 * Bit 2: User Page if set, Supervisor Page if clear
696 * Bit 1: Read-Write if set, Read-Only if clear
698 * ECX: Size of memory area to change
700 * EDX: Flat start address of memory area
702 * Output: EAX: Size of area changed
705 TRACE("[0002] EBX=%lx ECX=%lx EDX=%lx\n",
706 context->Ebx, context->Ecx, context->Edx);
708 /* FIXME */
710 context->Eax = context->Ecx;
711 break;
714 case 0x0003: /* Get Page Access Flags */
716 * Input: EDX: Flat address of page to query
718 * Output: EAX: Page access flags
719 * Bit 2: User Page if set, Supervisor Page if clear
720 * Bit 1: Read-Write if set, Read-Only if clear
723 TRACE("[0003] EDX=%lx\n", context->Edx);
725 /* FIXME */
727 context->Eax = 6;
728 break;
731 case 0x0004: /* Map Module */
733 * Input: ECX: IMTE (offset in Module Table) of new module
735 * EDX: Flat address of Win32s Module Table
737 * Output: EAX: 0 if OK
740 if (!context->Edx || CX_reg(context) == 0xFFFF)
742 TRACE("MapModule: Initialization call\n");
743 context->Eax = 0;
745 else
748 * Structure of a Win32s Module Table Entry:
750 struct Win32sModule
752 DWORD flags;
753 DWORD flatBaseAddr;
754 LPCSTR moduleName;
755 LPCSTR pathName;
756 LPCSTR unknown;
757 LPBYTE baseAddr;
758 DWORD hModule;
759 DWORD relocDelta;
763 * Note: This function should set up a demand-paged memory image
764 * of the given module. Since mmap does not allow file offsets
765 * not aligned at 1024 bytes, we simply load the image fully
766 * into memory.
769 struct Win32sModule *moduleTable =
770 (struct Win32sModule *)W32S_APP2WINE(context->Edx);
771 struct Win32sModule *module = moduleTable + context->Ecx;
773 IMAGE_NT_HEADERS *nt_header = RtlImageNtHeader( (HMODULE)module->baseAddr );
774 IMAGE_SECTION_HEADER *pe_seg = (IMAGE_SECTION_HEADER*)((char *)&nt_header->OptionalHeader +
775 nt_header->FileHeader.SizeOfOptionalHeader);
778 HFILE image = _lopen(module->pathName, OF_READ);
779 BOOL error = (image == HFILE_ERROR);
780 UINT i;
782 TRACE("MapModule: Loading %s\n", module->pathName);
784 for (i = 0;
785 !error && i < nt_header->FileHeader.NumberOfSections;
786 i++, pe_seg++)
787 if(!(pe_seg->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA))
789 DWORD off = pe_seg->PointerToRawData;
790 DWORD len = pe_seg->SizeOfRawData;
791 LPBYTE addr = module->baseAddr + pe_seg->VirtualAddress;
793 TRACE("MapModule: "
794 "Section %d at %08lx from %08lx len %08lx\n",
795 i, (DWORD)addr, off, len);
797 if ( _llseek(image, off, SEEK_SET) != off
798 || _lread(image, addr, len) != len)
799 error = TRUE;
802 _lclose(image);
804 if (error)
805 ERR("MapModule: Unable to load %s\n", module->pathName);
807 else if (module->relocDelta != 0)
809 IMAGE_DATA_DIRECTORY *dir = nt_header->OptionalHeader.DataDirectory
810 + IMAGE_DIRECTORY_ENTRY_BASERELOC;
811 IMAGE_BASE_RELOCATION *r = (IMAGE_BASE_RELOCATION *)
812 (dir->Size? module->baseAddr + dir->VirtualAddress : 0);
814 TRACE("MapModule: Reloc delta %08lx\n", module->relocDelta);
816 while (r && r->VirtualAddress)
818 LPBYTE page = module->baseAddr + r->VirtualAddress;
819 WORD *TypeOffset = (WORD *)(r + 1);
820 int count = (r->SizeOfBlock - sizeof(*r)) / sizeof(*TypeOffset);
822 TRACE("MapModule: %d relocations for page %08lx\n",
823 count, (DWORD)page);
825 for(i = 0; i < count; i++)
827 int offset = TypeOffset[i] & 0xFFF;
828 int type = TypeOffset[i] >> 12;
829 switch(type)
831 case IMAGE_REL_BASED_ABSOLUTE:
832 break;
833 case IMAGE_REL_BASED_HIGH:
834 *(WORD *)(page+offset) += HIWORD(module->relocDelta);
835 break;
836 case IMAGE_REL_BASED_LOW:
837 *(WORD *)(page+offset) += LOWORD(module->relocDelta);
838 break;
839 case IMAGE_REL_BASED_HIGHLOW:
840 *(DWORD*)(page+offset) += module->relocDelta;
841 break;
842 default:
843 WARN("MapModule: Unsupported fixup type\n");
844 break;
848 r = (IMAGE_BASE_RELOCATION *)((LPBYTE)r + r->SizeOfBlock);
852 context->Eax = 0;
853 RESET_CFLAG(context);
855 break;
858 case 0x0005: /* UnMap Module */
860 * Input: EDX: Flat address of module image
862 * Output: EAX: 1 if OK
865 TRACE("UnMapModule: %lx\n", (DWORD)W32S_APP2WINE(context->Edx));
867 /* As we didn't map anything, there's nothing to unmap ... */
869 context->Eax = 1;
870 break;
873 case 0x0006: /* VirtualAlloc */
875 * Input: ECX: Current Process
877 * EDX: Flat address of arguments on stack
879 * DWORD *retv [out] Flat base address of allocated region
880 * LPVOID base [in] Flat address of region to reserve/commit
881 * DWORD size [in] Size of region
882 * DWORD type [in] Type of allocation
883 * DWORD prot [in] Type of access protection
885 * Output: EAX: NtStatus
888 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
889 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
890 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
891 DWORD size = stack[2];
892 DWORD type = stack[3];
893 DWORD prot = stack[4];
894 DWORD result;
896 TRACE("VirtualAlloc(%lx, %lx, %lx, %lx, %lx)\n",
897 (DWORD)retv, (DWORD)base, size, type, prot);
899 if (type & 0x80000000)
901 WARN("VirtualAlloc: strange type %lx\n", type);
902 type &= 0x7fffffff;
905 if (!base && (type & MEM_COMMIT) && prot == PAGE_READONLY)
907 WARN("VirtualAlloc: NLS hack, allowing write access!\n");
908 prot = PAGE_READWRITE;
911 result = (DWORD)VirtualAlloc(base, size, type, prot);
913 if (W32S_WINE2APP(result))
914 *retv = W32S_WINE2APP(result),
915 context->Eax = STATUS_SUCCESS;
916 else
917 *retv = 0,
918 context->Eax = STATUS_NO_MEMORY; /* FIXME */
920 break;
923 case 0x0007: /* VirtualFree */
925 * Input: ECX: Current Process
927 * EDX: Flat address of arguments on stack
929 * DWORD *retv [out] TRUE if success, FALSE if failure
930 * LPVOID base [in] Flat address of region
931 * DWORD size [in] Size of region
932 * DWORD type [in] Type of operation
934 * Output: EAX: NtStatus
937 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
938 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
939 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
940 DWORD size = stack[2];
941 DWORD type = stack[3];
942 DWORD result;
944 TRACE("VirtualFree(%lx, %lx, %lx, %lx)\n",
945 (DWORD)retv, (DWORD)base, size, type);
947 result = VirtualFree(base, size, type);
949 if (result)
950 *retv = TRUE,
951 context->Eax = STATUS_SUCCESS;
952 else
953 *retv = FALSE,
954 context->Eax = STATUS_NO_MEMORY; /* FIXME */
956 break;
959 case 0x0008: /* VirtualProtect */
961 * Input: ECX: Current Process
963 * EDX: Flat address of arguments on stack
965 * DWORD *retv [out] TRUE if success, FALSE if failure
966 * LPVOID base [in] Flat address of region
967 * DWORD size [in] Size of region
968 * DWORD new_prot [in] Desired access protection
969 * DWORD *old_prot [out] Previous access protection
971 * Output: EAX: NtStatus
974 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
975 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
976 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
977 DWORD size = stack[2];
978 DWORD new_prot = stack[3];
979 DWORD *old_prot = (DWORD *)W32S_APP2WINE(stack[4]);
980 DWORD result;
982 TRACE("VirtualProtect(%lx, %lx, %lx, %lx, %lx)\n",
983 (DWORD)retv, (DWORD)base, size, new_prot, (DWORD)old_prot);
985 result = VirtualProtect(base, size, new_prot, old_prot);
987 if (result)
988 *retv = TRUE,
989 context->Eax = STATUS_SUCCESS;
990 else
991 *retv = FALSE,
992 context->Eax = STATUS_NO_MEMORY; /* FIXME */
994 break;
997 case 0x0009: /* VirtualQuery */
999 * Input: ECX: Current Process
1001 * EDX: Flat address of arguments on stack
1003 * DWORD *retv [out] Nr. bytes returned
1004 * LPVOID base [in] Flat address of region
1005 * LPMEMORY_BASIC_INFORMATION info [out] Info buffer
1006 * DWORD len [in] Size of buffer
1008 * Output: EAX: NtStatus
1011 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1012 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1013 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1014 PMEMORY_BASIC_INFORMATION info =
1015 (PMEMORY_BASIC_INFORMATION)W32S_APP2WINE(stack[2]);
1016 DWORD len = stack[3];
1017 DWORD result;
1019 TRACE("VirtualQuery(%lx, %lx, %lx, %lx)\n",
1020 (DWORD)retv, (DWORD)base, (DWORD)info, len);
1022 result = VirtualQuery(base, info, len);
1024 *retv = result;
1025 context->Eax = STATUS_SUCCESS;
1027 break;
1030 case 0x000A: /* SetVirtMemProcess */
1032 * Input: ECX: Process Handle
1034 * EDX: Flat address of region
1036 * Output: EAX: NtStatus
1039 TRACE("[000a] ECX=%lx EDX=%lx\n",
1040 context->Ecx, context->Edx);
1042 /* FIXME */
1044 context->Eax = STATUS_SUCCESS;
1045 break;
1048 case 0x000B: /* ??? some kind of cleanup */
1050 * Input: ECX: Process Handle
1052 * Output: EAX: NtStatus
1055 TRACE("[000b] ECX=%lx\n", context->Ecx);
1057 /* FIXME */
1059 context->Eax = STATUS_SUCCESS;
1060 break;
1063 case 0x000C: /* Set Debug Flags */
1065 * Input: EDX: Debug Flags
1067 * Output: EDX: Previous Debug Flags
1070 FIXME("[000c] EDX=%lx\n", context->Edx);
1072 /* FIXME */
1074 context->Edx = 0;
1075 break;
1078 case 0x000D: /* NtCreateSection */
1080 * Input: EDX: Flat address of arguments on stack
1082 * HANDLE32 *retv [out] Handle of Section created
1083 * DWORD flags1 [in] (?? unknown ??)
1084 * DWORD atom [in] Name of Section to create
1085 * LARGE_INTEGER *size [in] Size of Section
1086 * DWORD protect [in] Access protection
1087 * DWORD flags2 [in] (?? unknown ??)
1088 * HFILE32 hFile [in] Handle of file to map
1089 * DWORD psp [in] (Win32s: PSP that hFile belongs to)
1091 * Output: EAX: NtStatus
1094 DWORD *stack = (DWORD *) W32S_APP2WINE(context->Edx);
1095 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]);
1096 DWORD flags1 = stack[1];
1097 DWORD atom = stack[2];
1098 LARGE_INTEGER *size = (LARGE_INTEGER *)W32S_APP2WINE(stack[3]);
1099 DWORD protect = stack[4];
1100 DWORD flags2 = stack[5];
1101 HANDLE hFile = DosFileHandleToWin32Handle(stack[6]);
1102 DWORD psp = stack[7];
1104 HANDLE result = INVALID_HANDLE_VALUE;
1105 char name[128];
1107 TRACE("NtCreateSection(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1108 (DWORD)retv, flags1, atom, (DWORD)size, protect, flags2,
1109 (DWORD)hFile, psp);
1111 if (!atom || GlobalGetAtomNameA(atom, name, sizeof(name)))
1113 TRACE("NtCreateSection: name=%s\n", atom? name : NULL);
1115 result = CreateFileMappingA(hFile, NULL, protect,
1116 size? size->s.HighPart : 0,
1117 size? size->s.LowPart : 0,
1118 atom? name : NULL);
1121 if (result == INVALID_HANDLE_VALUE)
1122 WARN("NtCreateSection: failed!\n");
1123 else
1124 TRACE("NtCreateSection: returned %lx\n", (DWORD)result);
1126 if (result != INVALID_HANDLE_VALUE)
1127 *retv = result,
1128 context->Eax = STATUS_SUCCESS;
1129 else
1130 *retv = result,
1131 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1133 break;
1136 case 0x000E: /* NtOpenSection */
1138 * Input: EDX: Flat address of arguments on stack
1140 * HANDLE32 *retv [out] Handle of Section opened
1141 * DWORD protect [in] Access protection
1142 * DWORD atom [in] Name of Section to create
1144 * Output: EAX: NtStatus
1147 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1148 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]);
1149 DWORD protect = stack[1];
1150 DWORD atom = stack[2];
1152 HANDLE result = INVALID_HANDLE_VALUE;
1153 char name[128];
1155 TRACE("NtOpenSection(%lx, %lx, %lx)\n",
1156 (DWORD)retv, protect, atom);
1158 if (atom && GlobalGetAtomNameA(atom, name, sizeof(name)))
1160 TRACE("NtOpenSection: name=%s\n", name);
1162 result = OpenFileMappingA(protect, FALSE, name);
1165 if (result == INVALID_HANDLE_VALUE)
1166 WARN("NtOpenSection: failed!\n");
1167 else
1168 TRACE("NtOpenSection: returned %lx\n", (DWORD)result);
1170 if (result != INVALID_HANDLE_VALUE)
1171 *retv = result,
1172 context->Eax = STATUS_SUCCESS;
1173 else
1174 *retv = result,
1175 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1177 break;
1180 case 0x000F: /* NtCloseSection */
1182 * Input: EDX: Flat address of arguments on stack
1184 * HANDLE32 handle [in] Handle of Section to close
1185 * DWORD *id [out] Unique ID (?? unclear ??)
1187 * Output: EAX: NtStatus
1190 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1191 HANDLE handle = (HANDLE)stack[0];
1192 DWORD *id = (DWORD *)W32S_APP2WINE(stack[1]);
1194 TRACE("NtCloseSection(%lx, %lx)\n", (DWORD)handle, (DWORD)id);
1196 CloseHandle(handle);
1197 if (id) *id = 0; /* FIXME */
1199 context->Eax = STATUS_SUCCESS;
1201 break;
1204 case 0x0010: /* NtDupSection */
1206 * Input: EDX: Flat address of arguments on stack
1208 * HANDLE32 handle [in] Handle of Section to duplicate
1210 * Output: EAX: NtStatus
1213 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1214 HANDLE handle = (HANDLE)stack[0];
1215 HANDLE new_handle;
1217 TRACE("NtDupSection(%lx)\n", (DWORD)handle);
1219 DuplicateHandle( GetCurrentProcess(), handle,
1220 GetCurrentProcess(), &new_handle,
1221 0, FALSE, DUPLICATE_SAME_ACCESS );
1222 context->Eax = STATUS_SUCCESS;
1224 break;
1227 case 0x0011: /* NtMapViewOfSection */
1229 * Input: EDX: Flat address of arguments on stack
1231 * HANDLE32 SectionHandle [in] Section to be mapped
1232 * DWORD ProcessHandle [in] Process to be mapped into
1233 * DWORD * BaseAddress [in/out] Address to be mapped at
1234 * DWORD ZeroBits [in] (?? unclear ??)
1235 * DWORD CommitSize [in] (?? unclear ??)
1236 * LARGE_INTEGER *SectionOffset [in] Offset within section
1237 * DWORD * ViewSize [in] Size of view
1238 * DWORD InheritDisposition [in] (?? unclear ??)
1239 * DWORD AllocationType [in] (?? unclear ??)
1240 * DWORD Protect [in] Access protection
1242 * Output: EAX: NtStatus
1245 DWORD * stack = (DWORD *)W32S_APP2WINE(context->Edx);
1246 HANDLE SectionHandle = (HANDLE)stack[0];
1247 DWORD ProcessHandle = stack[1]; /* ignored */
1248 DWORD * BaseAddress = (DWORD *)W32S_APP2WINE(stack[2]);
1249 DWORD ZeroBits = stack[3];
1250 DWORD CommitSize = stack[4];
1251 LARGE_INTEGER *SectionOffset = (LARGE_INTEGER *)W32S_APP2WINE(stack[5]);
1252 DWORD * ViewSize = (DWORD *)W32S_APP2WINE(stack[6]);
1253 DWORD InheritDisposition = stack[7];
1254 DWORD AllocationType = stack[8];
1255 DWORD Protect = stack[9];
1257 LPBYTE address = (LPBYTE)(BaseAddress?
1258 W32S_APP2WINE(*BaseAddress) : 0);
1259 DWORD access = 0, result;
1261 switch (Protect & ~(PAGE_GUARD|PAGE_NOCACHE))
1263 case PAGE_READONLY: access = FILE_MAP_READ; break;
1264 case PAGE_READWRITE: access = FILE_MAP_WRITE; break;
1265 case PAGE_WRITECOPY: access = FILE_MAP_COPY; break;
1267 case PAGE_EXECUTE_READ: access = FILE_MAP_READ; break;
1268 case PAGE_EXECUTE_READWRITE: access = FILE_MAP_WRITE; break;
1269 case PAGE_EXECUTE_WRITECOPY: access = FILE_MAP_COPY; break;
1272 TRACE("NtMapViewOfSection"
1273 "(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1274 (DWORD)SectionHandle, ProcessHandle, (DWORD)BaseAddress,
1275 ZeroBits, CommitSize, (DWORD)SectionOffset, (DWORD)ViewSize,
1276 InheritDisposition, AllocationType, Protect);
1277 TRACE("NtMapViewOfSection: "
1278 "base=%lx, offset=%lx, size=%lx, access=%lx\n",
1279 (DWORD)address, SectionOffset? SectionOffset->s.LowPart : 0,
1280 ViewSize? *ViewSize : 0, access);
1282 result = (DWORD)MapViewOfFileEx(SectionHandle, access,
1283 SectionOffset? SectionOffset->s.HighPart : 0,
1284 SectionOffset? SectionOffset->s.LowPart : 0,
1285 ViewSize? *ViewSize : 0, address);
1287 TRACE("NtMapViewOfSection: result=%lx\n", result);
1289 if (W32S_WINE2APP(result))
1291 if (BaseAddress) *BaseAddress = W32S_WINE2APP(result);
1292 context->Eax = STATUS_SUCCESS;
1294 else
1295 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1297 break;
1300 case 0x0012: /* NtUnmapViewOfSection */
1302 * Input: EDX: Flat address of arguments on stack
1304 * DWORD ProcessHandle [in] Process (defining address space)
1305 * LPBYTE BaseAddress [in] Base address of view to be unmapped
1307 * Output: EAX: NtStatus
1310 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1311 DWORD ProcessHandle = stack[0]; /* ignored */
1312 LPBYTE BaseAddress = (LPBYTE)W32S_APP2WINE(stack[1]);
1314 TRACE("NtUnmapViewOfSection(%lx, %lx)\n",
1315 ProcessHandle, (DWORD)BaseAddress);
1317 UnmapViewOfFile(BaseAddress);
1319 context->Eax = STATUS_SUCCESS;
1321 break;
1324 case 0x0013: /* NtFlushVirtualMemory */
1326 * Input: EDX: Flat address of arguments on stack
1328 * DWORD ProcessHandle [in] Process (defining address space)
1329 * LPBYTE *BaseAddress [in?] Base address of range to be flushed
1330 * DWORD *ViewSize [in?] Number of bytes to be flushed
1331 * DWORD *unknown [???] (?? unknown ??)
1333 * Output: EAX: NtStatus
1336 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1337 DWORD ProcessHandle = stack[0]; /* ignored */
1338 DWORD *BaseAddress = (DWORD *)W32S_APP2WINE(stack[1]);
1339 DWORD *ViewSize = (DWORD *)W32S_APP2WINE(stack[2]);
1340 DWORD *unknown = (DWORD *)W32S_APP2WINE(stack[3]);
1342 LPBYTE address = (LPBYTE)(BaseAddress? W32S_APP2WINE(*BaseAddress) : 0);
1343 DWORD size = ViewSize? *ViewSize : 0;
1345 TRACE("NtFlushVirtualMemory(%lx, %lx, %lx, %lx)\n",
1346 ProcessHandle, (DWORD)BaseAddress, (DWORD)ViewSize,
1347 (DWORD)unknown);
1348 TRACE("NtFlushVirtualMemory: base=%lx, size=%lx\n",
1349 (DWORD)address, size);
1351 FlushViewOfFile(address, size);
1353 context->Eax = STATUS_SUCCESS;
1355 break;
1358 case 0x0014: /* Get/Set Debug Registers */
1360 * Input: ECX: 0 if Get, 1 if Set
1362 * EDX: Get: Flat address of buffer to receive values of
1363 * debug registers DR0 .. DR7
1364 * Set: Flat address of buffer containing values of
1365 * debug registers DR0 .. DR7 to be set
1366 * Output: None
1369 FIXME("[0014] ECX=%lx EDX=%lx\n",
1370 context->Ecx, context->Edx);
1372 /* FIXME */
1373 break;
1376 case 0x0015: /* Set Coprocessor Emulation Flag */
1378 * Input: EDX: 0 to deactivate, 1 to activate coprocessor emulation
1380 * Output: None
1383 TRACE("[0015] EDX=%lx\n", context->Edx);
1385 /* We don't care, as we always have a coprocessor anyway */
1386 break;
1389 case 0x0016: /* Init Win32S VxD PSP */
1391 * If called to query required PSP size:
1393 * Input: EBX: 0
1394 * Output: EDX: Required size of Win32s VxD PSP
1396 * If called to initialize allocated PSP:
1398 * Input: EBX: LoWord: Selector of Win32s VxD PSP
1399 * HiWord: Paragraph of Win32s VxD PSP (DOSMEM)
1400 * Output: None
1403 if (context->Ebx == 0)
1404 context->Edx = 0x80;
1405 else
1407 PDB16 *psp = MapSL( MAKESEGPTR( BX_reg(context), 0 ));
1408 psp->nbFiles = 32;
1409 psp->fileHandlesPtr = MAKELONG(HIWORD(context->Ebx), 0x5c);
1410 memset((LPBYTE)psp + 0x5c, '\xFF', 32);
1412 break;
1415 case 0x0017: /* Set Break Point */
1417 * Input: EBX: Offset of Break Point
1418 * CX: Selector of Break Point
1420 * Output: None
1423 FIXME("[0017] EBX=%lx CX=%x\n",
1424 context->Ebx, CX_reg(context));
1426 /* FIXME */
1427 break;
1430 case 0x0018: /* VirtualLock */
1432 * Input: ECX: Current Process
1434 * EDX: Flat address of arguments on stack
1436 * DWORD *retv [out] TRUE if success, FALSE if failure
1437 * LPVOID base [in] Flat address of range to lock
1438 * DWORD size [in] Size of range
1440 * Output: EAX: NtStatus
1443 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1444 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1445 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1446 DWORD size = stack[2];
1447 DWORD result;
1449 TRACE("VirtualLock(%lx, %lx, %lx)\n",
1450 (DWORD)retv, (DWORD)base, size);
1452 result = VirtualLock(base, size);
1454 if (result)
1455 *retv = TRUE,
1456 context->Eax = STATUS_SUCCESS;
1457 else
1458 *retv = FALSE,
1459 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1461 break;
1464 case 0x0019: /* VirtualUnlock */
1466 * Input: ECX: Current Process
1468 * EDX: Flat address of arguments on stack
1470 * DWORD *retv [out] TRUE if success, FALSE if failure
1471 * LPVOID base [in] Flat address of range to unlock
1472 * DWORD size [in] Size of range
1474 * Output: EAX: NtStatus
1477 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1478 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1479 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1480 DWORD size = stack[2];
1481 DWORD result;
1483 TRACE("VirtualUnlock(%lx, %lx, %lx)\n",
1484 (DWORD)retv, (DWORD)base, size);
1486 result = VirtualUnlock(base, size);
1488 if (result)
1489 *retv = TRUE,
1490 context->Eax = STATUS_SUCCESS;
1491 else
1492 *retv = FALSE,
1493 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1495 break;
1498 case 0x001A: /* KGetSystemInfo */
1500 * Input: None
1502 * Output: ECX: Start of sparse memory arena
1503 * EDX: End of sparse memory arena
1506 TRACE("KGetSystemInfo()\n");
1509 * Note: Win32s reserves 0GB - 2GB for Win 3.1 and uses 2GB - 4GB as
1510 * sparse memory arena. We do it the other way around, since
1511 * we have to reserve 3GB - 4GB for Linux, and thus use
1512 * 0GB - 3GB as sparse memory arena.
1514 * FIXME: What about other OSes ?
1517 context->Ecx = W32S_WINE2APP(0x00000000);
1518 context->Edx = W32S_WINE2APP(0xbfffffff);
1519 break;
1522 case 0x001B: /* KGlobalMemStat */
1524 * Input: ESI: Flat address of buffer to receive memory info
1526 * Output: None
1529 struct Win32sMemoryInfo
1531 DWORD DIPhys_Count; /* Total physical pages */
1532 DWORD DIFree_Count; /* Free physical pages */
1533 DWORD DILin_Total_Count; /* Total virtual pages (private arena) */
1534 DWORD DILin_Total_Free; /* Free virtual pages (private arena) */
1536 DWORD SparseTotal; /* Total size of sparse arena (bytes ?) */
1537 DWORD SparseFree; /* Free size of sparse arena (bytes ?) */
1540 struct Win32sMemoryInfo *info =
1541 (struct Win32sMemoryInfo *)W32S_APP2WINE(context->Esi);
1543 FIXME("KGlobalMemStat(%lx)\n", (DWORD)info);
1545 /* FIXME */
1547 break;
1550 case 0x001C: /* Enable/Disable Exceptions */
1552 * Input: ECX: 0 to disable, 1 to enable exception handling
1554 * Output: None
1557 TRACE("[001c] ECX=%lx\n", context->Ecx);
1559 /* FIXME */
1560 break;
1563 case 0x001D: /* VirtualAlloc called from 16-bit code */
1565 * Input: EDX: Segmented address of arguments on stack
1567 * LPVOID base [in] Flat address of region to reserve/commit
1568 * DWORD size [in] Size of region
1569 * DWORD type [in] Type of allocation
1570 * DWORD prot [in] Type of access protection
1572 * Output: EAX: NtStatus
1573 * EDX: Flat base address of allocated region
1576 DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) ));
1577 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]);
1578 DWORD size = stack[1];
1579 DWORD type = stack[2];
1580 DWORD prot = stack[3];
1581 DWORD result;
1583 TRACE("VirtualAlloc16(%lx, %lx, %lx, %lx)\n",
1584 (DWORD)base, size, type, prot);
1586 if (type & 0x80000000)
1588 WARN("VirtualAlloc16: strange type %lx\n", type);
1589 type &= 0x7fffffff;
1592 result = (DWORD)VirtualAlloc(base, size, type, prot);
1594 if (W32S_WINE2APP(result))
1595 context->Edx = W32S_WINE2APP(result),
1596 context->Eax = STATUS_SUCCESS;
1597 else
1598 context->Edx = 0,
1599 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1600 TRACE("VirtualAlloc16: returning base %lx\n", context->Edx);
1602 break;
1605 case 0x001E: /* VirtualFree called from 16-bit code */
1607 * Input: EDX: Segmented address of arguments on stack
1609 * LPVOID base [in] Flat address of region
1610 * DWORD size [in] Size of region
1611 * DWORD type [in] Type of operation
1613 * Output: EAX: NtStatus
1614 * EDX: TRUE if success, FALSE if failure
1617 DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) ));
1618 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]);
1619 DWORD size = stack[1];
1620 DWORD type = stack[2];
1621 DWORD result;
1623 TRACE("VirtualFree16(%lx, %lx, %lx)\n",
1624 (DWORD)base, size, type);
1626 result = VirtualFree(base, size, type);
1628 if (result)
1629 context->Edx = TRUE,
1630 context->Eax = STATUS_SUCCESS;
1631 else
1632 context->Edx = FALSE,
1633 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1635 break;
1638 case 0x001F: /* FWorkingSetSize */
1640 * Input: EDX: 0 if Get, 1 if Set
1642 * ECX: Get: Buffer to receive Working Set Size
1643 * Set: Buffer containing Working Set Size
1645 * Output: NtStatus
1648 DWORD *ptr = (DWORD *)W32S_APP2WINE(context->Ecx);
1649 BOOL set = context->Edx;
1651 TRACE("FWorkingSetSize(%lx, %lx)\n", (DWORD)ptr, (DWORD)set);
1653 if (set)
1654 /* We do it differently ... */;
1655 else
1656 *ptr = 0x100;
1658 context->Eax = STATUS_SUCCESS;
1660 break;
1663 default:
1664 VXD_BARF( context, "W32S" );