- Add a max wait time for selection notifies.
[wine.git] / msdos / vxd.c
blob67db9269975e4bd0a4ae7b2fca01e7a955f11d6f
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"
23 #include <fcntl.h>
24 #include <memory.h>
25 #include <sys/types.h>
26 #ifdef HAVE_UNISTD_H
27 # include <unistd.h>
28 #endif
29 #include "winbase.h"
30 #include "windef.h"
31 #include "ntddk.h"
32 #include "wingdi.h"
33 #include "winuser.h"
34 #include "wine/winbase16.h"
35 #include "wine/winuser16.h"
36 #include "msdos.h"
37 #include "miscemu.h"
38 #include "module.h"
39 #include "selectors.h"
40 #include "task.h"
41 #include "file.h"
42 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(vxd);
47 #define VXD_BARF(context,name) \
48 DPRINTF( "vxd %s: unknown/not implemented parameters:\n" \
49 "vxd %s: AX %04x, BX %04x, CX %04x, DX %04x, " \
50 "SI %04x, DI %04x, DS %04x, ES %04x\n", \
51 (name), (name), AX_reg(context), BX_reg(context), \
52 CX_reg(context), DX_reg(context), SI_reg(context), \
53 DI_reg(context), (WORD)context->SegDs, (WORD)context->SegEs )
55 UINT W32S_offset = 0;
57 static WORD VXD_WinVersion(void)
59 WORD version = LOWORD(GetVersion16());
60 return (version >> 8) | (version << 8);
63 /***********************************************************************
64 * VXD_VMM (WPROCS.401)
66 void WINAPI VXD_VMM ( CONTEXT86 *context )
68 unsigned service = AX_reg(context);
70 TRACE("[%04x] VMM\n", (UINT16)service);
72 switch(service)
74 case 0x0000: /* version */
75 AX_reg(context) = VXD_WinVersion();
76 RESET_CFLAG(context);
77 break;
79 case 0x026d: /* Get_Debug_Flag '/m' */
80 case 0x026e: /* Get_Debug_Flag '/n' */
81 AL_reg(context) = 0;
82 RESET_CFLAG(context);
83 break;
85 default:
86 VXD_BARF( context, "VMM" );
90 /***********************************************************************
91 * VXD_PageFile (WPROCS.433)
93 void WINAPI VXD_PageFile( CONTEXT86 *context )
95 unsigned service = AX_reg(context);
97 /* taken from Ralf Brown's Interrupt List */
99 TRACE("[%04x] PageFile\n", (UINT16)service );
101 switch(service)
103 case 0x00: /* get version, is this windows version? */
104 TRACE("returning version\n");
105 AX_reg(context) = VXD_WinVersion();
106 RESET_CFLAG(context);
107 break;
109 case 0x01: /* get swap file info */
110 TRACE("VxD PageFile: returning swap file info\n");
111 AX_reg(context) = 0x00; /* paging disabled */
112 context->Ecx = 0; /* maximum size of paging file */
113 /* FIXME: do I touch DS:SI or DS:DI? */
114 RESET_CFLAG(context);
115 break;
117 case 0x02: /* delete permanent swap on exit */
118 TRACE("VxD PageFile: supposed to delete swap\n");
119 RESET_CFLAG(context);
120 break;
122 case 0x03: /* current temporary swap file size */
123 TRACE("VxD PageFile: what is current temp. swap size\n");
124 RESET_CFLAG(context);
125 break;
127 case 0x04: /* read or write?? INTERRUP.D */
128 case 0x05: /* cancel?? INTERRUP.D */
129 case 0x06: /* test I/O valid INTERRUP.D */
130 default:
131 VXD_BARF( context, "pagefile" );
132 break;
136 /***********************************************************************
137 * VXD_Reboot (WPROCS.409)
139 void WINAPI VXD_Reboot ( CONTEXT86 *context )
141 unsigned service = AX_reg(context);
143 TRACE("[%04x] Reboot\n", (UINT16)service);
145 switch(service)
147 case 0x0000: /* version */
148 AX_reg(context) = VXD_WinVersion();
149 RESET_CFLAG(context);
150 break;
152 default:
153 VXD_BARF( context, "REBOOT" );
157 /***********************************************************************
158 * VXD_VDD (WPROCS.410)
160 void WINAPI VXD_VDD ( CONTEXT86 *context )
162 unsigned service = AX_reg(context);
164 TRACE("[%04x] VDD\n", (UINT16)service);
166 switch(service)
168 case 0x0000: /* version */
169 AX_reg(context) = VXD_WinVersion();
170 RESET_CFLAG(context);
171 break;
173 default:
174 VXD_BARF( context, "VDD" );
178 /***********************************************************************
179 * VXD_VMD (WPROCS.412)
181 void WINAPI VXD_VMD ( CONTEXT86 *context )
183 unsigned service = AX_reg(context);
185 TRACE("[%04x] VMD\n", (UINT16)service);
187 switch(service)
189 case 0x0000: /* version */
190 AX_reg(context) = VXD_WinVersion();
191 RESET_CFLAG(context);
192 break;
194 default:
195 VXD_BARF( context, "VMD" );
199 /***********************************************************************
200 * VXD_VXDLoader (WPROCS.439)
202 void WINAPI VXD_VXDLoader( CONTEXT86 *context )
204 unsigned service = AX_reg(context);
206 TRACE("[%04x] VXDLoader\n", (UINT16)service);
208 switch (service)
210 case 0x0000: /* get version */
211 TRACE("returning version\n");
212 AX_reg(context) = 0x0000;
213 DX_reg(context) = VXD_WinVersion();
214 RESET_CFLAG(context);
215 break;
217 case 0x0001: /* load device */
218 FIXME("load device %04lx:%04x (%s)\n",
219 context->SegDs, DX_reg(context),
220 debugstr_a(MapSL(MAKESEGPTR(context->SegDs, DX_reg(context)))));
221 AX_reg(context) = 0x0000;
222 context->SegEs = 0x0000;
223 DI_reg(context) = 0x0000;
224 RESET_CFLAG(context);
225 break;
227 case 0x0002: /* unload device */
228 FIXME("unload device (%08lx)\n", context->Ebx);
229 AX_reg(context) = 0x0000;
230 RESET_CFLAG(context);
231 break;
233 default:
234 VXD_BARF( context, "VXDLDR" );
235 AX_reg(context) = 0x000B; /* invalid function number */
236 SET_CFLAG(context);
237 break;
241 /***********************************************************************
242 * VXD_Shell (WPROCS.423)
244 void WINAPI VXD_Shell( CONTEXT86 *context )
246 unsigned service = DX_reg(context);
248 TRACE("[%04x] Shell\n", (UINT16)service);
250 switch (service) /* Ralf Brown says EDX, but I use DX instead */
252 case 0x0000:
253 TRACE("returning version\n");
254 AX_reg(context) = VXD_WinVersion();
255 context->Ebx = 1; /* system VM Handle */
256 break;
258 case 0x0001:
259 case 0x0002:
260 case 0x0003:
261 /* SHELL_SYSMODAL_Message
262 ebx virtual maschine handle
263 eax message box flags
264 ecx address of message
265 edi address of caption
266 return response in eax
268 case 0x0004:
269 /* SHELL_Message
270 ebx virtual maschine handle
271 eax message box flags
272 ecx address of message
273 edi address of caption
274 esi address callback
275 edx reference data for callback
276 return response in eax
278 case 0x0005:
279 VXD_BARF( context, "shell" );
280 break;
282 case 0x0006: /* SHELL_Get_VM_State */
283 TRACE("VxD Shell: returning VM state\n");
284 /* Actually we don't, not yet. We have to return a structure
285 * and I am not to sure how to set it up and return it yet,
286 * so for now let's do nothing. I can (hopefully) get this
287 * by the next release
289 /* RESET_CFLAG(context); */
290 break;
292 case 0x0007:
293 case 0x0008:
294 case 0x0009:
295 case 0x000A:
296 case 0x000B:
297 case 0x000C:
298 case 0x000D:
299 case 0x000E:
300 case 0x000F:
301 case 0x0010:
302 case 0x0011:
303 case 0x0012:
304 case 0x0013:
305 case 0x0014:
306 case 0x0015:
307 case 0x0016:
308 VXD_BARF( context, "SHELL" );
309 break;
311 /* the new Win95 shell API */
312 case 0x0100: /* get version */
313 AX_reg(context) = VXD_WinVersion();
314 break;
316 case 0x0104: /* retrieve Hook_Properties list */
317 case 0x0105: /* call Hook_Properties callbacks */
318 VXD_BARF( context, "SHELL" );
319 break;
321 case 0x0106: /* install timeout callback */
322 TRACE("VxD Shell: ignoring shell callback (%ld sec.)\n", context->Ebx);
323 SET_CFLAG(context);
324 break;
326 case 0x0107: /* get version of any VxD */
327 default:
328 VXD_BARF( context, "SHELL" );
329 break;
334 /***********************************************************************
335 * VXD_Comm (WPROCS.414)
337 void WINAPI VXD_Comm( CONTEXT86 *context )
339 unsigned service = AX_reg(context);
341 TRACE("[%04x] Comm\n", (UINT16)service);
343 switch (service)
345 case 0x0000: /* get version */
346 TRACE("returning version\n");
347 AX_reg(context) = VXD_WinVersion();
348 RESET_CFLAG(context);
349 break;
351 case 0x0001: /* set port global */
352 case 0x0002: /* get focus */
353 case 0x0003: /* virtualise port */
354 default:
355 VXD_BARF( context, "comm" );
359 /***********************************************************************
360 * VXD_Timer (WPROCS.405)
362 void WINAPI VXD_Timer( CONTEXT86 *context )
364 unsigned service = AX_reg(context);
366 TRACE("[%04x] Virtual Timer\n", (UINT16)service);
368 switch(service)
370 case 0x0000: /* version */
371 AX_reg(context) = VXD_WinVersion();
372 RESET_CFLAG(context);
373 break;
375 case 0x0100: /* clock tick time, in 840nsecs */
376 context->Eax = GetTickCount();
378 context->Edx = context->Eax >> 22;
379 context->Eax <<= 10; /* not very precise */
380 break;
382 case 0x0101: /* current Windows time, msecs */
383 case 0x0102: /* current VM time, msecs */
384 context->Eax = GetTickCount();
385 break;
387 default:
388 VXD_BARF( context, "VTD" );
392 /***********************************************************************
393 * VXD_TimerAPI (WPROCS.1490)
395 static DWORD System_Time = 0;
396 static WORD System_Time_Selector = 0;
397 static void System_Time_Tick( WORD timer ) { System_Time += 55; }
398 void WINAPI VXD_TimerAPI ( CONTEXT86 *context )
400 unsigned service = AX_reg(context);
402 TRACE("[%04x] TimerAPI\n", (UINT16)service);
404 switch(service)
406 case 0x0000: /* version */
407 AX_reg(context) = VXD_WinVersion();
408 RESET_CFLAG(context);
409 break;
411 case 0x0009: /* get system time selector */
412 if ( !System_Time_Selector )
414 System_Time_Selector = SELECTOR_AllocBlock( &System_Time, sizeof(DWORD), WINE_LDT_FLAGS_DATA );
415 CreateSystemTimer( 55, System_Time_Tick );
418 AX_reg(context) = System_Time_Selector;
419 RESET_CFLAG(context);
420 break;
422 default:
423 VXD_BARF( context, "VTDAPI" );
427 /***********************************************************************
428 * VXD_ConfigMG (WPROCS.451)
430 void WINAPI VXD_ConfigMG ( CONTEXT86 *context )
432 unsigned service = AX_reg(context);
434 TRACE("[%04x] ConfigMG\n", (UINT16)service);
436 switch(service)
438 case 0x0000: /* version */
439 AX_reg(context) = VXD_WinVersion();
440 RESET_CFLAG(context);
441 break;
443 default:
444 VXD_BARF( context, "CONFIGMG" );
448 /***********************************************************************
449 * VXD_Enable (WPROCS.455)
451 void WINAPI VXD_Enable ( CONTEXT86 *context )
453 unsigned service = AX_reg(context);
455 TRACE("[%04x] Enable\n", (UINT16)service);
457 switch(service)
459 case 0x0000: /* version */
460 AX_reg(context) = VXD_WinVersion();
461 RESET_CFLAG(context);
462 break;
464 default:
465 VXD_BARF( context, "ENABLE" );
469 /***********************************************************************
470 * VXD_APM (WPROCS.438)
472 void WINAPI VXD_APM ( CONTEXT86 *context )
474 unsigned service = AX_reg(context);
476 TRACE("[%04x] APM\n", (UINT16)service);
478 switch(service)
480 case 0x0000: /* version */
481 AX_reg(context) = VXD_WinVersion();
482 RESET_CFLAG(context);
483 break;
485 default:
486 VXD_BARF( context, "APM" );
490 /***********************************************************************
491 * VXD_Win32s (WPROCS.445)
493 * This is an implementation of the services of the Win32s VxD.
494 * Since official documentation of these does not seem to be available,
495 * certain arguments of some of the services remain unclear.
497 * FIXME: The following services are currently unimplemented:
498 * Exception handling (0x01, 0x1C)
499 * Debugger support (0x0C, 0x14, 0x17)
500 * Low-level memory access (0x02, 0x03, 0x0A, 0x0B)
501 * Memory Statistics (0x1B)
504 * We have a specific problem running Win32s on Linux (and probably also
505 * the other x86 unixes), since Win32s tries to allocate its main 'flat
506 * code/data segment' selectors with a base of 0xffff0000 (and limit 4GB).
507 * The rationale for this seems to be that they want one the one hand to
508 * be able to leave the Win 3.1 memory (starting with the main DOS memory)
509 * at linear address 0, but want at other hand to have offset 0 of the
510 * flat data/code segment point to an unmapped page (to catch NULL pointer
511 * accesses). Hence they allocate the flat segments with a base of 0xffff0000
512 * so that the Win 3.1 memory area at linear address zero shows up in the
513 * flat segments at offset 0x10000 (since linear addresses wrap around at
514 * 4GB). To compensate for that discrepancy between flat segment offsets
515 * and plain linear addresses, all flat pointers passed between the 32-bit
516 * and the 16-bit parts of Win32s are shifted by 0x10000 in the appropriate
517 * direction by the glue code (mainly) in W32SKRNL and WIN32S16.
519 * The problem for us is now that Linux does not allow a LDT selector with
520 * base 0xffff0000 to be created, since it would 'see' a part of the kernel
521 * address space. To address this problem we introduce *another* offset:
522 * We add 0x10000 to every linear address we get as an argument from Win32s.
523 * This means especially that the flat code/data selectors get actually
524 * allocated with base 0x0, so that flat offsets and (real) linear addresses
525 * do again agree! In fact, every call e.g. of a Win32s VxD service now
526 * has all pointer arguments (which are offsets in the flat data segement)
527 * first reduced by 0x10000 by the W32SKRNL glue code, and then again
528 * increased by 0x10000 by *our* code.
530 * Note that to keep everything consistent, this offset has to be applied by
531 * every Wine function that operates on 'linear addresses' passed to it by
532 * Win32s. Fortunately, since Win32s does not directly call any Wine 32-bit
533 * API routines, this affects only two locations: this VxD and the DPMI
534 * handler. (NOTE: Should any Win32s application pass a linear address to
535 * any routine apart from those, e.g. some other VxD handler, that code
536 * would have to take the offset into account as well!)
538 * The offset is set the first time any application calls the GetVersion()
539 * service of the Win32s VxD. (Note that the offset is never reset.)
543 void WINAPI VXD_Win32s( CONTEXT86 *context )
545 switch (AX_reg(context))
547 case 0x0000: /* Get Version */
549 * Input: None
551 * Output: EAX: LoWord: Win32s Version (1.30)
552 * HiWord: VxD Version (200)
554 * EBX: Build (172)
556 * ECX: ??? (1)
558 * EDX: Debugging Flags
560 * EDI: Error Flag
561 * 0 if OK,
562 * 1 if VMCPD VxD not found
565 TRACE("GetVersion()\n");
567 context->Eax = VXD_WinVersion() | (200 << 16);
568 context->Ebx = 0;
569 context->Ecx = 0;
570 context->Edx = 0;
571 context->Edi = 0;
574 * If this is the first time we are called for this process,
575 * hack the memory image of WIN32S16 so that it doesn't try
576 * to access the GDT directly ...
578 * The first code segment of WIN32S16 (version 1.30) contains
579 * an unexported function somewhere between the exported functions
580 * SetFS and StackLinearToSegmented that tries to find a selector
581 * in the LDT that maps to the memory image of the LDT itself.
582 * If it succeeds, it stores this selector into a global variable
583 * which will be used to speed up execution by using this selector
584 * to modify the LDT directly instead of using the DPMI calls.
586 * To perform this search of the LDT, this function uses the
587 * sgdt and sldt instructions to find the linear address of
588 * the (GDT and then) LDT. While those instructions themselves
589 * execute without problem, the linear address that sgdt returns
590 * points (at least under Linux) to the kernel address space, so
591 * that any subsequent access leads to a segfault.
593 * Fortunately, WIN32S16 still contains as a fallback option the
594 * mechanism of using DPMI calls to modify LDT selectors instead
595 * of direct writes to the LDT. Thus we can circumvent the problem
596 * by simply replacing the first byte of the offending function
597 * with an 'retf' instruction. This means that the global variable
598 * supposed to contain the LDT alias selector will remain zero,
599 * and hence WIN32S16 will fall back to using DPMI calls.
601 * The heuristic we employ to _find_ that function is as follows:
602 * We search between the addresses of the exported symbols SetFS
603 * and StackLinearToSegmented for the byte sequence '0F 01 04'
604 * (this is the opcode of 'sgdt [si]'). We then search backwards
605 * from this address for the last occurrence of 'CB' (retf) that marks
606 * the end of the preceeding function. The following byte (which
607 * should now be the first byte of the function we are looking for)
608 * will be replaced by 'CB' (retf).
610 * This heuristic works for the retail as well as the debug version
611 * of Win32s version 1.30. For versions earlier than that this
612 * hack should not be necessary at all, since the whole mechanism
613 * ('PERF130') was introduced only in 1.30 to improve the overall
614 * performance of Win32s.
617 if (!W32S_offset)
619 HMODULE16 hModule = GetModuleHandle16("win32s16");
620 SEGPTR func1 = (SEGPTR)GetProcAddress16(hModule, "SetFS");
621 SEGPTR func2 = (SEGPTR)GetProcAddress16(hModule, "StackLinearToSegmented");
623 if ( hModule && func1 && func2
624 && SELECTOROF(func1) == SELECTOROF(func2))
626 BYTE *start = MapSL(func1);
627 BYTE *end = MapSL(func2);
628 BYTE *p, *retv = NULL;
629 int found = 0;
631 for (p = start; p < end; p++)
632 if (*p == 0xCB) found = 0, retv = p;
633 else if (*p == 0x0F) found = 1;
634 else if (*p == 0x01 && found == 1) found = 2;
635 else if (*p == 0x04 && found == 2) { found = 3; break; }
636 else found = 0;
638 if (found == 3 && retv)
640 TRACE("PERF130 hack: "
641 "Replacing byte %02X at offset %04X:%04X\n",
642 *(retv+1), SELECTOROF(func1),
643 OFFSETOF(func1) + retv+1-start);
645 *(retv+1) = (BYTE)0xCB;
651 * Mark process as Win32s, so that subsequent DPMI calls
652 * will perform the W32S_APP2WINE/W32S_WINE2APP address shift.
654 W32S_offset = 0x10000;
655 break;
658 case 0x0001: /* Install Exception Handling */
660 * Input: EBX: Flat address of W32SKRNL Exception Data
662 * ECX: LoWord: Flat Code Selector
663 * HiWord: Flat Data Selector
665 * EDX: Flat address of W32SKRNL Exception Handler
666 * (this is equal to W32S_BackTo32 + 0x40)
668 * ESI: SEGPTR KERNEL.HASGPHANDLER
670 * EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10)
672 * Output: EAX: 0 if OK
675 TRACE("[0001] EBX=%lx ECX=%lx EDX=%lx ESI=%lx EDI=%lx\n",
676 context->Ebx, context->Ecx, context->Edx,
677 context->Esi, context->Edi);
679 /* FIXME */
681 context->Eax = 0;
682 break;
685 case 0x0002: /* Set Page Access Flags */
687 * Input: EBX: New access flags
688 * Bit 2: User Page if set, Supervisor Page if clear
689 * Bit 1: Read-Write if set, Read-Only if clear
691 * ECX: Size of memory area to change
693 * EDX: Flat start address of memory area
695 * Output: EAX: Size of area changed
698 TRACE("[0002] EBX=%lx ECX=%lx EDX=%lx\n",
699 context->Ebx, context->Ecx, context->Edx);
701 /* FIXME */
703 context->Eax = context->Ecx;
704 break;
707 case 0x0003: /* Get Page Access Flags */
709 * Input: EDX: Flat address of page to query
711 * Output: EAX: Page access flags
712 * Bit 2: User Page if set, Supervisor Page if clear
713 * Bit 1: Read-Write if set, Read-Only if clear
716 TRACE("[0003] EDX=%lx\n", context->Edx);
718 /* FIXME */
720 context->Eax = 6;
721 break;
724 case 0x0004: /* Map Module */
726 * Input: ECX: IMTE (offset in Module Table) of new module
728 * EDX: Flat address of Win32s Module Table
730 * Output: EAX: 0 if OK
733 if (!context->Edx || CX_reg(context) == 0xFFFF)
735 TRACE("MapModule: Initialization call\n");
736 context->Eax = 0;
738 else
741 * Structure of a Win32s Module Table Entry:
743 struct Win32sModule
745 DWORD flags;
746 DWORD flatBaseAddr;
747 LPCSTR moduleName;
748 LPCSTR pathName;
749 LPCSTR unknown;
750 LPBYTE baseAddr;
751 DWORD hModule;
752 DWORD relocDelta;
756 * Note: This function should set up a demand-paged memory image
757 * of the given module. Since mmap does not allow file offsets
758 * not aligned at 1024 bytes, we simply load the image fully
759 * into memory.
762 struct Win32sModule *moduleTable =
763 (struct Win32sModule *)W32S_APP2WINE(context->Edx);
764 struct Win32sModule *module = moduleTable + context->Ecx;
766 IMAGE_NT_HEADERS *nt_header = RtlImageNtHeader( (HMODULE)module->baseAddr );
767 IMAGE_SECTION_HEADER *pe_seg = (IMAGE_SECTION_HEADER*)((char *)&nt_header->OptionalHeader +
768 nt_header->FileHeader.SizeOfOptionalHeader);
771 HFILE image = _lopen(module->pathName, OF_READ);
772 BOOL error = (image == HFILE_ERROR);
773 UINT i;
775 TRACE("MapModule: Loading %s\n", module->pathName);
777 for (i = 0;
778 !error && i < nt_header->FileHeader.NumberOfSections;
779 i++, pe_seg++)
780 if(!(pe_seg->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA))
782 DWORD off = pe_seg->PointerToRawData;
783 DWORD len = pe_seg->SizeOfRawData;
784 LPBYTE addr = module->baseAddr + pe_seg->VirtualAddress;
786 TRACE("MapModule: "
787 "Section %d at %08lx from %08lx len %08lx\n",
788 i, (DWORD)addr, off, len);
790 if ( _llseek(image, off, SEEK_SET) != off
791 || _lread(image, addr, len) != len)
792 error = TRUE;
795 _lclose(image);
797 if (error)
798 ERR("MapModule: Unable to load %s\n", module->pathName);
800 else if (module->relocDelta != 0)
802 IMAGE_DATA_DIRECTORY *dir = nt_header->OptionalHeader.DataDirectory
803 + IMAGE_DIRECTORY_ENTRY_BASERELOC;
804 IMAGE_BASE_RELOCATION *r = (IMAGE_BASE_RELOCATION *)
805 (dir->Size? module->baseAddr + dir->VirtualAddress : 0);
807 TRACE("MapModule: Reloc delta %08lx\n", module->relocDelta);
809 while (r && r->VirtualAddress)
811 LPBYTE page = module->baseAddr + r->VirtualAddress;
812 WORD *TypeOffset = (WORD *)(r + 1);
813 int count = (r->SizeOfBlock - sizeof(*r)) / sizeof(*TypeOffset);
815 TRACE("MapModule: %d relocations for page %08lx\n",
816 count, (DWORD)page);
818 for(i = 0; i < count; i++)
820 int offset = TypeOffset[i] & 0xFFF;
821 int type = TypeOffset[i] >> 12;
822 switch(type)
824 case IMAGE_REL_BASED_ABSOLUTE:
825 break;
826 case IMAGE_REL_BASED_HIGH:
827 *(WORD *)(page+offset) += HIWORD(module->relocDelta);
828 break;
829 case IMAGE_REL_BASED_LOW:
830 *(WORD *)(page+offset) += LOWORD(module->relocDelta);
831 break;
832 case IMAGE_REL_BASED_HIGHLOW:
833 *(DWORD*)(page+offset) += module->relocDelta;
834 break;
835 default:
836 WARN("MapModule: Unsupported fixup type\n");
837 break;
841 r = (IMAGE_BASE_RELOCATION *)((LPBYTE)r + r->SizeOfBlock);
845 context->Eax = 0;
846 RESET_CFLAG(context);
848 break;
851 case 0x0005: /* UnMap Module */
853 * Input: EDX: Flat address of module image
855 * Output: EAX: 1 if OK
858 TRACE("UnMapModule: %lx\n", (DWORD)W32S_APP2WINE(context->Edx));
860 /* As we didn't map anything, there's nothing to unmap ... */
862 context->Eax = 1;
863 break;
866 case 0x0006: /* VirtualAlloc */
868 * Input: ECX: Current Process
870 * EDX: Flat address of arguments on stack
872 * DWORD *retv [out] Flat base address of allocated region
873 * LPVOID base [in] Flat address of region to reserve/commit
874 * DWORD size [in] Size of region
875 * DWORD type [in] Type of allocation
876 * DWORD prot [in] Type of access protection
878 * Output: EAX: NtStatus
881 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
882 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
883 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
884 DWORD size = stack[2];
885 DWORD type = stack[3];
886 DWORD prot = stack[4];
887 DWORD result;
889 TRACE("VirtualAlloc(%lx, %lx, %lx, %lx, %lx)\n",
890 (DWORD)retv, (DWORD)base, size, type, prot);
892 if (type & 0x80000000)
894 WARN("VirtualAlloc: strange type %lx\n", type);
895 type &= 0x7fffffff;
898 if (!base && (type & MEM_COMMIT) && prot == PAGE_READONLY)
900 WARN("VirtualAlloc: NLS hack, allowing write access!\n");
901 prot = PAGE_READWRITE;
904 result = (DWORD)VirtualAlloc(base, size, type, prot);
906 if (W32S_WINE2APP(result))
907 *retv = W32S_WINE2APP(result),
908 context->Eax = STATUS_SUCCESS;
909 else
910 *retv = 0,
911 context->Eax = STATUS_NO_MEMORY; /* FIXME */
913 break;
916 case 0x0007: /* VirtualFree */
918 * Input: ECX: Current Process
920 * EDX: Flat address of arguments on stack
922 * DWORD *retv [out] TRUE if success, FALSE if failure
923 * LPVOID base [in] Flat address of region
924 * DWORD size [in] Size of region
925 * DWORD type [in] Type of operation
927 * Output: EAX: NtStatus
930 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
931 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
932 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
933 DWORD size = stack[2];
934 DWORD type = stack[3];
935 DWORD result;
937 TRACE("VirtualFree(%lx, %lx, %lx, %lx)\n",
938 (DWORD)retv, (DWORD)base, size, type);
940 result = VirtualFree(base, size, type);
942 if (result)
943 *retv = TRUE,
944 context->Eax = STATUS_SUCCESS;
945 else
946 *retv = FALSE,
947 context->Eax = STATUS_NO_MEMORY; /* FIXME */
949 break;
952 case 0x0008: /* VirtualProtect */
954 * Input: ECX: Current Process
956 * EDX: Flat address of arguments on stack
958 * DWORD *retv [out] TRUE if success, FALSE if failure
959 * LPVOID base [in] Flat address of region
960 * DWORD size [in] Size of region
961 * DWORD new_prot [in] Desired access protection
962 * DWORD *old_prot [out] Previous access protection
964 * Output: EAX: NtStatus
967 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
968 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
969 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
970 DWORD size = stack[2];
971 DWORD new_prot = stack[3];
972 DWORD *old_prot = (DWORD *)W32S_APP2WINE(stack[4]);
973 DWORD result;
975 TRACE("VirtualProtect(%lx, %lx, %lx, %lx, %lx)\n",
976 (DWORD)retv, (DWORD)base, size, new_prot, (DWORD)old_prot);
978 result = VirtualProtect(base, size, new_prot, old_prot);
980 if (result)
981 *retv = TRUE,
982 context->Eax = STATUS_SUCCESS;
983 else
984 *retv = FALSE,
985 context->Eax = STATUS_NO_MEMORY; /* FIXME */
987 break;
990 case 0x0009: /* VirtualQuery */
992 * Input: ECX: Current Process
994 * EDX: Flat address of arguments on stack
996 * DWORD *retv [out] Nr. bytes returned
997 * LPVOID base [in] Flat address of region
998 * LPMEMORY_BASIC_INFORMATION info [out] Info buffer
999 * DWORD len [in] Size of buffer
1001 * Output: EAX: NtStatus
1004 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1005 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1006 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1007 LPMEMORY_BASIC_INFORMATION info =
1008 (LPMEMORY_BASIC_INFORMATION)W32S_APP2WINE(stack[2]);
1009 DWORD len = stack[3];
1010 DWORD result;
1012 TRACE("VirtualQuery(%lx, %lx, %lx, %lx)\n",
1013 (DWORD)retv, (DWORD)base, (DWORD)info, len);
1015 result = VirtualQuery(base, info, len);
1017 *retv = result;
1018 context->Eax = STATUS_SUCCESS;
1020 break;
1023 case 0x000A: /* SetVirtMemProcess */
1025 * Input: ECX: Process Handle
1027 * EDX: Flat address of region
1029 * Output: EAX: NtStatus
1032 TRACE("[000a] ECX=%lx EDX=%lx\n",
1033 context->Ecx, context->Edx);
1035 /* FIXME */
1037 context->Eax = STATUS_SUCCESS;
1038 break;
1041 case 0x000B: /* ??? some kind of cleanup */
1043 * Input: ECX: Process Handle
1045 * Output: EAX: NtStatus
1048 TRACE("[000b] ECX=%lx\n", context->Ecx);
1050 /* FIXME */
1052 context->Eax = STATUS_SUCCESS;
1053 break;
1056 case 0x000C: /* Set Debug Flags */
1058 * Input: EDX: Debug Flags
1060 * Output: EDX: Previous Debug Flags
1063 FIXME("[000c] EDX=%lx\n", context->Edx);
1065 /* FIXME */
1067 context->Edx = 0;
1068 break;
1071 case 0x000D: /* NtCreateSection */
1073 * Input: EDX: Flat address of arguments on stack
1075 * HANDLE32 *retv [out] Handle of Section created
1076 * DWORD flags1 [in] (?? unknown ??)
1077 * DWORD atom [in] Name of Section to create
1078 * LARGE_INTEGER *size [in] Size of Section
1079 * DWORD protect [in] Access protection
1080 * DWORD flags2 [in] (?? unknown ??)
1081 * HFILE32 hFile [in] Handle of file to map
1082 * DWORD psp [in] (Win32s: PSP that hFile belongs to)
1084 * Output: EAX: NtStatus
1087 DWORD *stack = (DWORD *) W32S_APP2WINE(context->Edx);
1088 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]);
1089 DWORD flags1 = stack[1];
1090 DWORD atom = stack[2];
1091 LARGE_INTEGER *size = (LARGE_INTEGER *)W32S_APP2WINE(stack[3]);
1092 DWORD protect = stack[4];
1093 DWORD flags2 = stack[5];
1094 HANDLE hFile = DosFileHandleToWin32Handle(stack[6]);
1095 DWORD psp = stack[7];
1097 HANDLE result = INVALID_HANDLE_VALUE;
1098 char name[128];
1100 TRACE("NtCreateSection(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1101 (DWORD)retv, flags1, atom, (DWORD)size, protect, flags2,
1102 (DWORD)hFile, psp);
1104 if (!atom || GlobalGetAtomNameA(atom, name, sizeof(name)))
1106 TRACE("NtCreateSection: name=%s\n", atom? name : NULL);
1108 result = CreateFileMappingA(hFile, NULL, protect,
1109 size? size->s.HighPart : 0,
1110 size? size->s.LowPart : 0,
1111 atom? name : NULL);
1114 if (result == INVALID_HANDLE_VALUE)
1115 WARN("NtCreateSection: failed!\n");
1116 else
1117 TRACE("NtCreateSection: returned %lx\n", (DWORD)result);
1119 if (result != INVALID_HANDLE_VALUE)
1120 *retv = result,
1121 context->Eax = STATUS_SUCCESS;
1122 else
1123 *retv = result,
1124 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1126 break;
1129 case 0x000E: /* NtOpenSection */
1131 * Input: EDX: Flat address of arguments on stack
1133 * HANDLE32 *retv [out] Handle of Section opened
1134 * DWORD protect [in] Access protection
1135 * DWORD atom [in] Name of Section to create
1137 * Output: EAX: NtStatus
1140 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1141 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]);
1142 DWORD protect = stack[1];
1143 DWORD atom = stack[2];
1145 HANDLE result = INVALID_HANDLE_VALUE;
1146 char name[128];
1148 TRACE("NtOpenSection(%lx, %lx, %lx)\n",
1149 (DWORD)retv, protect, atom);
1151 if (atom && GlobalGetAtomNameA(atom, name, sizeof(name)))
1153 TRACE("NtOpenSection: name=%s\n", name);
1155 result = OpenFileMappingA(protect, FALSE, name);
1158 if (result == INVALID_HANDLE_VALUE)
1159 WARN("NtOpenSection: failed!\n");
1160 else
1161 TRACE("NtOpenSection: returned %lx\n", (DWORD)result);
1163 if (result != INVALID_HANDLE_VALUE)
1164 *retv = result,
1165 context->Eax = STATUS_SUCCESS;
1166 else
1167 *retv = result,
1168 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1170 break;
1173 case 0x000F: /* NtCloseSection */
1175 * Input: EDX: Flat address of arguments on stack
1177 * HANDLE32 handle [in] Handle of Section to close
1178 * DWORD *id [out] Unique ID (?? unclear ??)
1180 * Output: EAX: NtStatus
1183 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1184 HANDLE handle = (HANDLE)stack[0];
1185 DWORD *id = (DWORD *)W32S_APP2WINE(stack[1]);
1187 TRACE("NtCloseSection(%lx, %lx)\n", (DWORD)handle, (DWORD)id);
1189 CloseHandle(handle);
1190 if (id) *id = 0; /* FIXME */
1192 context->Eax = STATUS_SUCCESS;
1194 break;
1197 case 0x0010: /* NtDupSection */
1199 * Input: EDX: Flat address of arguments on stack
1201 * HANDLE32 handle [in] Handle of Section to duplicate
1203 * Output: EAX: NtStatus
1206 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1207 HANDLE handle = (HANDLE)stack[0];
1208 HANDLE new_handle;
1210 TRACE("NtDupSection(%lx)\n", (DWORD)handle);
1212 DuplicateHandle( GetCurrentProcess(), handle,
1213 GetCurrentProcess(), &new_handle,
1214 0, FALSE, DUPLICATE_SAME_ACCESS );
1215 context->Eax = STATUS_SUCCESS;
1217 break;
1220 case 0x0011: /* NtMapViewOfSection */
1222 * Input: EDX: Flat address of arguments on stack
1224 * HANDLE32 SectionHandle [in] Section to be mapped
1225 * DWORD ProcessHandle [in] Process to be mapped into
1226 * DWORD * BaseAddress [in/out] Address to be mapped at
1227 * DWORD ZeroBits [in] (?? unclear ??)
1228 * DWORD CommitSize [in] (?? unclear ??)
1229 * LARGE_INTEGER *SectionOffset [in] Offset within section
1230 * DWORD * ViewSize [in] Size of view
1231 * DWORD InheritDisposition [in] (?? unclear ??)
1232 * DWORD AllocationType [in] (?? unclear ??)
1233 * DWORD Protect [in] Access protection
1235 * Output: EAX: NtStatus
1238 DWORD * stack = (DWORD *)W32S_APP2WINE(context->Edx);
1239 HANDLE SectionHandle = (HANDLE)stack[0];
1240 DWORD ProcessHandle = stack[1]; /* ignored */
1241 DWORD * BaseAddress = (DWORD *)W32S_APP2WINE(stack[2]);
1242 DWORD ZeroBits = stack[3];
1243 DWORD CommitSize = stack[4];
1244 LARGE_INTEGER *SectionOffset = (LARGE_INTEGER *)W32S_APP2WINE(stack[5]);
1245 DWORD * ViewSize = (DWORD *)W32S_APP2WINE(stack[6]);
1246 DWORD InheritDisposition = stack[7];
1247 DWORD AllocationType = stack[8];
1248 DWORD Protect = stack[9];
1250 LPBYTE address = (LPBYTE)(BaseAddress?
1251 W32S_APP2WINE(*BaseAddress) : 0);
1252 DWORD access = 0, result;
1254 switch (Protect & ~(PAGE_GUARD|PAGE_NOCACHE))
1256 case PAGE_READONLY: access = FILE_MAP_READ; break;
1257 case PAGE_READWRITE: access = FILE_MAP_WRITE; break;
1258 case PAGE_WRITECOPY: access = FILE_MAP_COPY; break;
1260 case PAGE_EXECUTE_READ: access = FILE_MAP_READ; break;
1261 case PAGE_EXECUTE_READWRITE: access = FILE_MAP_WRITE; break;
1262 case PAGE_EXECUTE_WRITECOPY: access = FILE_MAP_COPY; break;
1265 TRACE("NtMapViewOfSection"
1266 "(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1267 (DWORD)SectionHandle, ProcessHandle, (DWORD)BaseAddress,
1268 ZeroBits, CommitSize, (DWORD)SectionOffset, (DWORD)ViewSize,
1269 InheritDisposition, AllocationType, Protect);
1270 TRACE("NtMapViewOfSection: "
1271 "base=%lx, offset=%lx, size=%lx, access=%lx\n",
1272 (DWORD)address, SectionOffset? SectionOffset->s.LowPart : 0,
1273 ViewSize? *ViewSize : 0, access);
1275 result = (DWORD)MapViewOfFileEx(SectionHandle, access,
1276 SectionOffset? SectionOffset->s.HighPart : 0,
1277 SectionOffset? SectionOffset->s.LowPart : 0,
1278 ViewSize? *ViewSize : 0, address);
1280 TRACE("NtMapViewOfSection: result=%lx\n", result);
1282 if (W32S_WINE2APP(result))
1284 if (BaseAddress) *BaseAddress = W32S_WINE2APP(result);
1285 context->Eax = STATUS_SUCCESS;
1287 else
1288 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1290 break;
1293 case 0x0012: /* NtUnmapViewOfSection */
1295 * Input: EDX: Flat address of arguments on stack
1297 * DWORD ProcessHandle [in] Process (defining address space)
1298 * LPBYTE BaseAddress [in] Base address of view to be unmapped
1300 * Output: EAX: NtStatus
1303 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1304 DWORD ProcessHandle = stack[0]; /* ignored */
1305 LPBYTE BaseAddress = (LPBYTE)W32S_APP2WINE(stack[1]);
1307 TRACE("NtUnmapViewOfSection(%lx, %lx)\n",
1308 ProcessHandle, (DWORD)BaseAddress);
1310 UnmapViewOfFile(BaseAddress);
1312 context->Eax = STATUS_SUCCESS;
1314 break;
1317 case 0x0013: /* NtFlushVirtualMemory */
1319 * Input: EDX: Flat address of arguments on stack
1321 * DWORD ProcessHandle [in] Process (defining address space)
1322 * LPBYTE *BaseAddress [in?] Base address of range to be flushed
1323 * DWORD *ViewSize [in?] Number of bytes to be flushed
1324 * DWORD *unknown [???] (?? unknown ??)
1326 * Output: EAX: NtStatus
1329 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1330 DWORD ProcessHandle = stack[0]; /* ignored */
1331 DWORD *BaseAddress = (DWORD *)W32S_APP2WINE(stack[1]);
1332 DWORD *ViewSize = (DWORD *)W32S_APP2WINE(stack[2]);
1333 DWORD *unknown = (DWORD *)W32S_APP2WINE(stack[3]);
1335 LPBYTE address = (LPBYTE)(BaseAddress? W32S_APP2WINE(*BaseAddress) : 0);
1336 DWORD size = ViewSize? *ViewSize : 0;
1338 TRACE("NtFlushVirtualMemory(%lx, %lx, %lx, %lx)\n",
1339 ProcessHandle, (DWORD)BaseAddress, (DWORD)ViewSize,
1340 (DWORD)unknown);
1341 TRACE("NtFlushVirtualMemory: base=%lx, size=%lx\n",
1342 (DWORD)address, size);
1344 FlushViewOfFile(address, size);
1346 context->Eax = STATUS_SUCCESS;
1348 break;
1351 case 0x0014: /* Get/Set Debug Registers */
1353 * Input: ECX: 0 if Get, 1 if Set
1355 * EDX: Get: Flat address of buffer to receive values of
1356 * debug registers DR0 .. DR7
1357 * Set: Flat address of buffer containing values of
1358 * debug registers DR0 .. DR7 to be set
1359 * Output: None
1362 FIXME("[0014] ECX=%lx EDX=%lx\n",
1363 context->Ecx, context->Edx);
1365 /* FIXME */
1366 break;
1369 case 0x0015: /* Set Coprocessor Emulation Flag */
1371 * Input: EDX: 0 to deactivate, 1 to activate coprocessor emulation
1373 * Output: None
1376 TRACE("[0015] EDX=%lx\n", context->Edx);
1378 /* We don't care, as we always have a coprocessor anyway */
1379 break;
1382 case 0x0016: /* Init Win32S VxD PSP */
1384 * If called to query required PSP size:
1386 * Input: EBX: 0
1387 * Output: EDX: Required size of Win32s VxD PSP
1389 * If called to initialize allocated PSP:
1391 * Input: EBX: LoWord: Selector of Win32s VxD PSP
1392 * HiWord: Paragraph of Win32s VxD PSP (DOSMEM)
1393 * Output: None
1396 if (context->Ebx == 0)
1397 context->Edx = 0x80;
1398 else
1400 PDB16 *psp = MapSL( MAKESEGPTR( BX_reg(context), 0 ));
1401 psp->nbFiles = 32;
1402 psp->fileHandlesPtr = MAKELONG(HIWORD(context->Ebx), 0x5c);
1403 memset((LPBYTE)psp + 0x5c, '\xFF', 32);
1405 break;
1408 case 0x0017: /* Set Break Point */
1410 * Input: EBX: Offset of Break Point
1411 * CX: Selector of Break Point
1413 * Output: None
1416 FIXME("[0017] EBX=%lx CX=%x\n",
1417 context->Ebx, CX_reg(context));
1419 /* FIXME */
1420 break;
1423 case 0x0018: /* VirtualLock */
1425 * Input: ECX: Current Process
1427 * EDX: Flat address of arguments on stack
1429 * DWORD *retv [out] TRUE if success, FALSE if failure
1430 * LPVOID base [in] Flat address of range to lock
1431 * DWORD size [in] Size of range
1433 * Output: EAX: NtStatus
1436 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1437 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1438 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1439 DWORD size = stack[2];
1440 DWORD result;
1442 TRACE("VirtualLock(%lx, %lx, %lx)\n",
1443 (DWORD)retv, (DWORD)base, size);
1445 result = VirtualLock(base, size);
1447 if (result)
1448 *retv = TRUE,
1449 context->Eax = STATUS_SUCCESS;
1450 else
1451 *retv = FALSE,
1452 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1454 break;
1457 case 0x0019: /* VirtualUnlock */
1459 * Input: ECX: Current Process
1461 * EDX: Flat address of arguments on stack
1463 * DWORD *retv [out] TRUE if success, FALSE if failure
1464 * LPVOID base [in] Flat address of range to unlock
1465 * DWORD size [in] Size of range
1467 * Output: EAX: NtStatus
1470 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1471 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1472 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1473 DWORD size = stack[2];
1474 DWORD result;
1476 TRACE("VirtualUnlock(%lx, %lx, %lx)\n",
1477 (DWORD)retv, (DWORD)base, size);
1479 result = VirtualUnlock(base, size);
1481 if (result)
1482 *retv = TRUE,
1483 context->Eax = STATUS_SUCCESS;
1484 else
1485 *retv = FALSE,
1486 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1488 break;
1491 case 0x001A: /* KGetSystemInfo */
1493 * Input: None
1495 * Output: ECX: Start of sparse memory arena
1496 * EDX: End of sparse memory arena
1499 TRACE("KGetSystemInfo()\n");
1502 * Note: Win32s reserves 0GB - 2GB for Win 3.1 and uses 2GB - 4GB as
1503 * sparse memory arena. We do it the other way around, since
1504 * we have to reserve 3GB - 4GB for Linux, and thus use
1505 * 0GB - 3GB as sparse memory arena.
1507 * FIXME: What about other OSes ?
1510 context->Ecx = W32S_WINE2APP(0x00000000);
1511 context->Edx = W32S_WINE2APP(0xbfffffff);
1512 break;
1515 case 0x001B: /* KGlobalMemStat */
1517 * Input: ESI: Flat address of buffer to receive memory info
1519 * Output: None
1522 struct Win32sMemoryInfo
1524 DWORD DIPhys_Count; /* Total physical pages */
1525 DWORD DIFree_Count; /* Free physical pages */
1526 DWORD DILin_Total_Count; /* Total virtual pages (private arena) */
1527 DWORD DILin_Total_Free; /* Free virtual pages (private arena) */
1529 DWORD SparseTotal; /* Total size of sparse arena (bytes ?) */
1530 DWORD SparseFree; /* Free size of sparse arena (bytes ?) */
1533 struct Win32sMemoryInfo *info =
1534 (struct Win32sMemoryInfo *)W32S_APP2WINE(context->Esi);
1536 FIXME("KGlobalMemStat(%lx)\n", (DWORD)info);
1538 /* FIXME */
1540 break;
1543 case 0x001C: /* Enable/Disable Exceptions */
1545 * Input: ECX: 0 to disable, 1 to enable exception handling
1547 * Output: None
1550 TRACE("[001c] ECX=%lx\n", context->Ecx);
1552 /* FIXME */
1553 break;
1556 case 0x001D: /* VirtualAlloc called from 16-bit code */
1558 * Input: EDX: Segmented address of arguments on stack
1560 * LPVOID base [in] Flat address of region to reserve/commit
1561 * DWORD size [in] Size of region
1562 * DWORD type [in] Type of allocation
1563 * DWORD prot [in] Type of access protection
1565 * Output: EAX: NtStatus
1566 * EDX: Flat base address of allocated region
1569 DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) ));
1570 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]);
1571 DWORD size = stack[1];
1572 DWORD type = stack[2];
1573 DWORD prot = stack[3];
1574 DWORD result;
1576 TRACE("VirtualAlloc16(%lx, %lx, %lx, %lx)\n",
1577 (DWORD)base, size, type, prot);
1579 if (type & 0x80000000)
1581 WARN("VirtualAlloc16: strange type %lx\n", type);
1582 type &= 0x7fffffff;
1585 result = (DWORD)VirtualAlloc(base, size, type, prot);
1587 if (W32S_WINE2APP(result))
1588 context->Edx = W32S_WINE2APP(result),
1589 context->Eax = STATUS_SUCCESS;
1590 else
1591 context->Edx = 0,
1592 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1593 TRACE("VirtualAlloc16: returning base %lx\n", context->Edx);
1595 break;
1598 case 0x001E: /* VirtualFree called from 16-bit code */
1600 * Input: EDX: Segmented address of arguments on stack
1602 * LPVOID base [in] Flat address of region
1603 * DWORD size [in] Size of region
1604 * DWORD type [in] Type of operation
1606 * Output: EAX: NtStatus
1607 * EDX: TRUE if success, FALSE if failure
1610 DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) ));
1611 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]);
1612 DWORD size = stack[1];
1613 DWORD type = stack[2];
1614 DWORD result;
1616 TRACE("VirtualFree16(%lx, %lx, %lx)\n",
1617 (DWORD)base, size, type);
1619 result = VirtualFree(base, size, type);
1621 if (result)
1622 context->Edx = TRUE,
1623 context->Eax = STATUS_SUCCESS;
1624 else
1625 context->Edx = FALSE,
1626 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1628 break;
1631 case 0x001F: /* FWorkingSetSize */
1633 * Input: EDX: 0 if Get, 1 if Set
1635 * ECX: Get: Buffer to receive Working Set Size
1636 * Set: Buffer containing Working Set Size
1638 * Output: NtStatus
1641 DWORD *ptr = (DWORD *)W32S_APP2WINE(context->Ecx);
1642 BOOL set = context->Edx;
1644 TRACE("FWorkingSetSize(%lx, %lx)\n", (DWORD)ptr, (DWORD)set);
1646 if (set)
1647 /* We do it differently ... */;
1648 else
1649 *ptr = 0x100;
1651 context->Eax = STATUS_SUCCESS;
1653 break;
1656 default:
1657 VXD_BARF( context, "W32S" );