4 * Copyright 1998 Marcus Meissner
5 * Copyright 1998 Ulrich Weigand
6 * Copyright 1998 Patrik Stridvall
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include <sys/types.h>
29 #define WIN32_NO_STATUS
35 #include "kernel16_private.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(vxd
);
41 typedef DWORD (WINAPI
*VxDCallProc
)(DWORD
, CONTEXT
*);
42 typedef BOOL (WINAPI
*DeviceIoProc
)(DWORD
, LPVOID
, DWORD
, LPVOID
, DWORD
, LPDWORD
, LPOVERLAPPED
);
52 struct vxdcall_service
60 #define MAX_VXD_MODULES 32
62 static struct vxd_module vxd_modules
[MAX_VXD_MODULES
];
64 static struct vxdcall_service vxd_services
[] =
66 { {'v','m','m','.','v','x','d',0}, 0x0001, NULL
, NULL
},
67 { {'v','w','i','n','3','2','.','v','x','d',0}, 0x002a, NULL
, NULL
}
70 #define W32S_APP2WINE(addr) ((addr)? (DWORD)(addr) + W32S_offset : 0)
71 #define W32S_WINE2APP(addr) ((addr)? (DWORD)(addr) - W32S_offset : 0)
73 #define VXD_BARF(context,name) \
74 TRACE( "vxd %s: unknown/not implemented parameters:\n" \
75 "vxd %s: AX %04x, BX %04x, CX %04x, DX %04x, " \
76 "SI %04x, DI %04x, DS %04x, ES %04x\n", \
77 (name), (name), AX_reg(context), BX_reg(context), \
78 CX_reg(context), DX_reg(context), SI_reg(context), \
79 DI_reg(context), (WORD)context->SegDs, (WORD)context->SegEs )
81 static CRITICAL_SECTION vxd_section
;
82 static CRITICAL_SECTION_DEBUG critsect_debug
=
85 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
86 0, 0, { (DWORD_PTR
)(__FILE__
": vxd_section") }
88 static CRITICAL_SECTION vxd_section
= { &critsect_debug
, -1, 0, 0, 0, 0 };
90 static UINT W32S_offset
;
92 static WORD
VXD_WinVersion(void)
94 WORD version
= LOWORD(GetVersion16());
95 return (version
>> 8) | (version
<< 8);
98 /* retrieve the DeviceIoControl function for a Vxd given a file handle */
99 DeviceIoProc
__wine_vxd_get_proc( HANDLE handle
)
101 DeviceIoProc ret
= NULL
;
104 FILE_INTERNAL_INFORMATION info
;
106 status
= NtQueryInformationFile( handle
, &io
, &info
, sizeof(info
), FileInternalInformation
);
109 SetLastError( RtlNtStatusToDosError(status
) );
113 RtlEnterCriticalSection( &vxd_section
);
115 for (i
= 0; i
< MAX_VXD_MODULES
; i
++)
117 if (!vxd_modules
[i
].module
) break;
118 if (vxd_modules
[i
].index
.QuadPart
== info
.IndexNumber
.QuadPart
)
120 if (!(ret
= vxd_modules
[i
].proc
)) SetLastError( ERROR_INVALID_FUNCTION
);
124 /* FIXME: Here we could go through the directory to find the VxD name and load it. */
125 /* Let's wait to find out if there are actually apps out there that try to share */
126 /* VxD handles between processes, before we go to the trouble of implementing it. */
127 ERR( "handle %p not found in module list, inherited from another process?\n", handle
);
130 RtlLeaveCriticalSection( &vxd_section
);
135 /* load a VxD and return a file handle to it */
136 HANDLE
__wine_vxd_open( LPCWSTR filenameW
, DWORD access
, SECURITY_ATTRIBUTES
*sa
)
143 /* normalize the filename */
145 if (wcschr( filenameW
, '/' ) || wcschr( filenameW
, '\\' ))
147 SetLastError( ERROR_FILE_NOT_FOUND
);
150 p
= wcschr( filenameW
, '.' );
151 if (!p
&& lstrlenW( filenameW
) <= 8)
153 wcscpy( name
, filenameW
);
154 wcscat( name
, L
".vxd" );
156 else if (p
&& !wcsicmp( p
, L
".vxd" ) && lstrlenW( filenameW
) <= 12) /* existing extension has to be .vxd */
158 wcscpy( name
, filenameW
);
162 SetLastError( ERROR_FILE_NOT_FOUND
);
167 /* try to load the module first */
169 if (!(module
= LoadLibraryW( name
)))
171 FIXME( "Unknown/unsupported VxD %s. Try setting Windows version to 'nt40' or 'win31'.\n",
173 SetLastError( ERROR_FILE_NOT_FOUND
);
177 /* register the module in the global list if necessary */
179 RtlEnterCriticalSection( &vxd_section
);
181 for (i
= 0; i
< MAX_VXD_MODULES
; i
++)
183 if (vxd_modules
[i
].module
== module
)
185 handle
= vxd_modules
[i
].handle
;
186 goto done
; /* already registered */
188 if (!vxd_modules
[i
].module
) /* new one, register it */
190 WCHAR path
[MAX_PATH
];
192 FILE_INTERNAL_INFORMATION info
;
194 GetModuleFileNameW( module
, path
, MAX_PATH
);
195 handle
= CreateFileW( path
, 0, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, 0, 0 );
196 if (handle
== INVALID_HANDLE_VALUE
)
198 FreeLibrary( module
);
201 if (!NtQueryInformationFile( handle
, &io
, &info
, sizeof(info
), FileInternalInformation
))
202 vxd_modules
[i
].index
= info
.IndexNumber
;
204 vxd_modules
[i
].module
= module
;
205 vxd_modules
[i
].handle
= handle
;
206 vxd_modules
[i
].proc
= (DeviceIoProc
)GetProcAddress( module
, "DeviceIoControl" );
211 ERR("too many open VxD modules, please report\n" );
212 FreeLibrary( module
);
216 RtlLeaveCriticalSection( &vxd_section
);
217 if (!DuplicateHandle( GetCurrentProcess(), handle
, GetCurrentProcess(), &handle
, 0,
218 (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
),
219 DUPLICATE_SAME_ACCESS
))
225 /***********************************************************************
226 * VxDCall0 (KERNEL32.1)
227 * VxDCall1 (KERNEL32.2)
228 * VxDCall2 (KERNEL32.3)
229 * VxDCall3 (KERNEL32.4)
230 * VxDCall4 (KERNEL32.5)
231 * VxDCall5 (KERNEL32.6)
232 * VxDCall6 (KERNEL32.7)
233 * VxDCall7 (KERNEL32.8)
234 * VxDCall8 (KERNEL32.9)
236 void WINAPI
__regs_VxDCall( CONTEXT
*context
)
239 VxDCallProc proc
= NULL
;
240 DWORD service
= stack32_pop( context
);
242 RtlEnterCriticalSection( &vxd_section
);
243 for (i
= 0; i
< ARRAY_SIZE(vxd_services
); i
++)
245 if (HIWORD(service
) != vxd_services
[i
].service
) continue;
246 if (!vxd_services
[i
].module
) /* need to load it */
248 if ((vxd_services
[i
].module
= LoadLibraryW( vxd_services
[i
].name
)))
249 vxd_services
[i
].proc
= (VxDCallProc
)GetProcAddress( vxd_services
[i
].module
, "VxDCall" );
251 proc
= vxd_services
[i
].proc
;
254 RtlLeaveCriticalSection( &vxd_section
);
256 if (proc
) context
->Eax
= proc( service
, context
);
259 FIXME( "Unknown/unimplemented VxD (%08lx)\n", service
);
260 context
->Eax
= 0xffffffff; /* FIXME */
263 DEFINE_REGS_ENTRYPOINT( VxDCall
)
266 /***********************************************************************
267 * __wine_vxd_vmm (WPROCS.401)
269 void WINAPI
__wine_vxd_vmm ( CONTEXT
*context
)
271 unsigned service
= AX_reg(context
);
273 TRACE("[%04x] VMM\n", (UINT16
)service
);
277 case 0x0000: /* version */
278 SET_AX( context
, VXD_WinVersion() );
279 RESET_CFLAG(context
);
282 case 0x026d: /* Get_Debug_Flag '/m' */
283 case 0x026e: /* Get_Debug_Flag '/n' */
284 SET_AL( context
, 0 );
285 RESET_CFLAG(context
);
289 VXD_BARF( context
, "VMM" );
293 /***********************************************************************
294 * __wine_vxd_pagefile (WPROCS.433)
296 void WINAPI
__wine_vxd_pagefile( CONTEXT
*context
)
298 unsigned service
= AX_reg(context
);
300 /* taken from Ralf Brown's Interrupt List */
302 TRACE("[%04x] PageFile\n", (UINT16
)service
);
306 case 0x00: /* get version, is this windows version? */
307 TRACE("returning version\n");
308 SET_AX( context
, VXD_WinVersion() );
309 RESET_CFLAG(context
);
312 case 0x01: /* get swap file info */
313 TRACE("VxD PageFile: returning swap file info\n");
314 SET_AX( context
, 0x00 ); /* paging disabled */
315 context
->Ecx
= 0; /* maximum size of paging file */
316 /* FIXME: do I touch DS:SI or DS:DI? */
317 RESET_CFLAG(context
);
320 case 0x02: /* delete permanent swap on exit */
321 TRACE("VxD PageFile: supposed to delete swap\n");
322 RESET_CFLAG(context
);
325 case 0x03: /* current temporary swap file size */
326 TRACE("VxD PageFile: what is current temp. swap size\n");
327 RESET_CFLAG(context
);
330 case 0x04: /* read or write?? INTERRUP.D */
331 case 0x05: /* cancel?? INTERRUP.D */
332 case 0x06: /* test I/O valid INTERRUP.D */
334 VXD_BARF( context
, "pagefile" );
339 /***********************************************************************
340 * __wine_vxd_reboot (WPROCS.409)
342 void WINAPI
__wine_vxd_reboot( CONTEXT
*context
)
344 unsigned service
= AX_reg(context
);
346 TRACE("[%04x] Reboot\n", (UINT16
)service
);
350 case 0x0000: /* version */
351 SET_AX( context
, VXD_WinVersion() );
352 RESET_CFLAG(context
);
356 VXD_BARF( context
, "REBOOT" );
360 /***********************************************************************
361 * __wine_vxd_vdd (WPROCS.410)
363 void WINAPI
__wine_vxd_vdd( CONTEXT
*context
)
365 unsigned service
= AX_reg(context
);
367 TRACE("[%04x] VDD\n", (UINT16
)service
);
371 case 0x0000: /* version */
372 SET_AX( context
, VXD_WinVersion() );
373 RESET_CFLAG(context
);
377 VXD_BARF( context
, "VDD" );
381 /***********************************************************************
382 * __wine_vxd_vmd (WPROCS.412)
384 void WINAPI
__wine_vxd_vmd( CONTEXT
*context
)
386 unsigned service
= AX_reg(context
);
388 TRACE("[%04x] VMD\n", (UINT16
)service
);
392 case 0x0000: /* version */
393 SET_AX( context
, VXD_WinVersion() );
394 RESET_CFLAG(context
);
398 VXD_BARF( context
, "VMD" );
402 /***********************************************************************
403 * __wine_vxd_vxdloader (WPROCS.439)
405 void WINAPI
__wine_vxd_vxdloader( CONTEXT
*context
)
407 unsigned service
= AX_reg(context
);
409 TRACE("[%04x] VXDLoader\n", (UINT16
)service
);
413 case 0x0000: /* get version */
414 TRACE("returning version\n");
415 SET_AX( context
, 0x0000 );
416 SET_DX( context
, VXD_WinVersion() );
417 RESET_CFLAG(context
);
420 case 0x0001: /* load device */
421 FIXME("load device %04lx:%04x (%s)\n",
422 context
->SegDs
, DX_reg(context
),
423 debugstr_a(MapSL(MAKESEGPTR(context
->SegDs
, DX_reg(context
)))));
424 SET_AX( context
, 0x0000 );
425 context
->SegEs
= 0x0000;
426 SET_DI( context
, 0x0000 );
427 RESET_CFLAG(context
);
430 case 0x0002: /* unload device */
431 FIXME("unload device (%08lx)\n", context
->Ebx
);
432 SET_AX( context
, 0x0000 );
433 RESET_CFLAG(context
);
437 VXD_BARF( context
, "VXDLDR" );
438 SET_AX( context
, 0x000B ); /* invalid function number */
444 /***********************************************************************
445 * __wine_vxd_shell (WPROCS.423)
447 void WINAPI
__wine_vxd_shell( CONTEXT
*context
)
449 unsigned service
= DX_reg(context
);
451 TRACE("[%04x] Shell\n", (UINT16
)service
);
453 switch (service
) /* Ralf Brown says EDX, but I use DX instead */
456 TRACE("returning version\n");
457 SET_AX( context
, VXD_WinVersion() );
458 context
->Ebx
= 1; /* system VM Handle */
464 /* SHELL_SYSMODAL_Message
465 ebx virtual machine handle
466 eax message box flags
467 ecx address of message
468 edi address of caption
469 return response in eax
473 ebx virtual machine handle
474 eax message box flags
475 ecx address of message
476 edi address of caption
478 edx reference data for callback
479 return response in eax
482 VXD_BARF( context
, "shell" );
485 case 0x0006: /* SHELL_Get_VM_State */
486 TRACE("VxD Shell: returning VM state\n");
487 /* Actually we don't, not yet. We have to return a structure
488 * and I am not to sure how to set it up and return it yet,
489 * so for now let's do nothing. I can (hopefully) get this
490 * by the next release
492 /* RESET_CFLAG(context); */
511 VXD_BARF( context
, "SHELL" );
514 /* the new Win95 shell API */
515 case 0x0100: /* get version */
516 SET_AX( context
, VXD_WinVersion() );
519 case 0x0104: /* retrieve Hook_Properties list */
520 case 0x0105: /* call Hook_Properties callbacks */
521 VXD_BARF( context
, "SHELL" );
524 case 0x0106: /* install timeout callback */
525 TRACE("VxD Shell: ignoring shell callback (%ld sec.)\n", context
->Ebx
);
529 case 0x0107: /* get version of any VxD */
531 VXD_BARF( context
, "SHELL" );
537 /***********************************************************************
538 * __wine_vxd_comm (WPROCS.414)
540 void WINAPI
__wine_vxd_comm( CONTEXT
*context
)
542 unsigned service
= AX_reg(context
);
544 TRACE("[%04x] Comm\n", (UINT16
)service
);
548 case 0x0000: /* get version */
549 TRACE("returning version\n");
550 SET_AX( context
, VXD_WinVersion() );
551 RESET_CFLAG(context
);
554 case 0x0001: /* set port global */
555 case 0x0002: /* get focus */
556 case 0x0003: /* virtualise port */
558 VXD_BARF( context
, "comm" );
562 /***********************************************************************
563 * __wine_vxd_timer (WPROCS.405)
565 void WINAPI
__wine_vxd_timer( CONTEXT
*context
)
567 unsigned service
= AX_reg(context
);
569 TRACE("[%04x] Virtual Timer\n", (UINT16
)service
);
573 case 0x0000: /* version */
574 SET_AX( context
, VXD_WinVersion() );
575 RESET_CFLAG(context
);
578 case 0x0100: /* clock tick time, in 840nsecs */
579 context
->Eax
= GetTickCount();
581 context
->Edx
= context
->Eax
>> 22;
582 context
->Eax
<<= 10; /* not very precise */
585 case 0x0101: /* current Windows time, msecs */
586 case 0x0102: /* current VM time, msecs */
587 context
->Eax
= GetTickCount();
591 VXD_BARF( context
, "VTD" );
596 /***********************************************************************
599 static DWORD CALLBACK
timer_thread( void *arg
)
601 DWORD
*system_time
= arg
;
605 *system_time
= GetTickCount();
613 /***********************************************************************
614 * __wine_vxd_timerapi (WPROCS.1490)
616 void WINAPI
__wine_vxd_timerapi( CONTEXT
*context
)
618 static WORD System_Time_Selector
;
620 unsigned service
= AX_reg(context
);
622 TRACE("[%04x] TimerAPI\n", (UINT16
)service
);
626 case 0x0000: /* version */
627 SET_AX( context
, VXD_WinVersion() );
628 RESET_CFLAG(context
);
631 case 0x0009: /* get system time selector */
632 if ( !System_Time_Selector
)
634 HANDLE16 handle
= GlobalAlloc16( GMEM_FIXED
, sizeof(DWORD
) );
635 System_Time_Selector
= handle
| 7;
636 CloseHandle( CreateThread( NULL
, 0, timer_thread
, GlobalLock16(handle
), 0, NULL
) );
638 SET_AX( context
, System_Time_Selector
);
639 RESET_CFLAG(context
);
643 VXD_BARF( context
, "VTDAPI" );
647 /***********************************************************************
648 * __wine_vxd_configmg (WPROCS.451)
650 void WINAPI
__wine_vxd_configmg( CONTEXT
*context
)
652 unsigned service
= AX_reg(context
);
654 TRACE("[%04x] ConfigMG\n", (UINT16
)service
);
658 case 0x0000: /* version */
659 SET_AX( context
, VXD_WinVersion() );
660 RESET_CFLAG(context
);
664 VXD_BARF( context
, "CONFIGMG" );
668 /***********************************************************************
669 * __wine_vxd_enable (WPROCS.455)
671 void WINAPI
__wine_vxd_enable( CONTEXT
*context
)
673 unsigned service
= AX_reg(context
);
675 TRACE("[%04x] Enable\n", (UINT16
)service
);
679 case 0x0000: /* version */
680 SET_AX( context
, VXD_WinVersion() );
681 RESET_CFLAG(context
);
685 VXD_BARF( context
, "ENABLE" );
689 /***********************************************************************
690 * __wine_vxd_apm (WPROCS.438)
692 void WINAPI
__wine_vxd_apm( CONTEXT
*context
)
694 unsigned service
= AX_reg(context
);
696 TRACE("[%04x] APM\n", (UINT16
)service
);
700 case 0x0000: /* version */
701 SET_AX( context
, VXD_WinVersion() );
702 RESET_CFLAG(context
);
706 VXD_BARF( context
, "APM" );
710 /***********************************************************************
711 * __wine_vxd_win32s (WPROCS.445)
713 * This is an implementation of the services of the Win32s VxD.
714 * Since official documentation of these does not seem to be available,
715 * certain arguments of some of the services remain unclear.
717 * FIXME: The following services are currently unimplemented:
718 * Exception handling (0x01, 0x1C)
719 * Debugger support (0x0C, 0x14, 0x17)
720 * Low-level memory access (0x02, 0x03, 0x0A, 0x0B)
721 * Memory Statistics (0x1B)
724 * We have a specific problem running Win32s on Linux (and probably also
725 * the other x86 unixes), since Win32s tries to allocate its main 'flat
726 * code/data segment' selectors with a base of 0xffff0000 (and limit 4GB).
727 * The rationale for this seems to be that they want one the one hand to
728 * be able to leave the Win 3.1 memory (starting with the main DOS memory)
729 * at linear address 0, but want at other hand to have offset 0 of the
730 * flat data/code segment point to an unmapped page (to catch NULL pointer
731 * accesses). Hence they allocate the flat segments with a base of 0xffff0000
732 * so that the Win 3.1 memory area at linear address zero shows up in the
733 * flat segments at offset 0x10000 (since linear addresses wrap around at
734 * 4GB). To compensate for that discrepancy between flat segment offsets
735 * and plain linear addresses, all flat pointers passed between the 32-bit
736 * and the 16-bit parts of Win32s are shifted by 0x10000 in the appropriate
737 * direction by the glue code (mainly) in W32SKRNL and WIN32S16.
739 * The problem for us is now that Linux does not allow a LDT selector with
740 * base 0xffff0000 to be created, since it would 'see' a part of the kernel
741 * address space. To address this problem we introduce *another* offset:
742 * We add 0x10000 to every linear address we get as an argument from Win32s.
743 * This means especially that the flat code/data selectors get actually
744 * allocated with base 0x0, so that flat offsets and (real) linear addresses
745 * do again agree! In fact, every call e.g. of a Win32s VxD service now
746 * has all pointer arguments (which are offsets in the flat data segment)
747 * first reduced by 0x10000 by the W32SKRNL glue code, and then again
748 * increased by 0x10000 by *our* code.
750 * Note that to keep everything consistent, this offset has to be applied by
751 * every Wine function that operates on 'linear addresses' passed to it by
752 * Win32s. Fortunately, since Win32s does not directly call any Wine 32-bit
753 * API routines, this affects only two locations: this VxD and the DPMI
754 * handler. (NOTE: Should any Win32s application pass a linear address to
755 * any routine apart from those, e.g. some other VxD handler, that code
756 * would have to take the offset into account as well!)
758 * The offset is set the first time any application calls the GetVersion()
759 * service of the Win32s VxD. (Note that the offset is never reset.)
762 void WINAPI
__wine_vxd_win32s( CONTEXT
*context
)
764 switch (AX_reg(context
))
766 case 0x0000: /* Get Version */
770 * Output: EAX: LoWord: Win32s Version (1.30)
771 * HiWord: VxD Version (200)
777 * EDX: Debugging Flags
781 * 1 if VMCPD VxD not found
784 TRACE("GetVersion()\n");
786 context
->Eax
= VXD_WinVersion() | (200 << 16);
793 * If this is the first time we are called for this process,
794 * hack the memory image of WIN32S16 so that it doesn't try
795 * to access the GDT directly ...
797 * The first code segment of WIN32S16 (version 1.30) contains
798 * an unexported function somewhere between the exported functions
799 * SetFS and StackLinearToSegmented that tries to find a selector
800 * in the LDT that maps to the memory image of the LDT itself.
801 * If it succeeds, it stores this selector into a global variable
802 * which will be used to speed up execution by using this selector
803 * to modify the LDT directly instead of using the DPMI calls.
805 * To perform this search of the LDT, this function uses the
806 * sgdt and sldt instructions to find the linear address of
807 * the (GDT and then) LDT. While those instructions themselves
808 * execute without problem, the linear address that sgdt returns
809 * points (at least under Linux) to the kernel address space, so
810 * that any subsequent access leads to a segfault.
812 * Fortunately, WIN32S16 still contains as a fallback option the
813 * mechanism of using DPMI calls to modify LDT selectors instead
814 * of direct writes to the LDT. Thus we can circumvent the problem
815 * by simply replacing the first byte of the offending function
816 * with an 'retf' instruction. This means that the global variable
817 * supposed to contain the LDT alias selector will remain zero,
818 * and hence WIN32S16 will fall back to using DPMI calls.
820 * The heuristic we employ to _find_ that function is as follows:
821 * We search between the addresses of the exported symbols SetFS
822 * and StackLinearToSegmented for the byte sequence '0F 01 04'
823 * (this is the opcode of 'sgdt [si]'). We then search backwards
824 * from this address for the last occurrence of 'CB' (retf) that marks
825 * the end of the preceding function. The following byte (which
826 * should now be the first byte of the function we are looking for)
827 * will be replaced by 'CB' (retf).
829 * This heuristic works for the retail as well as the debug version
830 * of Win32s version 1.30. For versions earlier than that this
831 * hack should not be necessary at all, since the whole mechanism
832 * ('PERF130') was introduced only in 1.30 to improve the overall
833 * performance of Win32s.
838 HMODULE16 hModule
= GetModuleHandle16("win32s16");
839 SEGPTR func1
= (SEGPTR
)GetProcAddress16(hModule
, "SetFS");
840 SEGPTR func2
= (SEGPTR
)GetProcAddress16(hModule
, "StackLinearToSegmented");
842 if ( hModule
&& func1
&& func2
843 && SELECTOROF(func1
) == SELECTOROF(func2
))
845 BYTE
*start
= MapSL(func1
);
846 BYTE
*end
= MapSL(func2
);
847 BYTE
*p
, *retv
= NULL
;
850 for (p
= start
; p
< end
; p
++)
851 if (*p
== 0xCB) found
= 0, retv
= p
;
852 else if (*p
== 0x0F) found
= 1;
853 else if (*p
== 0x01 && found
== 1) found
= 2;
854 else if (*p
== 0x04 && found
== 2) { found
= 3; break; }
857 if (found
== 3 && retv
)
859 TRACE("PERF130 hack: "
860 "Replacing byte %02X at offset %04X:%04X\n",
861 *(retv
+1), SELECTOROF(func1
),
862 OFFSETOF(func1
) + retv
+1-start
);
864 *(retv
+1) = (BYTE
)0xCB;
870 * Mark process as Win32s, so that subsequent DPMI calls
871 * will perform the W32S_APP2WINE/W32S_WINE2APP address shift.
873 W32S_offset
= 0x10000;
877 case 0x0001: /* Install Exception Handling */
879 * Input: EBX: Flat address of W32SKRNL Exception Data
881 * ECX: LoWord: Flat Code Selector
882 * HiWord: Flat Data Selector
884 * EDX: Flat address of W32SKRNL Exception Handler
885 * (this is equal to W32S_BackTo32 + 0x40)
887 * ESI: SEGPTR KERNEL.HASGPHANDLER
889 * EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10)
891 * Output: EAX: 0 if OK
894 TRACE("[0001] EBX=%lx ECX=%lx EDX=%lx ESI=%lx EDI=%lx\n",
895 context
->Ebx
, context
->Ecx
, context
->Edx
,
896 context
->Esi
, context
->Edi
);
904 case 0x0002: /* Set Page Access Flags */
906 * Input: EBX: New access flags
907 * Bit 2: User Page if set, Supervisor Page if clear
908 * Bit 1: Read-Write if set, Read-Only if clear
910 * ECX: Size of memory area to change
912 * EDX: Flat start address of memory area
914 * Output: EAX: Size of area changed
917 TRACE("[0002] EBX=%lx ECX=%lx EDX=%lx\n",
918 context
->Ebx
, context
->Ecx
, context
->Edx
);
922 context
->Eax
= context
->Ecx
;
926 case 0x0003: /* Get Page Access Flags */
928 * Input: EDX: Flat address of page to query
930 * Output: EAX: Page access flags
931 * Bit 2: User Page if set, Supervisor Page if clear
932 * Bit 1: Read-Write if set, Read-Only if clear
935 TRACE("[0003] EDX=%lx\n", context
->Edx
);
943 case 0x0004: /* Map Module */
945 * Input: ECX: IMTE (offset in Module Table) of new module
947 * EDX: Flat address of Win32s Module Table
949 * Output: EAX: 0 if OK
952 if (!context
->Edx
|| CX_reg(context
) == 0xFFFF)
954 TRACE("MapModule: Initialization call\n");
960 * Structure of a Win32s Module Table Entry:
975 * Note: This function should set up a demand-paged memory image
976 * of the given module. Since mmap does not allow file offsets
977 * not aligned at 1024 bytes, we simply load the image fully
981 struct Win32sModule
*moduleTable
=
982 (struct Win32sModule
*)W32S_APP2WINE(context
->Edx
);
983 struct Win32sModule
*module
= moduleTable
+ context
->Ecx
;
985 IMAGE_NT_HEADERS
*nt_header
= RtlImageNtHeader( (HMODULE
)module
->baseAddr
);
986 IMAGE_SECTION_HEADER
*pe_seg
= IMAGE_FIRST_SECTION( nt_header
);
987 HFILE image
= _lopen(module
->pathName
, OF_READ
);
988 BOOL error
= (image
== HFILE_ERROR
);
991 TRACE("MapModule: Loading %s\n", module
->pathName
);
994 !error
&& i
< nt_header
->FileHeader
.NumberOfSections
;
996 if(!(pe_seg
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
))
998 DWORD off
= pe_seg
->PointerToRawData
;
999 DWORD len
= pe_seg
->SizeOfRawData
;
1000 LPBYTE addr
= module
->baseAddr
+ pe_seg
->VirtualAddress
;
1003 "Section %d at %08lx from %08lx len %08lx\n",
1004 i
, (DWORD
)addr
, off
, len
);
1006 if ( _llseek(image
, off
, SEEK_SET
) != off
1007 || _lread(image
, addr
, len
) != len
)
1014 ERR("MapModule: Unable to load %s\n", module
->pathName
);
1016 else if (module
->relocDelta
!= 0)
1018 IMAGE_DATA_DIRECTORY
*dir
= nt_header
->OptionalHeader
.DataDirectory
1019 + IMAGE_DIRECTORY_ENTRY_BASERELOC
;
1020 IMAGE_BASE_RELOCATION
*r
= (IMAGE_BASE_RELOCATION
*)
1021 (dir
->Size
? module
->baseAddr
+ dir
->VirtualAddress
: 0);
1023 TRACE("MapModule: Reloc delta %08lx\n", module
->relocDelta
);
1025 while (r
&& r
->VirtualAddress
)
1027 LPBYTE page
= module
->baseAddr
+ r
->VirtualAddress
;
1028 WORD
*TypeOffset
= (WORD
*)(r
+ 1);
1029 unsigned int count
= (r
->SizeOfBlock
- sizeof(*r
)) / sizeof(*TypeOffset
);
1031 TRACE("MapModule: %d relocations for page %08lx\n",
1032 count
, (DWORD
)page
);
1034 for(i
= 0; i
< count
; i
++)
1036 int offset
= TypeOffset
[i
] & 0xFFF;
1037 int type
= TypeOffset
[i
] >> 12;
1040 case IMAGE_REL_BASED_ABSOLUTE
:
1042 case IMAGE_REL_BASED_HIGH
:
1043 *(WORD
*)(page
+offset
) += HIWORD(module
->relocDelta
);
1045 case IMAGE_REL_BASED_LOW
:
1046 *(WORD
*)(page
+offset
) += LOWORD(module
->relocDelta
);
1048 case IMAGE_REL_BASED_HIGHLOW
:
1049 *(DWORD
*)(page
+offset
) += module
->relocDelta
;
1052 WARN("MapModule: Unsupported fixup type\n");
1057 r
= (IMAGE_BASE_RELOCATION
*)((LPBYTE
)r
+ r
->SizeOfBlock
);
1062 RESET_CFLAG(context
);
1067 case 0x0005: /* UnMap Module */
1069 * Input: EDX: Flat address of module image
1071 * Output: EAX: 1 if OK
1074 TRACE("UnMapModule: %lx\n", W32S_APP2WINE(context
->Edx
));
1076 /* As we didn't map anything, there's nothing to unmap ... */
1082 case 0x0006: /* VirtualAlloc */
1084 * Input: ECX: Current Process
1086 * EDX: Flat address of arguments on stack
1088 * DWORD *retv [out] Flat base address of allocated region
1089 * LPVOID base [in] Flat address of region to reserve/commit
1090 * DWORD size [in] Size of region
1091 * DWORD type [in] Type of allocation
1092 * DWORD prot [in] Type of access protection
1094 * Output: EAX: NtStatus
1097 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1098 DWORD
*retv
= (DWORD
*)W32S_APP2WINE(stack
[0]);
1099 LPVOID base
= (LPVOID
) W32S_APP2WINE(stack
[1]);
1100 DWORD size
= stack
[2];
1101 DWORD type
= stack
[3];
1102 DWORD prot
= stack
[4];
1105 TRACE("VirtualAlloc(%lx, %lx, %lx, %lx, %lx)\n",
1106 (DWORD
)retv
, (DWORD
)base
, size
, type
, prot
);
1108 if (type
& 0x80000000)
1110 WARN("VirtualAlloc: strange type %lx\n", type
);
1114 if (!base
&& (type
& MEM_COMMIT
) && prot
== PAGE_READONLY
)
1116 WARN("VirtualAlloc: NLS hack, allowing write access!\n");
1117 prot
= PAGE_READWRITE
;
1120 result
= (DWORD
)VirtualAlloc(base
, size
, type
, prot
);
1122 if (W32S_WINE2APP(result
))
1123 *retv
= W32S_WINE2APP(result
),
1124 context
->Eax
= STATUS_SUCCESS
;
1127 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1132 case 0x0007: /* VirtualFree */
1134 * Input: ECX: Current Process
1136 * EDX: Flat address of arguments on stack
1138 * DWORD *retv [out] TRUE if success, FALSE if failure
1139 * LPVOID base [in] Flat address of region
1140 * DWORD size [in] Size of region
1141 * DWORD type [in] Type of operation
1143 * Output: EAX: NtStatus
1146 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1147 DWORD
*retv
= (DWORD
*)W32S_APP2WINE(stack
[0]);
1148 LPVOID base
= (LPVOID
) W32S_APP2WINE(stack
[1]);
1149 DWORD size
= stack
[2];
1150 DWORD type
= stack
[3];
1153 TRACE("VirtualFree(%lx, %lx, %lx, %lx)\n",
1154 (DWORD
)retv
, (DWORD
)base
, size
, type
);
1156 result
= VirtualFree(base
, size
, type
);
1160 context
->Eax
= STATUS_SUCCESS
;
1163 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1168 case 0x0008: /* VirtualProtect */
1170 * Input: ECX: Current Process
1172 * EDX: Flat address of arguments on stack
1174 * DWORD *retv [out] TRUE if success, FALSE if failure
1175 * LPVOID base [in] Flat address of region
1176 * DWORD size [in] Size of region
1177 * DWORD new_prot [in] Desired access protection
1178 * DWORD *old_prot [out] Previous access protection
1180 * Output: EAX: NtStatus
1183 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1184 DWORD
*retv
= (DWORD
*)W32S_APP2WINE(stack
[0]);
1185 LPVOID base
= (LPVOID
) W32S_APP2WINE(stack
[1]);
1186 DWORD size
= stack
[2];
1187 DWORD new_prot
= stack
[3];
1188 DWORD
*old_prot
= (DWORD
*)W32S_APP2WINE(stack
[4]);
1191 TRACE("VirtualProtect(%lx, %lx, %lx, %lx, %lx)\n",
1192 (DWORD
)retv
, (DWORD
)base
, size
, new_prot
, (DWORD
)old_prot
);
1194 result
= VirtualProtect(base
, size
, new_prot
, old_prot
);
1198 context
->Eax
= STATUS_SUCCESS
;
1201 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1206 case 0x0009: /* VirtualQuery */
1208 * Input: ECX: Current Process
1210 * EDX: Flat address of arguments on stack
1212 * DWORD *retv [out] Nr. bytes returned
1213 * LPVOID base [in] Flat address of region
1214 * LPMEMORY_BASIC_INFORMATION info [out] Info buffer
1215 * DWORD len [in] Size of buffer
1217 * Output: EAX: NtStatus
1220 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1221 DWORD
*retv
= (DWORD
*)W32S_APP2WINE(stack
[0]);
1222 LPVOID base
= (LPVOID
) W32S_APP2WINE(stack
[1]);
1223 PMEMORY_BASIC_INFORMATION info
=
1224 (PMEMORY_BASIC_INFORMATION
)W32S_APP2WINE(stack
[2]);
1225 DWORD len
= stack
[3];
1228 TRACE("VirtualQuery(%lx, %lx, %lx, %lx)\n",
1229 (DWORD
)retv
, (DWORD
)base
, (DWORD
)info
, len
);
1231 result
= VirtualQuery(base
, info
, len
);
1234 context
->Eax
= STATUS_SUCCESS
;
1239 case 0x000A: /* SetVirtMemProcess */
1241 * Input: ECX: Process Handle
1243 * EDX: Flat address of region
1245 * Output: EAX: NtStatus
1248 TRACE("[000a] ECX=%lx EDX=%lx\n",
1249 context
->Ecx
, context
->Edx
);
1253 context
->Eax
= STATUS_SUCCESS
;
1257 case 0x000B: /* ??? some kind of cleanup */
1259 * Input: ECX: Process Handle
1261 * Output: EAX: NtStatus
1264 TRACE("[000b] ECX=%lx\n", context
->Ecx
);
1268 context
->Eax
= STATUS_SUCCESS
;
1272 case 0x000C: /* Set Debug Flags */
1274 * Input: EDX: Debug Flags
1276 * Output: EDX: Previous Debug Flags
1279 FIXME("[000c] EDX=%lx\n", context
->Edx
);
1287 case 0x000D: /* NtCreateSection */
1289 * Input: EDX: Flat address of arguments on stack
1291 * HANDLE32 *retv [out] Handle of Section created
1292 * DWORD flags1 [in] (?? unknown ??)
1293 * DWORD atom [in] Name of Section to create
1294 * LARGE_INTEGER *size [in] Size of Section
1295 * DWORD protect [in] Access protection
1296 * DWORD flags2 [in] (?? unknown ??)
1297 * HFILE32 hFile [in] Handle of file to map
1298 * DWORD psp [in] (Win32s: PSP that hFile belongs to)
1300 * Output: EAX: NtStatus
1303 DWORD
*stack
= (DWORD
*) W32S_APP2WINE(context
->Edx
);
1304 HANDLE
*retv
= (HANDLE
*)W32S_APP2WINE(stack
[0]);
1305 DWORD flags1
= stack
[1];
1306 DWORD atom
= stack
[2];
1307 LARGE_INTEGER
*size
= (LARGE_INTEGER
*)W32S_APP2WINE(stack
[3]);
1308 DWORD protect
= stack
[4];
1309 DWORD flags2
= stack
[5];
1310 HANDLE hFile
= DosFileHandleToWin32Handle(stack
[6]);
1311 DWORD psp
= stack
[7];
1313 HANDLE result
= INVALID_HANDLE_VALUE
;
1316 TRACE("NtCreateSection(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1317 (DWORD
)retv
, flags1
, atom
, (DWORD
)size
, protect
, flags2
,
1320 if (!atom
|| GlobalGetAtomNameA(atom
, name
, sizeof(name
)))
1322 TRACE("NtCreateSection: name=%s\n", atom
? name
: "");
1324 result
= CreateFileMappingA(hFile
, NULL
, protect
,
1325 size
? size
->u
.HighPart
: 0,
1326 size
? size
->u
.LowPart
: 0,
1330 if (result
== INVALID_HANDLE_VALUE
)
1331 WARN("NtCreateSection: failed!\n");
1333 TRACE("NtCreateSection: returned %lx\n", (DWORD
)result
);
1335 if (result
!= INVALID_HANDLE_VALUE
)
1337 context
->Eax
= STATUS_SUCCESS
;
1340 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1345 case 0x000E: /* NtOpenSection */
1347 * Input: EDX: Flat address of arguments on stack
1349 * HANDLE32 *retv [out] Handle of Section opened
1350 * DWORD protect [in] Access protection
1351 * DWORD atom [in] Name of Section to create
1353 * Output: EAX: NtStatus
1356 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1357 HANDLE
*retv
= (HANDLE
*)W32S_APP2WINE(stack
[0]);
1358 DWORD protect
= stack
[1];
1359 DWORD atom
= stack
[2];
1361 HANDLE result
= INVALID_HANDLE_VALUE
;
1364 TRACE("NtOpenSection(%lx, %lx, %lx)\n",
1365 (DWORD
)retv
, protect
, atom
);
1367 if (atom
&& GlobalGetAtomNameA(atom
, name
, sizeof(name
)))
1369 TRACE("NtOpenSection: name=%s\n", name
);
1371 result
= OpenFileMappingA(protect
, FALSE
, name
);
1374 if (result
== INVALID_HANDLE_VALUE
)
1375 WARN("NtOpenSection: failed!\n");
1377 TRACE("NtOpenSection: returned %lx\n", (DWORD
)result
);
1379 if (result
!= INVALID_HANDLE_VALUE
)
1381 context
->Eax
= STATUS_SUCCESS
;
1384 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1389 case 0x000F: /* NtCloseSection */
1391 * Input: EDX: Flat address of arguments on stack
1393 * HANDLE32 handle [in] Handle of Section to close
1394 * DWORD *id [out] Unique ID (?? unclear ??)
1396 * Output: EAX: NtStatus
1399 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1400 HANDLE handle
= (HANDLE
)stack
[0];
1401 DWORD
*id
= (DWORD
*)W32S_APP2WINE(stack
[1]);
1403 TRACE("NtCloseSection(%lx, %lx)\n", (DWORD
)handle
, (DWORD
)id
);
1405 CloseHandle(handle
);
1406 if (id
) *id
= 0; /* FIXME */
1408 context
->Eax
= STATUS_SUCCESS
;
1413 case 0x0010: /* NtDupSection */
1415 * Input: EDX: Flat address of arguments on stack
1417 * HANDLE32 handle [in] Handle of Section to duplicate
1419 * Output: EAX: NtStatus
1422 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1423 HANDLE handle
= (HANDLE
)stack
[0];
1426 TRACE("NtDupSection(%lx)\n", (DWORD
)handle
);
1428 DuplicateHandle( GetCurrentProcess(), handle
,
1429 GetCurrentProcess(), &new_handle
,
1430 0, FALSE
, DUPLICATE_SAME_ACCESS
);
1431 context
->Eax
= STATUS_SUCCESS
;
1436 case 0x0011: /* NtMapViewOfSection */
1438 * Input: EDX: Flat address of arguments on stack
1440 * HANDLE32 SectionHandle [in] Section to be mapped
1441 * DWORD ProcessHandle [in] Process to be mapped into
1442 * DWORD * BaseAddress [in/out] Address to be mapped at
1443 * DWORD ZeroBits [in] Upper address bits that should be null, starting from bit 31
1444 * DWORD CommitSize [in] (?? unclear ??)
1445 * LARGE_INTEGER *SectionOffset [in] Offset within section
1446 * DWORD * ViewSize [in] Size of view
1447 * DWORD InheritDisposition [in] (?? unclear ??)
1448 * DWORD AllocationType [in] (?? unclear ??)
1449 * DWORD Protect [in] Access protection
1451 * Output: EAX: NtStatus
1454 DWORD
* stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1455 HANDLE SectionHandle
= (HANDLE
)stack
[0];
1456 DWORD ProcessHandle
= stack
[1]; /* ignored */
1457 DWORD
* BaseAddress
= (DWORD
*)W32S_APP2WINE(stack
[2]);
1458 DWORD ZeroBits
= stack
[3];
1459 DWORD CommitSize
= stack
[4];
1460 LARGE_INTEGER
*SectionOffset
= (LARGE_INTEGER
*)W32S_APP2WINE(stack
[5]);
1461 DWORD
* ViewSize
= (DWORD
*)W32S_APP2WINE(stack
[6]);
1462 DWORD InheritDisposition
= stack
[7];
1463 DWORD AllocationType
= stack
[8];
1464 DWORD Protect
= stack
[9];
1466 LPBYTE address
= (LPBYTE
)(BaseAddress
?
1467 W32S_APP2WINE(*BaseAddress
) : 0);
1468 DWORD access
= 0, result
;
1470 switch (Protect
& ~(PAGE_GUARD
|PAGE_NOCACHE
))
1472 case PAGE_READONLY
: access
= FILE_MAP_READ
; break;
1473 case PAGE_READWRITE
: access
= FILE_MAP_WRITE
; break;
1474 case PAGE_WRITECOPY
: access
= FILE_MAP_COPY
; break;
1476 case PAGE_EXECUTE_READ
: access
= FILE_MAP_READ
; break;
1477 case PAGE_EXECUTE_READWRITE
: access
= FILE_MAP_WRITE
; break;
1478 case PAGE_EXECUTE_WRITECOPY
: access
= FILE_MAP_COPY
; break;
1481 TRACE("NtMapViewOfSection"
1482 "(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1483 (DWORD
)SectionHandle
, ProcessHandle
, (DWORD
)BaseAddress
,
1484 ZeroBits
, CommitSize
, (DWORD
)SectionOffset
, (DWORD
)ViewSize
,
1485 InheritDisposition
, AllocationType
, Protect
);
1486 TRACE("NtMapViewOfSection: "
1487 "base=%lx, offset=%lx, size=%lx, access=%lx\n",
1488 (DWORD
)address
, SectionOffset
? SectionOffset
->u
.LowPart
: 0,
1489 ViewSize
? *ViewSize
: 0, access
);
1491 result
= (DWORD
)MapViewOfFileEx(SectionHandle
, access
,
1492 SectionOffset
? SectionOffset
->u
.HighPart
: 0,
1493 SectionOffset
? SectionOffset
->u
.LowPart
: 0,
1494 ViewSize
? *ViewSize
: 0, address
);
1496 TRACE("NtMapViewOfSection: result=%lx\n", result
);
1498 if (W32S_WINE2APP(result
))
1500 if (BaseAddress
) *BaseAddress
= W32S_WINE2APP(result
);
1501 context
->Eax
= STATUS_SUCCESS
;
1504 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1509 case 0x0012: /* NtUnmapViewOfSection */
1511 * Input: EDX: Flat address of arguments on stack
1513 * DWORD ProcessHandle [in] Process (defining address space)
1514 * LPBYTE BaseAddress [in] Base address of view to be unmapped
1516 * Output: EAX: NtStatus
1519 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1520 DWORD ProcessHandle
= stack
[0]; /* ignored */
1521 LPBYTE BaseAddress
= (LPBYTE
)W32S_APP2WINE(stack
[1]);
1523 TRACE("NtUnmapViewOfSection(%lx, %lx)\n",
1524 ProcessHandle
, (DWORD
)BaseAddress
);
1526 UnmapViewOfFile(BaseAddress
);
1528 context
->Eax
= STATUS_SUCCESS
;
1533 case 0x0013: /* NtFlushVirtualMemory */
1535 * Input: EDX: Flat address of arguments on stack
1537 * DWORD ProcessHandle [in] Process (defining address space)
1538 * LPBYTE *BaseAddress [in?] Base address of range to be flushed
1539 * DWORD *ViewSize [in?] Number of bytes to be flushed
1540 * DWORD *unknown [???] (?? unknown ??)
1542 * Output: EAX: NtStatus
1545 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1546 DWORD ProcessHandle
= stack
[0]; /* ignored */
1547 DWORD
*BaseAddress
= (DWORD
*)W32S_APP2WINE(stack
[1]);
1548 DWORD
*ViewSize
= (DWORD
*)W32S_APP2WINE(stack
[2]);
1549 DWORD
*unknown
= (DWORD
*)W32S_APP2WINE(stack
[3]);
1551 LPBYTE address
= (LPBYTE
)(BaseAddress
? W32S_APP2WINE(*BaseAddress
) : 0);
1552 DWORD size
= ViewSize
? *ViewSize
: 0;
1554 TRACE("NtFlushVirtualMemory(%lx, %lx, %lx, %lx)\n",
1555 ProcessHandle
, (DWORD
)BaseAddress
, (DWORD
)ViewSize
,
1557 TRACE("NtFlushVirtualMemory: base=%lx, size=%lx\n",
1558 (DWORD
)address
, size
);
1560 FlushViewOfFile(address
, size
);
1562 context
->Eax
= STATUS_SUCCESS
;
1567 case 0x0014: /* Get/Set Debug Registers */
1569 * Input: ECX: 0 if Get, 1 if Set
1571 * EDX: Get: Flat address of buffer to receive values of
1572 * debug registers DR0 .. DR7
1573 * Set: Flat address of buffer containing values of
1574 * debug registers DR0 .. DR7 to be set
1578 FIXME("[0014] ECX=%lx EDX=%lx\n",
1579 context
->Ecx
, context
->Edx
);
1585 case 0x0015: /* Set Coprocessor Emulation Flag */
1587 * Input: EDX: 0 to deactivate, 1 to activate coprocessor emulation
1592 TRACE("[0015] EDX=%lx\n", context
->Edx
);
1594 /* We don't care, as we always have a coprocessor anyway */
1598 case 0x0016: /* Init Win32S VxD PSP */
1600 * If called to query required PSP size:
1603 * Output: EDX: Required size of Win32s VxD PSP
1605 * If called to initialize allocated PSP:
1607 * Input: EBX: LoWord: Selector of Win32s VxD PSP
1608 * HiWord: Paragraph of Win32s VxD PSP (DOSMEM)
1612 if (context
->Ebx
== 0)
1613 context
->Edx
= 0x80;
1616 PDB16
*psp
= MapSL( MAKESEGPTR( BX_reg(context
), 0 ));
1618 psp
->fileHandlesPtr
= MAKELONG(HIWORD(context
->Ebx
), 0x5c);
1619 memset((LPBYTE
)psp
+ 0x5c, '\xFF', 32);
1624 case 0x0017: /* Set Break Point */
1626 * Input: EBX: Offset of Break Point
1627 * CX: Selector of Break Point
1632 FIXME("[0017] EBX=%lx CX=%x\n",
1633 context
->Ebx
, CX_reg(context
));
1639 case 0x0018: /* VirtualLock */
1641 * Input: ECX: Current Process
1643 * EDX: Flat address of arguments on stack
1645 * DWORD *retv [out] TRUE if success, FALSE if failure
1646 * LPVOID base [in] Flat address of range to lock
1647 * DWORD size [in] Size of range
1649 * Output: EAX: NtStatus
1652 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1653 DWORD
*retv
= (DWORD
*)W32S_APP2WINE(stack
[0]);
1654 LPVOID base
= (LPVOID
) W32S_APP2WINE(stack
[1]);
1655 DWORD size
= stack
[2];
1658 TRACE("VirtualLock(%lx, %lx, %lx)\n",
1659 (DWORD
)retv
, (DWORD
)base
, size
);
1661 result
= VirtualLock(base
, size
);
1665 context
->Eax
= STATUS_SUCCESS
;
1668 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1673 case 0x0019: /* VirtualUnlock */
1675 * Input: ECX: Current Process
1677 * EDX: Flat address of arguments on stack
1679 * DWORD *retv [out] TRUE if success, FALSE if failure
1680 * LPVOID base [in] Flat address of range to unlock
1681 * DWORD size [in] Size of range
1683 * Output: EAX: NtStatus
1686 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1687 DWORD
*retv
= (DWORD
*)W32S_APP2WINE(stack
[0]);
1688 LPVOID base
= (LPVOID
) W32S_APP2WINE(stack
[1]);
1689 DWORD size
= stack
[2];
1692 TRACE("VirtualUnlock(%lx, %lx, %lx)\n",
1693 (DWORD
)retv
, (DWORD
)base
, size
);
1695 result
= VirtualUnlock(base
, size
);
1699 context
->Eax
= STATUS_SUCCESS
;
1702 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1707 case 0x001A: /* KGetSystemInfo */
1711 * Output: ECX: Start of sparse memory arena
1712 * EDX: End of sparse memory arena
1715 TRACE("KGetSystemInfo()\n");
1718 * Note: Win32s reserves 0GB - 2GB for Win 3.1 and uses 2GB - 4GB as
1719 * sparse memory arena. We do it the other way around, since
1720 * we have to reserve 3GB - 4GB for Linux, and thus use
1721 * 0GB - 3GB as sparse memory arena.
1723 * FIXME: What about other OSes ?
1726 context
->Ecx
= W32S_WINE2APP(0x00000000);
1727 context
->Edx
= W32S_WINE2APP(0xbfffffff);
1731 case 0x001B: /* KGlobalMemStat */
1733 * Input: ESI: Flat address of buffer to receive memory info
1738 struct Win32sMemoryInfo
1740 DWORD DIPhys_Count
; /* Total physical pages */
1741 DWORD DIFree_Count
; /* Free physical pages */
1742 DWORD DILin_Total_Count
; /* Total virtual pages (private arena) */
1743 DWORD DILin_Total_Free
; /* Free virtual pages (private arena) */
1745 DWORD SparseTotal
; /* Total size of sparse arena (bytes ?) */
1746 DWORD SparseFree
; /* Free size of sparse arena (bytes ?) */
1749 struct Win32sMemoryInfo
*info
=
1750 (struct Win32sMemoryInfo
*)W32S_APP2WINE(context
->Esi
);
1752 FIXME("KGlobalMemStat(%lx)\n", (DWORD
)info
);
1759 case 0x001C: /* Enable/Disable Exceptions */
1761 * Input: ECX: 0 to disable, 1 to enable exception handling
1766 TRACE("[001c] ECX=%lx\n", context
->Ecx
);
1772 case 0x001D: /* VirtualAlloc called from 16-bit code */
1774 * Input: EDX: Segmented address of arguments on stack
1776 * LPVOID base [in] Flat address of region to reserve/commit
1777 * DWORD size [in] Size of region
1778 * DWORD type [in] Type of allocation
1779 * DWORD prot [in] Type of access protection
1781 * Output: EAX: NtStatus
1782 * EDX: Flat base address of allocated region
1785 DWORD
*stack
= MapSL( MAKESEGPTR( LOWORD(context
->Edx
), HIWORD(context
->Edx
) ));
1786 LPVOID base
= (LPVOID
)W32S_APP2WINE(stack
[0]);
1787 DWORD size
= stack
[1];
1788 DWORD type
= stack
[2];
1789 DWORD prot
= stack
[3];
1792 TRACE("VirtualAlloc16(%lx, %lx, %lx, %lx)\n",
1793 (DWORD
)base
, size
, type
, prot
);
1795 if (type
& 0x80000000)
1797 WARN("VirtualAlloc16: strange type %lx\n", type
);
1801 result
= (DWORD
)VirtualAlloc(base
, size
, type
, prot
);
1803 if (W32S_WINE2APP(result
))
1804 context
->Edx
= W32S_WINE2APP(result
),
1805 context
->Eax
= STATUS_SUCCESS
;
1808 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1809 TRACE("VirtualAlloc16: returning base %lx\n", context
->Edx
);
1814 case 0x001E: /* VirtualFree called from 16-bit code */
1816 * Input: EDX: Segmented address of arguments on stack
1818 * LPVOID base [in] Flat address of region
1819 * DWORD size [in] Size of region
1820 * DWORD type [in] Type of operation
1822 * Output: EAX: NtStatus
1823 * EDX: TRUE if success, FALSE if failure
1826 DWORD
*stack
= MapSL( MAKESEGPTR( LOWORD(context
->Edx
), HIWORD(context
->Edx
) ));
1827 LPVOID base
= (LPVOID
)W32S_APP2WINE(stack
[0]);
1828 DWORD size
= stack
[1];
1829 DWORD type
= stack
[2];
1832 TRACE("VirtualFree16(%lx, %lx, %lx)\n",
1833 (DWORD
)base
, size
, type
);
1835 result
= VirtualFree(base
, size
, type
);
1838 context
->Edx
= TRUE
,
1839 context
->Eax
= STATUS_SUCCESS
;
1841 context
->Edx
= FALSE
,
1842 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1847 case 0x001F: /* FWorkingSetSize */
1849 * Input: EDX: 0 if Get, 1 if Set
1851 * ECX: Get: Buffer to receive Working Set Size
1852 * Set: Buffer containing Working Set Size
1857 DWORD
*ptr
= (DWORD
*)W32S_APP2WINE(context
->Ecx
);
1858 BOOL set
= context
->Edx
;
1860 TRACE("FWorkingSetSize(%lx, %lx)\n", (DWORD
)ptr
, (DWORD
)set
);
1863 /* We do it differently ... */;
1867 context
->Eax
= STATUS_SUCCESS
;
1872 VXD_BARF( context
, "W32S" );