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
22 #include "wine/port.h"
28 #include <sys/types.h>
33 #define NONAMELESSUNION
34 #define NONAMELESSSTRUCT
42 #include "wine/winbase16.h"
43 #include "wine/winuser16.h"
46 #include "selectors.h"
49 #include "wine/debug.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(vxd
);
53 #define W32S_APP2WINE(addr) ((addr)? (DWORD)(addr) + W32S_offset : 0)
54 #define W32S_WINE2APP(addr) ((addr)? (DWORD)(addr) - W32S_offset : 0)
56 #define VXD_BARF(context,name) \
57 DPRINTF( "vxd %s: unknown/not implemented parameters:\n" \
58 "vxd %s: AX %04x, BX %04x, CX %04x, DX %04x, " \
59 "SI %04x, DI %04x, DS %04x, ES %04x\n", \
60 (name), (name), AX_reg(context), BX_reg(context), \
61 CX_reg(context), DX_reg(context), SI_reg(context), \
62 DI_reg(context), (WORD)context->SegDs, (WORD)context->SegEs )
66 static WORD
VXD_WinVersion(void)
68 WORD version
= LOWORD(GetVersion16());
69 return (version
>> 8) | (version
<< 8);
72 /***********************************************************************
73 * VXD_VMM (WPROCS.401)
75 void WINAPI
VXD_VMM ( CONTEXT86
*context
)
77 unsigned service
= AX_reg(context
);
79 TRACE("[%04x] VMM\n", (UINT16
)service
);
83 case 0x0000: /* version */
84 SET_AX( context
, VXD_WinVersion() );
88 case 0x026d: /* Get_Debug_Flag '/m' */
89 case 0x026e: /* Get_Debug_Flag '/n' */
95 VXD_BARF( context
, "VMM" );
99 /***********************************************************************
100 * VXD_PageFile (WPROCS.433)
102 void WINAPI
VXD_PageFile( CONTEXT86
*context
)
104 unsigned service
= AX_reg(context
);
106 /* taken from Ralf Brown's Interrupt List */
108 TRACE("[%04x] PageFile\n", (UINT16
)service
);
112 case 0x00: /* get version, is this windows version? */
113 TRACE("returning version\n");
114 SET_AX( context
, VXD_WinVersion() );
115 RESET_CFLAG(context
);
118 case 0x01: /* get swap file info */
119 TRACE("VxD PageFile: returning swap file info\n");
120 SET_AX( context
, 0x00 ); /* paging disabled */
121 context
->Ecx
= 0; /* maximum size of paging file */
122 /* FIXME: do I touch DS:SI or DS:DI? */
123 RESET_CFLAG(context
);
126 case 0x02: /* delete permanent swap on exit */
127 TRACE("VxD PageFile: supposed to delete swap\n");
128 RESET_CFLAG(context
);
131 case 0x03: /* current temporary swap file size */
132 TRACE("VxD PageFile: what is current temp. swap size\n");
133 RESET_CFLAG(context
);
136 case 0x04: /* read or write?? INTERRUP.D */
137 case 0x05: /* cancel?? INTERRUP.D */
138 case 0x06: /* test I/O valid INTERRUP.D */
140 VXD_BARF( context
, "pagefile" );
145 /***********************************************************************
146 * VXD_Reboot (WPROCS.409)
148 void WINAPI
VXD_Reboot ( CONTEXT86
*context
)
150 unsigned service
= AX_reg(context
);
152 TRACE("[%04x] Reboot\n", (UINT16
)service
);
156 case 0x0000: /* version */
157 SET_AX( context
, VXD_WinVersion() );
158 RESET_CFLAG(context
);
162 VXD_BARF( context
, "REBOOT" );
166 /***********************************************************************
167 * VXD_VDD (WPROCS.410)
169 void WINAPI
VXD_VDD ( CONTEXT86
*context
)
171 unsigned service
= AX_reg(context
);
173 TRACE("[%04x] VDD\n", (UINT16
)service
);
177 case 0x0000: /* version */
178 SET_AX( context
, VXD_WinVersion() );
179 RESET_CFLAG(context
);
183 VXD_BARF( context
, "VDD" );
187 /***********************************************************************
188 * VXD_VMD (WPROCS.412)
190 void WINAPI
VXD_VMD ( CONTEXT86
*context
)
192 unsigned service
= AX_reg(context
);
194 TRACE("[%04x] VMD\n", (UINT16
)service
);
198 case 0x0000: /* version */
199 SET_AX( context
, VXD_WinVersion() );
200 RESET_CFLAG(context
);
204 VXD_BARF( context
, "VMD" );
208 /***********************************************************************
209 * VXD_VXDLoader (WPROCS.439)
211 void WINAPI
VXD_VXDLoader( CONTEXT86
*context
)
213 unsigned service
= AX_reg(context
);
215 TRACE("[%04x] VXDLoader\n", (UINT16
)service
);
219 case 0x0000: /* get version */
220 TRACE("returning version\n");
221 SET_AX( context
, 0x0000 );
222 SET_DX( context
, VXD_WinVersion() );
223 RESET_CFLAG(context
);
226 case 0x0001: /* load device */
227 FIXME("load device %04lx:%04x (%s)\n",
228 context
->SegDs
, DX_reg(context
),
229 debugstr_a(MapSL(MAKESEGPTR(context
->SegDs
, DX_reg(context
)))));
230 SET_AX( context
, 0x0000 );
231 context
->SegEs
= 0x0000;
232 SET_DI( context
, 0x0000 );
233 RESET_CFLAG(context
);
236 case 0x0002: /* unload device */
237 FIXME("unload device (%08lx)\n", context
->Ebx
);
238 SET_AX( context
, 0x0000 );
239 RESET_CFLAG(context
);
243 VXD_BARF( context
, "VXDLDR" );
244 SET_AX( context
, 0x000B ); /* invalid function number */
250 /***********************************************************************
251 * VXD_Shell (WPROCS.423)
253 void WINAPI
VXD_Shell( CONTEXT86
*context
)
255 unsigned service
= DX_reg(context
);
257 TRACE("[%04x] Shell\n", (UINT16
)service
);
259 switch (service
) /* Ralf Brown says EDX, but I use DX instead */
262 TRACE("returning version\n");
263 SET_AX( context
, VXD_WinVersion() );
264 context
->Ebx
= 1; /* system VM Handle */
270 /* SHELL_SYSMODAL_Message
271 ebx virtual maschine handle
272 eax message box flags
273 ecx address of message
274 edi address of caption
275 return response in eax
279 ebx virtual maschine handle
280 eax message box flags
281 ecx address of message
282 edi address of caption
284 edx reference data for callback
285 return response in eax
288 VXD_BARF( context
, "shell" );
291 case 0x0006: /* SHELL_Get_VM_State */
292 TRACE("VxD Shell: returning VM state\n");
293 /* Actually we don't, not yet. We have to return a structure
294 * and I am not to sure how to set it up and return it yet,
295 * so for now let's do nothing. I can (hopefully) get this
296 * by the next release
298 /* RESET_CFLAG(context); */
317 VXD_BARF( context
, "SHELL" );
320 /* the new Win95 shell API */
321 case 0x0100: /* get version */
322 SET_AX( context
, VXD_WinVersion() );
325 case 0x0104: /* retrieve Hook_Properties list */
326 case 0x0105: /* call Hook_Properties callbacks */
327 VXD_BARF( context
, "SHELL" );
330 case 0x0106: /* install timeout callback */
331 TRACE("VxD Shell: ignoring shell callback (%ld sec.)\n", context
->Ebx
);
335 case 0x0107: /* get version of any VxD */
337 VXD_BARF( context
, "SHELL" );
343 /***********************************************************************
344 * VXD_Comm (WPROCS.414)
346 void WINAPI
VXD_Comm( CONTEXT86
*context
)
348 unsigned service
= AX_reg(context
);
350 TRACE("[%04x] Comm\n", (UINT16
)service
);
354 case 0x0000: /* get version */
355 TRACE("returning version\n");
356 SET_AX( context
, VXD_WinVersion() );
357 RESET_CFLAG(context
);
360 case 0x0001: /* set port global */
361 case 0x0002: /* get focus */
362 case 0x0003: /* virtualise port */
364 VXD_BARF( context
, "comm" );
368 /***********************************************************************
369 * VXD_Timer (WPROCS.405)
371 void WINAPI
VXD_Timer( CONTEXT86
*context
)
373 unsigned service
= AX_reg(context
);
375 TRACE("[%04x] Virtual Timer\n", (UINT16
)service
);
379 case 0x0000: /* version */
380 SET_AX( context
, VXD_WinVersion() );
381 RESET_CFLAG(context
);
384 case 0x0100: /* clock tick time, in 840nsecs */
385 context
->Eax
= GetTickCount();
387 context
->Edx
= context
->Eax
>> 22;
388 context
->Eax
<<= 10; /* not very precise */
391 case 0x0101: /* current Windows time, msecs */
392 case 0x0102: /* current VM time, msecs */
393 context
->Eax
= GetTickCount();
397 VXD_BARF( context
, "VTD" );
402 /***********************************************************************
405 static DWORD CALLBACK
timer_thread( void *arg
)
407 DWORD
*system_time
= arg
;
411 *system_time
= GetTickCount();
417 /***********************************************************************
418 * VXD_TimerAPI (WPROCS.1490)
420 void WINAPI
VXD_TimerAPI ( CONTEXT86
*context
)
422 static WORD System_Time_Selector
;
424 unsigned service
= AX_reg(context
);
426 TRACE("[%04x] TimerAPI\n", (UINT16
)service
);
430 case 0x0000: /* version */
431 SET_AX( context
, VXD_WinVersion() );
432 RESET_CFLAG(context
);
435 case 0x0009: /* get system time selector */
436 if ( !System_Time_Selector
)
438 HANDLE16 handle
= GlobalAlloc16( GMEM_FIXED
, sizeof(DWORD
) );
439 System_Time_Selector
= handle
| 7;
440 CloseHandle( CreateThread( NULL
, 0, timer_thread
, GlobalLock16(handle
), 0, NULL
) );
442 SET_AX( context
, System_Time_Selector
);
443 RESET_CFLAG(context
);
447 VXD_BARF( context
, "VTDAPI" );
451 /***********************************************************************
452 * VXD_ConfigMG (WPROCS.451)
454 void WINAPI
VXD_ConfigMG ( CONTEXT86
*context
)
456 unsigned service
= AX_reg(context
);
458 TRACE("[%04x] ConfigMG\n", (UINT16
)service
);
462 case 0x0000: /* version */
463 SET_AX( context
, VXD_WinVersion() );
464 RESET_CFLAG(context
);
468 VXD_BARF( context
, "CONFIGMG" );
472 /***********************************************************************
473 * VXD_Enable (WPROCS.455)
475 void WINAPI
VXD_Enable ( CONTEXT86
*context
)
477 unsigned service
= AX_reg(context
);
479 TRACE("[%04x] Enable\n", (UINT16
)service
);
483 case 0x0000: /* version */
484 SET_AX( context
, VXD_WinVersion() );
485 RESET_CFLAG(context
);
489 VXD_BARF( context
, "ENABLE" );
493 /***********************************************************************
494 * VXD_APM (WPROCS.438)
496 void WINAPI
VXD_APM ( CONTEXT86
*context
)
498 unsigned service
= AX_reg(context
);
500 TRACE("[%04x] APM\n", (UINT16
)service
);
504 case 0x0000: /* version */
505 SET_AX( context
, VXD_WinVersion() );
506 RESET_CFLAG(context
);
510 VXD_BARF( context
, "APM" );
514 /***********************************************************************
515 * VXD_Win32s (WPROCS.445)
517 * This is an implementation of the services of the Win32s VxD.
518 * Since official documentation of these does not seem to be available,
519 * certain arguments of some of the services remain unclear.
521 * FIXME: The following services are currently unimplemented:
522 * Exception handling (0x01, 0x1C)
523 * Debugger support (0x0C, 0x14, 0x17)
524 * Low-level memory access (0x02, 0x03, 0x0A, 0x0B)
525 * Memory Statistics (0x1B)
528 * We have a specific problem running Win32s on Linux (and probably also
529 * the other x86 unixes), since Win32s tries to allocate its main 'flat
530 * code/data segment' selectors with a base of 0xffff0000 (and limit 4GB).
531 * The rationale for this seems to be that they want one the one hand to
532 * be able to leave the Win 3.1 memory (starting with the main DOS memory)
533 * at linear address 0, but want at other hand to have offset 0 of the
534 * flat data/code segment point to an unmapped page (to catch NULL pointer
535 * accesses). Hence they allocate the flat segments with a base of 0xffff0000
536 * so that the Win 3.1 memory area at linear address zero shows up in the
537 * flat segments at offset 0x10000 (since linear addresses wrap around at
538 * 4GB). To compensate for that discrepancy between flat segment offsets
539 * and plain linear addresses, all flat pointers passed between the 32-bit
540 * and the 16-bit parts of Win32s are shifted by 0x10000 in the appropriate
541 * direction by the glue code (mainly) in W32SKRNL and WIN32S16.
543 * The problem for us is now that Linux does not allow a LDT selector with
544 * base 0xffff0000 to be created, since it would 'see' a part of the kernel
545 * address space. To address this problem we introduce *another* offset:
546 * We add 0x10000 to every linear address we get as an argument from Win32s.
547 * This means especially that the flat code/data selectors get actually
548 * allocated with base 0x0, so that flat offsets and (real) linear addresses
549 * do again agree! In fact, every call e.g. of a Win32s VxD service now
550 * has all pointer arguments (which are offsets in the flat data segement)
551 * first reduced by 0x10000 by the W32SKRNL glue code, and then again
552 * increased by 0x10000 by *our* code.
554 * Note that to keep everything consistent, this offset has to be applied by
555 * every Wine function that operates on 'linear addresses' passed to it by
556 * Win32s. Fortunately, since Win32s does not directly call any Wine 32-bit
557 * API routines, this affects only two locations: this VxD and the DPMI
558 * handler. (NOTE: Should any Win32s application pass a linear address to
559 * any routine apart from those, e.g. some other VxD handler, that code
560 * would have to take the offset into account as well!)
562 * The offset is set the first time any application calls the GetVersion()
563 * service of the Win32s VxD. (Note that the offset is never reset.)
567 void WINAPI
VXD_Win32s( CONTEXT86
*context
)
569 switch (AX_reg(context
))
571 case 0x0000: /* Get Version */
575 * Output: EAX: LoWord: Win32s Version (1.30)
576 * HiWord: VxD Version (200)
582 * EDX: Debugging Flags
586 * 1 if VMCPD VxD not found
589 TRACE("GetVersion()\n");
591 context
->Eax
= VXD_WinVersion() | (200 << 16);
598 * If this is the first time we are called for this process,
599 * hack the memory image of WIN32S16 so that it doesn't try
600 * to access the GDT directly ...
602 * The first code segment of WIN32S16 (version 1.30) contains
603 * an unexported function somewhere between the exported functions
604 * SetFS and StackLinearToSegmented that tries to find a selector
605 * in the LDT that maps to the memory image of the LDT itself.
606 * If it succeeds, it stores this selector into a global variable
607 * which will be used to speed up execution by using this selector
608 * to modify the LDT directly instead of using the DPMI calls.
610 * To perform this search of the LDT, this function uses the
611 * sgdt and sldt instructions to find the linear address of
612 * the (GDT and then) LDT. While those instructions themselves
613 * execute without problem, the linear address that sgdt returns
614 * points (at least under Linux) to the kernel address space, so
615 * that any subsequent access leads to a segfault.
617 * Fortunately, WIN32S16 still contains as a fallback option the
618 * mechanism of using DPMI calls to modify LDT selectors instead
619 * of direct writes to the LDT. Thus we can circumvent the problem
620 * by simply replacing the first byte of the offending function
621 * with an 'retf' instruction. This means that the global variable
622 * supposed to contain the LDT alias selector will remain zero,
623 * and hence WIN32S16 will fall back to using DPMI calls.
625 * The heuristic we employ to _find_ that function is as follows:
626 * We search between the addresses of the exported symbols SetFS
627 * and StackLinearToSegmented for the byte sequence '0F 01 04'
628 * (this is the opcode of 'sgdt [si]'). We then search backwards
629 * from this address for the last occurrence of 'CB' (retf) that marks
630 * the end of the preceeding function. The following byte (which
631 * should now be the first byte of the function we are looking for)
632 * will be replaced by 'CB' (retf).
634 * This heuristic works for the retail as well as the debug version
635 * of Win32s version 1.30. For versions earlier than that this
636 * hack should not be necessary at all, since the whole mechanism
637 * ('PERF130') was introduced only in 1.30 to improve the overall
638 * performance of Win32s.
643 HMODULE16 hModule
= GetModuleHandle16("win32s16");
644 SEGPTR func1
= (SEGPTR
)GetProcAddress16(hModule
, "SetFS");
645 SEGPTR func2
= (SEGPTR
)GetProcAddress16(hModule
, "StackLinearToSegmented");
647 if ( hModule
&& func1
&& func2
648 && SELECTOROF(func1
) == SELECTOROF(func2
))
650 BYTE
*start
= MapSL(func1
);
651 BYTE
*end
= MapSL(func2
);
652 BYTE
*p
, *retv
= NULL
;
655 for (p
= start
; p
< end
; p
++)
656 if (*p
== 0xCB) found
= 0, retv
= p
;
657 else if (*p
== 0x0F) found
= 1;
658 else if (*p
== 0x01 && found
== 1) found
= 2;
659 else if (*p
== 0x04 && found
== 2) { found
= 3; break; }
662 if (found
== 3 && retv
)
664 TRACE("PERF130 hack: "
665 "Replacing byte %02X at offset %04X:%04X\n",
666 *(retv
+1), SELECTOROF(func1
),
667 OFFSETOF(func1
) + retv
+1-start
);
669 *(retv
+1) = (BYTE
)0xCB;
675 * Mark process as Win32s, so that subsequent DPMI calls
676 * will perform the W32S_APP2WINE/W32S_WINE2APP address shift.
678 W32S_offset
= 0x10000;
682 case 0x0001: /* Install Exception Handling */
684 * Input: EBX: Flat address of W32SKRNL Exception Data
686 * ECX: LoWord: Flat Code Selector
687 * HiWord: Flat Data Selector
689 * EDX: Flat address of W32SKRNL Exception Handler
690 * (this is equal to W32S_BackTo32 + 0x40)
692 * ESI: SEGPTR KERNEL.HASGPHANDLER
694 * EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10)
696 * Output: EAX: 0 if OK
699 TRACE("[0001] EBX=%lx ECX=%lx EDX=%lx ESI=%lx EDI=%lx\n",
700 context
->Ebx
, context
->Ecx
, context
->Edx
,
701 context
->Esi
, context
->Edi
);
709 case 0x0002: /* Set Page Access Flags */
711 * Input: EBX: New access flags
712 * Bit 2: User Page if set, Supervisor Page if clear
713 * Bit 1: Read-Write if set, Read-Only if clear
715 * ECX: Size of memory area to change
717 * EDX: Flat start address of memory area
719 * Output: EAX: Size of area changed
722 TRACE("[0002] EBX=%lx ECX=%lx EDX=%lx\n",
723 context
->Ebx
, context
->Ecx
, context
->Edx
);
727 context
->Eax
= context
->Ecx
;
731 case 0x0003: /* Get Page Access Flags */
733 * Input: EDX: Flat address of page to query
735 * Output: EAX: Page access flags
736 * Bit 2: User Page if set, Supervisor Page if clear
737 * Bit 1: Read-Write if set, Read-Only if clear
740 TRACE("[0003] EDX=%lx\n", context
->Edx
);
748 case 0x0004: /* Map Module */
750 * Input: ECX: IMTE (offset in Module Table) of new module
752 * EDX: Flat address of Win32s Module Table
754 * Output: EAX: 0 if OK
757 if (!context
->Edx
|| CX_reg(context
) == 0xFFFF)
759 TRACE("MapModule: Initialization call\n");
765 * Structure of a Win32s Module Table Entry:
780 * Note: This function should set up a demand-paged memory image
781 * of the given module. Since mmap does not allow file offsets
782 * not aligned at 1024 bytes, we simply load the image fully
786 struct Win32sModule
*moduleTable
=
787 (struct Win32sModule
*)W32S_APP2WINE(context
->Edx
);
788 struct Win32sModule
*module
= moduleTable
+ context
->Ecx
;
790 IMAGE_NT_HEADERS
*nt_header
= RtlImageNtHeader( (HMODULE
)module
->baseAddr
);
791 IMAGE_SECTION_HEADER
*pe_seg
= (IMAGE_SECTION_HEADER
*)((char *)&nt_header
->OptionalHeader
+
792 nt_header
->FileHeader
.SizeOfOptionalHeader
);
795 HFILE image
= _lopen(module
->pathName
, OF_READ
);
796 BOOL error
= (image
== HFILE_ERROR
);
799 TRACE("MapModule: Loading %s\n", module
->pathName
);
802 !error
&& i
< nt_header
->FileHeader
.NumberOfSections
;
804 if(!(pe_seg
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
))
806 DWORD off
= pe_seg
->PointerToRawData
;
807 DWORD len
= pe_seg
->SizeOfRawData
;
808 LPBYTE addr
= module
->baseAddr
+ pe_seg
->VirtualAddress
;
811 "Section %d at %08lx from %08lx len %08lx\n",
812 i
, (DWORD
)addr
, off
, len
);
814 if ( _llseek(image
, off
, SEEK_SET
) != off
815 || _lread(image
, addr
, len
) != len
)
822 ERR("MapModule: Unable to load %s\n", module
->pathName
);
824 else if (module
->relocDelta
!= 0)
826 IMAGE_DATA_DIRECTORY
*dir
= nt_header
->OptionalHeader
.DataDirectory
827 + IMAGE_DIRECTORY_ENTRY_BASERELOC
;
828 IMAGE_BASE_RELOCATION
*r
= (IMAGE_BASE_RELOCATION
*)
829 (dir
->Size
? module
->baseAddr
+ dir
->VirtualAddress
: 0);
831 TRACE("MapModule: Reloc delta %08lx\n", module
->relocDelta
);
833 while (r
&& r
->VirtualAddress
)
835 LPBYTE page
= module
->baseAddr
+ r
->VirtualAddress
;
836 WORD
*TypeOffset
= (WORD
*)(r
+ 1);
837 int count
= (r
->SizeOfBlock
- sizeof(*r
)) / sizeof(*TypeOffset
);
839 TRACE("MapModule: %d relocations for page %08lx\n",
842 for(i
= 0; i
< count
; i
++)
844 int offset
= TypeOffset
[i
] & 0xFFF;
845 int type
= TypeOffset
[i
] >> 12;
848 case IMAGE_REL_BASED_ABSOLUTE
:
850 case IMAGE_REL_BASED_HIGH
:
851 *(WORD
*)(page
+offset
) += HIWORD(module
->relocDelta
);
853 case IMAGE_REL_BASED_LOW
:
854 *(WORD
*)(page
+offset
) += LOWORD(module
->relocDelta
);
856 case IMAGE_REL_BASED_HIGHLOW
:
857 *(DWORD
*)(page
+offset
) += module
->relocDelta
;
860 WARN("MapModule: Unsupported fixup type\n");
865 r
= (IMAGE_BASE_RELOCATION
*)((LPBYTE
)r
+ r
->SizeOfBlock
);
870 RESET_CFLAG(context
);
875 case 0x0005: /* UnMap Module */
877 * Input: EDX: Flat address of module image
879 * Output: EAX: 1 if OK
882 TRACE("UnMapModule: %lx\n", (DWORD
)W32S_APP2WINE(context
->Edx
));
884 /* As we didn't map anything, there's nothing to unmap ... */
890 case 0x0006: /* VirtualAlloc */
892 * Input: ECX: Current Process
894 * EDX: Flat address of arguments on stack
896 * DWORD *retv [out] Flat base address of allocated region
897 * LPVOID base [in] Flat address of region to reserve/commit
898 * DWORD size [in] Size of region
899 * DWORD type [in] Type of allocation
900 * DWORD prot [in] Type of access protection
902 * Output: EAX: NtStatus
905 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
906 DWORD
*retv
= (DWORD
*)W32S_APP2WINE(stack
[0]);
907 LPVOID base
= (LPVOID
) W32S_APP2WINE(stack
[1]);
908 DWORD size
= stack
[2];
909 DWORD type
= stack
[3];
910 DWORD prot
= stack
[4];
913 TRACE("VirtualAlloc(%lx, %lx, %lx, %lx, %lx)\n",
914 (DWORD
)retv
, (DWORD
)base
, size
, type
, prot
);
916 if (type
& 0x80000000)
918 WARN("VirtualAlloc: strange type %lx\n", type
);
922 if (!base
&& (type
& MEM_COMMIT
) && prot
== PAGE_READONLY
)
924 WARN("VirtualAlloc: NLS hack, allowing write access!\n");
925 prot
= PAGE_READWRITE
;
928 result
= (DWORD
)VirtualAlloc(base
, size
, type
, prot
);
930 if (W32S_WINE2APP(result
))
931 *retv
= W32S_WINE2APP(result
),
932 context
->Eax
= STATUS_SUCCESS
;
935 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
940 case 0x0007: /* VirtualFree */
942 * Input: ECX: Current Process
944 * EDX: Flat address of arguments on stack
946 * DWORD *retv [out] TRUE if success, FALSE if failure
947 * LPVOID base [in] Flat address of region
948 * DWORD size [in] Size of region
949 * DWORD type [in] Type of operation
951 * Output: EAX: NtStatus
954 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
955 DWORD
*retv
= (DWORD
*)W32S_APP2WINE(stack
[0]);
956 LPVOID base
= (LPVOID
) W32S_APP2WINE(stack
[1]);
957 DWORD size
= stack
[2];
958 DWORD type
= stack
[3];
961 TRACE("VirtualFree(%lx, %lx, %lx, %lx)\n",
962 (DWORD
)retv
, (DWORD
)base
, size
, type
);
964 result
= VirtualFree(base
, size
, type
);
968 context
->Eax
= STATUS_SUCCESS
;
971 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
976 case 0x0008: /* VirtualProtect */
978 * Input: ECX: Current Process
980 * EDX: Flat address of arguments on stack
982 * DWORD *retv [out] TRUE if success, FALSE if failure
983 * LPVOID base [in] Flat address of region
984 * DWORD size [in] Size of region
985 * DWORD new_prot [in] Desired access protection
986 * DWORD *old_prot [out] Previous access protection
988 * Output: EAX: NtStatus
991 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
992 DWORD
*retv
= (DWORD
*)W32S_APP2WINE(stack
[0]);
993 LPVOID base
= (LPVOID
) W32S_APP2WINE(stack
[1]);
994 DWORD size
= stack
[2];
995 DWORD new_prot
= stack
[3];
996 DWORD
*old_prot
= (DWORD
*)W32S_APP2WINE(stack
[4]);
999 TRACE("VirtualProtect(%lx, %lx, %lx, %lx, %lx)\n",
1000 (DWORD
)retv
, (DWORD
)base
, size
, new_prot
, (DWORD
)old_prot
);
1002 result
= VirtualProtect(base
, size
, new_prot
, old_prot
);
1006 context
->Eax
= STATUS_SUCCESS
;
1009 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1014 case 0x0009: /* VirtualQuery */
1016 * Input: ECX: Current Process
1018 * EDX: Flat address of arguments on stack
1020 * DWORD *retv [out] Nr. bytes returned
1021 * LPVOID base [in] Flat address of region
1022 * LPMEMORY_BASIC_INFORMATION info [out] Info buffer
1023 * DWORD len [in] Size of buffer
1025 * Output: EAX: NtStatus
1028 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1029 DWORD
*retv
= (DWORD
*)W32S_APP2WINE(stack
[0]);
1030 LPVOID base
= (LPVOID
) W32S_APP2WINE(stack
[1]);
1031 PMEMORY_BASIC_INFORMATION info
=
1032 (PMEMORY_BASIC_INFORMATION
)W32S_APP2WINE(stack
[2]);
1033 DWORD len
= stack
[3];
1036 TRACE("VirtualQuery(%lx, %lx, %lx, %lx)\n",
1037 (DWORD
)retv
, (DWORD
)base
, (DWORD
)info
, len
);
1039 result
= VirtualQuery(base
, info
, len
);
1042 context
->Eax
= STATUS_SUCCESS
;
1047 case 0x000A: /* SetVirtMemProcess */
1049 * Input: ECX: Process Handle
1051 * EDX: Flat address of region
1053 * Output: EAX: NtStatus
1056 TRACE("[000a] ECX=%lx EDX=%lx\n",
1057 context
->Ecx
, context
->Edx
);
1061 context
->Eax
= STATUS_SUCCESS
;
1065 case 0x000B: /* ??? some kind of cleanup */
1067 * Input: ECX: Process Handle
1069 * Output: EAX: NtStatus
1072 TRACE("[000b] ECX=%lx\n", context
->Ecx
);
1076 context
->Eax
= STATUS_SUCCESS
;
1080 case 0x000C: /* Set Debug Flags */
1082 * Input: EDX: Debug Flags
1084 * Output: EDX: Previous Debug Flags
1087 FIXME("[000c] EDX=%lx\n", context
->Edx
);
1095 case 0x000D: /* NtCreateSection */
1097 * Input: EDX: Flat address of arguments on stack
1099 * HANDLE32 *retv [out] Handle of Section created
1100 * DWORD flags1 [in] (?? unknown ??)
1101 * DWORD atom [in] Name of Section to create
1102 * LARGE_INTEGER *size [in] Size of Section
1103 * DWORD protect [in] Access protection
1104 * DWORD flags2 [in] (?? unknown ??)
1105 * HFILE32 hFile [in] Handle of file to map
1106 * DWORD psp [in] (Win32s: PSP that hFile belongs to)
1108 * Output: EAX: NtStatus
1111 DWORD
*stack
= (DWORD
*) W32S_APP2WINE(context
->Edx
);
1112 HANDLE
*retv
= (HANDLE
*)W32S_APP2WINE(stack
[0]);
1113 DWORD flags1
= stack
[1];
1114 DWORD atom
= stack
[2];
1115 LARGE_INTEGER
*size
= (LARGE_INTEGER
*)W32S_APP2WINE(stack
[3]);
1116 DWORD protect
= stack
[4];
1117 DWORD flags2
= stack
[5];
1118 HANDLE hFile
= DosFileHandleToWin32Handle(stack
[6]);
1119 DWORD psp
= stack
[7];
1121 HANDLE result
= INVALID_HANDLE_VALUE
;
1124 TRACE("NtCreateSection(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1125 (DWORD
)retv
, flags1
, atom
, (DWORD
)size
, protect
, flags2
,
1128 if (!atom
|| GlobalGetAtomNameA(atom
, name
, sizeof(name
)))
1130 TRACE("NtCreateSection: name=%s\n", atom
? name
: NULL
);
1132 result
= CreateFileMappingA(hFile
, NULL
, protect
,
1133 size
? size
->s
.HighPart
: 0,
1134 size
? size
->s
.LowPart
: 0,
1138 if (result
== INVALID_HANDLE_VALUE
)
1139 WARN("NtCreateSection: failed!\n");
1141 TRACE("NtCreateSection: returned %lx\n", (DWORD
)result
);
1143 if (result
!= INVALID_HANDLE_VALUE
)
1145 context
->Eax
= STATUS_SUCCESS
;
1148 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1153 case 0x000E: /* NtOpenSection */
1155 * Input: EDX: Flat address of arguments on stack
1157 * HANDLE32 *retv [out] Handle of Section opened
1158 * DWORD protect [in] Access protection
1159 * DWORD atom [in] Name of Section to create
1161 * Output: EAX: NtStatus
1164 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1165 HANDLE
*retv
= (HANDLE
*)W32S_APP2WINE(stack
[0]);
1166 DWORD protect
= stack
[1];
1167 DWORD atom
= stack
[2];
1169 HANDLE result
= INVALID_HANDLE_VALUE
;
1172 TRACE("NtOpenSection(%lx, %lx, %lx)\n",
1173 (DWORD
)retv
, protect
, atom
);
1175 if (atom
&& GlobalGetAtomNameA(atom
, name
, sizeof(name
)))
1177 TRACE("NtOpenSection: name=%s\n", name
);
1179 result
= OpenFileMappingA(protect
, FALSE
, name
);
1182 if (result
== INVALID_HANDLE_VALUE
)
1183 WARN("NtOpenSection: failed!\n");
1185 TRACE("NtOpenSection: returned %lx\n", (DWORD
)result
);
1187 if (result
!= INVALID_HANDLE_VALUE
)
1189 context
->Eax
= STATUS_SUCCESS
;
1192 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1197 case 0x000F: /* NtCloseSection */
1199 * Input: EDX: Flat address of arguments on stack
1201 * HANDLE32 handle [in] Handle of Section to close
1202 * DWORD *id [out] Unique ID (?? unclear ??)
1204 * Output: EAX: NtStatus
1207 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1208 HANDLE handle
= (HANDLE
)stack
[0];
1209 DWORD
*id
= (DWORD
*)W32S_APP2WINE(stack
[1]);
1211 TRACE("NtCloseSection(%lx, %lx)\n", (DWORD
)handle
, (DWORD
)id
);
1213 CloseHandle(handle
);
1214 if (id
) *id
= 0; /* FIXME */
1216 context
->Eax
= STATUS_SUCCESS
;
1221 case 0x0010: /* NtDupSection */
1223 * Input: EDX: Flat address of arguments on stack
1225 * HANDLE32 handle [in] Handle of Section to duplicate
1227 * Output: EAX: NtStatus
1230 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1231 HANDLE handle
= (HANDLE
)stack
[0];
1234 TRACE("NtDupSection(%lx)\n", (DWORD
)handle
);
1236 DuplicateHandle( GetCurrentProcess(), handle
,
1237 GetCurrentProcess(), &new_handle
,
1238 0, FALSE
, DUPLICATE_SAME_ACCESS
);
1239 context
->Eax
= STATUS_SUCCESS
;
1244 case 0x0011: /* NtMapViewOfSection */
1246 * Input: EDX: Flat address of arguments on stack
1248 * HANDLE32 SectionHandle [in] Section to be mapped
1249 * DWORD ProcessHandle [in] Process to be mapped into
1250 * DWORD * BaseAddress [in/out] Address to be mapped at
1251 * DWORD ZeroBits [in] (?? unclear ??)
1252 * DWORD CommitSize [in] (?? unclear ??)
1253 * LARGE_INTEGER *SectionOffset [in] Offset within section
1254 * DWORD * ViewSize [in] Size of view
1255 * DWORD InheritDisposition [in] (?? unclear ??)
1256 * DWORD AllocationType [in] (?? unclear ??)
1257 * DWORD Protect [in] Access protection
1259 * Output: EAX: NtStatus
1262 DWORD
* stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1263 HANDLE SectionHandle
= (HANDLE
)stack
[0];
1264 DWORD ProcessHandle
= stack
[1]; /* ignored */
1265 DWORD
* BaseAddress
= (DWORD
*)W32S_APP2WINE(stack
[2]);
1266 DWORD ZeroBits
= stack
[3];
1267 DWORD CommitSize
= stack
[4];
1268 LARGE_INTEGER
*SectionOffset
= (LARGE_INTEGER
*)W32S_APP2WINE(stack
[5]);
1269 DWORD
* ViewSize
= (DWORD
*)W32S_APP2WINE(stack
[6]);
1270 DWORD InheritDisposition
= stack
[7];
1271 DWORD AllocationType
= stack
[8];
1272 DWORD Protect
= stack
[9];
1274 LPBYTE address
= (LPBYTE
)(BaseAddress
?
1275 W32S_APP2WINE(*BaseAddress
) : 0);
1276 DWORD access
= 0, result
;
1278 switch (Protect
& ~(PAGE_GUARD
|PAGE_NOCACHE
))
1280 case PAGE_READONLY
: access
= FILE_MAP_READ
; break;
1281 case PAGE_READWRITE
: access
= FILE_MAP_WRITE
; break;
1282 case PAGE_WRITECOPY
: access
= FILE_MAP_COPY
; break;
1284 case PAGE_EXECUTE_READ
: access
= FILE_MAP_READ
; break;
1285 case PAGE_EXECUTE_READWRITE
: access
= FILE_MAP_WRITE
; break;
1286 case PAGE_EXECUTE_WRITECOPY
: access
= FILE_MAP_COPY
; break;
1289 TRACE("NtMapViewOfSection"
1290 "(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1291 (DWORD
)SectionHandle
, ProcessHandle
, (DWORD
)BaseAddress
,
1292 ZeroBits
, CommitSize
, (DWORD
)SectionOffset
, (DWORD
)ViewSize
,
1293 InheritDisposition
, AllocationType
, Protect
);
1294 TRACE("NtMapViewOfSection: "
1295 "base=%lx, offset=%lx, size=%lx, access=%lx\n",
1296 (DWORD
)address
, SectionOffset
? SectionOffset
->s
.LowPart
: 0,
1297 ViewSize
? *ViewSize
: 0, access
);
1299 result
= (DWORD
)MapViewOfFileEx(SectionHandle
, access
,
1300 SectionOffset
? SectionOffset
->s
.HighPart
: 0,
1301 SectionOffset
? SectionOffset
->s
.LowPart
: 0,
1302 ViewSize
? *ViewSize
: 0, address
);
1304 TRACE("NtMapViewOfSection: result=%lx\n", result
);
1306 if (W32S_WINE2APP(result
))
1308 if (BaseAddress
) *BaseAddress
= W32S_WINE2APP(result
);
1309 context
->Eax
= STATUS_SUCCESS
;
1312 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1317 case 0x0012: /* NtUnmapViewOfSection */
1319 * Input: EDX: Flat address of arguments on stack
1321 * DWORD ProcessHandle [in] Process (defining address space)
1322 * LPBYTE BaseAddress [in] Base address of view to be unmapped
1324 * Output: EAX: NtStatus
1327 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1328 DWORD ProcessHandle
= stack
[0]; /* ignored */
1329 LPBYTE BaseAddress
= (LPBYTE
)W32S_APP2WINE(stack
[1]);
1331 TRACE("NtUnmapViewOfSection(%lx, %lx)\n",
1332 ProcessHandle
, (DWORD
)BaseAddress
);
1334 UnmapViewOfFile(BaseAddress
);
1336 context
->Eax
= STATUS_SUCCESS
;
1341 case 0x0013: /* NtFlushVirtualMemory */
1343 * Input: EDX: Flat address of arguments on stack
1345 * DWORD ProcessHandle [in] Process (defining address space)
1346 * LPBYTE *BaseAddress [in?] Base address of range to be flushed
1347 * DWORD *ViewSize [in?] Number of bytes to be flushed
1348 * DWORD *unknown [???] (?? unknown ??)
1350 * Output: EAX: NtStatus
1353 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1354 DWORD ProcessHandle
= stack
[0]; /* ignored */
1355 DWORD
*BaseAddress
= (DWORD
*)W32S_APP2WINE(stack
[1]);
1356 DWORD
*ViewSize
= (DWORD
*)W32S_APP2WINE(stack
[2]);
1357 DWORD
*unknown
= (DWORD
*)W32S_APP2WINE(stack
[3]);
1359 LPBYTE address
= (LPBYTE
)(BaseAddress
? W32S_APP2WINE(*BaseAddress
) : 0);
1360 DWORD size
= ViewSize
? *ViewSize
: 0;
1362 TRACE("NtFlushVirtualMemory(%lx, %lx, %lx, %lx)\n",
1363 ProcessHandle
, (DWORD
)BaseAddress
, (DWORD
)ViewSize
,
1365 TRACE("NtFlushVirtualMemory: base=%lx, size=%lx\n",
1366 (DWORD
)address
, size
);
1368 FlushViewOfFile(address
, size
);
1370 context
->Eax
= STATUS_SUCCESS
;
1375 case 0x0014: /* Get/Set Debug Registers */
1377 * Input: ECX: 0 if Get, 1 if Set
1379 * EDX: Get: Flat address of buffer to receive values of
1380 * debug registers DR0 .. DR7
1381 * Set: Flat address of buffer containing values of
1382 * debug registers DR0 .. DR7 to be set
1386 FIXME("[0014] ECX=%lx EDX=%lx\n",
1387 context
->Ecx
, context
->Edx
);
1393 case 0x0015: /* Set Coprocessor Emulation Flag */
1395 * Input: EDX: 0 to deactivate, 1 to activate coprocessor emulation
1400 TRACE("[0015] EDX=%lx\n", context
->Edx
);
1402 /* We don't care, as we always have a coprocessor anyway */
1406 case 0x0016: /* Init Win32S VxD PSP */
1408 * If called to query required PSP size:
1411 * Output: EDX: Required size of Win32s VxD PSP
1413 * If called to initialize allocated PSP:
1415 * Input: EBX: LoWord: Selector of Win32s VxD PSP
1416 * HiWord: Paragraph of Win32s VxD PSP (DOSMEM)
1420 if (context
->Ebx
== 0)
1421 context
->Edx
= 0x80;
1424 PDB16
*psp
= MapSL( MAKESEGPTR( BX_reg(context
), 0 ));
1426 psp
->fileHandlesPtr
= MAKELONG(HIWORD(context
->Ebx
), 0x5c);
1427 memset((LPBYTE
)psp
+ 0x5c, '\xFF', 32);
1432 case 0x0017: /* Set Break Point */
1434 * Input: EBX: Offset of Break Point
1435 * CX: Selector of Break Point
1440 FIXME("[0017] EBX=%lx CX=%x\n",
1441 context
->Ebx
, CX_reg(context
));
1447 case 0x0018: /* VirtualLock */
1449 * Input: ECX: Current Process
1451 * EDX: Flat address of arguments on stack
1453 * DWORD *retv [out] TRUE if success, FALSE if failure
1454 * LPVOID base [in] Flat address of range to lock
1455 * DWORD size [in] Size of range
1457 * Output: EAX: NtStatus
1460 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1461 DWORD
*retv
= (DWORD
*)W32S_APP2WINE(stack
[0]);
1462 LPVOID base
= (LPVOID
) W32S_APP2WINE(stack
[1]);
1463 DWORD size
= stack
[2];
1466 TRACE("VirtualLock(%lx, %lx, %lx)\n",
1467 (DWORD
)retv
, (DWORD
)base
, size
);
1469 result
= VirtualLock(base
, size
);
1473 context
->Eax
= STATUS_SUCCESS
;
1476 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1481 case 0x0019: /* VirtualUnlock */
1483 * Input: ECX: Current Process
1485 * EDX: Flat address of arguments on stack
1487 * DWORD *retv [out] TRUE if success, FALSE if failure
1488 * LPVOID base [in] Flat address of range to unlock
1489 * DWORD size [in] Size of range
1491 * Output: EAX: NtStatus
1494 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1495 DWORD
*retv
= (DWORD
*)W32S_APP2WINE(stack
[0]);
1496 LPVOID base
= (LPVOID
) W32S_APP2WINE(stack
[1]);
1497 DWORD size
= stack
[2];
1500 TRACE("VirtualUnlock(%lx, %lx, %lx)\n",
1501 (DWORD
)retv
, (DWORD
)base
, size
);
1503 result
= VirtualUnlock(base
, size
);
1507 context
->Eax
= STATUS_SUCCESS
;
1510 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1515 case 0x001A: /* KGetSystemInfo */
1519 * Output: ECX: Start of sparse memory arena
1520 * EDX: End of sparse memory arena
1523 TRACE("KGetSystemInfo()\n");
1526 * Note: Win32s reserves 0GB - 2GB for Win 3.1 and uses 2GB - 4GB as
1527 * sparse memory arena. We do it the other way around, since
1528 * we have to reserve 3GB - 4GB for Linux, and thus use
1529 * 0GB - 3GB as sparse memory arena.
1531 * FIXME: What about other OSes ?
1534 context
->Ecx
= W32S_WINE2APP(0x00000000);
1535 context
->Edx
= W32S_WINE2APP(0xbfffffff);
1539 case 0x001B: /* KGlobalMemStat */
1541 * Input: ESI: Flat address of buffer to receive memory info
1546 struct Win32sMemoryInfo
1548 DWORD DIPhys_Count
; /* Total physical pages */
1549 DWORD DIFree_Count
; /* Free physical pages */
1550 DWORD DILin_Total_Count
; /* Total virtual pages (private arena) */
1551 DWORD DILin_Total_Free
; /* Free virtual pages (private arena) */
1553 DWORD SparseTotal
; /* Total size of sparse arena (bytes ?) */
1554 DWORD SparseFree
; /* Free size of sparse arena (bytes ?) */
1557 struct Win32sMemoryInfo
*info
=
1558 (struct Win32sMemoryInfo
*)W32S_APP2WINE(context
->Esi
);
1560 FIXME("KGlobalMemStat(%lx)\n", (DWORD
)info
);
1567 case 0x001C: /* Enable/Disable Exceptions */
1569 * Input: ECX: 0 to disable, 1 to enable exception handling
1574 TRACE("[001c] ECX=%lx\n", context
->Ecx
);
1580 case 0x001D: /* VirtualAlloc called from 16-bit code */
1582 * Input: EDX: Segmented address of arguments on stack
1584 * LPVOID base [in] Flat address of region to reserve/commit
1585 * DWORD size [in] Size of region
1586 * DWORD type [in] Type of allocation
1587 * DWORD prot [in] Type of access protection
1589 * Output: EAX: NtStatus
1590 * EDX: Flat base address of allocated region
1593 DWORD
*stack
= MapSL( MAKESEGPTR( LOWORD(context
->Edx
), HIWORD(context
->Edx
) ));
1594 LPVOID base
= (LPVOID
)W32S_APP2WINE(stack
[0]);
1595 DWORD size
= stack
[1];
1596 DWORD type
= stack
[2];
1597 DWORD prot
= stack
[3];
1600 TRACE("VirtualAlloc16(%lx, %lx, %lx, %lx)\n",
1601 (DWORD
)base
, size
, type
, prot
);
1603 if (type
& 0x80000000)
1605 WARN("VirtualAlloc16: strange type %lx\n", type
);
1609 result
= (DWORD
)VirtualAlloc(base
, size
, type
, prot
);
1611 if (W32S_WINE2APP(result
))
1612 context
->Edx
= W32S_WINE2APP(result
),
1613 context
->Eax
= STATUS_SUCCESS
;
1616 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1617 TRACE("VirtualAlloc16: returning base %lx\n", context
->Edx
);
1622 case 0x001E: /* VirtualFree called from 16-bit code */
1624 * Input: EDX: Segmented address of arguments on stack
1626 * LPVOID base [in] Flat address of region
1627 * DWORD size [in] Size of region
1628 * DWORD type [in] Type of operation
1630 * Output: EAX: NtStatus
1631 * EDX: TRUE if success, FALSE if failure
1634 DWORD
*stack
= MapSL( MAKESEGPTR( LOWORD(context
->Edx
), HIWORD(context
->Edx
) ));
1635 LPVOID base
= (LPVOID
)W32S_APP2WINE(stack
[0]);
1636 DWORD size
= stack
[1];
1637 DWORD type
= stack
[2];
1640 TRACE("VirtualFree16(%lx, %lx, %lx)\n",
1641 (DWORD
)base
, size
, type
);
1643 result
= VirtualFree(base
, size
, type
);
1646 context
->Edx
= TRUE
,
1647 context
->Eax
= STATUS_SUCCESS
;
1649 context
->Edx
= FALSE
,
1650 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1655 case 0x001F: /* FWorkingSetSize */
1657 * Input: EDX: 0 if Get, 1 if Set
1659 * ECX: Get: Buffer to receive Working Set Size
1660 * Set: Buffer containing Working Set Size
1665 DWORD
*ptr
= (DWORD
*)W32S_APP2WINE(context
->Ecx
);
1666 BOOL set
= context
->Edx
;
1668 TRACE("FWorkingSetSize(%lx, %lx)\n", (DWORD
)ptr
, (DWORD
)set
);
1671 /* We do it differently ... */;
1675 context
->Eax
= STATUS_SUCCESS
;
1681 VXD_BARF( context
, "W32S" );