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 W32S_APP2WINE(addr) ((addr)? (DWORD)(addr) + W32S_offset : 0)
84 #define W32S_WINE2APP(addr) ((addr)? (DWORD)(addr) - W32S_offset : 0)
86 #define VXD_BARF(context,name) \
87 TRACE( "vxd %s: unknown/not implemented parameters:\n" \
88 "vxd %s: AX %04x, BX %04x, CX %04x, DX %04x, " \
89 "SI %04x, DI %04x, DS %04x, ES %04x\n", \
90 (name), (name), AX_reg(context), BX_reg(context), \
91 CX_reg(context), DX_reg(context), SI_reg(context), \
92 DI_reg(context), (WORD)context->SegDs, (WORD)context->SegEs )
94 static CRITICAL_SECTION vxd_section
;
95 static CRITICAL_SECTION_DEBUG critsect_debug
=
98 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
99 0, 0, { (DWORD_PTR
)(__FILE__
": vxd_section") }
101 static CRITICAL_SECTION vxd_section
= { &critsect_debug
, -1, 0, 0, 0, 0 };
103 static UINT W32S_offset
;
105 static WORD
VXD_WinVersion(void)
107 WORD version
= LOWORD(GetVersion16());
108 return (version
>> 8) | (version
<< 8);
111 /* create a file handle to represent a VxD, by opening a dummy file in the wineserver directory */
112 static HANDLE
open_vxd_handle( LPCWSTR name
)
114 static const WCHAR prefixW
[] = {'\\','?','?','\\','u','n','i','x'};
115 const char *dir
= wine_get_server_dir();
119 OBJECT_ATTRIBUTES attr
;
120 UNICODE_STRING nameW
;
123 len
= MultiByteToWideChar( CP_UNIXCP
, 0, dir
, -1, NULL
, 0 );
124 nameW
.Length
= sizeof(prefixW
) + (len
+ strlenW( name
)) * sizeof(WCHAR
);
125 nameW
.MaximumLength
= nameW
.Length
+ sizeof(WCHAR
);
126 if (!(nameW
.Buffer
= HeapAlloc( GetProcessHeap(), 0, nameW
.MaximumLength
)))
128 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
131 memcpy( nameW
.Buffer
, prefixW
, sizeof(prefixW
) );
132 MultiByteToWideChar( CP_UNIXCP
, 0, dir
, -1, nameW
.Buffer
+ ARRAY_SIZE(prefixW
), len
);
133 len
+= ARRAY_SIZE(prefixW
);
134 nameW
.Buffer
[len
-1] = '/';
135 strcpyW( nameW
.Buffer
+ len
, name
);
137 attr
.Length
= sizeof(attr
);
138 attr
.RootDirectory
= 0;
140 attr
.ObjectName
= &nameW
;
141 attr
.SecurityDescriptor
= NULL
;
142 attr
.SecurityQualityOfService
= NULL
;
144 status
= NtCreateFile( &ret
, SYNCHRONIZE
, &attr
, &io
, NULL
, 0,
145 FILE_SHARE_READ
|FILE_SHARE_WRITE
, FILE_OPEN_IF
,
146 FILE_SYNCHRONOUS_IO_ALERT
, NULL
, 0 );
150 SetLastError( RtlNtStatusToDosError(status
) );
152 RtlFreeUnicodeString( &nameW
);
156 /* retrieve the DeviceIoControl function for a Vxd given a file handle */
157 DeviceIoProc
__wine_vxd_get_proc( HANDLE handle
)
159 DeviceIoProc ret
= NULL
;
162 FILE_INTERNAL_INFORMATION info
;
164 status
= NtQueryInformationFile( handle
, &io
, &info
, sizeof(info
), FileInternalInformation
);
167 SetLastError( RtlNtStatusToDosError(status
) );
171 RtlEnterCriticalSection( &vxd_section
);
173 for (i
= 0; i
< MAX_VXD_MODULES
; i
++)
175 if (!vxd_modules
[i
].module
) break;
176 if (vxd_modules
[i
].index
.QuadPart
== info
.IndexNumber
.QuadPart
)
178 if (!(ret
= vxd_modules
[i
].proc
)) SetLastError( ERROR_INVALID_FUNCTION
);
182 /* FIXME: Here we could go through the directory to find the VxD name and load it. */
183 /* Let's wait to find out if there are actually apps out there that try to share */
184 /* VxD handles between processes, before we go to the trouble of implementing it. */
185 ERR( "handle %p not found in module list, inherited from another process?\n", handle
);
188 RtlLeaveCriticalSection( &vxd_section
);
193 /* load a VxD and return a file handle to it */
194 HANDLE
__wine_vxd_open( LPCWSTR filenameW
, DWORD access
, SECURITY_ATTRIBUTES
*sa
)
196 static const WCHAR dotVxDW
[] = {'.','v','x','d',0};
202 /* normalize the filename */
204 if (strlenW( filenameW
) >= ARRAY_SIZE(name
) - 4 ||
205 strchrW( filenameW
, '/' ) || strchrW( filenameW
, '\\' ))
207 SetLastError( ERROR_FILE_NOT_FOUND
);
210 strcpyW( name
, filenameW
);
212 p
= strchrW( name
, '.' );
213 if (!p
) strcatW( name
, dotVxDW
);
214 else if (strcmpiW( p
, dotVxDW
)) /* existing extension has to be .vxd */
216 SetLastError( ERROR_FILE_NOT_FOUND
);
220 /* try to load the module first */
222 if (!(module
= LoadLibraryW( name
)))
224 FIXME( "Unknown/unsupported VxD %s. Try setting Windows version to 'nt40' or 'win31'.\n",
226 SetLastError( ERROR_FILE_NOT_FOUND
);
230 /* register the module in the global list if necessary */
232 RtlEnterCriticalSection( &vxd_section
);
234 for (i
= 0; i
< MAX_VXD_MODULES
; i
++)
236 if (vxd_modules
[i
].module
== module
)
238 handle
= vxd_modules
[i
].handle
;
239 goto done
; /* already registered */
241 if (!vxd_modules
[i
].module
) /* new one, register it */
244 FILE_INTERNAL_INFORMATION info
;
246 /* get a file handle to the dummy file */
247 if (!(handle
= open_vxd_handle( name
)))
249 FreeLibrary( module
);
252 if (!NtQueryInformationFile( handle
, &io
, &info
, sizeof(info
), FileInternalInformation
))
253 vxd_modules
[i
].index
= info
.IndexNumber
;
255 vxd_modules
[i
].module
= module
;
256 vxd_modules
[i
].handle
= handle
;
257 vxd_modules
[i
].proc
= (DeviceIoProc
)GetProcAddress( module
, "DeviceIoControl" );
262 ERR("too many open VxD modules, please report\n" );
263 FreeLibrary( module
);
267 RtlLeaveCriticalSection( &vxd_section
);
268 if (!DuplicateHandle( GetCurrentProcess(), handle
, GetCurrentProcess(), &handle
, 0,
269 (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
),
270 DUP_HANDLE_SAME_ACCESS
))
276 /***********************************************************************
277 * VxDCall0 (KERNEL32.1)
278 * VxDCall1 (KERNEL32.2)
279 * VxDCall2 (KERNEL32.3)
280 * VxDCall3 (KERNEL32.4)
281 * VxDCall4 (KERNEL32.5)
282 * VxDCall5 (KERNEL32.6)
283 * VxDCall6 (KERNEL32.7)
284 * VxDCall7 (KERNEL32.8)
285 * VxDCall8 (KERNEL32.9)
287 void WINAPI DECLSPEC_HIDDEN
__regs_VxDCall( CONTEXT
*context
)
290 VxDCallProc proc
= NULL
;
291 DWORD service
= stack32_pop( context
);
293 RtlEnterCriticalSection( &vxd_section
);
294 for (i
= 0; i
< ARRAY_SIZE(vxd_services
); i
++)
296 if (HIWORD(service
) != vxd_services
[i
].service
) continue;
297 if (!vxd_services
[i
].module
) /* need to load it */
299 if ((vxd_services
[i
].module
= LoadLibraryW( vxd_services
[i
].name
)))
300 vxd_services
[i
].proc
= (VxDCallProc
)GetProcAddress( vxd_services
[i
].module
, "VxDCall" );
302 proc
= vxd_services
[i
].proc
;
305 RtlLeaveCriticalSection( &vxd_section
);
307 if (proc
) context
->Eax
= proc( service
, context
);
310 FIXME( "Unknown/unimplemented VxD (%08x)\n", service
);
311 context
->Eax
= 0xffffffff; /* FIXME */
314 DEFINE_REGS_ENTRYPOINT( VxDCall
)
317 /***********************************************************************
318 * __wine_vxd_vmm (WPROCS.401)
320 void WINAPI
__wine_vxd_vmm ( CONTEXT
*context
)
322 unsigned service
= AX_reg(context
);
324 TRACE("[%04x] VMM\n", (UINT16
)service
);
328 case 0x0000: /* version */
329 SET_AX( context
, VXD_WinVersion() );
330 RESET_CFLAG(context
);
333 case 0x026d: /* Get_Debug_Flag '/m' */
334 case 0x026e: /* Get_Debug_Flag '/n' */
335 SET_AL( context
, 0 );
336 RESET_CFLAG(context
);
340 VXD_BARF( context
, "VMM" );
344 /***********************************************************************
345 * __wine_vxd_pagefile (WPROCS.433)
347 void WINAPI
__wine_vxd_pagefile( CONTEXT
*context
)
349 unsigned service
= AX_reg(context
);
351 /* taken from Ralf Brown's Interrupt List */
353 TRACE("[%04x] PageFile\n", (UINT16
)service
);
357 case 0x00: /* get version, is this windows version? */
358 TRACE("returning version\n");
359 SET_AX( context
, VXD_WinVersion() );
360 RESET_CFLAG(context
);
363 case 0x01: /* get swap file info */
364 TRACE("VxD PageFile: returning swap file info\n");
365 SET_AX( context
, 0x00 ); /* paging disabled */
366 context
->Ecx
= 0; /* maximum size of paging file */
367 /* FIXME: do I touch DS:SI or DS:DI? */
368 RESET_CFLAG(context
);
371 case 0x02: /* delete permanent swap on exit */
372 TRACE("VxD PageFile: supposed to delete swap\n");
373 RESET_CFLAG(context
);
376 case 0x03: /* current temporary swap file size */
377 TRACE("VxD PageFile: what is current temp. swap size\n");
378 RESET_CFLAG(context
);
381 case 0x04: /* read or write?? INTERRUP.D */
382 case 0x05: /* cancel?? INTERRUP.D */
383 case 0x06: /* test I/O valid INTERRUP.D */
385 VXD_BARF( context
, "pagefile" );
390 /***********************************************************************
391 * __wine_vxd_reboot (WPROCS.409)
393 void WINAPI
__wine_vxd_reboot( CONTEXT
*context
)
395 unsigned service
= AX_reg(context
);
397 TRACE("[%04x] Reboot\n", (UINT16
)service
);
401 case 0x0000: /* version */
402 SET_AX( context
, VXD_WinVersion() );
403 RESET_CFLAG(context
);
407 VXD_BARF( context
, "REBOOT" );
411 /***********************************************************************
412 * __wine_vxd_vdd (WPROCS.410)
414 void WINAPI
__wine_vxd_vdd( CONTEXT
*context
)
416 unsigned service
= AX_reg(context
);
418 TRACE("[%04x] VDD\n", (UINT16
)service
);
422 case 0x0000: /* version */
423 SET_AX( context
, VXD_WinVersion() );
424 RESET_CFLAG(context
);
428 VXD_BARF( context
, "VDD" );
432 /***********************************************************************
433 * __wine_vxd_vmd (WPROCS.412)
435 void WINAPI
__wine_vxd_vmd( CONTEXT
*context
)
437 unsigned service
= AX_reg(context
);
439 TRACE("[%04x] VMD\n", (UINT16
)service
);
443 case 0x0000: /* version */
444 SET_AX( context
, VXD_WinVersion() );
445 RESET_CFLAG(context
);
449 VXD_BARF( context
, "VMD" );
453 /***********************************************************************
454 * __wine_vxd_vxdloader (WPROCS.439)
456 void WINAPI
__wine_vxd_vxdloader( CONTEXT
*context
)
458 unsigned service
= AX_reg(context
);
460 TRACE("[%04x] VXDLoader\n", (UINT16
)service
);
464 case 0x0000: /* get version */
465 TRACE("returning version\n");
466 SET_AX( context
, 0x0000 );
467 SET_DX( context
, VXD_WinVersion() );
468 RESET_CFLAG(context
);
471 case 0x0001: /* load device */
472 FIXME("load device %04x:%04x (%s)\n",
473 context
->SegDs
, DX_reg(context
),
474 debugstr_a(MapSL(MAKESEGPTR(context
->SegDs
, DX_reg(context
)))));
475 SET_AX( context
, 0x0000 );
476 context
->SegEs
= 0x0000;
477 SET_DI( context
, 0x0000 );
478 RESET_CFLAG(context
);
481 case 0x0002: /* unload device */
482 FIXME("unload device (%08x)\n", context
->Ebx
);
483 SET_AX( context
, 0x0000 );
484 RESET_CFLAG(context
);
488 VXD_BARF( context
, "VXDLDR" );
489 SET_AX( context
, 0x000B ); /* invalid function number */
495 /***********************************************************************
496 * __wine_vxd_shell (WPROCS.423)
498 void WINAPI
__wine_vxd_shell( CONTEXT
*context
)
500 unsigned service
= DX_reg(context
);
502 TRACE("[%04x] Shell\n", (UINT16
)service
);
504 switch (service
) /* Ralf Brown says EDX, but I use DX instead */
507 TRACE("returning version\n");
508 SET_AX( context
, VXD_WinVersion() );
509 context
->Ebx
= 1; /* system VM Handle */
515 /* SHELL_SYSMODAL_Message
516 ebx virtual machine handle
517 eax message box flags
518 ecx address of message
519 edi address of caption
520 return response in eax
524 ebx virtual machine handle
525 eax message box flags
526 ecx address of message
527 edi address of caption
529 edx reference data for callback
530 return response in eax
533 VXD_BARF( context
, "shell" );
536 case 0x0006: /* SHELL_Get_VM_State */
537 TRACE("VxD Shell: returning VM state\n");
538 /* Actually we don't, not yet. We have to return a structure
539 * and I am not to sure how to set it up and return it yet,
540 * so for now let's do nothing. I can (hopefully) get this
541 * by the next release
543 /* RESET_CFLAG(context); */
562 VXD_BARF( context
, "SHELL" );
565 /* the new Win95 shell API */
566 case 0x0100: /* get version */
567 SET_AX( context
, VXD_WinVersion() );
570 case 0x0104: /* retrieve Hook_Properties list */
571 case 0x0105: /* call Hook_Properties callbacks */
572 VXD_BARF( context
, "SHELL" );
575 case 0x0106: /* install timeout callback */
576 TRACE("VxD Shell: ignoring shell callback (%d sec.)\n", context
->Ebx
);
580 case 0x0107: /* get version of any VxD */
582 VXD_BARF( context
, "SHELL" );
588 /***********************************************************************
589 * __wine_vxd_comm (WPROCS.414)
591 void WINAPI
__wine_vxd_comm( CONTEXT
*context
)
593 unsigned service
= AX_reg(context
);
595 TRACE("[%04x] Comm\n", (UINT16
)service
);
599 case 0x0000: /* get version */
600 TRACE("returning version\n");
601 SET_AX( context
, VXD_WinVersion() );
602 RESET_CFLAG(context
);
605 case 0x0001: /* set port global */
606 case 0x0002: /* get focus */
607 case 0x0003: /* virtualise port */
609 VXD_BARF( context
, "comm" );
613 /***********************************************************************
614 * __wine_vxd_timer (WPROCS.405)
616 void WINAPI
__wine_vxd_timer( CONTEXT
*context
)
618 unsigned service
= AX_reg(context
);
620 TRACE("[%04x] Virtual Timer\n", (UINT16
)service
);
624 case 0x0000: /* version */
625 SET_AX( context
, VXD_WinVersion() );
626 RESET_CFLAG(context
);
629 case 0x0100: /* clock tick time, in 840nsecs */
630 context
->Eax
= GetTickCount();
632 context
->Edx
= context
->Eax
>> 22;
633 context
->Eax
<<= 10; /* not very precise */
636 case 0x0101: /* current Windows time, msecs */
637 case 0x0102: /* current VM time, msecs */
638 context
->Eax
= GetTickCount();
642 VXD_BARF( context
, "VTD" );
647 /***********************************************************************
650 static DWORD CALLBACK
timer_thread( void *arg
)
652 DWORD
*system_time
= arg
;
656 *system_time
= GetTickCount();
664 /***********************************************************************
665 * __wine_vxd_timerapi (WPROCS.1490)
667 void WINAPI
__wine_vxd_timerapi( CONTEXT
*context
)
669 static WORD System_Time_Selector
;
671 unsigned service
= AX_reg(context
);
673 TRACE("[%04x] TimerAPI\n", (UINT16
)service
);
677 case 0x0000: /* version */
678 SET_AX( context
, VXD_WinVersion() );
679 RESET_CFLAG(context
);
682 case 0x0009: /* get system time selector */
683 if ( !System_Time_Selector
)
685 HANDLE16 handle
= GlobalAlloc16( GMEM_FIXED
, sizeof(DWORD
) );
686 System_Time_Selector
= handle
| 7;
687 CloseHandle( CreateThread( NULL
, 0, timer_thread
, GlobalLock16(handle
), 0, NULL
) );
689 SET_AX( context
, System_Time_Selector
);
690 RESET_CFLAG(context
);
694 VXD_BARF( context
, "VTDAPI" );
698 /***********************************************************************
699 * __wine_vxd_configmg (WPROCS.451)
701 void WINAPI
__wine_vxd_configmg( CONTEXT
*context
)
703 unsigned service
= AX_reg(context
);
705 TRACE("[%04x] ConfigMG\n", (UINT16
)service
);
709 case 0x0000: /* version */
710 SET_AX( context
, VXD_WinVersion() );
711 RESET_CFLAG(context
);
715 VXD_BARF( context
, "CONFIGMG" );
719 /***********************************************************************
720 * __wine_vxd_enable (WPROCS.455)
722 void WINAPI
__wine_vxd_enable( CONTEXT
*context
)
724 unsigned service
= AX_reg(context
);
726 TRACE("[%04x] Enable\n", (UINT16
)service
);
730 case 0x0000: /* version */
731 SET_AX( context
, VXD_WinVersion() );
732 RESET_CFLAG(context
);
736 VXD_BARF( context
, "ENABLE" );
740 /***********************************************************************
741 * __wine_vxd_apm (WPROCS.438)
743 void WINAPI
__wine_vxd_apm( CONTEXT
*context
)
745 unsigned service
= AX_reg(context
);
747 TRACE("[%04x] APM\n", (UINT16
)service
);
751 case 0x0000: /* version */
752 SET_AX( context
, VXD_WinVersion() );
753 RESET_CFLAG(context
);
757 VXD_BARF( context
, "APM" );
761 /***********************************************************************
762 * __wine_vxd_win32s (WPROCS.445)
764 * This is an implementation of the services of the Win32s VxD.
765 * Since official documentation of these does not seem to be available,
766 * certain arguments of some of the services remain unclear.
768 * FIXME: The following services are currently unimplemented:
769 * Exception handling (0x01, 0x1C)
770 * Debugger support (0x0C, 0x14, 0x17)
771 * Low-level memory access (0x02, 0x03, 0x0A, 0x0B)
772 * Memory Statistics (0x1B)
775 * We have a specific problem running Win32s on Linux (and probably also
776 * the other x86 unixes), since Win32s tries to allocate its main 'flat
777 * code/data segment' selectors with a base of 0xffff0000 (and limit 4GB).
778 * The rationale for this seems to be that they want one the one hand to
779 * be able to leave the Win 3.1 memory (starting with the main DOS memory)
780 * at linear address 0, but want at other hand to have offset 0 of the
781 * flat data/code segment point to an unmapped page (to catch NULL pointer
782 * accesses). Hence they allocate the flat segments with a base of 0xffff0000
783 * so that the Win 3.1 memory area at linear address zero shows up in the
784 * flat segments at offset 0x10000 (since linear addresses wrap around at
785 * 4GB). To compensate for that discrepancy between flat segment offsets
786 * and plain linear addresses, all flat pointers passed between the 32-bit
787 * and the 16-bit parts of Win32s are shifted by 0x10000 in the appropriate
788 * direction by the glue code (mainly) in W32SKRNL and WIN32S16.
790 * The problem for us is now that Linux does not allow a LDT selector with
791 * base 0xffff0000 to be created, since it would 'see' a part of the kernel
792 * address space. To address this problem we introduce *another* offset:
793 * We add 0x10000 to every linear address we get as an argument from Win32s.
794 * This means especially that the flat code/data selectors get actually
795 * allocated with base 0x0, so that flat offsets and (real) linear addresses
796 * do again agree! In fact, every call e.g. of a Win32s VxD service now
797 * has all pointer arguments (which are offsets in the flat data segment)
798 * first reduced by 0x10000 by the W32SKRNL glue code, and then again
799 * increased by 0x10000 by *our* code.
801 * Note that to keep everything consistent, this offset has to be applied by
802 * every Wine function that operates on 'linear addresses' passed to it by
803 * Win32s. Fortunately, since Win32s does not directly call any Wine 32-bit
804 * API routines, this affects only two locations: this VxD and the DPMI
805 * handler. (NOTE: Should any Win32s application pass a linear address to
806 * any routine apart from those, e.g. some other VxD handler, that code
807 * would have to take the offset into account as well!)
809 * The offset is set the first time any application calls the GetVersion()
810 * service of the Win32s VxD. (Note that the offset is never reset.)
813 void WINAPI
__wine_vxd_win32s( CONTEXT
*context
)
815 switch (AX_reg(context
))
817 case 0x0000: /* Get Version */
821 * Output: EAX: LoWord: Win32s Version (1.30)
822 * HiWord: VxD Version (200)
828 * EDX: Debugging Flags
832 * 1 if VMCPD VxD not found
835 TRACE("GetVersion()\n");
837 context
->Eax
= VXD_WinVersion() | (200 << 16);
844 * If this is the first time we are called for this process,
845 * hack the memory image of WIN32S16 so that it doesn't try
846 * to access the GDT directly ...
848 * The first code segment of WIN32S16 (version 1.30) contains
849 * an unexported function somewhere between the exported functions
850 * SetFS and StackLinearToSegmented that tries to find a selector
851 * in the LDT that maps to the memory image of the LDT itself.
852 * If it succeeds, it stores this selector into a global variable
853 * which will be used to speed up execution by using this selector
854 * to modify the LDT directly instead of using the DPMI calls.
856 * To perform this search of the LDT, this function uses the
857 * sgdt and sldt instructions to find the linear address of
858 * the (GDT and then) LDT. While those instructions themselves
859 * execute without problem, the linear address that sgdt returns
860 * points (at least under Linux) to the kernel address space, so
861 * that any subsequent access leads to a segfault.
863 * Fortunately, WIN32S16 still contains as a fallback option the
864 * mechanism of using DPMI calls to modify LDT selectors instead
865 * of direct writes to the LDT. Thus we can circumvent the problem
866 * by simply replacing the first byte of the offending function
867 * with an 'retf' instruction. This means that the global variable
868 * supposed to contain the LDT alias selector will remain zero,
869 * and hence WIN32S16 will fall back to using DPMI calls.
871 * The heuristic we employ to _find_ that function is as follows:
872 * We search between the addresses of the exported symbols SetFS
873 * and StackLinearToSegmented for the byte sequence '0F 01 04'
874 * (this is the opcode of 'sgdt [si]'). We then search backwards
875 * from this address for the last occurrence of 'CB' (retf) that marks
876 * the end of the preceding function. The following byte (which
877 * should now be the first byte of the function we are looking for)
878 * will be replaced by 'CB' (retf).
880 * This heuristic works for the retail as well as the debug version
881 * of Win32s version 1.30. For versions earlier than that this
882 * hack should not be necessary at all, since the whole mechanism
883 * ('PERF130') was introduced only in 1.30 to improve the overall
884 * performance of Win32s.
889 HMODULE16 hModule
= GetModuleHandle16("win32s16");
890 SEGPTR func1
= (SEGPTR
)GetProcAddress16(hModule
, "SetFS");
891 SEGPTR func2
= (SEGPTR
)GetProcAddress16(hModule
, "StackLinearToSegmented");
893 if ( hModule
&& func1
&& func2
894 && SELECTOROF(func1
) == SELECTOROF(func2
))
896 BYTE
*start
= MapSL(func1
);
897 BYTE
*end
= MapSL(func2
);
898 BYTE
*p
, *retv
= NULL
;
901 for (p
= start
; p
< end
; p
++)
902 if (*p
== 0xCB) found
= 0, retv
= p
;
903 else if (*p
== 0x0F) found
= 1;
904 else if (*p
== 0x01 && found
== 1) found
= 2;
905 else if (*p
== 0x04 && found
== 2) { found
= 3; break; }
908 if (found
== 3 && retv
)
910 TRACE("PERF130 hack: "
911 "Replacing byte %02X at offset %04X:%04X\n",
912 *(retv
+1), SELECTOROF(func1
),
913 OFFSETOF(func1
) + retv
+1-start
);
915 *(retv
+1) = (BYTE
)0xCB;
921 * Mark process as Win32s, so that subsequent DPMI calls
922 * will perform the W32S_APP2WINE/W32S_WINE2APP address shift.
924 W32S_offset
= 0x10000;
928 case 0x0001: /* Install Exception Handling */
930 * Input: EBX: Flat address of W32SKRNL Exception Data
932 * ECX: LoWord: Flat Code Selector
933 * HiWord: Flat Data Selector
935 * EDX: Flat address of W32SKRNL Exception Handler
936 * (this is equal to W32S_BackTo32 + 0x40)
938 * ESI: SEGPTR KERNEL.HASGPHANDLER
940 * EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10)
942 * Output: EAX: 0 if OK
945 TRACE("[0001] EBX=%x ECX=%x EDX=%x ESI=%x EDI=%x\n",
946 context
->Ebx
, context
->Ecx
, context
->Edx
,
947 context
->Esi
, context
->Edi
);
955 case 0x0002: /* Set Page Access Flags */
957 * Input: EBX: New access flags
958 * Bit 2: User Page if set, Supervisor Page if clear
959 * Bit 1: Read-Write if set, Read-Only if clear
961 * ECX: Size of memory area to change
963 * EDX: Flat start address of memory area
965 * Output: EAX: Size of area changed
968 TRACE("[0002] EBX=%x ECX=%x EDX=%x\n",
969 context
->Ebx
, context
->Ecx
, context
->Edx
);
973 context
->Eax
= context
->Ecx
;
977 case 0x0003: /* Get Page Access Flags */
979 * Input: EDX: Flat address of page to query
981 * Output: EAX: Page access flags
982 * Bit 2: User Page if set, Supervisor Page if clear
983 * Bit 1: Read-Write if set, Read-Only if clear
986 TRACE("[0003] EDX=%x\n", context
->Edx
);
994 case 0x0004: /* Map Module */
996 * Input: ECX: IMTE (offset in Module Table) of new module
998 * EDX: Flat address of Win32s Module Table
1000 * Output: EAX: 0 if OK
1003 if (!context
->Edx
|| CX_reg(context
) == 0xFFFF)
1005 TRACE("MapModule: Initialization call\n");
1011 * Structure of a Win32s Module Table Entry:
1026 * Note: This function should set up a demand-paged memory image
1027 * of the given module. Since mmap does not allow file offsets
1028 * not aligned at 1024 bytes, we simply load the image fully
1032 struct Win32sModule
*moduleTable
=
1033 (struct Win32sModule
*)W32S_APP2WINE(context
->Edx
);
1034 struct Win32sModule
*module
= moduleTable
+ context
->Ecx
;
1036 IMAGE_NT_HEADERS
*nt_header
= RtlImageNtHeader( (HMODULE
)module
->baseAddr
);
1037 IMAGE_SECTION_HEADER
*pe_seg
= (IMAGE_SECTION_HEADER
*)((char *)&nt_header
->OptionalHeader
+
1038 nt_header
->FileHeader
.SizeOfOptionalHeader
);
1041 HFILE image
= _lopen(module
->pathName
, OF_READ
);
1042 BOOL error
= (image
== HFILE_ERROR
);
1045 TRACE("MapModule: Loading %s\n", module
->pathName
);
1048 !error
&& i
< nt_header
->FileHeader
.NumberOfSections
;
1050 if(!(pe_seg
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
))
1052 DWORD off
= pe_seg
->PointerToRawData
;
1053 DWORD len
= pe_seg
->SizeOfRawData
;
1054 LPBYTE addr
= module
->baseAddr
+ pe_seg
->VirtualAddress
;
1057 "Section %d at %08x from %08x len %08x\n",
1058 i
, (DWORD
)addr
, off
, len
);
1060 if ( _llseek(image
, off
, SEEK_SET
) != off
1061 || _lread(image
, addr
, len
) != len
)
1068 ERR("MapModule: Unable to load %s\n", module
->pathName
);
1070 else if (module
->relocDelta
!= 0)
1072 IMAGE_DATA_DIRECTORY
*dir
= nt_header
->OptionalHeader
.DataDirectory
1073 + IMAGE_DIRECTORY_ENTRY_BASERELOC
;
1074 IMAGE_BASE_RELOCATION
*r
= (IMAGE_BASE_RELOCATION
*)
1075 (dir
->Size
? module
->baseAddr
+ dir
->VirtualAddress
: 0);
1077 TRACE("MapModule: Reloc delta %08x\n", module
->relocDelta
);
1079 while (r
&& r
->VirtualAddress
)
1081 LPBYTE page
= module
->baseAddr
+ r
->VirtualAddress
;
1082 WORD
*TypeOffset
= (WORD
*)(r
+ 1);
1083 unsigned int count
= (r
->SizeOfBlock
- sizeof(*r
)) / sizeof(*TypeOffset
);
1085 TRACE("MapModule: %d relocations for page %08x\n",
1086 count
, (DWORD
)page
);
1088 for(i
= 0; i
< count
; i
++)
1090 int offset
= TypeOffset
[i
] & 0xFFF;
1091 int type
= TypeOffset
[i
] >> 12;
1094 case IMAGE_REL_BASED_ABSOLUTE
:
1096 case IMAGE_REL_BASED_HIGH
:
1097 *(WORD
*)(page
+offset
) += HIWORD(module
->relocDelta
);
1099 case IMAGE_REL_BASED_LOW
:
1100 *(WORD
*)(page
+offset
) += LOWORD(module
->relocDelta
);
1102 case IMAGE_REL_BASED_HIGHLOW
:
1103 *(DWORD
*)(page
+offset
) += module
->relocDelta
;
1106 WARN("MapModule: Unsupported fixup type\n");
1111 r
= (IMAGE_BASE_RELOCATION
*)((LPBYTE
)r
+ r
->SizeOfBlock
);
1116 RESET_CFLAG(context
);
1121 case 0x0005: /* UnMap Module */
1123 * Input: EDX: Flat address of module image
1125 * Output: EAX: 1 if OK
1128 TRACE("UnMapModule: %x\n", W32S_APP2WINE(context
->Edx
));
1130 /* As we didn't map anything, there's nothing to unmap ... */
1136 case 0x0006: /* VirtualAlloc */
1138 * Input: ECX: Current Process
1140 * EDX: Flat address of arguments on stack
1142 * DWORD *retv [out] Flat base address of allocated region
1143 * LPVOID base [in] Flat address of region to reserve/commit
1144 * DWORD size [in] Size of region
1145 * DWORD type [in] Type of allocation
1146 * DWORD prot [in] Type of access protection
1148 * Output: EAX: NtStatus
1151 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1152 DWORD
*retv
= (DWORD
*)W32S_APP2WINE(stack
[0]);
1153 LPVOID base
= (LPVOID
) W32S_APP2WINE(stack
[1]);
1154 DWORD size
= stack
[2];
1155 DWORD type
= stack
[3];
1156 DWORD prot
= stack
[4];
1159 TRACE("VirtualAlloc(%x, %x, %x, %x, %x)\n",
1160 (DWORD
)retv
, (DWORD
)base
, size
, type
, prot
);
1162 if (type
& 0x80000000)
1164 WARN("VirtualAlloc: strange type %x\n", type
);
1168 if (!base
&& (type
& MEM_COMMIT
) && prot
== PAGE_READONLY
)
1170 WARN("VirtualAlloc: NLS hack, allowing write access!\n");
1171 prot
= PAGE_READWRITE
;
1174 result
= (DWORD
)VirtualAlloc(base
, size
, type
, prot
);
1176 if (W32S_WINE2APP(result
))
1177 *retv
= W32S_WINE2APP(result
),
1178 context
->Eax
= STATUS_SUCCESS
;
1181 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1186 case 0x0007: /* VirtualFree */
1188 * Input: ECX: Current Process
1190 * EDX: Flat address of arguments on stack
1192 * DWORD *retv [out] TRUE if success, FALSE if failure
1193 * LPVOID base [in] Flat address of region
1194 * DWORD size [in] Size of region
1195 * DWORD type [in] Type of operation
1197 * Output: EAX: NtStatus
1200 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1201 DWORD
*retv
= (DWORD
*)W32S_APP2WINE(stack
[0]);
1202 LPVOID base
= (LPVOID
) W32S_APP2WINE(stack
[1]);
1203 DWORD size
= stack
[2];
1204 DWORD type
= stack
[3];
1207 TRACE("VirtualFree(%x, %x, %x, %x)\n",
1208 (DWORD
)retv
, (DWORD
)base
, size
, type
);
1210 result
= VirtualFree(base
, size
, type
);
1214 context
->Eax
= STATUS_SUCCESS
;
1217 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1222 case 0x0008: /* VirtualProtect */
1224 * Input: ECX: Current Process
1226 * EDX: Flat address of arguments on stack
1228 * DWORD *retv [out] TRUE if success, FALSE if failure
1229 * LPVOID base [in] Flat address of region
1230 * DWORD size [in] Size of region
1231 * DWORD new_prot [in] Desired access protection
1232 * DWORD *old_prot [out] Previous access protection
1234 * Output: EAX: NtStatus
1237 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1238 DWORD
*retv
= (DWORD
*)W32S_APP2WINE(stack
[0]);
1239 LPVOID base
= (LPVOID
) W32S_APP2WINE(stack
[1]);
1240 DWORD size
= stack
[2];
1241 DWORD new_prot
= stack
[3];
1242 DWORD
*old_prot
= (DWORD
*)W32S_APP2WINE(stack
[4]);
1245 TRACE("VirtualProtect(%x, %x, %x, %x, %x)\n",
1246 (DWORD
)retv
, (DWORD
)base
, size
, new_prot
, (DWORD
)old_prot
);
1248 result
= VirtualProtect(base
, size
, new_prot
, old_prot
);
1252 context
->Eax
= STATUS_SUCCESS
;
1255 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1260 case 0x0009: /* VirtualQuery */
1262 * Input: ECX: Current Process
1264 * EDX: Flat address of arguments on stack
1266 * DWORD *retv [out] Nr. bytes returned
1267 * LPVOID base [in] Flat address of region
1268 * LPMEMORY_BASIC_INFORMATION info [out] Info buffer
1269 * DWORD len [in] Size of buffer
1271 * Output: EAX: NtStatus
1274 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1275 DWORD
*retv
= (DWORD
*)W32S_APP2WINE(stack
[0]);
1276 LPVOID base
= (LPVOID
) W32S_APP2WINE(stack
[1]);
1277 PMEMORY_BASIC_INFORMATION info
=
1278 (PMEMORY_BASIC_INFORMATION
)W32S_APP2WINE(stack
[2]);
1279 DWORD len
= stack
[3];
1282 TRACE("VirtualQuery(%x, %x, %x, %x)\n",
1283 (DWORD
)retv
, (DWORD
)base
, (DWORD
)info
, len
);
1285 result
= VirtualQuery(base
, info
, len
);
1288 context
->Eax
= STATUS_SUCCESS
;
1293 case 0x000A: /* SetVirtMemProcess */
1295 * Input: ECX: Process Handle
1297 * EDX: Flat address of region
1299 * Output: EAX: NtStatus
1302 TRACE("[000a] ECX=%x EDX=%x\n",
1303 context
->Ecx
, context
->Edx
);
1307 context
->Eax
= STATUS_SUCCESS
;
1311 case 0x000B: /* ??? some kind of cleanup */
1313 * Input: ECX: Process Handle
1315 * Output: EAX: NtStatus
1318 TRACE("[000b] ECX=%x\n", context
->Ecx
);
1322 context
->Eax
= STATUS_SUCCESS
;
1326 case 0x000C: /* Set Debug Flags */
1328 * Input: EDX: Debug Flags
1330 * Output: EDX: Previous Debug Flags
1333 FIXME("[000c] EDX=%x\n", context
->Edx
);
1341 case 0x000D: /* NtCreateSection */
1343 * Input: EDX: Flat address of arguments on stack
1345 * HANDLE32 *retv [out] Handle of Section created
1346 * DWORD flags1 [in] (?? unknown ??)
1347 * DWORD atom [in] Name of Section to create
1348 * LARGE_INTEGER *size [in] Size of Section
1349 * DWORD protect [in] Access protection
1350 * DWORD flags2 [in] (?? unknown ??)
1351 * HFILE32 hFile [in] Handle of file to map
1352 * DWORD psp [in] (Win32s: PSP that hFile belongs to)
1354 * Output: EAX: NtStatus
1357 DWORD
*stack
= (DWORD
*) W32S_APP2WINE(context
->Edx
);
1358 HANDLE
*retv
= (HANDLE
*)W32S_APP2WINE(stack
[0]);
1359 DWORD flags1
= stack
[1];
1360 DWORD atom
= stack
[2];
1361 LARGE_INTEGER
*size
= (LARGE_INTEGER
*)W32S_APP2WINE(stack
[3]);
1362 DWORD protect
= stack
[4];
1363 DWORD flags2
= stack
[5];
1364 HANDLE hFile
= DosFileHandleToWin32Handle(stack
[6]);
1365 DWORD psp
= stack
[7];
1367 HANDLE result
= INVALID_HANDLE_VALUE
;
1370 TRACE("NtCreateSection(%x, %x, %x, %x, %x, %x, %x, %x)\n",
1371 (DWORD
)retv
, flags1
, atom
, (DWORD
)size
, protect
, flags2
,
1374 if (!atom
|| GlobalGetAtomNameA(atom
, name
, sizeof(name
)))
1376 TRACE("NtCreateSection: name=%s\n", atom
? name
: NULL
);
1378 result
= CreateFileMappingA(hFile
, NULL
, protect
,
1379 size
? size
->u
.HighPart
: 0,
1380 size
? size
->u
.LowPart
: 0,
1384 if (result
== INVALID_HANDLE_VALUE
)
1385 WARN("NtCreateSection: failed!\n");
1387 TRACE("NtCreateSection: returned %x\n", (DWORD
)result
);
1389 if (result
!= INVALID_HANDLE_VALUE
)
1391 context
->Eax
= STATUS_SUCCESS
;
1394 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1399 case 0x000E: /* NtOpenSection */
1401 * Input: EDX: Flat address of arguments on stack
1403 * HANDLE32 *retv [out] Handle of Section opened
1404 * DWORD protect [in] Access protection
1405 * DWORD atom [in] Name of Section to create
1407 * Output: EAX: NtStatus
1410 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1411 HANDLE
*retv
= (HANDLE
*)W32S_APP2WINE(stack
[0]);
1412 DWORD protect
= stack
[1];
1413 DWORD atom
= stack
[2];
1415 HANDLE result
= INVALID_HANDLE_VALUE
;
1418 TRACE("NtOpenSection(%x, %x, %x)\n",
1419 (DWORD
)retv
, protect
, atom
);
1421 if (atom
&& GlobalGetAtomNameA(atom
, name
, sizeof(name
)))
1423 TRACE("NtOpenSection: name=%s\n", name
);
1425 result
= OpenFileMappingA(protect
, FALSE
, name
);
1428 if (result
== INVALID_HANDLE_VALUE
)
1429 WARN("NtOpenSection: failed!\n");
1431 TRACE("NtOpenSection: returned %x\n", (DWORD
)result
);
1433 if (result
!= INVALID_HANDLE_VALUE
)
1435 context
->Eax
= STATUS_SUCCESS
;
1438 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1443 case 0x000F: /* NtCloseSection */
1445 * Input: EDX: Flat address of arguments on stack
1447 * HANDLE32 handle [in] Handle of Section to close
1448 * DWORD *id [out] Unique ID (?? unclear ??)
1450 * Output: EAX: NtStatus
1453 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1454 HANDLE handle
= (HANDLE
)stack
[0];
1455 DWORD
*id
= (DWORD
*)W32S_APP2WINE(stack
[1]);
1457 TRACE("NtCloseSection(%x, %x)\n", (DWORD
)handle
, (DWORD
)id
);
1459 CloseHandle(handle
);
1460 if (id
) *id
= 0; /* FIXME */
1462 context
->Eax
= STATUS_SUCCESS
;
1467 case 0x0010: /* NtDupSection */
1469 * Input: EDX: Flat address of arguments on stack
1471 * HANDLE32 handle [in] Handle of Section to duplicate
1473 * Output: EAX: NtStatus
1476 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1477 HANDLE handle
= (HANDLE
)stack
[0];
1480 TRACE("NtDupSection(%x)\n", (DWORD
)handle
);
1482 DuplicateHandle( GetCurrentProcess(), handle
,
1483 GetCurrentProcess(), &new_handle
,
1484 0, FALSE
, DUPLICATE_SAME_ACCESS
);
1485 context
->Eax
= STATUS_SUCCESS
;
1490 case 0x0011: /* NtMapViewOfSection */
1492 * Input: EDX: Flat address of arguments on stack
1494 * HANDLE32 SectionHandle [in] Section to be mapped
1495 * DWORD ProcessHandle [in] Process to be mapped into
1496 * DWORD * BaseAddress [in/out] Address to be mapped at
1497 * DWORD ZeroBits [in] (?? unclear ??)
1498 * DWORD CommitSize [in] (?? unclear ??)
1499 * LARGE_INTEGER *SectionOffset [in] Offset within section
1500 * DWORD * ViewSize [in] Size of view
1501 * DWORD InheritDisposition [in] (?? unclear ??)
1502 * DWORD AllocationType [in] (?? unclear ??)
1503 * DWORD Protect [in] Access protection
1505 * Output: EAX: NtStatus
1508 DWORD
* stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1509 HANDLE SectionHandle
= (HANDLE
)stack
[0];
1510 DWORD ProcessHandle
= stack
[1]; /* ignored */
1511 DWORD
* BaseAddress
= (DWORD
*)W32S_APP2WINE(stack
[2]);
1512 DWORD ZeroBits
= stack
[3];
1513 DWORD CommitSize
= stack
[4];
1514 LARGE_INTEGER
*SectionOffset
= (LARGE_INTEGER
*)W32S_APP2WINE(stack
[5]);
1515 DWORD
* ViewSize
= (DWORD
*)W32S_APP2WINE(stack
[6]);
1516 DWORD InheritDisposition
= stack
[7];
1517 DWORD AllocationType
= stack
[8];
1518 DWORD Protect
= stack
[9];
1520 LPBYTE address
= (LPBYTE
)(BaseAddress
?
1521 W32S_APP2WINE(*BaseAddress
) : 0);
1522 DWORD access
= 0, result
;
1524 switch (Protect
& ~(PAGE_GUARD
|PAGE_NOCACHE
))
1526 case PAGE_READONLY
: access
= FILE_MAP_READ
; break;
1527 case PAGE_READWRITE
: access
= FILE_MAP_WRITE
; break;
1528 case PAGE_WRITECOPY
: access
= FILE_MAP_COPY
; break;
1530 case PAGE_EXECUTE_READ
: access
= FILE_MAP_READ
; break;
1531 case PAGE_EXECUTE_READWRITE
: access
= FILE_MAP_WRITE
; break;
1532 case PAGE_EXECUTE_WRITECOPY
: access
= FILE_MAP_COPY
; break;
1535 TRACE("NtMapViewOfSection"
1536 "(%x, %x, %x, %x, %x, %x, %x, %x, %x, %x)\n",
1537 (DWORD
)SectionHandle
, ProcessHandle
, (DWORD
)BaseAddress
,
1538 ZeroBits
, CommitSize
, (DWORD
)SectionOffset
, (DWORD
)ViewSize
,
1539 InheritDisposition
, AllocationType
, Protect
);
1540 TRACE("NtMapViewOfSection: "
1541 "base=%x, offset=%x, size=%x, access=%x\n",
1542 (DWORD
)address
, SectionOffset
? SectionOffset
->u
.LowPart
: 0,
1543 ViewSize
? *ViewSize
: 0, access
);
1545 result
= (DWORD
)MapViewOfFileEx(SectionHandle
, access
,
1546 SectionOffset
? SectionOffset
->u
.HighPart
: 0,
1547 SectionOffset
? SectionOffset
->u
.LowPart
: 0,
1548 ViewSize
? *ViewSize
: 0, address
);
1550 TRACE("NtMapViewOfSection: result=%x\n", result
);
1552 if (W32S_WINE2APP(result
))
1554 if (BaseAddress
) *BaseAddress
= W32S_WINE2APP(result
);
1555 context
->Eax
= STATUS_SUCCESS
;
1558 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1563 case 0x0012: /* NtUnmapViewOfSection */
1565 * Input: EDX: Flat address of arguments on stack
1567 * DWORD ProcessHandle [in] Process (defining address space)
1568 * LPBYTE BaseAddress [in] Base address of view to be unmapped
1570 * Output: EAX: NtStatus
1573 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1574 DWORD ProcessHandle
= stack
[0]; /* ignored */
1575 LPBYTE BaseAddress
= (LPBYTE
)W32S_APP2WINE(stack
[1]);
1577 TRACE("NtUnmapViewOfSection(%x, %x)\n",
1578 ProcessHandle
, (DWORD
)BaseAddress
);
1580 UnmapViewOfFile(BaseAddress
);
1582 context
->Eax
= STATUS_SUCCESS
;
1587 case 0x0013: /* NtFlushVirtualMemory */
1589 * Input: EDX: Flat address of arguments on stack
1591 * DWORD ProcessHandle [in] Process (defining address space)
1592 * LPBYTE *BaseAddress [in?] Base address of range to be flushed
1593 * DWORD *ViewSize [in?] Number of bytes to be flushed
1594 * DWORD *unknown [???] (?? unknown ??)
1596 * Output: EAX: NtStatus
1599 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1600 DWORD ProcessHandle
= stack
[0]; /* ignored */
1601 DWORD
*BaseAddress
= (DWORD
*)W32S_APP2WINE(stack
[1]);
1602 DWORD
*ViewSize
= (DWORD
*)W32S_APP2WINE(stack
[2]);
1603 DWORD
*unknown
= (DWORD
*)W32S_APP2WINE(stack
[3]);
1605 LPBYTE address
= (LPBYTE
)(BaseAddress
? W32S_APP2WINE(*BaseAddress
) : 0);
1606 DWORD size
= ViewSize
? *ViewSize
: 0;
1608 TRACE("NtFlushVirtualMemory(%x, %x, %x, %x)\n",
1609 ProcessHandle
, (DWORD
)BaseAddress
, (DWORD
)ViewSize
,
1611 TRACE("NtFlushVirtualMemory: base=%x, size=%x\n",
1612 (DWORD
)address
, size
);
1614 FlushViewOfFile(address
, size
);
1616 context
->Eax
= STATUS_SUCCESS
;
1621 case 0x0014: /* Get/Set Debug Registers */
1623 * Input: ECX: 0 if Get, 1 if Set
1625 * EDX: Get: Flat address of buffer to receive values of
1626 * debug registers DR0 .. DR7
1627 * Set: Flat address of buffer containing values of
1628 * debug registers DR0 .. DR7 to be set
1632 FIXME("[0014] ECX=%x EDX=%x\n",
1633 context
->Ecx
, context
->Edx
);
1639 case 0x0015: /* Set Coprocessor Emulation Flag */
1641 * Input: EDX: 0 to deactivate, 1 to activate coprocessor emulation
1646 TRACE("[0015] EDX=%x\n", context
->Edx
);
1648 /* We don't care, as we always have a coprocessor anyway */
1652 case 0x0016: /* Init Win32S VxD PSP */
1654 * If called to query required PSP size:
1657 * Output: EDX: Required size of Win32s VxD PSP
1659 * If called to initialize allocated PSP:
1661 * Input: EBX: LoWord: Selector of Win32s VxD PSP
1662 * HiWord: Paragraph of Win32s VxD PSP (DOSMEM)
1666 if (context
->Ebx
== 0)
1667 context
->Edx
= 0x80;
1670 PDB16
*psp
= MapSL( MAKESEGPTR( BX_reg(context
), 0 ));
1672 psp
->fileHandlesPtr
= MAKELONG(HIWORD(context
->Ebx
), 0x5c);
1673 memset((LPBYTE
)psp
+ 0x5c, '\xFF', 32);
1678 case 0x0017: /* Set Break Point */
1680 * Input: EBX: Offset of Break Point
1681 * CX: Selector of Break Point
1686 FIXME("[0017] EBX=%x CX=%x\n",
1687 context
->Ebx
, CX_reg(context
));
1693 case 0x0018: /* VirtualLock */
1695 * Input: ECX: Current Process
1697 * EDX: Flat address of arguments on stack
1699 * DWORD *retv [out] TRUE if success, FALSE if failure
1700 * LPVOID base [in] Flat address of range to lock
1701 * DWORD size [in] Size of range
1703 * Output: EAX: NtStatus
1706 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1707 DWORD
*retv
= (DWORD
*)W32S_APP2WINE(stack
[0]);
1708 LPVOID base
= (LPVOID
) W32S_APP2WINE(stack
[1]);
1709 DWORD size
= stack
[2];
1712 TRACE("VirtualLock(%x, %x, %x)\n",
1713 (DWORD
)retv
, (DWORD
)base
, size
);
1715 result
= VirtualLock(base
, size
);
1719 context
->Eax
= STATUS_SUCCESS
;
1722 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1727 case 0x0019: /* VirtualUnlock */
1729 * Input: ECX: Current Process
1731 * EDX: Flat address of arguments on stack
1733 * DWORD *retv [out] TRUE if success, FALSE if failure
1734 * LPVOID base [in] Flat address of range to unlock
1735 * DWORD size [in] Size of range
1737 * Output: EAX: NtStatus
1740 DWORD
*stack
= (DWORD
*)W32S_APP2WINE(context
->Edx
);
1741 DWORD
*retv
= (DWORD
*)W32S_APP2WINE(stack
[0]);
1742 LPVOID base
= (LPVOID
) W32S_APP2WINE(stack
[1]);
1743 DWORD size
= stack
[2];
1746 TRACE("VirtualUnlock(%x, %x, %x)\n",
1747 (DWORD
)retv
, (DWORD
)base
, size
);
1749 result
= VirtualUnlock(base
, size
);
1753 context
->Eax
= STATUS_SUCCESS
;
1756 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1761 case 0x001A: /* KGetSystemInfo */
1765 * Output: ECX: Start of sparse memory arena
1766 * EDX: End of sparse memory arena
1769 TRACE("KGetSystemInfo()\n");
1772 * Note: Win32s reserves 0GB - 2GB for Win 3.1 and uses 2GB - 4GB as
1773 * sparse memory arena. We do it the other way around, since
1774 * we have to reserve 3GB - 4GB for Linux, and thus use
1775 * 0GB - 3GB as sparse memory arena.
1777 * FIXME: What about other OSes ?
1780 context
->Ecx
= W32S_WINE2APP(0x00000000);
1781 context
->Edx
= W32S_WINE2APP(0xbfffffff);
1785 case 0x001B: /* KGlobalMemStat */
1787 * Input: ESI: Flat address of buffer to receive memory info
1792 struct Win32sMemoryInfo
1794 DWORD DIPhys_Count
; /* Total physical pages */
1795 DWORD DIFree_Count
; /* Free physical pages */
1796 DWORD DILin_Total_Count
; /* Total virtual pages (private arena) */
1797 DWORD DILin_Total_Free
; /* Free virtual pages (private arena) */
1799 DWORD SparseTotal
; /* Total size of sparse arena (bytes ?) */
1800 DWORD SparseFree
; /* Free size of sparse arena (bytes ?) */
1803 struct Win32sMemoryInfo
*info
=
1804 (struct Win32sMemoryInfo
*)W32S_APP2WINE(context
->Esi
);
1806 FIXME("KGlobalMemStat(%x)\n", (DWORD
)info
);
1813 case 0x001C: /* Enable/Disable Exceptions */
1815 * Input: ECX: 0 to disable, 1 to enable exception handling
1820 TRACE("[001c] ECX=%x\n", context
->Ecx
);
1826 case 0x001D: /* VirtualAlloc called from 16-bit code */
1828 * Input: EDX: Segmented address of arguments on stack
1830 * LPVOID base [in] Flat address of region to reserve/commit
1831 * DWORD size [in] Size of region
1832 * DWORD type [in] Type of allocation
1833 * DWORD prot [in] Type of access protection
1835 * Output: EAX: NtStatus
1836 * EDX: Flat base address of allocated region
1839 DWORD
*stack
= MapSL( MAKESEGPTR( LOWORD(context
->Edx
), HIWORD(context
->Edx
) ));
1840 LPVOID base
= (LPVOID
)W32S_APP2WINE(stack
[0]);
1841 DWORD size
= stack
[1];
1842 DWORD type
= stack
[2];
1843 DWORD prot
= stack
[3];
1846 TRACE("VirtualAlloc16(%x, %x, %x, %x)\n",
1847 (DWORD
)base
, size
, type
, prot
);
1849 if (type
& 0x80000000)
1851 WARN("VirtualAlloc16: strange type %x\n", type
);
1855 result
= (DWORD
)VirtualAlloc(base
, size
, type
, prot
);
1857 if (W32S_WINE2APP(result
))
1858 context
->Edx
= W32S_WINE2APP(result
),
1859 context
->Eax
= STATUS_SUCCESS
;
1862 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1863 TRACE("VirtualAlloc16: returning base %x\n", context
->Edx
);
1868 case 0x001E: /* VirtualFree called from 16-bit code */
1870 * Input: EDX: Segmented address of arguments on stack
1872 * LPVOID base [in] Flat address of region
1873 * DWORD size [in] Size of region
1874 * DWORD type [in] Type of operation
1876 * Output: EAX: NtStatus
1877 * EDX: TRUE if success, FALSE if failure
1880 DWORD
*stack
= MapSL( MAKESEGPTR( LOWORD(context
->Edx
), HIWORD(context
->Edx
) ));
1881 LPVOID base
= (LPVOID
)W32S_APP2WINE(stack
[0]);
1882 DWORD size
= stack
[1];
1883 DWORD type
= stack
[2];
1886 TRACE("VirtualFree16(%x, %x, %x)\n",
1887 (DWORD
)base
, size
, type
);
1889 result
= VirtualFree(base
, size
, type
);
1892 context
->Edx
= TRUE
,
1893 context
->Eax
= STATUS_SUCCESS
;
1895 context
->Edx
= FALSE
,
1896 context
->Eax
= STATUS_NO_MEMORY
; /* FIXME */
1901 case 0x001F: /* FWorkingSetSize */
1903 * Input: EDX: 0 if Get, 1 if Set
1905 * ECX: Get: Buffer to receive Working Set Size
1906 * Set: Buffer containing Working Set Size
1911 DWORD
*ptr
= (DWORD
*)W32S_APP2WINE(context
->Ecx
);
1912 BOOL set
= context
->Edx
;
1914 TRACE("FWorkingSetSize(%x, %x)\n", (DWORD
)ptr
, (DWORD
)set
);
1917 /* We do it differently ... */;
1921 context
->Eax
= STATUS_SUCCESS
;
1926 VXD_BARF( context
, "W32S" );