Added support for nested server waits (to allow waiting in signal
[wine/multimedia.git] / msdos / vxd.c
bloba4a35c62f07a240b2f77ae1973f09fd254e79199
1 /*
2 * VxD emulation
4 * Copyright 1995 Anand Kumria
5 */
7 #include <fcntl.h>
8 #include <memory.h>
9 #include <sys/types.h>
10 #include <unistd.h>
11 #include "winbase.h"
12 #include "windef.h"
13 #include "wingdi.h"
14 #include "winuser.h"
15 #include "wine/winbase16.h"
16 #include "wine/winuser16.h"
17 #include "msdos.h"
18 #include "miscemu.h"
19 #include "module.h"
20 #include "selectors.h"
21 #include "task.h"
22 #include "file.h"
23 #include "debugtools.h"
25 DEFAULT_DEBUG_CHANNEL(vxd);
28 #define VXD_BARF(context,name) \
29 DPRINTF( "vxd %s: unknown/not implemented parameters:\n" \
30 "vxd %s: AX %04x, BX %04x, CX %04x, DX %04x, " \
31 "SI %04x, DI %04x, DS %04x, ES %04x\n", \
32 (name), (name), AX_reg(context), BX_reg(context), \
33 CX_reg(context), DX_reg(context), SI_reg(context), \
34 DI_reg(context), (WORD)context->SegDs, (WORD)context->SegEs )
36 UINT W32S_offset = 0;
38 static WORD VXD_WinVersion(void)
40 WORD version = LOWORD(GetVersion16());
41 return (version >> 8) | (version << 8);
44 /***********************************************************************
45 * VXD_VMM
47 void WINAPI VXD_VMM ( CONTEXT86 *context )
49 unsigned service = AX_reg(context);
51 TRACE("[%04x] VMM\n", (UINT16)service);
53 switch(service)
55 case 0x0000: /* version */
56 AX_reg(context) = VXD_WinVersion();
57 RESET_CFLAG(context);
58 break;
60 case 0x026d: /* Get_Debug_Flag '/m' */
61 case 0x026e: /* Get_Debug_Flag '/n' */
62 AL_reg(context) = 0;
63 RESET_CFLAG(context);
64 break;
66 default:
67 VXD_BARF( context, "VMM" );
71 /***********************************************************************
72 * VXD_PageFile
74 void WINAPI VXD_PageFile( CONTEXT86 *context )
76 unsigned service = AX_reg(context);
78 /* taken from Ralf Brown's Interrupt List */
80 TRACE("[%04x] PageFile\n", (UINT16)service );
82 switch(service)
84 case 0x00: /* get version, is this windows version? */
85 TRACE("returning version\n");
86 AX_reg(context) = VXD_WinVersion();
87 RESET_CFLAG(context);
88 break;
90 case 0x01: /* get swap file info */
91 TRACE("VxD PageFile: returning swap file info\n");
92 AX_reg(context) = 0x00; /* paging disabled */
93 context->Ecx = 0; /* maximum size of paging file */
94 /* FIXME: do I touch DS:SI or DS:DI? */
95 RESET_CFLAG(context);
96 break;
98 case 0x02: /* delete permanent swap on exit */
99 TRACE("VxD PageFile: supposed to delete swap\n");
100 RESET_CFLAG(context);
101 break;
103 case 0x03: /* current temporary swap file size */
104 TRACE("VxD PageFile: what is current temp. swap size\n");
105 RESET_CFLAG(context);
106 break;
108 case 0x04: /* read or write?? INTERRUP.D */
109 case 0x05: /* cancel?? INTERRUP.D */
110 case 0x06: /* test I/O valid INTERRUP.D */
111 default:
112 VXD_BARF( context, "pagefile" );
113 break;
117 /***********************************************************************
118 * VXD_Reboot
120 void WINAPI VXD_Reboot ( CONTEXT86 *context )
122 unsigned service = AX_reg(context);
124 TRACE("[%04x] Reboot\n", (UINT16)service);
126 switch(service)
128 case 0x0000: /* version */
129 AX_reg(context) = VXD_WinVersion();
130 RESET_CFLAG(context);
131 break;
133 default:
134 VXD_BARF( context, "REBOOT" );
138 /***********************************************************************
139 * VXD_VDD
141 void WINAPI VXD_VDD ( CONTEXT86 *context )
143 unsigned service = AX_reg(context);
145 TRACE("[%04x] VDD\n", (UINT16)service);
147 switch(service)
149 case 0x0000: /* version */
150 AX_reg(context) = VXD_WinVersion();
151 RESET_CFLAG(context);
152 break;
154 default:
155 VXD_BARF( context, "VDD" );
159 /***********************************************************************
160 * VXD_VMD
162 void WINAPI VXD_VMD ( CONTEXT86 *context )
164 unsigned service = AX_reg(context);
166 TRACE("[%04x] VMD\n", (UINT16)service);
168 switch(service)
170 case 0x0000: /* version */
171 AX_reg(context) = VXD_WinVersion();
172 RESET_CFLAG(context);
173 break;
175 default:
176 VXD_BARF( context, "VMD" );
180 /***********************************************************************
181 * VXD_VXDLoader
183 void WINAPI VXD_VXDLoader( CONTEXT86 *context )
185 unsigned service = AX_reg(context);
187 TRACE("[%04x] VXDLoader\n", (UINT16)service);
189 switch (service)
191 case 0x0000: /* get version */
192 TRACE("returning version\n");
193 AX_reg(context) = 0x0000;
194 DX_reg(context) = VXD_WinVersion();
195 RESET_CFLAG(context);
196 break;
198 case 0x0001: /* load device */
199 FIXME("load device %04lx:%04x (%s)\n",
200 context->SegDs, DX_reg(context),
201 debugstr_a(MapSL(MAKESEGPTR(context->SegDs, DX_reg(context)))));
202 AX_reg(context) = 0x0000;
203 context->SegEs = 0x0000;
204 DI_reg(context) = 0x0000;
205 RESET_CFLAG(context);
206 break;
208 case 0x0002: /* unload device */
209 FIXME("unload device (%08lx)\n", context->Ebx);
210 AX_reg(context) = 0x0000;
211 RESET_CFLAG(context);
212 break;
214 default:
215 VXD_BARF( context, "VXDLDR" );
216 AX_reg(context) = 0x000B; /* invalid function number */
217 SET_CFLAG(context);
218 break;
222 /***********************************************************************
223 * VXD_Shell
225 void WINAPI VXD_Shell( CONTEXT86 *context )
227 unsigned service = DX_reg(context);
229 TRACE("[%04x] Shell\n", (UINT16)service);
231 switch (service) /* Ralf Brown says EDX, but I use DX instead */
233 case 0x0000:
234 TRACE("returning version\n");
235 AX_reg(context) = VXD_WinVersion();
236 context->Ebx = 1; /* system VM Handle */
237 break;
239 case 0x0001:
240 case 0x0002:
241 case 0x0003:
242 /* SHELL_SYSMODAL_Message
243 ebx virtual maschine handle
244 eax message box flags
245 ecx address of message
246 edi address of caption
247 return response in eax
249 case 0x0004:
250 /* SHELL_Message
251 ebx virtual maschine handle
252 eax message box flags
253 ecx address of message
254 edi address of caption
255 esi address callback
256 edx reference data for callback
257 return response in eax
259 case 0x0005:
260 VXD_BARF( context, "shell" );
261 break;
263 case 0x0006: /* SHELL_Get_VM_State */
264 TRACE("VxD Shell: returning VM state\n");
265 /* Actually we don't, not yet. We have to return a structure
266 * and I am not to sure how to set it up and return it yet,
267 * so for now let's do nothing. I can (hopefully) get this
268 * by the next release
270 /* RESET_CFLAG(context); */
271 break;
273 case 0x0007:
274 case 0x0008:
275 case 0x0009:
276 case 0x000A:
277 case 0x000B:
278 case 0x000C:
279 case 0x000D:
280 case 0x000E:
281 case 0x000F:
282 case 0x0010:
283 case 0x0011:
284 case 0x0012:
285 case 0x0013:
286 case 0x0014:
287 case 0x0015:
288 case 0x0016:
289 VXD_BARF( context, "SHELL" );
290 break;
292 /* the new Win95 shell API */
293 case 0x0100: /* get version */
294 AX_reg(context) = VXD_WinVersion();
295 break;
297 case 0x0104: /* retrieve Hook_Properties list */
298 case 0x0105: /* call Hook_Properties callbacks */
299 VXD_BARF( context, "SHELL" );
300 break;
302 case 0x0106: /* install timeout callback */
303 TRACE("VxD Shell: ignoring shell callback (%ld sec.)\n", context->Ebx);
304 SET_CFLAG(context);
305 break;
307 case 0x0107: /* get version of any VxD */
308 default:
309 VXD_BARF( context, "SHELL" );
310 break;
315 /***********************************************************************
316 * VXD_Comm
318 void WINAPI VXD_Comm( CONTEXT86 *context )
320 unsigned service = AX_reg(context);
322 TRACE("[%04x] Comm\n", (UINT16)service);
324 switch (service)
326 case 0x0000: /* get version */
327 TRACE("returning version\n");
328 AX_reg(context) = VXD_WinVersion();
329 RESET_CFLAG(context);
330 break;
332 case 0x0001: /* set port global */
333 case 0x0002: /* get focus */
334 case 0x0003: /* virtualise port */
335 default:
336 VXD_BARF( context, "comm" );
340 /***********************************************************************
341 * VXD_Timer
343 void WINAPI VXD_Timer( CONTEXT86 *context )
345 unsigned service = AX_reg(context);
347 TRACE("[%04x] Virtual Timer\n", (UINT16)service);
349 switch(service)
351 case 0x0000: /* version */
352 AX_reg(context) = VXD_WinVersion();
353 RESET_CFLAG(context);
354 break;
356 case 0x0100: /* clock tick time, in 840nsecs */
357 context->Eax = GetTickCount();
359 context->Edx = context->Eax >> 22;
360 context->Eax <<= 10; /* not very precise */
361 break;
363 case 0x0101: /* current Windows time, msecs */
364 case 0x0102: /* current VM time, msecs */
365 context->Eax = GetTickCount();
366 break;
368 default:
369 VXD_BARF( context, "VTD" );
373 /***********************************************************************
374 * VXD_TimerAPI
376 static DWORD System_Time = 0;
377 static WORD System_Time_Selector = 0;
378 static void System_Time_Tick( WORD timer ) { System_Time += 55; }
379 void WINAPI VXD_TimerAPI ( CONTEXT86 *context )
381 unsigned service = AX_reg(context);
383 TRACE("[%04x] TimerAPI\n", (UINT16)service);
385 switch(service)
387 case 0x0000: /* version */
388 AX_reg(context) = VXD_WinVersion();
389 RESET_CFLAG(context);
390 break;
392 case 0x0009: /* get system time selector */
393 if ( !System_Time_Selector )
395 System_Time_Selector = SELECTOR_AllocBlock( &System_Time, sizeof(DWORD), WINE_LDT_FLAGS_DATA );
396 CreateSystemTimer( 55, System_Time_Tick );
399 AX_reg(context) = System_Time_Selector;
400 RESET_CFLAG(context);
401 break;
403 default:
404 VXD_BARF( context, "VTDAPI" );
408 /***********************************************************************
409 * VXD_ConfigMG
411 void WINAPI VXD_ConfigMG ( CONTEXT86 *context )
413 unsigned service = AX_reg(context);
415 TRACE("[%04x] ConfigMG\n", (UINT16)service);
417 switch(service)
419 case 0x0000: /* version */
420 AX_reg(context) = VXD_WinVersion();
421 RESET_CFLAG(context);
422 break;
424 default:
425 VXD_BARF( context, "CONFIGMG" );
429 /***********************************************************************
430 * VXD_Enable
432 void WINAPI VXD_Enable ( CONTEXT86 *context )
434 unsigned service = AX_reg(context);
436 TRACE("[%04x] Enable\n", (UINT16)service);
438 switch(service)
440 case 0x0000: /* version */
441 AX_reg(context) = VXD_WinVersion();
442 RESET_CFLAG(context);
443 break;
445 default:
446 VXD_BARF( context, "ENABLE" );
450 /***********************************************************************
451 * VXD_APM
453 void WINAPI VXD_APM ( CONTEXT86 *context )
455 unsigned service = AX_reg(context);
457 TRACE("[%04x] APM\n", (UINT16)service);
459 switch(service)
461 case 0x0000: /* version */
462 AX_reg(context) = VXD_WinVersion();
463 RESET_CFLAG(context);
464 break;
466 default:
467 VXD_BARF( context, "APM" );
471 /***********************************************************************
472 * VXD_Win32s
474 * This is an implementation of the services of the Win32s VxD.
475 * Since official documentation of these does not seem to be available,
476 * certain arguments of some of the services remain unclear.
478 * FIXME: The following services are currently unimplemented:
479 * Exception handling (0x01, 0x1C)
480 * Debugger support (0x0C, 0x14, 0x17)
481 * Low-level memory access (0x02, 0x03, 0x0A, 0x0B)
482 * Memory Statistics (0x1B)
485 * We have a specific problem running Win32s on Linux (and probably also
486 * the other x86 unixes), since Win32s tries to allocate its main 'flat
487 * code/data segment' selectors with a base of 0xffff0000 (and limit 4GB).
488 * The rationale for this seems to be that they want one the one hand to
489 * be able to leave the Win 3.1 memory (starting with the main DOS memory)
490 * at linear address 0, but want at other hand to have offset 0 of the
491 * flat data/code segment point to an unmapped page (to catch NULL pointer
492 * accesses). Hence they allocate the flat segments with a base of 0xffff0000
493 * so that the Win 3.1 memory area at linear address zero shows up in the
494 * flat segments at offset 0x10000 (since linear addresses wrap around at
495 * 4GB). To compensate for that discrepancy between flat segment offsets
496 * and plain linear addresses, all flat pointers passed between the 32-bit
497 * and the 16-bit parts of Win32s are shifted by 0x10000 in the appropriate
498 * direction by the glue code (mainly) in W32SKRNL and WIN32S16.
500 * The problem for us is now that Linux does not allow a LDT selector with
501 * base 0xffff0000 to be created, since it would 'see' a part of the kernel
502 * address space. To address this problem we introduce *another* offset:
503 * We add 0x10000 to every linear address we get as an argument from Win32s.
504 * This means especially that the flat code/data selectors get actually
505 * allocated with base 0x0, so that flat offsets and (real) linear addresses
506 * do again agree! In fact, every call e.g. of a Win32s VxD service now
507 * has all pointer arguments (which are offsets in the flat data segement)
508 * first reduced by 0x10000 by the W32SKRNL glue code, and then again
509 * increased by 0x10000 by *our* code.
511 * Note that to keep everything consistent, this offset has to be applied by
512 * every Wine function that operates on 'linear addresses' passed to it by
513 * Win32s. Fortunately, since Win32s does not directly call any Wine 32-bit
514 * API routines, this affects only two locations: this VxD and the DPMI
515 * handler. (NOTE: Should any Win32s application pass a linear address to
516 * any routine apart from those, e.g. some other VxD handler, that code
517 * would have to take the offset into account as well!)
519 * The offset is set the first time any application calls the GetVersion()
520 * service of the Win32s VxD. (Note that the offset is never reset.)
524 void WINAPI VXD_Win32s( CONTEXT86 *context )
526 switch (AX_reg(context))
528 case 0x0000: /* Get Version */
530 * Input: None
532 * Output: EAX: LoWord: Win32s Version (1.30)
533 * HiWord: VxD Version (200)
535 * EBX: Build (172)
537 * ECX: ??? (1)
539 * EDX: Debugging Flags
541 * EDI: Error Flag
542 * 0 if OK,
543 * 1 if VMCPD VxD not found
546 TRACE("GetVersion()\n");
548 context->Eax = VXD_WinVersion() | (200 << 16);
549 context->Ebx = 0;
550 context->Ecx = 0;
551 context->Edx = 0;
552 context->Edi = 0;
555 * If this is the first time we are called for this process,
556 * hack the memory image of WIN32S16 so that it doesn't try
557 * to access the GDT directly ...
559 * The first code segment of WIN32S16 (version 1.30) contains
560 * an unexported function somewhere between the exported functions
561 * SetFS and StackLinearToSegmented that tries to find a selector
562 * in the LDT that maps to the memory image of the LDT itself.
563 * If it succeeds, it stores this selector into a global variable
564 * which will be used to speed up execution by using this selector
565 * to modify the LDT directly instead of using the DPMI calls.
567 * To perform this search of the LDT, this function uses the
568 * sgdt and sldt instructions to find the linear address of
569 * the (GDT and then) LDT. While those instructions themselves
570 * execute without problem, the linear address that sgdt returns
571 * points (at least under Linux) to the kernel address space, so
572 * that any subsequent access leads to a segfault.
574 * Fortunately, WIN32S16 still contains as a fallback option the
575 * mechanism of using DPMI calls to modify LDT selectors instead
576 * of direct writes to the LDT. Thus we can circumvent the problem
577 * by simply replacing the first byte of the offending function
578 * with an 'retf' instruction. This means that the global variable
579 * supposed to contain the LDT alias selector will remain zero,
580 * and hence WIN32S16 will fall back to using DPMI calls.
582 * The heuristic we employ to _find_ that function is as follows:
583 * We search between the addresses of the exported symbols SetFS
584 * and StackLinearToSegmented for the byte sequence '0F 01 04'
585 * (this is the opcode of 'sgdt [si]'). We then search backwards
586 * from this address for the last occurrance of 'CB' (retf) that marks
587 * the end of the preceeding function. The following byte (which
588 * should now be the first byte of the function we are looking for)
589 * will be replaced by 'CB' (retf).
591 * This heuristic works for the retail as well as the debug version
592 * of Win32s version 1.30. For versions earlier than that this
593 * hack should not be necessary at all, since the whole mechanism
594 * ('PERF130') was introduced only in 1.30 to improve the overall
595 * performance of Win32s.
598 if (!W32S_offset)
600 HMODULE16 hModule = GetModuleHandle16("win32s16");
601 SEGPTR func1 = (SEGPTR)GetProcAddress16(hModule, "SetFS");
602 SEGPTR func2 = (SEGPTR)GetProcAddress16(hModule, "StackLinearToSegmented");
604 if ( hModule && func1 && func2
605 && SELECTOROF(func1) == SELECTOROF(func2))
607 BYTE *start = MapSL(func1);
608 BYTE *end = MapSL(func2);
609 BYTE *p, *retv = NULL;
610 int found = 0;
612 for (p = start; p < end; p++)
613 if (*p == 0xCB) found = 0, retv = p;
614 else if (*p == 0x0F) found = 1;
615 else if (*p == 0x01 && found == 1) found = 2;
616 else if (*p == 0x04 && found == 2) { found = 3; break; }
617 else found = 0;
619 if (found == 3 && retv)
621 TRACE("PERF130 hack: "
622 "Replacing byte %02X at offset %04X:%04X\n",
623 *(retv+1), SELECTOROF(func1),
624 OFFSETOF(func1) + retv+1-start);
626 *(retv+1) = (BYTE)0xCB;
632 * Mark process as Win32s, so that subsequent DPMI calls
633 * will perform the W32S_APP2WINE/W32S_WINE2APP address shift.
635 W32S_offset = 0x10000;
636 break;
639 case 0x0001: /* Install Exception Handling */
641 * Input: EBX: Flat address of W32SKRNL Exception Data
643 * ECX: LoWord: Flat Code Selector
644 * HiWord: Flat Data Selector
646 * EDX: Flat address of W32SKRNL Exception Handler
647 * (this is equal to W32S_BackTo32 + 0x40)
649 * ESI: SEGPTR KERNEL.HASGPHANDLER
651 * EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10)
653 * Output: EAX: 0 if OK
656 TRACE("[0001] EBX=%lx ECX=%lx EDX=%lx ESI=%lx EDI=%lx\n",
657 context->Ebx, context->Ecx, context->Edx,
658 context->Esi, context->Edi);
660 /* FIXME */
662 context->Eax = 0;
663 break;
666 case 0x0002: /* Set Page Access Flags */
668 * Input: EBX: New access flags
669 * Bit 2: User Page if set, Supervisor Page if clear
670 * Bit 1: Read-Write if set, Read-Only if clear
672 * ECX: Size of memory area to change
674 * EDX: Flat start address of memory area
676 * Output: EAX: Size of area changed
679 TRACE("[0002] EBX=%lx ECX=%lx EDX=%lx\n",
680 context->Ebx, context->Ecx, context->Edx);
682 /* FIXME */
684 context->Eax = context->Ecx;
685 break;
688 case 0x0003: /* Get Page Access Flags */
690 * Input: EDX: Flat address of page to query
692 * Output: EAX: Page access flags
693 * Bit 2: User Page if set, Supervisor Page if clear
694 * Bit 1: Read-Write if set, Read-Only if clear
697 TRACE("[0003] EDX=%lx\n", context->Edx);
699 /* FIXME */
701 context->Eax = 6;
702 break;
705 case 0x0004: /* Map Module */
707 * Input: ECX: IMTE (offset in Module Table) of new module
709 * EDX: Flat address of Win32s Module Table
711 * Output: EAX: 0 if OK
714 if (!context->Edx || CX_reg(context) == 0xFFFF)
716 TRACE("MapModule: Initialization call\n");
717 context->Eax = 0;
719 else
722 * Structure of a Win32s Module Table Entry:
724 struct Win32sModule
726 DWORD flags;
727 DWORD flatBaseAddr;
728 LPCSTR moduleName;
729 LPCSTR pathName;
730 LPCSTR unknown;
731 LPBYTE baseAddr;
732 DWORD hModule;
733 DWORD relocDelta;
737 * Note: This function should set up a demand-paged memory image
738 * of the given module. Since mmap does not allow file offsets
739 * not aligned at 1024 bytes, we simply load the image fully
740 * into memory.
743 struct Win32sModule *moduleTable =
744 (struct Win32sModule *)W32S_APP2WINE(context->Edx);
745 struct Win32sModule *module = moduleTable + context->Ecx;
747 IMAGE_NT_HEADERS *nt_header = PE_HEADER(module->baseAddr);
748 IMAGE_SECTION_HEADER *pe_seg = PE_SECTIONS(module->baseAddr);
750 HFILE image = _lopen(module->pathName, OF_READ);
751 BOOL error = (image == HFILE_ERROR);
752 UINT i;
754 TRACE("MapModule: Loading %s\n", module->pathName);
756 for (i = 0;
757 !error && i < nt_header->FileHeader.NumberOfSections;
758 i++, pe_seg++)
759 if(!(pe_seg->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA))
761 DWORD off = pe_seg->PointerToRawData;
762 DWORD len = pe_seg->SizeOfRawData;
763 LPBYTE addr = module->baseAddr + pe_seg->VirtualAddress;
765 TRACE("MapModule: "
766 "Section %d at %08lx from %08lx len %08lx\n",
767 i, (DWORD)addr, off, len);
769 if ( _llseek(image, off, SEEK_SET) != off
770 || _lread(image, addr, len) != len)
771 error = TRUE;
774 _lclose(image);
776 if (error)
777 ERR("MapModule: Unable to load %s\n", module->pathName);
779 else if (module->relocDelta != 0)
781 IMAGE_DATA_DIRECTORY *dir = nt_header->OptionalHeader.DataDirectory
782 + IMAGE_DIRECTORY_ENTRY_BASERELOC;
783 IMAGE_BASE_RELOCATION *r = (IMAGE_BASE_RELOCATION *)
784 (dir->Size? module->baseAddr + dir->VirtualAddress : 0);
786 TRACE("MapModule: Reloc delta %08lx\n", module->relocDelta);
788 while (r && r->VirtualAddress)
790 LPBYTE page = module->baseAddr + r->VirtualAddress;
791 int count = (r->SizeOfBlock - 8) / 2;
793 TRACE("MapModule: %d relocations for page %08lx\n",
794 count, (DWORD)page);
796 for(i = 0; i < count; i++)
798 int offset = r->TypeOffset[i] & 0xFFF;
799 int type = r->TypeOffset[i] >> 12;
800 switch(type)
802 case IMAGE_REL_BASED_ABSOLUTE:
803 break;
804 case IMAGE_REL_BASED_HIGH:
805 *(WORD *)(page+offset) += HIWORD(module->relocDelta);
806 break;
807 case IMAGE_REL_BASED_LOW:
808 *(WORD *)(page+offset) += LOWORD(module->relocDelta);
809 break;
810 case IMAGE_REL_BASED_HIGHLOW:
811 *(DWORD*)(page+offset) += module->relocDelta;
812 break;
813 default:
814 WARN("MapModule: Unsupported fixup type\n");
815 break;
819 r = (IMAGE_BASE_RELOCATION *)((LPBYTE)r + r->SizeOfBlock);
823 context->Eax = 0;
824 RESET_CFLAG(context);
826 break;
829 case 0x0005: /* UnMap Module */
831 * Input: EDX: Flat address of module image
833 * Output: EAX: 1 if OK
836 TRACE("UnMapModule: %lx\n", (DWORD)W32S_APP2WINE(context->Edx));
838 /* As we didn't map anything, there's nothing to unmap ... */
840 context->Eax = 1;
841 break;
844 case 0x0006: /* VirtualAlloc */
846 * Input: ECX: Current Process
848 * EDX: Flat address of arguments on stack
850 * DWORD *retv [out] Flat base address of allocated region
851 * LPVOID base [in] Flat address of region to reserve/commit
852 * DWORD size [in] Size of region
853 * DWORD type [in] Type of allocation
854 * DWORD prot [in] Type of access protection
856 * Output: EAX: NtStatus
859 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
860 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
861 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
862 DWORD size = stack[2];
863 DWORD type = stack[3];
864 DWORD prot = stack[4];
865 DWORD result;
867 TRACE("VirtualAlloc(%lx, %lx, %lx, %lx, %lx)\n",
868 (DWORD)retv, (DWORD)base, size, type, prot);
870 if (type & 0x80000000)
872 WARN("VirtualAlloc: strange type %lx\n", type);
873 type &= 0x7fffffff;
876 if (!base && (type & MEM_COMMIT) && prot == PAGE_READONLY)
878 WARN("VirtualAlloc: NLS hack, allowing write access!\n");
879 prot = PAGE_READWRITE;
882 result = (DWORD)VirtualAlloc(base, size, type, prot);
884 if (W32S_WINE2APP(result))
885 *retv = W32S_WINE2APP(result),
886 context->Eax = STATUS_SUCCESS;
887 else
888 *retv = 0,
889 context->Eax = STATUS_NO_MEMORY; /* FIXME */
891 break;
894 case 0x0007: /* VirtualFree */
896 * Input: ECX: Current Process
898 * EDX: Flat address of arguments on stack
900 * DWORD *retv [out] TRUE if success, FALSE if failure
901 * LPVOID base [in] Flat address of region
902 * DWORD size [in] Size of region
903 * DWORD type [in] Type of operation
905 * Output: EAX: NtStatus
908 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
909 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
910 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
911 DWORD size = stack[2];
912 DWORD type = stack[3];
913 DWORD result;
915 TRACE("VirtualFree(%lx, %lx, %lx, %lx)\n",
916 (DWORD)retv, (DWORD)base, size, type);
918 result = VirtualFree(base, size, type);
920 if (result)
921 *retv = TRUE,
922 context->Eax = STATUS_SUCCESS;
923 else
924 *retv = FALSE,
925 context->Eax = STATUS_NO_MEMORY; /* FIXME */
927 break;
930 case 0x0008: /* VirtualProtect */
932 * Input: ECX: Current Process
934 * EDX: Flat address of arguments on stack
936 * DWORD *retv [out] TRUE if success, FALSE if failure
937 * LPVOID base [in] Flat address of region
938 * DWORD size [in] Size of region
939 * DWORD new_prot [in] Desired access protection
940 * DWORD *old_prot [out] Previous access protection
942 * Output: EAX: NtStatus
945 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
946 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
947 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
948 DWORD size = stack[2];
949 DWORD new_prot = stack[3];
950 DWORD *old_prot = (DWORD *)W32S_APP2WINE(stack[4]);
951 DWORD result;
953 TRACE("VirtualProtect(%lx, %lx, %lx, %lx, %lx)\n",
954 (DWORD)retv, (DWORD)base, size, new_prot, (DWORD)old_prot);
956 result = VirtualProtect(base, size, new_prot, old_prot);
958 if (result)
959 *retv = TRUE,
960 context->Eax = STATUS_SUCCESS;
961 else
962 *retv = FALSE,
963 context->Eax = STATUS_NO_MEMORY; /* FIXME */
965 break;
968 case 0x0009: /* VirtualQuery */
970 * Input: ECX: Current Process
972 * EDX: Flat address of arguments on stack
974 * DWORD *retv [out] Nr. bytes returned
975 * LPVOID base [in] Flat address of region
976 * LPMEMORY_BASIC_INFORMATION info [out] Info buffer
977 * DWORD len [in] Size of buffer
979 * Output: EAX: NtStatus
982 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
983 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
984 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
985 LPMEMORY_BASIC_INFORMATION info =
986 (LPMEMORY_BASIC_INFORMATION)W32S_APP2WINE(stack[2]);
987 DWORD len = stack[3];
988 DWORD result;
990 TRACE("VirtualQuery(%lx, %lx, %lx, %lx)\n",
991 (DWORD)retv, (DWORD)base, (DWORD)info, len);
993 result = VirtualQuery(base, info, len);
995 *retv = result;
996 context->Eax = STATUS_SUCCESS;
998 break;
1001 case 0x000A: /* SetVirtMemProcess */
1003 * Input: ECX: Process Handle
1005 * EDX: Flat address of region
1007 * Output: EAX: NtStatus
1010 TRACE("[000a] ECX=%lx EDX=%lx\n",
1011 context->Ecx, context->Edx);
1013 /* FIXME */
1015 context->Eax = STATUS_SUCCESS;
1016 break;
1019 case 0x000B: /* ??? some kind of cleanup */
1021 * Input: ECX: Process Handle
1023 * Output: EAX: NtStatus
1026 TRACE("[000b] ECX=%lx\n", context->Ecx);
1028 /* FIXME */
1030 context->Eax = STATUS_SUCCESS;
1031 break;
1034 case 0x000C: /* Set Debug Flags */
1036 * Input: EDX: Debug Flags
1038 * Output: EDX: Previous Debug Flags
1041 FIXME("[000c] EDX=%lx\n", context->Edx);
1043 /* FIXME */
1045 context->Edx = 0;
1046 break;
1049 case 0x000D: /* NtCreateSection */
1051 * Input: EDX: Flat address of arguments on stack
1053 * HANDLE32 *retv [out] Handle of Section created
1054 * DWORD flags1 [in] (?? unknown ??)
1055 * DWORD atom [in] Name of Section to create
1056 * LARGE_INTEGER *size [in] Size of Section
1057 * DWORD protect [in] Access protection
1058 * DWORD flags2 [in] (?? unknown ??)
1059 * HFILE32 hFile [in] Handle of file to map
1060 * DWORD psp [in] (Win32s: PSP that hFile belongs to)
1062 * Output: EAX: NtStatus
1065 DWORD *stack = (DWORD *) W32S_APP2WINE(context->Edx);
1066 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]);
1067 DWORD flags1 = stack[1];
1068 DWORD atom = stack[2];
1069 LARGE_INTEGER *size = (LARGE_INTEGER *)W32S_APP2WINE(stack[3]);
1070 DWORD protect = stack[4];
1071 DWORD flags2 = stack[5];
1072 HANDLE hFile = DosFileHandleToWin32Handle(stack[6]);
1073 DWORD psp = stack[7];
1075 HANDLE result = INVALID_HANDLE_VALUE;
1076 char name[128];
1078 TRACE("NtCreateSection(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1079 (DWORD)retv, flags1, atom, (DWORD)size, protect, flags2,
1080 (DWORD)hFile, psp);
1082 if (!atom || GlobalGetAtomNameA(atom, name, sizeof(name)))
1084 TRACE("NtCreateSection: name=%s\n", atom? name : NULL);
1086 result = CreateFileMappingA(hFile, NULL, protect,
1087 size? size->s.HighPart : 0,
1088 size? size->s.LowPart : 0,
1089 atom? name : NULL);
1092 if (result == INVALID_HANDLE_VALUE)
1093 WARN("NtCreateSection: failed!\n");
1094 else
1095 TRACE("NtCreateSection: returned %lx\n", (DWORD)result);
1097 if (result != INVALID_HANDLE_VALUE)
1098 *retv = result,
1099 context->Eax = STATUS_SUCCESS;
1100 else
1101 *retv = result,
1102 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1104 break;
1107 case 0x000E: /* NtOpenSection */
1109 * Input: EDX: Flat address of arguments on stack
1111 * HANDLE32 *retv [out] Handle of Section opened
1112 * DWORD protect [in] Access protection
1113 * DWORD atom [in] Name of Section to create
1115 * Output: EAX: NtStatus
1118 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1119 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]);
1120 DWORD protect = stack[1];
1121 DWORD atom = stack[2];
1123 HANDLE result = INVALID_HANDLE_VALUE;
1124 char name[128];
1126 TRACE("NtOpenSection(%lx, %lx, %lx)\n",
1127 (DWORD)retv, protect, atom);
1129 if (atom && GlobalGetAtomNameA(atom, name, sizeof(name)))
1131 TRACE("NtOpenSection: name=%s\n", name);
1133 result = OpenFileMappingA(protect, FALSE, name);
1136 if (result == INVALID_HANDLE_VALUE)
1137 WARN("NtOpenSection: failed!\n");
1138 else
1139 TRACE("NtOpenSection: returned %lx\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 0x000F: /* NtCloseSection */
1153 * Input: EDX: Flat address of arguments on stack
1155 * HANDLE32 handle [in] Handle of Section to close
1156 * DWORD *id [out] Unique ID (?? unclear ??)
1158 * Output: EAX: NtStatus
1161 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1162 HANDLE handle = stack[0];
1163 DWORD *id = (DWORD *)W32S_APP2WINE(stack[1]);
1165 TRACE("NtCloseSection(%lx, %lx)\n", (DWORD)handle, (DWORD)id);
1167 CloseHandle(handle);
1168 if (id) *id = 0; /* FIXME */
1170 context->Eax = STATUS_SUCCESS;
1172 break;
1175 case 0x0010: /* NtDupSection */
1177 * Input: EDX: Flat address of arguments on stack
1179 * HANDLE32 handle [in] Handle of Section to duplicate
1181 * Output: EAX: NtStatus
1184 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1185 HANDLE handle = stack[0];
1186 HANDLE new_handle;
1188 TRACE("NtDupSection(%lx)\n", (DWORD)handle);
1190 DuplicateHandle( GetCurrentProcess(), handle,
1191 GetCurrentProcess(), &new_handle,
1192 0, FALSE, DUPLICATE_SAME_ACCESS );
1193 context->Eax = STATUS_SUCCESS;
1195 break;
1198 case 0x0011: /* NtMapViewOfSection */
1200 * Input: EDX: Flat address of arguments on stack
1202 * HANDLE32 SectionHandle [in] Section to be mapped
1203 * DWORD ProcessHandle [in] Process to be mapped into
1204 * DWORD * BaseAddress [in/out] Address to be mapped at
1205 * DWORD ZeroBits [in] (?? unclear ??)
1206 * DWORD CommitSize [in] (?? unclear ??)
1207 * LARGE_INTEGER *SectionOffset [in] Offset within section
1208 * DWORD * ViewSize [in] Size of view
1209 * DWORD InheritDisposition [in] (?? unclear ??)
1210 * DWORD AllocationType [in] (?? unclear ??)
1211 * DWORD Protect [in] Access protection
1213 * Output: EAX: NtStatus
1216 DWORD * stack = (DWORD *)W32S_APP2WINE(context->Edx);
1217 HANDLE SectionHandle = stack[0];
1218 DWORD ProcessHandle = stack[1]; /* ignored */
1219 DWORD * BaseAddress = (DWORD *)W32S_APP2WINE(stack[2]);
1220 DWORD ZeroBits = stack[3];
1221 DWORD CommitSize = stack[4];
1222 LARGE_INTEGER *SectionOffset = (LARGE_INTEGER *)W32S_APP2WINE(stack[5]);
1223 DWORD * ViewSize = (DWORD *)W32S_APP2WINE(stack[6]);
1224 DWORD InheritDisposition = stack[7];
1225 DWORD AllocationType = stack[8];
1226 DWORD Protect = stack[9];
1228 LPBYTE address = (LPBYTE)(BaseAddress?
1229 W32S_APP2WINE(*BaseAddress) : 0);
1230 DWORD access = 0, result;
1232 switch (Protect & ~(PAGE_GUARD|PAGE_NOCACHE))
1234 case PAGE_READONLY: access = FILE_MAP_READ; break;
1235 case PAGE_READWRITE: access = FILE_MAP_WRITE; break;
1236 case PAGE_WRITECOPY: access = FILE_MAP_COPY; break;
1238 case PAGE_EXECUTE_READ: access = FILE_MAP_READ; break;
1239 case PAGE_EXECUTE_READWRITE: access = FILE_MAP_WRITE; break;
1240 case PAGE_EXECUTE_WRITECOPY: access = FILE_MAP_COPY; break;
1243 TRACE("NtMapViewOfSection"
1244 "(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1245 (DWORD)SectionHandle, ProcessHandle, (DWORD)BaseAddress,
1246 ZeroBits, CommitSize, (DWORD)SectionOffset, (DWORD)ViewSize,
1247 InheritDisposition, AllocationType, Protect);
1248 TRACE("NtMapViewOfSection: "
1249 "base=%lx, offset=%lx, size=%lx, access=%lx\n",
1250 (DWORD)address, SectionOffset? SectionOffset->s.LowPart : 0,
1251 ViewSize? *ViewSize : 0, access);
1253 result = (DWORD)MapViewOfFileEx(SectionHandle, access,
1254 SectionOffset? SectionOffset->s.HighPart : 0,
1255 SectionOffset? SectionOffset->s.LowPart : 0,
1256 ViewSize? *ViewSize : 0, address);
1258 TRACE("NtMapViewOfSection: result=%lx\n", result);
1260 if (W32S_WINE2APP(result))
1262 if (BaseAddress) *BaseAddress = W32S_WINE2APP(result);
1263 context->Eax = STATUS_SUCCESS;
1265 else
1266 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1268 break;
1271 case 0x0012: /* NtUnmapViewOfSection */
1273 * Input: EDX: Flat address of arguments on stack
1275 * DWORD ProcessHandle [in] Process (defining address space)
1276 * LPBYTE BaseAddress [in] Base address of view to be unmapped
1278 * Output: EAX: NtStatus
1281 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1282 DWORD ProcessHandle = stack[0]; /* ignored */
1283 LPBYTE BaseAddress = (LPBYTE)W32S_APP2WINE(stack[1]);
1285 TRACE("NtUnmapViewOfSection(%lx, %lx)\n",
1286 ProcessHandle, (DWORD)BaseAddress);
1288 UnmapViewOfFile(BaseAddress);
1290 context->Eax = STATUS_SUCCESS;
1292 break;
1295 case 0x0013: /* NtFlushVirtualMemory */
1297 * Input: EDX: Flat address of arguments on stack
1299 * DWORD ProcessHandle [in] Process (defining address space)
1300 * LPBYTE *BaseAddress [in?] Base address of range to be flushed
1301 * DWORD *ViewSize [in?] Number of bytes to be flushed
1302 * DWORD *unknown [???] (?? unknown ??)
1304 * Output: EAX: NtStatus
1307 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1308 DWORD ProcessHandle = stack[0]; /* ignored */
1309 DWORD *BaseAddress = (DWORD *)W32S_APP2WINE(stack[1]);
1310 DWORD *ViewSize = (DWORD *)W32S_APP2WINE(stack[2]);
1311 DWORD *unknown = (DWORD *)W32S_APP2WINE(stack[3]);
1313 LPBYTE address = (LPBYTE)(BaseAddress? W32S_APP2WINE(*BaseAddress) : 0);
1314 DWORD size = ViewSize? *ViewSize : 0;
1316 TRACE("NtFlushVirtualMemory(%lx, %lx, %lx, %lx)\n",
1317 ProcessHandle, (DWORD)BaseAddress, (DWORD)ViewSize,
1318 (DWORD)unknown);
1319 TRACE("NtFlushVirtualMemory: base=%lx, size=%lx\n",
1320 (DWORD)address, size);
1322 FlushViewOfFile(address, size);
1324 context->Eax = STATUS_SUCCESS;
1326 break;
1329 case 0x0014: /* Get/Set Debug Registers */
1331 * Input: ECX: 0 if Get, 1 if Set
1333 * EDX: Get: Flat address of buffer to receive values of
1334 * debug registers DR0 .. DR7
1335 * Set: Flat address of buffer containing values of
1336 * debug registers DR0 .. DR7 to be set
1337 * Output: None
1340 FIXME("[0014] ECX=%lx EDX=%lx\n",
1341 context->Ecx, context->Edx);
1343 /* FIXME */
1344 break;
1347 case 0x0015: /* Set Coprocessor Emulation Flag */
1349 * Input: EDX: 0 to deactivate, 1 to activate coprocessor emulation
1351 * Output: None
1354 TRACE("[0015] EDX=%lx\n", context->Edx);
1356 /* We don't care, as we always have a coprocessor anyway */
1357 break;
1360 case 0x0016: /* Init Win32S VxD PSP */
1362 * If called to query required PSP size:
1364 * Input: EBX: 0
1365 * Output: EDX: Required size of Win32s VxD PSP
1367 * If called to initialize allocated PSP:
1369 * Input: EBX: LoWord: Selector of Win32s VxD PSP
1370 * HiWord: Paragraph of Win32s VxD PSP (DOSMEM)
1371 * Output: None
1374 if (context->Ebx == 0)
1375 context->Edx = 0x80;
1376 else
1378 PDB16 *psp = MapSL( MAKESEGPTR( BX_reg(context), 0 ));
1379 psp->nbFiles = 32;
1380 psp->fileHandlesPtr = MAKELONG(HIWORD(context->Ebx), 0x5c);
1381 memset((LPBYTE)psp + 0x5c, '\xFF', 32);
1383 break;
1386 case 0x0017: /* Set Break Point */
1388 * Input: EBX: Offset of Break Point
1389 * CX: Selector of Break Point
1391 * Output: None
1394 FIXME("[0017] EBX=%lx CX=%x\n",
1395 context->Ebx, CX_reg(context));
1397 /* FIXME */
1398 break;
1401 case 0x0018: /* VirtualLock */
1403 * Input: ECX: Current Process
1405 * EDX: Flat address of arguments on stack
1407 * DWORD *retv [out] TRUE if success, FALSE if failure
1408 * LPVOID base [in] Flat address of range to lock
1409 * DWORD size [in] Size of range
1411 * Output: EAX: NtStatus
1414 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1415 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1416 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1417 DWORD size = stack[2];
1418 DWORD result;
1420 TRACE("VirtualLock(%lx, %lx, %lx)\n",
1421 (DWORD)retv, (DWORD)base, size);
1423 result = VirtualLock(base, size);
1425 if (result)
1426 *retv = TRUE,
1427 context->Eax = STATUS_SUCCESS;
1428 else
1429 *retv = FALSE,
1430 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1432 break;
1435 case 0x0019: /* VirtualUnlock */
1437 * Input: ECX: Current Process
1439 * EDX: Flat address of arguments on stack
1441 * DWORD *retv [out] TRUE if success, FALSE if failure
1442 * LPVOID base [in] Flat address of range to unlock
1443 * DWORD size [in] Size of range
1445 * Output: EAX: NtStatus
1448 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1449 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1450 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1451 DWORD size = stack[2];
1452 DWORD result;
1454 TRACE("VirtualUnlock(%lx, %lx, %lx)\n",
1455 (DWORD)retv, (DWORD)base, size);
1457 result = VirtualUnlock(base, size);
1459 if (result)
1460 *retv = TRUE,
1461 context->Eax = STATUS_SUCCESS;
1462 else
1463 *retv = FALSE,
1464 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1466 break;
1469 case 0x001A: /* KGetSystemInfo */
1471 * Input: None
1473 * Output: ECX: Start of sparse memory arena
1474 * EDX: End of sparse memory arena
1477 TRACE("KGetSystemInfo()\n");
1480 * Note: Win32s reserves 0GB - 2GB for Win 3.1 and uses 2GB - 4GB as
1481 * sparse memory arena. We do it the other way around, since
1482 * we have to reserve 3GB - 4GB for Linux, and thus use
1483 * 0GB - 3GB as sparse memory arena.
1485 * FIXME: What about other OSes ?
1488 context->Ecx = W32S_WINE2APP(0x00000000);
1489 context->Edx = W32S_WINE2APP(0xbfffffff);
1490 break;
1493 case 0x001B: /* KGlobalMemStat */
1495 * Input: ESI: Flat address of buffer to receive memory info
1497 * Output: None
1500 struct Win32sMemoryInfo
1502 DWORD DIPhys_Count; /* Total physical pages */
1503 DWORD DIFree_Count; /* Free physical pages */
1504 DWORD DILin_Total_Count; /* Total virtual pages (private arena) */
1505 DWORD DILin_Total_Free; /* Free virtual pages (private arena) */
1507 DWORD SparseTotal; /* Total size of sparse arena (bytes ?) */
1508 DWORD SparseFree; /* Free size of sparse arena (bytes ?) */
1511 struct Win32sMemoryInfo *info =
1512 (struct Win32sMemoryInfo *)W32S_APP2WINE(context->Esi);
1514 FIXME("KGlobalMemStat(%lx)\n", (DWORD)info);
1516 /* FIXME */
1518 break;
1521 case 0x001C: /* Enable/Disable Exceptions */
1523 * Input: ECX: 0 to disable, 1 to enable exception handling
1525 * Output: None
1528 TRACE("[001c] ECX=%lx\n", context->Ecx);
1530 /* FIXME */
1531 break;
1534 case 0x001D: /* VirtualAlloc called from 16-bit code */
1536 * Input: EDX: Segmented address of arguments on stack
1538 * LPVOID base [in] Flat address of region to reserve/commit
1539 * DWORD size [in] Size of region
1540 * DWORD type [in] Type of allocation
1541 * DWORD prot [in] Type of access protection
1543 * Output: EAX: NtStatus
1544 * EDX: Flat base address of allocated region
1547 DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) ));
1548 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]);
1549 DWORD size = stack[1];
1550 DWORD type = stack[2];
1551 DWORD prot = stack[3];
1552 DWORD result;
1554 TRACE("VirtualAlloc16(%lx, %lx, %lx, %lx)\n",
1555 (DWORD)base, size, type, prot);
1557 if (type & 0x80000000)
1559 WARN("VirtualAlloc16: strange type %lx\n", type);
1560 type &= 0x7fffffff;
1563 result = (DWORD)VirtualAlloc(base, size, type, prot);
1565 if (W32S_WINE2APP(result))
1566 context->Edx = W32S_WINE2APP(result),
1567 context->Eax = STATUS_SUCCESS;
1568 else
1569 context->Edx = 0,
1570 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1571 TRACE("VirtualAlloc16: returning base %lx\n", context->Edx);
1573 break;
1576 case 0x001E: /* VirtualFree called from 16-bit code */
1578 * Input: EDX: Segmented address of arguments on stack
1580 * LPVOID base [in] Flat address of region
1581 * DWORD size [in] Size of region
1582 * DWORD type [in] Type of operation
1584 * Output: EAX: NtStatus
1585 * EDX: TRUE if success, FALSE if failure
1588 DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) ));
1589 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]);
1590 DWORD size = stack[1];
1591 DWORD type = stack[2];
1592 DWORD result;
1594 TRACE("VirtualFree16(%lx, %lx, %lx)\n",
1595 (DWORD)base, size, type);
1597 result = VirtualFree(base, size, type);
1599 if (result)
1600 context->Edx = TRUE,
1601 context->Eax = STATUS_SUCCESS;
1602 else
1603 context->Edx = FALSE,
1604 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1606 break;
1609 case 0x001F: /* FWorkingSetSize */
1611 * Input: EDX: 0 if Get, 1 if Set
1613 * ECX: Get: Buffer to receive Working Set Size
1614 * Set: Buffer containing Working Set Size
1616 * Output: NtStatus
1619 DWORD *ptr = (DWORD *)W32S_APP2WINE(context->Ecx);
1620 BOOL set = context->Edx;
1622 TRACE("FWorkingSetSize(%lx, %lx)\n", (DWORD)ptr, (DWORD)set);
1624 if (set)
1625 /* We do it differently ... */;
1626 else
1627 *ptr = 0x100;
1629 context->Eax = STATUS_SUCCESS;
1631 break;
1634 default:
1635 VXD_BARF( context, "W32S" );