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 "wine/port.h"
30 #include <sys/types.h>
31 #ifdef HAVE_SYS_STAT_H
32 # include <sys/stat.h>
38 #define WIN32_NO_STATUS
39 #define NONAMELESSUNION
45 #include "kernel16_private.h"
47 #include "wine/library.h"
48 #include "wine/unicode.h"
49 #include "wine/server.h"
50 #include "wine/debug.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(vxd
);
54 typedef DWORD (WINAPI
*VxDCallProc
)(DWORD
, CONTEXT
*);
55 typedef BOOL (WINAPI
*DeviceIoProc
)(DWORD
, LPVOID
, DWORD
, LPVOID
, DWORD
, LPDWORD
, LPOVERLAPPED
);
65 struct vxdcall_service
73 #define MAX_VXD_MODULES 32
75 static struct vxd_module vxd_modules
[MAX_VXD_MODULES
];
77 static struct vxdcall_service vxd_services
[] =
79 { {'v','m','m','.','v','x','d',0}, 0x0001, NULL
, NULL
},
80 { {'v','w','i','n','3','2','.','v','x','d',0}, 0x002a, NULL
, NULL
}
83 #define NB_VXD_SERVICES (sizeof(vxd_services)/sizeof(vxd_services[0]))
85 #define W32S_APP2WINE(addr) ((addr)? (DWORD)(addr) + W32S_offset : 0)
86 #define W32S_WINE2APP(addr) ((addr)? (DWORD)(addr) - W32S_offset : 0)
88 #define VXD_BARF(context,name) \
89 TRACE( "vxd %s: unknown/not implemented parameters:\n" \
90 "vxd %s: AX %04x, BX %04x, CX %04x, DX %04x, " \
91 "SI %04x, DI %04x, DS %04x, ES %04x\n", \
92 (name), (name), AX_reg(context), BX_reg(context), \
93 CX_reg(context), DX_reg(context), SI_reg(context), \
94 DI_reg(context), (WORD)context->SegDs, (WORD)context->SegEs )
96 static CRITICAL_SECTION vxd_section
;
97 static CRITICAL_SECTION_DEBUG critsect_debug
=
100 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
101 0, 0, { (DWORD_PTR
)(__FILE__
": vxd_section") }
103 static CRITICAL_SECTION vxd_section
= { &critsect_debug
, -1, 0, 0, 0, 0 };
105 static UINT W32S_offset
;
107 static WORD
VXD_WinVersion(void)
109 WORD version
= LOWORD(GetVersion16());
110 return (version
>> 8) | (version
<< 8);
113 /* create a file handle to represent a VxD, by opening a dummy file in the wineserver directory */
114 static HANDLE
open_vxd_handle( LPCWSTR name
)
116 static const WCHAR prefixW
[] = {'\\','?','?','\\','u','n','i','x'};
117 const char *dir
= wine_get_server_dir();
121 OBJECT_ATTRIBUTES attr
;
122 UNICODE_STRING nameW
;
125 len
= MultiByteToWideChar( CP_UNIXCP
, 0, dir
, -1, NULL
, 0 );
126 nameW
.Length
= sizeof(prefixW
) + (len
+ strlenW( name
)) * sizeof(WCHAR
);
127 nameW
.MaximumLength
= nameW
.Length
+ sizeof(WCHAR
);
128 if (!(nameW
.Buffer
= HeapAlloc( GetProcessHeap(), 0, nameW
.MaximumLength
)))
130 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
133 memcpy( nameW
.Buffer
, prefixW
, sizeof(prefixW
) );
134 MultiByteToWideChar( CP_UNIXCP
, 0, dir
, -1, nameW
.Buffer
+ sizeof(prefixW
)/sizeof(WCHAR
), len
);
135 len
+= sizeof(prefixW
) / sizeof(WCHAR
);
136 nameW
.Buffer
[len
-1] = '/';
137 strcpyW( nameW
.Buffer
+ len
, name
);
139 attr
.Length
= sizeof(attr
);
140 attr
.RootDirectory
= 0;
142 attr
.ObjectName
= &nameW
;
143 attr
.SecurityDescriptor
= NULL
;
144 attr
.SecurityQualityOfService
= NULL
;
146 status
= NtCreateFile( &ret
, SYNCHRONIZE
, &attr
, &io
, NULL
, 0,
147 FILE_SHARE_READ
|FILE_SHARE_WRITE
, FILE_OPEN_IF
,
148 FILE_SYNCHRONOUS_IO_ALERT
, NULL
, 0 );
152 SetLastError( RtlNtStatusToDosError(status
) );
154 RtlFreeUnicodeString( &nameW
);
158 /* retrieve the DeviceIoControl function for a Vxd given a file handle */
159 DeviceIoProc
__wine_vxd_get_proc( HANDLE handle
)
161 DeviceIoProc ret
= NULL
;
164 FILE_INTERNAL_INFORMATION info
;
166 status
= NtQueryInformationFile( handle
, &io
, &info
, sizeof(info
), FileInternalInformation
);
169 SetLastError( RtlNtStatusToDosError(status
) );
173 RtlEnterCriticalSection( &vxd_section
);
175 for (i
= 0; i
< MAX_VXD_MODULES
; i
++)
177 if (!vxd_modules
[i
].module
) break;
178 if (vxd_modules
[i
].index
.QuadPart
== info
.IndexNumber
.QuadPart
)
180 if (!(ret
= vxd_modules
[i
].proc
)) SetLastError( ERROR_INVALID_FUNCTION
);
184 /* FIXME: Here we could go through the directory to find the VxD name and load it. */
185 /* Let's wait to find out if there are actually apps out there that try to share */
186 /* VxD handles between processes, before we go to the trouble of implementing it. */
187 ERR( "handle %p not found in module list, inherited from another process?\n", handle
);
190 RtlLeaveCriticalSection( &vxd_section
);
195 /* load a VxD and return a file handle to it */
196 HANDLE
__wine_vxd_open( LPCWSTR filenameW
, DWORD access
, SECURITY_ATTRIBUTES
*sa
)
198 static const WCHAR dotVxDW
[] = {'.','v','x','d',0};
204 /* normalize the filename */
206 if (strlenW( filenameW
) >= sizeof(name
)/sizeof(WCHAR
) - 4 ||
207 strchrW( filenameW
, '/' ) || strchrW( filenameW
, '\\' ))
209 SetLastError( ERROR_FILE_NOT_FOUND
);
212 strcpyW( name
, filenameW
);
214 p
= strchrW( name
, '.' );
215 if (!p
) strcatW( name
, dotVxDW
);
216 else if (strcmpiW( p
, dotVxDW
)) /* existing extension has to be .vxd */
218 SetLastError( ERROR_FILE_NOT_FOUND
);
222 /* try to load the module first */
224 if (!(module
= LoadLibraryW( name
)))
226 FIXME( "Unknown/unsupported VxD %s. Try setting Windows version to 'nt40' or 'win31'.\n",
228 SetLastError( ERROR_FILE_NOT_FOUND
);
232 /* register the module in the global list if necessary */
234 RtlEnterCriticalSection( &vxd_section
);
236 for (i
= 0; i
< MAX_VXD_MODULES
; i
++)
238 if (vxd_modules
[i
].module
== module
)
240 handle
= vxd_modules
[i
].handle
;
241 goto done
; /* already registered */
243 if (!vxd_modules
[i
].module
) /* new one, register it */
246 FILE_INTERNAL_INFORMATION info
;
248 /* get a file handle to the dummy file */
249 if (!(handle
= open_vxd_handle( name
)))
251 FreeLibrary( module
);
254 if (!NtQueryInformationFile( handle
, &io
, &info
, sizeof(info
), FileInternalInformation
))
255 vxd_modules
[i
].index
= info
.IndexNumber
;
257 vxd_modules
[i
].module
= module
;
258 vxd_modules
[i
].handle
= handle
;
259 vxd_modules
[i
].proc
= (DeviceIoProc
)GetProcAddress( module
, "DeviceIoControl" );
264 ERR("too many open VxD modules, please report\n" );
265 FreeLibrary( module
);
269 RtlLeaveCriticalSection( &vxd_section
);
270 if (!DuplicateHandle( GetCurrentProcess(), handle
, GetCurrentProcess(), &handle
, 0,
271 (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
),
272 DUP_HANDLE_SAME_ACCESS
))
278 /***********************************************************************
279 * VxDCall0 (KERNEL32.1)
280 * VxDCall1 (KERNEL32.2)
281 * VxDCall2 (KERNEL32.3)
282 * VxDCall3 (KERNEL32.4)
283 * VxDCall4 (KERNEL32.5)
284 * VxDCall5 (KERNEL32.6)
285 * VxDCall6 (KERNEL32.7)
286 * VxDCall7 (KERNEL32.8)
287 * VxDCall8 (KERNEL32.9)
289 void WINAPI DECLSPEC_HIDDEN
__regs_VxDCall( CONTEXT
*context
)
292 VxDCallProc proc
= NULL
;
293 DWORD service
= stack32_pop( context
);
295 RtlEnterCriticalSection( &vxd_section
);
296 for (i
= 0; i
< NB_VXD_SERVICES
; i
++)
298 if (HIWORD(service
) != vxd_services
[i
].service
) continue;
299 if (!vxd_services
[i
].module
) /* need to load it */
301 if ((vxd_services
[i
].module
= LoadLibraryW( vxd_services
[i
].name
)))
302 vxd_services
[i
].proc
= (VxDCallProc
)GetProcAddress( vxd_services
[i
].module
, "VxDCall" );
304 proc
= vxd_services
[i
].proc
;
307 RtlLeaveCriticalSection( &vxd_section
);
309 if (proc
) context
->Eax
= proc( service
, context
);
312 FIXME( "Unknown/unimplemented VxD (%08x)\n", service
);
313 context
->Eax
= 0xffffffff; /* FIXME */
316 DEFINE_REGS_ENTRYPOINT( VxDCall
)
319 /***********************************************************************
320 * __wine_vxd_vmm (WPROCS.401)
322 void WINAPI
__wine_vxd_vmm ( CONTEXT
*context
)
324 unsigned service
= AX_reg(context
);
326 TRACE("[%04x] VMM\n", (UINT16
)service
);
330 case 0x0000: /* version */
331 SET_AX( context
, VXD_WinVersion() );
332 RESET_CFLAG(context
);
335 case 0x026d: /* Get_Debug_Flag '/m' */
336 case 0x026e: /* Get_Debug_Flag '/n' */
337 SET_AL( context
, 0 );
338 RESET_CFLAG(context
);
342 VXD_BARF( context
, "VMM" );
346 /***********************************************************************
347 * __wine_vxd_pagefile (WPROCS.433)
349 void WINAPI
__wine_vxd_pagefile( CONTEXT
*context
)
351 unsigned service
= AX_reg(context
);
353 /* taken from Ralf Brown's Interrupt List */
355 TRACE("[%04x] PageFile\n", (UINT16
)service
);
359 case 0x00: /* get version, is this windows version? */
360 TRACE("returning version\n");
361 SET_AX( context
, VXD_WinVersion() );
362 RESET_CFLAG(context
);
365 case 0x01: /* get swap file info */
366 TRACE("VxD PageFile: returning swap file info\n");
367 SET_AX( context
, 0x00 ); /* paging disabled */
368 context
->Ecx
= 0; /* maximum size of paging file */
369 /* FIXME: do I touch DS:SI or DS:DI? */
370 RESET_CFLAG(context
);
373 case 0x02: /* delete permanent swap on exit */
374 TRACE("VxD PageFile: supposed to delete swap\n");
375 RESET_CFLAG(context
);
378 case 0x03: /* current temporary swap file size */
379 TRACE("VxD PageFile: what is current temp. swap size\n");
380 RESET_CFLAG(context
);
383 case 0x04: /* read or write?? INTERRUP.D */
384 case 0x05: /* cancel?? INTERRUP.D */
385 case 0x06: /* test I/O valid INTERRUP.D */
387 VXD_BARF( context
, "pagefile" );
392 /***********************************************************************
393 * __wine_vxd_reboot (WPROCS.409)
395 void WINAPI
__wine_vxd_reboot( CONTEXT
*context
)
397 unsigned service
= AX_reg(context
);
399 TRACE("[%04x] Reboot\n", (UINT16
)service
);
403 case 0x0000: /* version */
404 SET_AX( context
, VXD_WinVersion() );
405 RESET_CFLAG(context
);
409 VXD_BARF( context
, "REBOOT" );
413 /***********************************************************************
414 * __wine_vxd_vdd (WPROCS.410)
416 void WINAPI
__wine_vxd_vdd( CONTEXT
*context
)
418 unsigned service
= AX_reg(context
);
420 TRACE("[%04x] VDD\n", (UINT16
)service
);
424 case 0x0000: /* version */
425 SET_AX( context
, VXD_WinVersion() );
426 RESET_CFLAG(context
);
430 VXD_BARF( context
, "VDD" );
434 /***********************************************************************
435 * __wine_vxd_vmd (WPROCS.412)
437 void WINAPI
__wine_vxd_vmd( CONTEXT
*context
)
439 unsigned service
= AX_reg(context
);
441 TRACE("[%04x] VMD\n", (UINT16
)service
);
445 case 0x0000: /* version */
446 SET_AX( context
, VXD_WinVersion() );
447 RESET_CFLAG(context
);
451 VXD_BARF( context
, "VMD" );
455 /***********************************************************************
456 * __wine_vxd_vxdloader (WPROCS.439)
458 void WINAPI
__wine_vxd_vxdloader( CONTEXT
*context
)
460 unsigned service
= AX_reg(context
);
462 TRACE("[%04x] VXDLoader\n", (UINT16
)service
);
466 case 0x0000: /* get version */
467 TRACE("returning version\n");
468 SET_AX( context
, 0x0000 );
469 SET_DX( context
, VXD_WinVersion() );
470 RESET_CFLAG(context
);
473 case 0x0001: /* load device */
474 FIXME("load device %04x:%04x (%s)\n",
475 context
->SegDs
, DX_reg(context
),
476 debugstr_a(MapSL(MAKESEGPTR(context
->SegDs
, DX_reg(context
)))));
477 SET_AX( context
, 0x0000 );
478 context
->SegEs
= 0x0000;
479 SET_DI( context
, 0x0000 );
480 RESET_CFLAG(context
);
483 case 0x0002: /* unload device */
484 FIXME("unload device (%08x)\n", context
->Ebx
);
485 SET_AX( context
, 0x0000 );
486 RESET_CFLAG(context
);
490 VXD_BARF( context
, "VXDLDR" );
491 SET_AX( context
, 0x000B ); /* invalid function number */
497 /***********************************************************************
498 * __wine_vxd_shell (WPROCS.423)
500 void WINAPI
__wine_vxd_shell( CONTEXT
*context
)
502 unsigned service
= DX_reg(context
);
504 TRACE("[%04x] Shell\n", (UINT16
)service
);
506 switch (service
) /* Ralf Brown says EDX, but I use DX instead */
509 TRACE("returning version\n");
510 SET_AX( context
, VXD_WinVersion() );
511 context
->Ebx
= 1; /* system VM Handle */
517 /* SHELL_SYSMODAL_Message
518 ebx virtual machine handle
519 eax message box flags
520 ecx address of message
521 edi address of caption
522 return response in eax
526 ebx virtual machine handle
527 eax message box flags
528 ecx address of message
529 edi address of caption
531 edx reference data for callback
532 return response in eax
535 VXD_BARF( context
, "shell" );
538 case 0x0006: /* SHELL_Get_VM_State */
539 TRACE("VxD Shell: returning VM state\n");
540 /* Actually we don't, not yet. We have to return a structure
541 * and I am not to sure how to set it up and return it yet,
542 * so for now let's do nothing. I can (hopefully) get this
543 * by the next release
545 /* RESET_CFLAG(context); */
564 VXD_BARF( context
, "SHELL" );
567 /* the new Win95 shell API */
568 case 0x0100: /* get version */
569 SET_AX( context
, VXD_WinVersion() );
572 case 0x0104: /* retrieve Hook_Properties list */
573 case 0x0105: /* call Hook_Properties callbacks */
574 VXD_BARF( context
, "SHELL" );
577 case 0x0106: /* install timeout callback */
578 TRACE("VxD Shell: ignoring shell callback (%d sec.)\n", context
->Ebx
);
582 case 0x0107: /* get version of any VxD */
584 VXD_BARF( context
, "SHELL" );
590 /***********************************************************************
591 * __wine_vxd_comm (WPROCS.414)
593 void WINAPI
__wine_vxd_comm( CONTEXT
*context
)
595 unsigned service
= AX_reg(context
);
597 TRACE("[%04x] Comm\n", (UINT16
)service
);
601 case 0x0000: /* get version */
602 TRACE("returning version\n");
603 SET_AX( context
, VXD_WinVersion() );
604 RESET_CFLAG(context
);
607 case 0x0001: /* set port global */
608 case 0x0002: /* get focus */
609 case 0x0003: /* virtualise port */
611 VXD_BARF( context
, "comm" );
615 /***********************************************************************
616 * __wine_vxd_timer (WPROCS.405)
618 void WINAPI
__wine_vxd_timer( CONTEXT
*context
)
620 unsigned service
= AX_reg(context
);
622 TRACE("[%04x] Virtual Timer\n", (UINT16
)service
);
626 case 0x0000: /* version */
627 SET_AX( context
, VXD_WinVersion() );
628 RESET_CFLAG(context
);
631 case 0x0100: /* clock tick time, in 840nsecs */
632 context
->Eax
= GetTickCount();
634 context
->Edx
= context
->Eax
>> 22;
635 context
->Eax
<<= 10; /* not very precise */
638 case 0x0101: /* current Windows time, msecs */
639 case 0x0102: /* current VM time, msecs */
640 context
->Eax
= GetTickCount();
644 VXD_BARF( context
, "VTD" );
649 /***********************************************************************
652 static DWORD CALLBACK
timer_thread( void *arg
)
654 DWORD
*system_time
= arg
;
658 *system_time
= GetTickCount();
666 /***********************************************************************
667 * __wine_vxd_timerapi (WPROCS.1490)
669 void WINAPI
__wine_vxd_timerapi( CONTEXT
*context
)
671 static WORD System_Time_Selector
;
673 unsigned service
= AX_reg(context
);
675 TRACE("[%04x] TimerAPI\n", (UINT16
)service
);
679 case 0x0000: /* version */
680 SET_AX( context
, VXD_WinVersion() );
681 RESET_CFLAG(context
);
684 case 0x0009: /* get system time selector */
685 if ( !System_Time_Selector
)
687 HANDLE16 handle
= GlobalAlloc16( GMEM_FIXED
, sizeof(DWORD
) );
688 System_Time_Selector
= handle
| 7;
689 CloseHandle( CreateThread( NULL
, 0, timer_thread
, GlobalLock16(handle
), 0, NULL
) );
691 SET_AX( context
, System_Time_Selector
);
692 RESET_CFLAG(context
);
696 VXD_BARF( context
, "VTDAPI" );
700 /***********************************************************************
701 * __wine_vxd_configmg (WPROCS.451)
703 void WINAPI
__wine_vxd_configmg( CONTEXT
*context
)
705 unsigned service
= AX_reg(context
);
707 TRACE("[%04x] ConfigMG\n", (UINT16
)service
);
711 case 0x0000: /* version */
712 SET_AX( context
, VXD_WinVersion() );
713 RESET_CFLAG(context
);
717 VXD_BARF( context
, "CONFIGMG" );
721 /***********************************************************************
722 * __wine_vxd_enable (WPROCS.455)
724 void WINAPI
__wine_vxd_enable( CONTEXT
*context
)
726 unsigned service
= AX_reg(context
);
728 TRACE("[%04x] Enable\n", (UINT16
)service
);
732 case 0x0000: /* version */
733 SET_AX( context
, VXD_WinVersion() );
734 RESET_CFLAG(context
);
738 VXD_BARF( context
, "ENABLE" );
742 /***********************************************************************
743 * __wine_vxd_apm (WPROCS.438)
745 void WINAPI
__wine_vxd_apm( CONTEXT
*context
)
747 unsigned service
= AX_reg(context
);
749 TRACE("[%04x] APM\n", (UINT16
)service
);
753 case 0x0000: /* version */
754 SET_AX( context
, VXD_WinVersion() );
755 RESET_CFLAG(context
);
759 VXD_BARF( context
, "APM" );
763 /***********************************************************************
764 * __wine_vxd_win32s (WPROCS.445)
766 * This is an implementation of the services of the Win32s VxD.
767 * Since official documentation of these does not seem to be available,
768 * certain arguments of some of the services remain unclear.
770 * FIXME: The following services are currently unimplemented:
771 * Exception handling (0x01, 0x1C)
772 * Debugger support (0x0C, 0x14, 0x17)
773 * Low-level memory access (0x02, 0x03, 0x0A, 0x0B)
774 * Memory Statistics (0x1B)
777 * We have a specific problem running Win32s on Linux (and probably also
778 * the other x86 unixes), since Win32s tries to allocate its main 'flat
779 * code/data segment' selectors with a base of 0xffff0000 (and limit 4GB).
780 * The rationale for this seems to be that they want one the one hand to
781 * be able to leave the Win 3.1 memory (starting with the main DOS memory)
782 * at linear address 0, but want at other hand to have offset 0 of the
783 * flat data/code segment point to an unmapped page (to catch NULL pointer
784 * accesses). Hence they allocate the flat segments with a base of 0xffff0000
785 * so that the Win 3.1 memory area at linear address zero shows up in the
786 * flat segments at offset 0x10000 (since linear addresses wrap around at
787 * 4GB). To compensate for that discrepancy between flat segment offsets
788 * and plain linear addresses, all flat pointers passed between the 32-bit
789 * and the 16-bit parts of Win32s are shifted by 0x10000 in the appropriate
790 * direction by the glue code (mainly) in W32SKRNL and WIN32S16.
792 * The problem for us is now that Linux does not allow a LDT selector with
793 * base 0xffff0000 to be created, since it would 'see' a part of the kernel
794 * address space. To address this problem we introduce *another* offset:
795 * We add 0x10000 to every linear address we get as an argument from Win32s.
796 * This means especially that the flat code/data selectors get actually
797 * allocated with base 0x0, so that flat offsets and (real) linear addresses
798 * do again agree! In fact, every call e.g. of a Win32s VxD service now
799 * has all pointer arguments (which are offsets in the flat data segment)
800 * first reduced by 0x10000 by the W32SKRNL glue code, and then again
801 * increased by 0x10000 by *our* code.
803 * Note that to keep everything consistent, this offset has to be applied by
804 * every Wine function that operates on 'linear addresses' passed to it by
805 * Win32s. Fortunately, since Win32s does not directly call any Wine 32-bit
806 * API routines, this affects only two locations: this VxD and the DPMI
807 * handler. (NOTE: Should any Win32s application pass a linear address to
808 * any routine apart from those, e.g. some other VxD handler, that code
809 * would have to take the offset into account as well!)
811 * The offset is set the first time any application calls the GetVersion()
812 * service of the Win32s VxD. (Note that the offset is never reset.)
815 void WINAPI
__wine_vxd_win32s( CONTEXT
*context
)
817 switch (AX_reg(context
))
819 case 0x0000: /* Get Version */
823 * Output: EAX: LoWord: Win32s Version (1.30)
824 * HiWord: VxD Version (200)
830 * EDX: Debugging Flags
834 * 1 if VMCPD VxD not found
837 TRACE("GetVersion()\n");
839 context
->Eax
= VXD_WinVersion() | (200 << 16);
846 * If this is the first time we are called for this process,
847 * hack the memory image of WIN32S16 so that it doesn't try
848 * to access the GDT directly ...
850 * The first code segment of WIN32S16 (version 1.30) contains
851 * an unexported function somewhere between the exported functions
852 * SetFS and StackLinearToSegmented that tries to find a selector
853 * in the LDT that maps to the memory image of the LDT itself.
854 * If it succeeds, it stores this selector into a global variable
855 * which will be used to speed up execution by using this selector
856 * to modify the LDT directly instead of using the DPMI calls.
858 * To perform this search of the LDT, this function uses the
859 * sgdt and sldt instructions to find the linear address of
860 * the (GDT and then) LDT. While those instructions themselves
861 * execute without problem, the linear address that sgdt returns
862 * points (at least under Linux) to the kernel address space, so
863 * that any subsequent access leads to a segfault.
865 * Fortunately, WIN32S16 still contains as a fallback option the
866 * mechanism of using DPMI calls to modify LDT selectors instead
867 * of direct writes to the LDT. Thus we can circumvent the problem
868 * by simply replacing the first byte of the offending function
869 * with an 'retf' instruction. This means that the global variable
870 * supposed to contain the LDT alias selector will remain zero,
871 * and hence WIN32S16 will fall back to using DPMI calls.
873 * The heuristic we employ to _find_ that function is as follows:
874 * We search between the addresses of the exported symbols SetFS
875 * and StackLinearToSegmented for the byte sequence '0F 01 04'
876 * (this is the opcode of 'sgdt [si]'). We then search backwards
877 * from this address for the last occurrence of 'CB' (retf) that marks
878 * the end of the preceding function. The following byte (which
879 * should now be the first byte of the function we are looking for)
880 * will be replaced by 'CB' (retf).
882 * This heuristic works for the retail as well as the debug version
883 * of Win32s version 1.30. For versions earlier than that this
884 * hack should not be necessary at all, since the whole mechanism
885 * ('PERF130') was introduced only in 1.30 to improve the overall
886 * performance of Win32s.
891 HMODULE16 hModule
= GetModuleHandle16("win32s16");
892 SEGPTR func1
= (SEGPTR
)GetProcAddress16(hModule
, "SetFS");
893 SEGPTR func2
= (SEGPTR
)GetProcAddress16(hModule
, "StackLinearToSegmented");
895 if ( hModule
&& func1
&& func2
896 && SELECTOROF(func1
) == SELECTOROF(func2
))
898 BYTE
*start
= MapSL(func1
);
899 BYTE
*end
= MapSL(func2
);
900 BYTE
*p
, *retv
= NULL
;
903 for (p
= start
; p
< end
; p
++)
904 if (*p
== 0xCB) found
= 0, retv
= p
;
905 else if (*p
== 0x0F) found
= 1;
906 else if (*p
== 0x01 && found
== 1) found
= 2;
907 else if (*p
== 0x04 && found
== 2) { found
= 3; break; }
910 if (found
== 3 && retv
)
912 TRACE("PERF130 hack: "
913 "Replacing byte %02X at offset %04X:%04X\n",
914 *(retv
+1), SELECTOROF(func1
),
915 OFFSETOF(func1
) + retv
+1-start
);
917 *(retv
+1) = (BYTE
)0xCB;
923 * Mark process as Win32s, so that subsequent DPMI calls
924 * will perform the W32S_APP2WINE/W32S_WINE2APP address shift.
926 W32S_offset
= 0x10000;
930 case 0x0001: /* Install Exception Handling */
932 * Input: EBX: Flat address of W32SKRNL Exception Data
934 * ECX: LoWord: Flat Code Selector
935 * HiWord: Flat Data Selector
937 * EDX: Flat address of W32SKRNL Exception Handler
938 * (this is equal to W32S_BackTo32 + 0x40)
940 * ESI: SEGPTR KERNEL.HASGPHANDLER
942 * EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10)
944 * Output: EAX: 0 if OK
947 TRACE("[0001] EBX=%x ECX=%x EDX=%x ESI=%x EDI=%x\n",
948 context
->Ebx
, context
->Ecx
, context
->Edx
,
949 context
->Esi
, context
->Edi
);
957 case 0x0002: /* Set Page Access Flags */
959 * Input: EBX: New access flags
960 * Bit 2: User Page if set, Supervisor Page if clear
961 * Bit 1: Read-Write if set, Read-Only if clear
963 * ECX: Size of memory area to change
965 * EDX: Flat start address of memory area
967 * Output: EAX: Size of area changed
970 TRACE("[0002] EBX=%x ECX=%x EDX=%x\n",
971 context
->Ebx
, context
->Ecx
, context
->Edx
);
975 context
->Eax
= context
->Ecx
;
979 case 0x0003: /* Get Page Access Flags */
981 * Input: EDX: Flat address of page to query
983 * Output: EAX: Page access flags
984 * Bit 2: User Page if set, Supervisor Page if clear
985 * Bit 1: Read-Write if set, Read-Only if clear
988 TRACE("[0003] EDX=%x\n", context
->Edx
);
996 case 0x0004: /* Map Module */
998 * Input: ECX: IMTE (offset in Module Table) of new module
1000 * EDX: Flat address of Win32s Module Table
1002 * Output: EAX: 0 if OK
1005 if (!context
->Edx
|| CX_reg(context
) == 0xFFFF)
1007 TRACE("MapModule: Initialization call\n");
1013 * Structure of a Win32s Module Table Entry:
1028 * Note: This function should set up a demand-paged memory image
1029 * of the given module. Since mmap does not allow file offsets
1030 * not aligned at 1024 bytes, we simply load the image fully
1034 struct Win32sModule
*moduleTable
=
1035 (struct Win32sModule
*)W32S_APP2WINE(context
->Edx
);
1036 struct Win32sModule
*module
= moduleTable
+ context
->Ecx
;
1038 IMAGE_NT_HEADERS
*nt_header
= RtlImageNtHeader( (HMODULE
)module
->baseAddr
);
1039 IMAGE_SECTION_HEADER
*pe_seg
= (IMAGE_SECTION_HEADER
*)((char *)&nt_header
->OptionalHeader
+
1040 nt_header
->FileHeader
.SizeOfOptionalHeader
);
1043 HFILE image
= _lopen(module
->pathName
, OF_READ
);
1044 BOOL error
= (image
== HFILE_ERROR
);
1047 TRACE("MapModule: Loading %s\n", module
->pathName
);
1050 !error
&& i
< nt_header
->FileHeader
.NumberOfSections
;
1052 if(!(pe_seg
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
))
1054 DWORD off
= pe_seg
->PointerToRawData
;
1055 DWORD len
= pe_seg
->SizeOfRawData
;
1056 LPBYTE addr
= module
->baseAddr
+ pe_seg
->VirtualAddress
;
1059 "Section %d at %08x from %08x len %08x\n",
1060 i
, (DWORD
)addr
, off
, len
);
1062 if ( _llseek(image
, off
, SEEK_SET
) != off
1063 || _lread(image
, addr
, len
) != len
)
1070 ERR("MapModule: Unable to load %s\n", module
->pathName
);
1072 else if (module
->relocDelta
!= 0)
1074 IMAGE_DATA_DIRECTORY
*dir
= nt_header
->OptionalHeader
.DataDirectory
1075 + IMAGE_DIRECTORY_ENTRY_BASERELOC
;
1076 IMAGE_BASE_RELOCATION
*r
= (IMAGE_BASE_RELOCATION
*)
1077 (dir
->Size
? module
->baseAddr
+ dir
->VirtualAddress
: 0);
1079 TRACE("MapModule: Reloc delta %08x\n", module
->relocDelta
);
1081 while (r
&& r
->VirtualAddress
)
1083 LPBYTE page
= module
->baseAddr
+ r
->VirtualAddress
;
1084 WORD
*TypeOffset
= (WORD
*)(r
+ 1);
1085 unsigned int count
= (r
->SizeOfBlock
- sizeof(*r
)) / sizeof(*TypeOffset
);
1087 TRACE("MapModule: %d relocations for page %08x\n",
1088 count
, (DWORD
)page
);
1090 for(i
= 0; i
< count
; i
++)
1092 int offset
= TypeOffset
[i
] & 0xFFF;
1093 int type
= TypeOffset
[i
] >> 12;
1096 case IMAGE_REL_BASED_ABSOLUTE
:
1098 case IMAGE_REL_BASED_HIGH
:
1099 *(WORD
*)(page
+offset
) += HIWORD(module
->relocDelta
);
1101 case IMAGE_REL_BASED_LOW
:
1102 *(WORD
*)(page
+offset
) += LOWORD(module
->relocDelta
);
1104 case IMAGE_REL_BASED_HIGHLOW
:
1105 *(DWORD
*)(page
+offset
) += module
->relocDelta
;
1108 WARN("MapModule: Unsupported fixup type\n");
1113 r
= (IMAGE_BASE_RELOCATION
*)((LPBYTE
)r
+ r
->SizeOfBlock
);
1118 RESET_CFLAG(context
);
1123 case 0x0005: /* UnMap Module */
1125 * Input: EDX: Flat address of module image
1127 * Output: EAX: 1 if OK
1130 TRACE("UnMapModule: %x\n", W32S_APP2WINE(context
->Edx
));
1132 /* As we didn't map anything, there's nothing to unmap ... */
1138 case 0x0006: /* VirtualAlloc */
1140 * Input: ECX: Current Process
1142 * EDX: Flat address of arguments on stack
1144 * DWORD *retv [out] Flat base address of allocated region
1145 * LPVOID base [in] Flat address of region to reserve/commit
1146 * DWORD size [in] Size of region
1147 * DWORD type [in] Type of allocation
1148 * DWORD prot [in] Type of access protection
1150 * Output: EAX: NtStatus
1153 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1154 DWORD
*retv
= (DWORD
*)W32S_APP2WINE(stack
[0]);
1155 LPVOID base
= (LPVOID
) W32S_APP2WINE(stack
[1]);
1156 DWORD size
= stack
[2];
1157 DWORD type
= stack
[3];
1158 DWORD prot
= stack
[4];
1161 TRACE("VirtualAlloc(%x, %x, %x, %x, %x)\n",
1162 (DWORD
)retv
, (DWORD
)base
, size
, type
, prot
);
1164 if (type
& 0x80000000)
1166 WARN("VirtualAlloc: strange type %x\n", type
);
1170 if (!base
&& (type
& MEM_COMMIT
) && prot
== PAGE_READONLY
)
1172 WARN("VirtualAlloc: NLS hack, allowing write access!\n");
1173 prot
= PAGE_READWRITE
;
1176 result
= (DWORD
)VirtualAlloc(base
, size
, type
, prot
);
1178 if (W32S_WINE2APP(result
))
1179 *retv
= W32S_WINE2APP(result
),
1180 context
->Eax
= STATUS_SUCCESS
;
1183 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1188 case 0x0007: /* VirtualFree */
1190 * Input: ECX: Current Process
1192 * EDX: Flat address of arguments on stack
1194 * DWORD *retv [out] TRUE if success, FALSE if failure
1195 * LPVOID base [in] Flat address of region
1196 * DWORD size [in] Size of region
1197 * DWORD type [in] Type of operation
1199 * Output: EAX: NtStatus
1202 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1203 DWORD
*retv
= (DWORD
*)W32S_APP2WINE(stack
[0]);
1204 LPVOID base
= (LPVOID
) W32S_APP2WINE(stack
[1]);
1205 DWORD size
= stack
[2];
1206 DWORD type
= stack
[3];
1209 TRACE("VirtualFree(%x, %x, %x, %x)\n",
1210 (DWORD
)retv
, (DWORD
)base
, size
, type
);
1212 result
= VirtualFree(base
, size
, type
);
1216 context
->Eax
= STATUS_SUCCESS
;
1219 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1224 case 0x0008: /* VirtualProtect */
1226 * Input: ECX: Current Process
1228 * EDX: Flat address of arguments on stack
1230 * DWORD *retv [out] TRUE if success, FALSE if failure
1231 * LPVOID base [in] Flat address of region
1232 * DWORD size [in] Size of region
1233 * DWORD new_prot [in] Desired access protection
1234 * DWORD *old_prot [out] Previous access protection
1236 * Output: EAX: NtStatus
1239 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1240 DWORD
*retv
= (DWORD
*)W32S_APP2WINE(stack
[0]);
1241 LPVOID base
= (LPVOID
) W32S_APP2WINE(stack
[1]);
1242 DWORD size
= stack
[2];
1243 DWORD new_prot
= stack
[3];
1244 DWORD
*old_prot
= (DWORD
*)W32S_APP2WINE(stack
[4]);
1247 TRACE("VirtualProtect(%x, %x, %x, %x, %x)\n",
1248 (DWORD
)retv
, (DWORD
)base
, size
, new_prot
, (DWORD
)old_prot
);
1250 result
= VirtualProtect(base
, size
, new_prot
, old_prot
);
1254 context
->Eax
= STATUS_SUCCESS
;
1257 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1262 case 0x0009: /* VirtualQuery */
1264 * Input: ECX: Current Process
1266 * EDX: Flat address of arguments on stack
1268 * DWORD *retv [out] Nr. bytes returned
1269 * LPVOID base [in] Flat address of region
1270 * LPMEMORY_BASIC_INFORMATION info [out] Info buffer
1271 * DWORD len [in] Size of buffer
1273 * Output: EAX: NtStatus
1276 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1277 DWORD
*retv
= (DWORD
*)W32S_APP2WINE(stack
[0]);
1278 LPVOID base
= (LPVOID
) W32S_APP2WINE(stack
[1]);
1279 PMEMORY_BASIC_INFORMATION info
=
1280 (PMEMORY_BASIC_INFORMATION
)W32S_APP2WINE(stack
[2]);
1281 DWORD len
= stack
[3];
1284 TRACE("VirtualQuery(%x, %x, %x, %x)\n",
1285 (DWORD
)retv
, (DWORD
)base
, (DWORD
)info
, len
);
1287 result
= VirtualQuery(base
, info
, len
);
1290 context
->Eax
= STATUS_SUCCESS
;
1295 case 0x000A: /* SetVirtMemProcess */
1297 * Input: ECX: Process Handle
1299 * EDX: Flat address of region
1301 * Output: EAX: NtStatus
1304 TRACE("[000a] ECX=%x EDX=%x\n",
1305 context
->Ecx
, context
->Edx
);
1309 context
->Eax
= STATUS_SUCCESS
;
1313 case 0x000B: /* ??? some kind of cleanup */
1315 * Input: ECX: Process Handle
1317 * Output: EAX: NtStatus
1320 TRACE("[000b] ECX=%x\n", context
->Ecx
);
1324 context
->Eax
= STATUS_SUCCESS
;
1328 case 0x000C: /* Set Debug Flags */
1330 * Input: EDX: Debug Flags
1332 * Output: EDX: Previous Debug Flags
1335 FIXME("[000c] EDX=%x\n", context
->Edx
);
1343 case 0x000D: /* NtCreateSection */
1345 * Input: EDX: Flat address of arguments on stack
1347 * HANDLE32 *retv [out] Handle of Section created
1348 * DWORD flags1 [in] (?? unknown ??)
1349 * DWORD atom [in] Name of Section to create
1350 * LARGE_INTEGER *size [in] Size of Section
1351 * DWORD protect [in] Access protection
1352 * DWORD flags2 [in] (?? unknown ??)
1353 * HFILE32 hFile [in] Handle of file to map
1354 * DWORD psp [in] (Win32s: PSP that hFile belongs to)
1356 * Output: EAX: NtStatus
1359 DWORD
*stack
= (DWORD
*) W32S_APP2WINE(context
->Edx
);
1360 HANDLE
*retv
= (HANDLE
*)W32S_APP2WINE(stack
[0]);
1361 DWORD flags1
= stack
[1];
1362 DWORD atom
= stack
[2];
1363 LARGE_INTEGER
*size
= (LARGE_INTEGER
*)W32S_APP2WINE(stack
[3]);
1364 DWORD protect
= stack
[4];
1365 DWORD flags2
= stack
[5];
1366 HANDLE hFile
= DosFileHandleToWin32Handle(stack
[6]);
1367 DWORD psp
= stack
[7];
1369 HANDLE result
= INVALID_HANDLE_VALUE
;
1372 TRACE("NtCreateSection(%x, %x, %x, %x, %x, %x, %x, %x)\n",
1373 (DWORD
)retv
, flags1
, atom
, (DWORD
)size
, protect
, flags2
,
1376 if (!atom
|| GlobalGetAtomNameA(atom
, name
, sizeof(name
)))
1378 TRACE("NtCreateSection: name=%s\n", atom
? name
: NULL
);
1380 result
= CreateFileMappingA(hFile
, NULL
, protect
,
1381 size
? size
->u
.HighPart
: 0,
1382 size
? size
->u
.LowPart
: 0,
1386 if (result
== INVALID_HANDLE_VALUE
)
1387 WARN("NtCreateSection: failed!\n");
1389 TRACE("NtCreateSection: returned %x\n", (DWORD
)result
);
1391 if (result
!= INVALID_HANDLE_VALUE
)
1393 context
->Eax
= STATUS_SUCCESS
;
1396 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1401 case 0x000E: /* NtOpenSection */
1403 * Input: EDX: Flat address of arguments on stack
1405 * HANDLE32 *retv [out] Handle of Section opened
1406 * DWORD protect [in] Access protection
1407 * DWORD atom [in] Name of Section to create
1409 * Output: EAX: NtStatus
1412 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1413 HANDLE
*retv
= (HANDLE
*)W32S_APP2WINE(stack
[0]);
1414 DWORD protect
= stack
[1];
1415 DWORD atom
= stack
[2];
1417 HANDLE result
= INVALID_HANDLE_VALUE
;
1420 TRACE("NtOpenSection(%x, %x, %x)\n",
1421 (DWORD
)retv
, protect
, atom
);
1423 if (atom
&& GlobalGetAtomNameA(atom
, name
, sizeof(name
)))
1425 TRACE("NtOpenSection: name=%s\n", name
);
1427 result
= OpenFileMappingA(protect
, FALSE
, name
);
1430 if (result
== INVALID_HANDLE_VALUE
)
1431 WARN("NtOpenSection: failed!\n");
1433 TRACE("NtOpenSection: returned %x\n", (DWORD
)result
);
1435 if (result
!= INVALID_HANDLE_VALUE
)
1437 context
->Eax
= STATUS_SUCCESS
;
1440 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1445 case 0x000F: /* NtCloseSection */
1447 * Input: EDX: Flat address of arguments on stack
1449 * HANDLE32 handle [in] Handle of Section to close
1450 * DWORD *id [out] Unique ID (?? unclear ??)
1452 * Output: EAX: NtStatus
1455 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1456 HANDLE handle
= (HANDLE
)stack
[0];
1457 DWORD
*id
= (DWORD
*)W32S_APP2WINE(stack
[1]);
1459 TRACE("NtCloseSection(%x, %x)\n", (DWORD
)handle
, (DWORD
)id
);
1461 CloseHandle(handle
);
1462 if (id
) *id
= 0; /* FIXME */
1464 context
->Eax
= STATUS_SUCCESS
;
1469 case 0x0010: /* NtDupSection */
1471 * Input: EDX: Flat address of arguments on stack
1473 * HANDLE32 handle [in] Handle of Section to duplicate
1475 * Output: EAX: NtStatus
1478 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1479 HANDLE handle
= (HANDLE
)stack
[0];
1482 TRACE("NtDupSection(%x)\n", (DWORD
)handle
);
1484 DuplicateHandle( GetCurrentProcess(), handle
,
1485 GetCurrentProcess(), &new_handle
,
1486 0, FALSE
, DUPLICATE_SAME_ACCESS
);
1487 context
->Eax
= STATUS_SUCCESS
;
1492 case 0x0011: /* NtMapViewOfSection */
1494 * Input: EDX: Flat address of arguments on stack
1496 * HANDLE32 SectionHandle [in] Section to be mapped
1497 * DWORD ProcessHandle [in] Process to be mapped into
1498 * DWORD * BaseAddress [in/out] Address to be mapped at
1499 * DWORD ZeroBits [in] (?? unclear ??)
1500 * DWORD CommitSize [in] (?? unclear ??)
1501 * LARGE_INTEGER *SectionOffset [in] Offset within section
1502 * DWORD * ViewSize [in] Size of view
1503 * DWORD InheritDisposition [in] (?? unclear ??)
1504 * DWORD AllocationType [in] (?? unclear ??)
1505 * DWORD Protect [in] Access protection
1507 * Output: EAX: NtStatus
1510 DWORD
* stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1511 HANDLE SectionHandle
= (HANDLE
)stack
[0];
1512 DWORD ProcessHandle
= stack
[1]; /* ignored */
1513 DWORD
* BaseAddress
= (DWORD
*)W32S_APP2WINE(stack
[2]);
1514 DWORD ZeroBits
= stack
[3];
1515 DWORD CommitSize
= stack
[4];
1516 LARGE_INTEGER
*SectionOffset
= (LARGE_INTEGER
*)W32S_APP2WINE(stack
[5]);
1517 DWORD
* ViewSize
= (DWORD
*)W32S_APP2WINE(stack
[6]);
1518 DWORD InheritDisposition
= stack
[7];
1519 DWORD AllocationType
= stack
[8];
1520 DWORD Protect
= stack
[9];
1522 LPBYTE address
= (LPBYTE
)(BaseAddress
?
1523 W32S_APP2WINE(*BaseAddress
) : 0);
1524 DWORD access
= 0, result
;
1526 switch (Protect
& ~(PAGE_GUARD
|PAGE_NOCACHE
))
1528 case PAGE_READONLY
: access
= FILE_MAP_READ
; break;
1529 case PAGE_READWRITE
: access
= FILE_MAP_WRITE
; break;
1530 case PAGE_WRITECOPY
: access
= FILE_MAP_COPY
; break;
1532 case PAGE_EXECUTE_READ
: access
= FILE_MAP_READ
; break;
1533 case PAGE_EXECUTE_READWRITE
: access
= FILE_MAP_WRITE
; break;
1534 case PAGE_EXECUTE_WRITECOPY
: access
= FILE_MAP_COPY
; break;
1537 TRACE("NtMapViewOfSection"
1538 "(%x, %x, %x, %x, %x, %x, %x, %x, %x, %x)\n",
1539 (DWORD
)SectionHandle
, ProcessHandle
, (DWORD
)BaseAddress
,
1540 ZeroBits
, CommitSize
, (DWORD
)SectionOffset
, (DWORD
)ViewSize
,
1541 InheritDisposition
, AllocationType
, Protect
);
1542 TRACE("NtMapViewOfSection: "
1543 "base=%x, offset=%x, size=%x, access=%x\n",
1544 (DWORD
)address
, SectionOffset
? SectionOffset
->u
.LowPart
: 0,
1545 ViewSize
? *ViewSize
: 0, access
);
1547 result
= (DWORD
)MapViewOfFileEx(SectionHandle
, access
,
1548 SectionOffset
? SectionOffset
->u
.HighPart
: 0,
1549 SectionOffset
? SectionOffset
->u
.LowPart
: 0,
1550 ViewSize
? *ViewSize
: 0, address
);
1552 TRACE("NtMapViewOfSection: result=%x\n", result
);
1554 if (W32S_WINE2APP(result
))
1556 if (BaseAddress
) *BaseAddress
= W32S_WINE2APP(result
);
1557 context
->Eax
= STATUS_SUCCESS
;
1560 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1565 case 0x0012: /* NtUnmapViewOfSection */
1567 * Input: EDX: Flat address of arguments on stack
1569 * DWORD ProcessHandle [in] Process (defining address space)
1570 * LPBYTE BaseAddress [in] Base address of view to be unmapped
1572 * Output: EAX: NtStatus
1575 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1576 DWORD ProcessHandle
= stack
[0]; /* ignored */
1577 LPBYTE BaseAddress
= (LPBYTE
)W32S_APP2WINE(stack
[1]);
1579 TRACE("NtUnmapViewOfSection(%x, %x)\n",
1580 ProcessHandle
, (DWORD
)BaseAddress
);
1582 UnmapViewOfFile(BaseAddress
);
1584 context
->Eax
= STATUS_SUCCESS
;
1589 case 0x0013: /* NtFlushVirtualMemory */
1591 * Input: EDX: Flat address of arguments on stack
1593 * DWORD ProcessHandle [in] Process (defining address space)
1594 * LPBYTE *BaseAddress [in?] Base address of range to be flushed
1595 * DWORD *ViewSize [in?] Number of bytes to be flushed
1596 * DWORD *unknown [???] (?? unknown ??)
1598 * Output: EAX: NtStatus
1601 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1602 DWORD ProcessHandle
= stack
[0]; /* ignored */
1603 DWORD
*BaseAddress
= (DWORD
*)W32S_APP2WINE(stack
[1]);
1604 DWORD
*ViewSize
= (DWORD
*)W32S_APP2WINE(stack
[2]);
1605 DWORD
*unknown
= (DWORD
*)W32S_APP2WINE(stack
[3]);
1607 LPBYTE address
= (LPBYTE
)(BaseAddress
? W32S_APP2WINE(*BaseAddress
) : 0);
1608 DWORD size
= ViewSize
? *ViewSize
: 0;
1610 TRACE("NtFlushVirtualMemory(%x, %x, %x, %x)\n",
1611 ProcessHandle
, (DWORD
)BaseAddress
, (DWORD
)ViewSize
,
1613 TRACE("NtFlushVirtualMemory: base=%x, size=%x\n",
1614 (DWORD
)address
, size
);
1616 FlushViewOfFile(address
, size
);
1618 context
->Eax
= STATUS_SUCCESS
;
1623 case 0x0014: /* Get/Set Debug Registers */
1625 * Input: ECX: 0 if Get, 1 if Set
1627 * EDX: Get: Flat address of buffer to receive values of
1628 * debug registers DR0 .. DR7
1629 * Set: Flat address of buffer containing values of
1630 * debug registers DR0 .. DR7 to be set
1634 FIXME("[0014] ECX=%x EDX=%x\n",
1635 context
->Ecx
, context
->Edx
);
1641 case 0x0015: /* Set Coprocessor Emulation Flag */
1643 * Input: EDX: 0 to deactivate, 1 to activate coprocessor emulation
1648 TRACE("[0015] EDX=%x\n", context
->Edx
);
1650 /* We don't care, as we always have a coprocessor anyway */
1654 case 0x0016: /* Init Win32S VxD PSP */
1656 * If called to query required PSP size:
1659 * Output: EDX: Required size of Win32s VxD PSP
1661 * If called to initialize allocated PSP:
1663 * Input: EBX: LoWord: Selector of Win32s VxD PSP
1664 * HiWord: Paragraph of Win32s VxD PSP (DOSMEM)
1668 if (context
->Ebx
== 0)
1669 context
->Edx
= 0x80;
1672 PDB16
*psp
= MapSL( MAKESEGPTR( BX_reg(context
), 0 ));
1674 psp
->fileHandlesPtr
= MAKELONG(HIWORD(context
->Ebx
), 0x5c);
1675 memset((LPBYTE
)psp
+ 0x5c, '\xFF', 32);
1680 case 0x0017: /* Set Break Point */
1682 * Input: EBX: Offset of Break Point
1683 * CX: Selector of Break Point
1688 FIXME("[0017] EBX=%x CX=%x\n",
1689 context
->Ebx
, CX_reg(context
));
1695 case 0x0018: /* VirtualLock */
1697 * Input: ECX: Current Process
1699 * EDX: Flat address of arguments on stack
1701 * DWORD *retv [out] TRUE if success, FALSE if failure
1702 * LPVOID base [in] Flat address of range to lock
1703 * DWORD size [in] Size of range
1705 * Output: EAX: NtStatus
1708 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1709 DWORD
*retv
= (DWORD
*)W32S_APP2WINE(stack
[0]);
1710 LPVOID base
= (LPVOID
) W32S_APP2WINE(stack
[1]);
1711 DWORD size
= stack
[2];
1714 TRACE("VirtualLock(%x, %x, %x)\n",
1715 (DWORD
)retv
, (DWORD
)base
, size
);
1717 result
= VirtualLock(base
, size
);
1721 context
->Eax
= STATUS_SUCCESS
;
1724 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1729 case 0x0019: /* VirtualUnlock */
1731 * Input: ECX: Current Process
1733 * EDX: Flat address of arguments on stack
1735 * DWORD *retv [out] TRUE if success, FALSE if failure
1736 * LPVOID base [in] Flat address of range to unlock
1737 * DWORD size [in] Size of range
1739 * Output: EAX: NtStatus
1742 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1743 DWORD
*retv
= (DWORD
*)W32S_APP2WINE(stack
[0]);
1744 LPVOID base
= (LPVOID
) W32S_APP2WINE(stack
[1]);
1745 DWORD size
= stack
[2];
1748 TRACE("VirtualUnlock(%x, %x, %x)\n",
1749 (DWORD
)retv
, (DWORD
)base
, size
);
1751 result
= VirtualUnlock(base
, size
);
1755 context
->Eax
= STATUS_SUCCESS
;
1758 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1763 case 0x001A: /* KGetSystemInfo */
1767 * Output: ECX: Start of sparse memory arena
1768 * EDX: End of sparse memory arena
1771 TRACE("KGetSystemInfo()\n");
1774 * Note: Win32s reserves 0GB - 2GB for Win 3.1 and uses 2GB - 4GB as
1775 * sparse memory arena. We do it the other way around, since
1776 * we have to reserve 3GB - 4GB for Linux, and thus use
1777 * 0GB - 3GB as sparse memory arena.
1779 * FIXME: What about other OSes ?
1782 context
->Ecx
= W32S_WINE2APP(0x00000000);
1783 context
->Edx
= W32S_WINE2APP(0xbfffffff);
1787 case 0x001B: /* KGlobalMemStat */
1789 * Input: ESI: Flat address of buffer to receive memory info
1794 struct Win32sMemoryInfo
1796 DWORD DIPhys_Count
; /* Total physical pages */
1797 DWORD DIFree_Count
; /* Free physical pages */
1798 DWORD DILin_Total_Count
; /* Total virtual pages (private arena) */
1799 DWORD DILin_Total_Free
; /* Free virtual pages (private arena) */
1801 DWORD SparseTotal
; /* Total size of sparse arena (bytes ?) */
1802 DWORD SparseFree
; /* Free size of sparse arena (bytes ?) */
1805 struct Win32sMemoryInfo
*info
=
1806 (struct Win32sMemoryInfo
*)W32S_APP2WINE(context
->Esi
);
1808 FIXME("KGlobalMemStat(%x)\n", (DWORD
)info
);
1815 case 0x001C: /* Enable/Disable Exceptions */
1817 * Input: ECX: 0 to disable, 1 to enable exception handling
1822 TRACE("[001c] ECX=%x\n", context
->Ecx
);
1828 case 0x001D: /* VirtualAlloc called from 16-bit code */
1830 * Input: EDX: Segmented address of arguments on stack
1832 * LPVOID base [in] Flat address of region to reserve/commit
1833 * DWORD size [in] Size of region
1834 * DWORD type [in] Type of allocation
1835 * DWORD prot [in] Type of access protection
1837 * Output: EAX: NtStatus
1838 * EDX: Flat base address of allocated region
1841 DWORD
*stack
= MapSL( MAKESEGPTR( LOWORD(context
->Edx
), HIWORD(context
->Edx
) ));
1842 LPVOID base
= (LPVOID
)W32S_APP2WINE(stack
[0]);
1843 DWORD size
= stack
[1];
1844 DWORD type
= stack
[2];
1845 DWORD prot
= stack
[3];
1848 TRACE("VirtualAlloc16(%x, %x, %x, %x)\n",
1849 (DWORD
)base
, size
, type
, prot
);
1851 if (type
& 0x80000000)
1853 WARN("VirtualAlloc16: strange type %x\n", type
);
1857 result
= (DWORD
)VirtualAlloc(base
, size
, type
, prot
);
1859 if (W32S_WINE2APP(result
))
1860 context
->Edx
= W32S_WINE2APP(result
),
1861 context
->Eax
= STATUS_SUCCESS
;
1864 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1865 TRACE("VirtualAlloc16: returning base %x\n", context
->Edx
);
1870 case 0x001E: /* VirtualFree called from 16-bit code */
1872 * Input: EDX: Segmented address of arguments on stack
1874 * LPVOID base [in] Flat address of region
1875 * DWORD size [in] Size of region
1876 * DWORD type [in] Type of operation
1878 * Output: EAX: NtStatus
1879 * EDX: TRUE if success, FALSE if failure
1882 DWORD
*stack
= MapSL( MAKESEGPTR( LOWORD(context
->Edx
), HIWORD(context
->Edx
) ));
1883 LPVOID base
= (LPVOID
)W32S_APP2WINE(stack
[0]);
1884 DWORD size
= stack
[1];
1885 DWORD type
= stack
[2];
1888 TRACE("VirtualFree16(%x, %x, %x)\n",
1889 (DWORD
)base
, size
, type
);
1891 result
= VirtualFree(base
, size
, type
);
1894 context
->Edx
= TRUE
,
1895 context
->Eax
= STATUS_SUCCESS
;
1897 context
->Edx
= FALSE
,
1898 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1903 case 0x001F: /* FWorkingSetSize */
1905 * Input: EDX: 0 if Get, 1 if Set
1907 * ECX: Get: Buffer to receive Working Set Size
1908 * Set: Buffer containing Working Set Size
1913 DWORD
*ptr
= (DWORD
*)W32S_APP2WINE(context
->Ecx
);
1914 BOOL set
= context
->Edx
;
1916 TRACE("FWorkingSetSize(%x, %x)\n", (DWORD
)ptr
, (DWORD
)set
);
1919 /* We do it differently ... */;
1923 context
->Eax
= STATUS_SUCCESS
;
1928 VXD_BARF( context
, "W32S" );