user32: Move *RegisterDeviceNotification*() to input.c.
[wine.git] / dlls / krnl386.exe16 / vxd.c
blobab9d916d834fcfdf287340f4a6bc6c4eb7613ec9
1 /*
2 * Win32 VxD functions
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
23 #include <stdlib.h>
24 #include <sys/types.h>
25 #include <string.h>
26 #include <stdarg.h>
28 #include "ntstatus.h"
29 #define WIN32_NO_STATUS
30 #define NONAMELESSUNION
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winerror.h"
34 #include "winternl.h"
35 #include "winioctl.h"
36 #include "kernel16_private.h"
37 #include "dosexe.h"
38 #include "wine/server.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(vxd);
43 typedef DWORD (WINAPI *VxDCallProc)(DWORD, CONTEXT *);
44 typedef BOOL (WINAPI *DeviceIoProc)(DWORD, LPVOID, DWORD, LPVOID, DWORD, LPDWORD, LPOVERLAPPED);
46 struct vxd_module
48 LARGE_INTEGER index;
49 HANDLE handle;
50 HMODULE module;
51 DeviceIoProc proc;
54 struct vxdcall_service
56 WCHAR name[12];
57 DWORD service;
58 HMODULE module;
59 VxDCallProc proc;
62 #define MAX_VXD_MODULES 32
64 static struct vxd_module vxd_modules[MAX_VXD_MODULES];
66 static struct vxdcall_service vxd_services[] =
68 { {'v','m','m','.','v','x','d',0}, 0x0001, NULL, NULL },
69 { {'v','w','i','n','3','2','.','v','x','d',0}, 0x002a, NULL, NULL }
72 #define W32S_APP2WINE(addr) ((addr)? (DWORD)(addr) + W32S_offset : 0)
73 #define W32S_WINE2APP(addr) ((addr)? (DWORD)(addr) - W32S_offset : 0)
75 #define VXD_BARF(context,name) \
76 TRACE( "vxd %s: unknown/not implemented parameters:\n" \
77 "vxd %s: AX %04x, BX %04x, CX %04x, DX %04x, " \
78 "SI %04x, DI %04x, DS %04x, ES %04x\n", \
79 (name), (name), AX_reg(context), BX_reg(context), \
80 CX_reg(context), DX_reg(context), SI_reg(context), \
81 DI_reg(context), (WORD)context->SegDs, (WORD)context->SegEs )
83 static CRITICAL_SECTION vxd_section;
84 static CRITICAL_SECTION_DEBUG critsect_debug =
86 0, 0, &vxd_section,
87 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
88 0, 0, { (DWORD_PTR)(__FILE__ ": vxd_section") }
90 static CRITICAL_SECTION vxd_section = { &critsect_debug, -1, 0, 0, 0, 0 };
92 static UINT W32S_offset;
94 static WORD VXD_WinVersion(void)
96 WORD version = LOWORD(GetVersion16());
97 return (version >> 8) | (version << 8);
100 /* retrieve the DeviceIoControl function for a Vxd given a file handle */
101 DeviceIoProc __wine_vxd_get_proc( HANDLE handle )
103 DeviceIoProc ret = NULL;
104 int status, i;
105 IO_STATUS_BLOCK io;
106 FILE_INTERNAL_INFORMATION info;
108 status = NtQueryInformationFile( handle, &io, &info, sizeof(info), FileInternalInformation );
109 if (status)
111 SetLastError( RtlNtStatusToDosError(status) );
112 return NULL;
115 RtlEnterCriticalSection( &vxd_section );
117 for (i = 0; i < MAX_VXD_MODULES; i++)
119 if (!vxd_modules[i].module) break;
120 if (vxd_modules[i].index.QuadPart == info.IndexNumber.QuadPart)
122 if (!(ret = vxd_modules[i].proc)) SetLastError( ERROR_INVALID_FUNCTION );
123 goto done;
126 /* FIXME: Here we could go through the directory to find the VxD name and load it. */
127 /* Let's wait to find out if there are actually apps out there that try to share */
128 /* VxD handles between processes, before we go to the trouble of implementing it. */
129 ERR( "handle %p not found in module list, inherited from another process?\n", handle );
131 done:
132 RtlLeaveCriticalSection( &vxd_section );
133 return ret;
137 /* load a VxD and return a file handle to it */
138 HANDLE __wine_vxd_open( LPCWSTR filenameW, DWORD access, SECURITY_ATTRIBUTES *sa )
140 static const WCHAR dotVxDW[] = {'.','v','x','d',0};
141 int i;
142 HANDLE handle;
143 HMODULE module;
144 WCHAR *p, name[16];
146 /* normalize the filename */
148 if (lstrlenW( filenameW ) >= ARRAY_SIZE(name) - 4 ||
149 wcschr( filenameW, '/' ) || wcschr( filenameW, '\\' ))
151 SetLastError( ERROR_FILE_NOT_FOUND );
152 return 0;
154 lstrcpyW( name, filenameW );
155 wcslwr( name );
156 p = wcschr( name, '.' );
157 if (!p) lstrcatW( name, dotVxDW );
158 else if (wcsicmp( p, dotVxDW )) /* existing extension has to be .vxd */
160 SetLastError( ERROR_FILE_NOT_FOUND );
161 return 0;
164 /* try to load the module first */
166 if (!(module = LoadLibraryW( name )))
168 FIXME( "Unknown/unsupported VxD %s. Try setting Windows version to 'nt40' or 'win31'.\n",
169 debugstr_w(name) );
170 SetLastError( ERROR_FILE_NOT_FOUND );
171 return 0;
174 /* register the module in the global list if necessary */
176 RtlEnterCriticalSection( &vxd_section );
178 for (i = 0; i < MAX_VXD_MODULES; i++)
180 if (vxd_modules[i].module == module)
182 handle = vxd_modules[i].handle;
183 goto done; /* already registered */
185 if (!vxd_modules[i].module) /* new one, register it */
187 WCHAR path[MAX_PATH];
188 IO_STATUS_BLOCK io;
189 FILE_INTERNAL_INFORMATION info;
191 GetModuleFileNameW( module, path, MAX_PATH );
192 handle = CreateFileW( path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 );
193 if (handle == INVALID_HANDLE_VALUE)
195 FreeLibrary( module );
196 goto done;
198 if (!NtQueryInformationFile( handle, &io, &info, sizeof(info), FileInternalInformation ))
199 vxd_modules[i].index = info.IndexNumber;
201 vxd_modules[i].module = module;
202 vxd_modules[i].handle = handle;
203 vxd_modules[i].proc = (DeviceIoProc)GetProcAddress( module, "DeviceIoControl" );
204 goto done;
208 ERR("too many open VxD modules, please report\n" );
209 FreeLibrary( module );
210 handle = 0;
212 done:
213 RtlLeaveCriticalSection( &vxd_section );
214 if (!DuplicateHandle( GetCurrentProcess(), handle, GetCurrentProcess(), &handle, 0,
215 (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle),
216 DUP_HANDLE_SAME_ACCESS ))
217 handle = 0;
218 return handle;
222 /***********************************************************************
223 * VxDCall0 (KERNEL32.1)
224 * VxDCall1 (KERNEL32.2)
225 * VxDCall2 (KERNEL32.3)
226 * VxDCall3 (KERNEL32.4)
227 * VxDCall4 (KERNEL32.5)
228 * VxDCall5 (KERNEL32.6)
229 * VxDCall6 (KERNEL32.7)
230 * VxDCall7 (KERNEL32.8)
231 * VxDCall8 (KERNEL32.9)
233 void WINAPI DECLSPEC_HIDDEN __regs_VxDCall( CONTEXT *context )
235 unsigned int i;
236 VxDCallProc proc = NULL;
237 DWORD service = stack32_pop( context );
239 RtlEnterCriticalSection( &vxd_section );
240 for (i = 0; i < ARRAY_SIZE(vxd_services); i++)
242 if (HIWORD(service) != vxd_services[i].service) continue;
243 if (!vxd_services[i].module) /* need to load it */
245 if ((vxd_services[i].module = LoadLibraryW( vxd_services[i].name )))
246 vxd_services[i].proc = (VxDCallProc)GetProcAddress( vxd_services[i].module, "VxDCall" );
248 proc = vxd_services[i].proc;
249 break;
251 RtlLeaveCriticalSection( &vxd_section );
253 if (proc) context->Eax = proc( service, context );
254 else
256 FIXME( "Unknown/unimplemented VxD (%08x)\n", service);
257 context->Eax = 0xffffffff; /* FIXME */
260 DEFINE_REGS_ENTRYPOINT( VxDCall )
263 /***********************************************************************
264 * __wine_vxd_vmm (WPROCS.401)
266 void WINAPI __wine_vxd_vmm ( CONTEXT *context )
268 unsigned service = AX_reg(context);
270 TRACE("[%04x] VMM\n", (UINT16)service);
272 switch(service)
274 case 0x0000: /* version */
275 SET_AX( context, VXD_WinVersion() );
276 RESET_CFLAG(context);
277 break;
279 case 0x026d: /* Get_Debug_Flag '/m' */
280 case 0x026e: /* Get_Debug_Flag '/n' */
281 SET_AL( context, 0 );
282 RESET_CFLAG(context);
283 break;
285 default:
286 VXD_BARF( context, "VMM" );
290 /***********************************************************************
291 * __wine_vxd_pagefile (WPROCS.433)
293 void WINAPI __wine_vxd_pagefile( CONTEXT *context )
295 unsigned service = AX_reg(context);
297 /* taken from Ralf Brown's Interrupt List */
299 TRACE("[%04x] PageFile\n", (UINT16)service );
301 switch(service)
303 case 0x00: /* get version, is this windows version? */
304 TRACE("returning version\n");
305 SET_AX( context, VXD_WinVersion() );
306 RESET_CFLAG(context);
307 break;
309 case 0x01: /* get swap file info */
310 TRACE("VxD PageFile: returning swap file info\n");
311 SET_AX( context, 0x00 ); /* paging disabled */
312 context->Ecx = 0; /* maximum size of paging file */
313 /* FIXME: do I touch DS:SI or DS:DI? */
314 RESET_CFLAG(context);
315 break;
317 case 0x02: /* delete permanent swap on exit */
318 TRACE("VxD PageFile: supposed to delete swap\n");
319 RESET_CFLAG(context);
320 break;
322 case 0x03: /* current temporary swap file size */
323 TRACE("VxD PageFile: what is current temp. swap size\n");
324 RESET_CFLAG(context);
325 break;
327 case 0x04: /* read or write?? INTERRUP.D */
328 case 0x05: /* cancel?? INTERRUP.D */
329 case 0x06: /* test I/O valid INTERRUP.D */
330 default:
331 VXD_BARF( context, "pagefile" );
332 break;
336 /***********************************************************************
337 * __wine_vxd_reboot (WPROCS.409)
339 void WINAPI __wine_vxd_reboot( CONTEXT *context )
341 unsigned service = AX_reg(context);
343 TRACE("[%04x] Reboot\n", (UINT16)service);
345 switch(service)
347 case 0x0000: /* version */
348 SET_AX( context, VXD_WinVersion() );
349 RESET_CFLAG(context);
350 break;
352 default:
353 VXD_BARF( context, "REBOOT" );
357 /***********************************************************************
358 * __wine_vxd_vdd (WPROCS.410)
360 void WINAPI __wine_vxd_vdd( CONTEXT *context )
362 unsigned service = AX_reg(context);
364 TRACE("[%04x] VDD\n", (UINT16)service);
366 switch(service)
368 case 0x0000: /* version */
369 SET_AX( context, VXD_WinVersion() );
370 RESET_CFLAG(context);
371 break;
373 default:
374 VXD_BARF( context, "VDD" );
378 /***********************************************************************
379 * __wine_vxd_vmd (WPROCS.412)
381 void WINAPI __wine_vxd_vmd( CONTEXT *context )
383 unsigned service = AX_reg(context);
385 TRACE("[%04x] VMD\n", (UINT16)service);
387 switch(service)
389 case 0x0000: /* version */
390 SET_AX( context, VXD_WinVersion() );
391 RESET_CFLAG(context);
392 break;
394 default:
395 VXD_BARF( context, "VMD" );
399 /***********************************************************************
400 * __wine_vxd_vxdloader (WPROCS.439)
402 void WINAPI __wine_vxd_vxdloader( CONTEXT *context )
404 unsigned service = AX_reg(context);
406 TRACE("[%04x] VXDLoader\n", (UINT16)service);
408 switch (service)
410 case 0x0000: /* get version */
411 TRACE("returning version\n");
412 SET_AX( context, 0x0000 );
413 SET_DX( context, VXD_WinVersion() );
414 RESET_CFLAG(context);
415 break;
417 case 0x0001: /* load device */
418 FIXME("load device %04x:%04x (%s)\n",
419 context->SegDs, DX_reg(context),
420 debugstr_a(MapSL(MAKESEGPTR(context->SegDs, DX_reg(context)))));
421 SET_AX( context, 0x0000 );
422 context->SegEs = 0x0000;
423 SET_DI( context, 0x0000 );
424 RESET_CFLAG(context);
425 break;
427 case 0x0002: /* unload device */
428 FIXME("unload device (%08x)\n", context->Ebx);
429 SET_AX( context, 0x0000 );
430 RESET_CFLAG(context);
431 break;
433 default:
434 VXD_BARF( context, "VXDLDR" );
435 SET_AX( context, 0x000B ); /* invalid function number */
436 SET_CFLAG(context);
437 break;
441 /***********************************************************************
442 * __wine_vxd_shell (WPROCS.423)
444 void WINAPI __wine_vxd_shell( CONTEXT *context )
446 unsigned service = DX_reg(context);
448 TRACE("[%04x] Shell\n", (UINT16)service);
450 switch (service) /* Ralf Brown says EDX, but I use DX instead */
452 case 0x0000:
453 TRACE("returning version\n");
454 SET_AX( context, VXD_WinVersion() );
455 context->Ebx = 1; /* system VM Handle */
456 break;
458 case 0x0001:
459 case 0x0002:
460 case 0x0003:
461 /* SHELL_SYSMODAL_Message
462 ebx virtual machine handle
463 eax message box flags
464 ecx address of message
465 edi address of caption
466 return response in eax
468 case 0x0004:
469 /* SHELL_Message
470 ebx virtual machine handle
471 eax message box flags
472 ecx address of message
473 edi address of caption
474 esi address callback
475 edx reference data for callback
476 return response in eax
478 case 0x0005:
479 VXD_BARF( context, "shell" );
480 break;
482 case 0x0006: /* SHELL_Get_VM_State */
483 TRACE("VxD Shell: returning VM state\n");
484 /* Actually we don't, not yet. We have to return a structure
485 * and I am not to sure how to set it up and return it yet,
486 * so for now let's do nothing. I can (hopefully) get this
487 * by the next release
489 /* RESET_CFLAG(context); */
490 break;
492 case 0x0007:
493 case 0x0008:
494 case 0x0009:
495 case 0x000A:
496 case 0x000B:
497 case 0x000C:
498 case 0x000D:
499 case 0x000E:
500 case 0x000F:
501 case 0x0010:
502 case 0x0011:
503 case 0x0012:
504 case 0x0013:
505 case 0x0014:
506 case 0x0015:
507 case 0x0016:
508 VXD_BARF( context, "SHELL" );
509 break;
511 /* the new Win95 shell API */
512 case 0x0100: /* get version */
513 SET_AX( context, VXD_WinVersion() );
514 break;
516 case 0x0104: /* retrieve Hook_Properties list */
517 case 0x0105: /* call Hook_Properties callbacks */
518 VXD_BARF( context, "SHELL" );
519 break;
521 case 0x0106: /* install timeout callback */
522 TRACE("VxD Shell: ignoring shell callback (%d sec.)\n", context->Ebx);
523 SET_CFLAG(context);
524 break;
526 case 0x0107: /* get version of any VxD */
527 default:
528 VXD_BARF( context, "SHELL" );
529 break;
534 /***********************************************************************
535 * __wine_vxd_comm (WPROCS.414)
537 void WINAPI __wine_vxd_comm( CONTEXT *context )
539 unsigned service = AX_reg(context);
541 TRACE("[%04x] Comm\n", (UINT16)service);
543 switch (service)
545 case 0x0000: /* get version */
546 TRACE("returning version\n");
547 SET_AX( context, VXD_WinVersion() );
548 RESET_CFLAG(context);
549 break;
551 case 0x0001: /* set port global */
552 case 0x0002: /* get focus */
553 case 0x0003: /* virtualise port */
554 default:
555 VXD_BARF( context, "comm" );
559 /***********************************************************************
560 * __wine_vxd_timer (WPROCS.405)
562 void WINAPI __wine_vxd_timer( CONTEXT *context )
564 unsigned service = AX_reg(context);
566 TRACE("[%04x] Virtual Timer\n", (UINT16)service);
568 switch(service)
570 case 0x0000: /* version */
571 SET_AX( context, VXD_WinVersion() );
572 RESET_CFLAG(context);
573 break;
575 case 0x0100: /* clock tick time, in 840nsecs */
576 context->Eax = GetTickCount();
578 context->Edx = context->Eax >> 22;
579 context->Eax <<= 10; /* not very precise */
580 break;
582 case 0x0101: /* current Windows time, msecs */
583 case 0x0102: /* current VM time, msecs */
584 context->Eax = GetTickCount();
585 break;
587 default:
588 VXD_BARF( context, "VTD" );
593 /***********************************************************************
594 * timer_thread
596 static DWORD CALLBACK timer_thread( void *arg )
598 DWORD *system_time = arg;
600 for (;;)
602 *system_time = GetTickCount();
603 Sleep( 55 );
606 return 0;
610 /***********************************************************************
611 * __wine_vxd_timerapi (WPROCS.1490)
613 void WINAPI __wine_vxd_timerapi( CONTEXT *context )
615 static WORD System_Time_Selector;
617 unsigned service = AX_reg(context);
619 TRACE("[%04x] TimerAPI\n", (UINT16)service);
621 switch(service)
623 case 0x0000: /* version */
624 SET_AX( context, VXD_WinVersion() );
625 RESET_CFLAG(context);
626 break;
628 case 0x0009: /* get system time selector */
629 if ( !System_Time_Selector )
631 HANDLE16 handle = GlobalAlloc16( GMEM_FIXED, sizeof(DWORD) );
632 System_Time_Selector = handle | 7;
633 CloseHandle( CreateThread( NULL, 0, timer_thread, GlobalLock16(handle), 0, NULL ) );
635 SET_AX( context, System_Time_Selector );
636 RESET_CFLAG(context);
637 break;
639 default:
640 VXD_BARF( context, "VTDAPI" );
644 /***********************************************************************
645 * __wine_vxd_configmg (WPROCS.451)
647 void WINAPI __wine_vxd_configmg( CONTEXT *context )
649 unsigned service = AX_reg(context);
651 TRACE("[%04x] ConfigMG\n", (UINT16)service);
653 switch(service)
655 case 0x0000: /* version */
656 SET_AX( context, VXD_WinVersion() );
657 RESET_CFLAG(context);
658 break;
660 default:
661 VXD_BARF( context, "CONFIGMG" );
665 /***********************************************************************
666 * __wine_vxd_enable (WPROCS.455)
668 void WINAPI __wine_vxd_enable( CONTEXT *context )
670 unsigned service = AX_reg(context);
672 TRACE("[%04x] Enable\n", (UINT16)service);
674 switch(service)
676 case 0x0000: /* version */
677 SET_AX( context, VXD_WinVersion() );
678 RESET_CFLAG(context);
679 break;
681 default:
682 VXD_BARF( context, "ENABLE" );
686 /***********************************************************************
687 * __wine_vxd_apm (WPROCS.438)
689 void WINAPI __wine_vxd_apm( CONTEXT *context )
691 unsigned service = AX_reg(context);
693 TRACE("[%04x] APM\n", (UINT16)service);
695 switch(service)
697 case 0x0000: /* version */
698 SET_AX( context, VXD_WinVersion() );
699 RESET_CFLAG(context);
700 break;
702 default:
703 VXD_BARF( context, "APM" );
707 /***********************************************************************
708 * __wine_vxd_win32s (WPROCS.445)
710 * This is an implementation of the services of the Win32s VxD.
711 * Since official documentation of these does not seem to be available,
712 * certain arguments of some of the services remain unclear.
714 * FIXME: The following services are currently unimplemented:
715 * Exception handling (0x01, 0x1C)
716 * Debugger support (0x0C, 0x14, 0x17)
717 * Low-level memory access (0x02, 0x03, 0x0A, 0x0B)
718 * Memory Statistics (0x1B)
721 * We have a specific problem running Win32s on Linux (and probably also
722 * the other x86 unixes), since Win32s tries to allocate its main 'flat
723 * code/data segment' selectors with a base of 0xffff0000 (and limit 4GB).
724 * The rationale for this seems to be that they want one the one hand to
725 * be able to leave the Win 3.1 memory (starting with the main DOS memory)
726 * at linear address 0, but want at other hand to have offset 0 of the
727 * flat data/code segment point to an unmapped page (to catch NULL pointer
728 * accesses). Hence they allocate the flat segments with a base of 0xffff0000
729 * so that the Win 3.1 memory area at linear address zero shows up in the
730 * flat segments at offset 0x10000 (since linear addresses wrap around at
731 * 4GB). To compensate for that discrepancy between flat segment offsets
732 * and plain linear addresses, all flat pointers passed between the 32-bit
733 * and the 16-bit parts of Win32s are shifted by 0x10000 in the appropriate
734 * direction by the glue code (mainly) in W32SKRNL and WIN32S16.
736 * The problem for us is now that Linux does not allow a LDT selector with
737 * base 0xffff0000 to be created, since it would 'see' a part of the kernel
738 * address space. To address this problem we introduce *another* offset:
739 * We add 0x10000 to every linear address we get as an argument from Win32s.
740 * This means especially that the flat code/data selectors get actually
741 * allocated with base 0x0, so that flat offsets and (real) linear addresses
742 * do again agree! In fact, every call e.g. of a Win32s VxD service now
743 * has all pointer arguments (which are offsets in the flat data segment)
744 * first reduced by 0x10000 by the W32SKRNL glue code, and then again
745 * increased by 0x10000 by *our* code.
747 * Note that to keep everything consistent, this offset has to be applied by
748 * every Wine function that operates on 'linear addresses' passed to it by
749 * Win32s. Fortunately, since Win32s does not directly call any Wine 32-bit
750 * API routines, this affects only two locations: this VxD and the DPMI
751 * handler. (NOTE: Should any Win32s application pass a linear address to
752 * any routine apart from those, e.g. some other VxD handler, that code
753 * would have to take the offset into account as well!)
755 * The offset is set the first time any application calls the GetVersion()
756 * service of the Win32s VxD. (Note that the offset is never reset.)
759 void WINAPI __wine_vxd_win32s( CONTEXT *context )
761 switch (AX_reg(context))
763 case 0x0000: /* Get Version */
765 * Input: None
767 * Output: EAX: LoWord: Win32s Version (1.30)
768 * HiWord: VxD Version (200)
770 * EBX: Build (172)
772 * ECX: ??? (1)
774 * EDX: Debugging Flags
776 * EDI: Error Flag
777 * 0 if OK,
778 * 1 if VMCPD VxD not found
781 TRACE("GetVersion()\n");
783 context->Eax = VXD_WinVersion() | (200 << 16);
784 context->Ebx = 0;
785 context->Ecx = 0;
786 context->Edx = 0;
787 context->Edi = 0;
790 * If this is the first time we are called for this process,
791 * hack the memory image of WIN32S16 so that it doesn't try
792 * to access the GDT directly ...
794 * The first code segment of WIN32S16 (version 1.30) contains
795 * an unexported function somewhere between the exported functions
796 * SetFS and StackLinearToSegmented that tries to find a selector
797 * in the LDT that maps to the memory image of the LDT itself.
798 * If it succeeds, it stores this selector into a global variable
799 * which will be used to speed up execution by using this selector
800 * to modify the LDT directly instead of using the DPMI calls.
802 * To perform this search of the LDT, this function uses the
803 * sgdt and sldt instructions to find the linear address of
804 * the (GDT and then) LDT. While those instructions themselves
805 * execute without problem, the linear address that sgdt returns
806 * points (at least under Linux) to the kernel address space, so
807 * that any subsequent access leads to a segfault.
809 * Fortunately, WIN32S16 still contains as a fallback option the
810 * mechanism of using DPMI calls to modify LDT selectors instead
811 * of direct writes to the LDT. Thus we can circumvent the problem
812 * by simply replacing the first byte of the offending function
813 * with an 'retf' instruction. This means that the global variable
814 * supposed to contain the LDT alias selector will remain zero,
815 * and hence WIN32S16 will fall back to using DPMI calls.
817 * The heuristic we employ to _find_ that function is as follows:
818 * We search between the addresses of the exported symbols SetFS
819 * and StackLinearToSegmented for the byte sequence '0F 01 04'
820 * (this is the opcode of 'sgdt [si]'). We then search backwards
821 * from this address for the last occurrence of 'CB' (retf) that marks
822 * the end of the preceding function. The following byte (which
823 * should now be the first byte of the function we are looking for)
824 * will be replaced by 'CB' (retf).
826 * This heuristic works for the retail as well as the debug version
827 * of Win32s version 1.30. For versions earlier than that this
828 * hack should not be necessary at all, since the whole mechanism
829 * ('PERF130') was introduced only in 1.30 to improve the overall
830 * performance of Win32s.
833 if (!W32S_offset)
835 HMODULE16 hModule = GetModuleHandle16("win32s16");
836 SEGPTR func1 = (SEGPTR)GetProcAddress16(hModule, "SetFS");
837 SEGPTR func2 = (SEGPTR)GetProcAddress16(hModule, "StackLinearToSegmented");
839 if ( hModule && func1 && func2
840 && SELECTOROF(func1) == SELECTOROF(func2))
842 BYTE *start = MapSL(func1);
843 BYTE *end = MapSL(func2);
844 BYTE *p, *retv = NULL;
845 int found = 0;
847 for (p = start; p < end; p++)
848 if (*p == 0xCB) found = 0, retv = p;
849 else if (*p == 0x0F) found = 1;
850 else if (*p == 0x01 && found == 1) found = 2;
851 else if (*p == 0x04 && found == 2) { found = 3; break; }
852 else found = 0;
854 if (found == 3 && retv)
856 TRACE("PERF130 hack: "
857 "Replacing byte %02X at offset %04X:%04X\n",
858 *(retv+1), SELECTOROF(func1),
859 OFFSETOF(func1) + retv+1-start);
861 *(retv+1) = (BYTE)0xCB;
867 * Mark process as Win32s, so that subsequent DPMI calls
868 * will perform the W32S_APP2WINE/W32S_WINE2APP address shift.
870 W32S_offset = 0x10000;
871 break;
874 case 0x0001: /* Install Exception Handling */
876 * Input: EBX: Flat address of W32SKRNL Exception Data
878 * ECX: LoWord: Flat Code Selector
879 * HiWord: Flat Data Selector
881 * EDX: Flat address of W32SKRNL Exception Handler
882 * (this is equal to W32S_BackTo32 + 0x40)
884 * ESI: SEGPTR KERNEL.HASGPHANDLER
886 * EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10)
888 * Output: EAX: 0 if OK
891 TRACE("[0001] EBX=%x ECX=%x EDX=%x ESI=%x EDI=%x\n",
892 context->Ebx, context->Ecx, context->Edx,
893 context->Esi, context->Edi);
895 /* FIXME */
897 context->Eax = 0;
898 break;
901 case 0x0002: /* Set Page Access Flags */
903 * Input: EBX: New access flags
904 * Bit 2: User Page if set, Supervisor Page if clear
905 * Bit 1: Read-Write if set, Read-Only if clear
907 * ECX: Size of memory area to change
909 * EDX: Flat start address of memory area
911 * Output: EAX: Size of area changed
914 TRACE("[0002] EBX=%x ECX=%x EDX=%x\n",
915 context->Ebx, context->Ecx, context->Edx);
917 /* FIXME */
919 context->Eax = context->Ecx;
920 break;
923 case 0x0003: /* Get Page Access Flags */
925 * Input: EDX: Flat address of page to query
927 * Output: EAX: Page access flags
928 * Bit 2: User Page if set, Supervisor Page if clear
929 * Bit 1: Read-Write if set, Read-Only if clear
932 TRACE("[0003] EDX=%x\n", context->Edx);
934 /* FIXME */
936 context->Eax = 6;
937 break;
940 case 0x0004: /* Map Module */
942 * Input: ECX: IMTE (offset in Module Table) of new module
944 * EDX: Flat address of Win32s Module Table
946 * Output: EAX: 0 if OK
949 if (!context->Edx || CX_reg(context) == 0xFFFF)
951 TRACE("MapModule: Initialization call\n");
952 context->Eax = 0;
954 else
957 * Structure of a Win32s Module Table Entry:
959 struct Win32sModule
961 DWORD flags;
962 DWORD flatBaseAddr;
963 LPCSTR moduleName;
964 LPCSTR pathName;
965 LPCSTR unknown;
966 LPBYTE baseAddr;
967 DWORD hModule;
968 DWORD relocDelta;
972 * Note: This function should set up a demand-paged memory image
973 * of the given module. Since mmap does not allow file offsets
974 * not aligned at 1024 bytes, we simply load the image fully
975 * into memory.
978 struct Win32sModule *moduleTable =
979 (struct Win32sModule *)W32S_APP2WINE(context->Edx);
980 struct Win32sModule *module = moduleTable + context->Ecx;
982 IMAGE_NT_HEADERS *nt_header = RtlImageNtHeader( (HMODULE)module->baseAddr );
983 IMAGE_SECTION_HEADER *pe_seg = (IMAGE_SECTION_HEADER*)((char *)&nt_header->OptionalHeader +
984 nt_header->FileHeader.SizeOfOptionalHeader);
987 HFILE image = _lopen(module->pathName, OF_READ);
988 BOOL error = (image == HFILE_ERROR);
989 UINT i;
991 TRACE("MapModule: Loading %s\n", module->pathName);
993 for (i = 0;
994 !error && i < nt_header->FileHeader.NumberOfSections;
995 i++, pe_seg++)
996 if(!(pe_seg->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA))
998 DWORD off = pe_seg->PointerToRawData;
999 DWORD len = pe_seg->SizeOfRawData;
1000 LPBYTE addr = module->baseAddr + pe_seg->VirtualAddress;
1002 TRACE("MapModule: "
1003 "Section %d at %08x from %08x len %08x\n",
1004 i, (DWORD)addr, off, len);
1006 if ( _llseek(image, off, SEEK_SET) != off
1007 || _lread(image, addr, len) != len)
1008 error = TRUE;
1011 _lclose(image);
1013 if (error)
1014 ERR("MapModule: Unable to load %s\n", module->pathName);
1016 else if (module->relocDelta != 0)
1018 IMAGE_DATA_DIRECTORY *dir = nt_header->OptionalHeader.DataDirectory
1019 + IMAGE_DIRECTORY_ENTRY_BASERELOC;
1020 IMAGE_BASE_RELOCATION *r = (IMAGE_BASE_RELOCATION *)
1021 (dir->Size? module->baseAddr + dir->VirtualAddress : 0);
1023 TRACE("MapModule: Reloc delta %08x\n", module->relocDelta);
1025 while (r && r->VirtualAddress)
1027 LPBYTE page = module->baseAddr + r->VirtualAddress;
1028 WORD *TypeOffset = (WORD *)(r + 1);
1029 unsigned int count = (r->SizeOfBlock - sizeof(*r)) / sizeof(*TypeOffset);
1031 TRACE("MapModule: %d relocations for page %08x\n",
1032 count, (DWORD)page);
1034 for(i = 0; i < count; i++)
1036 int offset = TypeOffset[i] & 0xFFF;
1037 int type = TypeOffset[i] >> 12;
1038 switch(type)
1040 case IMAGE_REL_BASED_ABSOLUTE:
1041 break;
1042 case IMAGE_REL_BASED_HIGH:
1043 *(WORD *)(page+offset) += HIWORD(module->relocDelta);
1044 break;
1045 case IMAGE_REL_BASED_LOW:
1046 *(WORD *)(page+offset) += LOWORD(module->relocDelta);
1047 break;
1048 case IMAGE_REL_BASED_HIGHLOW:
1049 *(DWORD*)(page+offset) += module->relocDelta;
1050 break;
1051 default:
1052 WARN("MapModule: Unsupported fixup type\n");
1053 break;
1057 r = (IMAGE_BASE_RELOCATION *)((LPBYTE)r + r->SizeOfBlock);
1061 context->Eax = 0;
1062 RESET_CFLAG(context);
1064 break;
1067 case 0x0005: /* UnMap Module */
1069 * Input: EDX: Flat address of module image
1071 * Output: EAX: 1 if OK
1074 TRACE("UnMapModule: %x\n", W32S_APP2WINE(context->Edx));
1076 /* As we didn't map anything, there's nothing to unmap ... */
1078 context->Eax = 1;
1079 break;
1082 case 0x0006: /* VirtualAlloc */
1084 * Input: ECX: Current Process
1086 * EDX: Flat address of arguments on stack
1088 * DWORD *retv [out] Flat base address of allocated region
1089 * LPVOID base [in] Flat address of region to reserve/commit
1090 * DWORD size [in] Size of region
1091 * DWORD type [in] Type of allocation
1092 * DWORD prot [in] Type of access protection
1094 * Output: EAX: NtStatus
1097 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1098 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1099 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1100 DWORD size = stack[2];
1101 DWORD type = stack[3];
1102 DWORD prot = stack[4];
1103 DWORD result;
1105 TRACE("VirtualAlloc(%x, %x, %x, %x, %x)\n",
1106 (DWORD)retv, (DWORD)base, size, type, prot);
1108 if (type & 0x80000000)
1110 WARN("VirtualAlloc: strange type %x\n", type);
1111 type &= 0x7fffffff;
1114 if (!base && (type & MEM_COMMIT) && prot == PAGE_READONLY)
1116 WARN("VirtualAlloc: NLS hack, allowing write access!\n");
1117 prot = PAGE_READWRITE;
1120 result = (DWORD)VirtualAlloc(base, size, type, prot);
1122 if (W32S_WINE2APP(result))
1123 *retv = W32S_WINE2APP(result),
1124 context->Eax = STATUS_SUCCESS;
1125 else
1126 *retv = 0,
1127 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1129 break;
1132 case 0x0007: /* VirtualFree */
1134 * Input: ECX: Current Process
1136 * EDX: Flat address of arguments on stack
1138 * DWORD *retv [out] TRUE if success, FALSE if failure
1139 * LPVOID base [in] Flat address of region
1140 * DWORD size [in] Size of region
1141 * DWORD type [in] Type of operation
1143 * Output: EAX: NtStatus
1146 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1147 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1148 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1149 DWORD size = stack[2];
1150 DWORD type = stack[3];
1151 DWORD result;
1153 TRACE("VirtualFree(%x, %x, %x, %x)\n",
1154 (DWORD)retv, (DWORD)base, size, type);
1156 result = VirtualFree(base, size, type);
1158 if (result)
1159 *retv = TRUE,
1160 context->Eax = STATUS_SUCCESS;
1161 else
1162 *retv = FALSE,
1163 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1165 break;
1168 case 0x0008: /* VirtualProtect */
1170 * Input: ECX: Current Process
1172 * EDX: Flat address of arguments on stack
1174 * DWORD *retv [out] TRUE if success, FALSE if failure
1175 * LPVOID base [in] Flat address of region
1176 * DWORD size [in] Size of region
1177 * DWORD new_prot [in] Desired access protection
1178 * DWORD *old_prot [out] Previous access protection
1180 * Output: EAX: NtStatus
1183 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1184 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1185 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1186 DWORD size = stack[2];
1187 DWORD new_prot = stack[3];
1188 DWORD *old_prot = (DWORD *)W32S_APP2WINE(stack[4]);
1189 DWORD result;
1191 TRACE("VirtualProtect(%x, %x, %x, %x, %x)\n",
1192 (DWORD)retv, (DWORD)base, size, new_prot, (DWORD)old_prot);
1194 result = VirtualProtect(base, size, new_prot, old_prot);
1196 if (result)
1197 *retv = TRUE,
1198 context->Eax = STATUS_SUCCESS;
1199 else
1200 *retv = FALSE,
1201 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1203 break;
1206 case 0x0009: /* VirtualQuery */
1208 * Input: ECX: Current Process
1210 * EDX: Flat address of arguments on stack
1212 * DWORD *retv [out] Nr. bytes returned
1213 * LPVOID base [in] Flat address of region
1214 * LPMEMORY_BASIC_INFORMATION info [out] Info buffer
1215 * DWORD len [in] Size of buffer
1217 * Output: EAX: NtStatus
1220 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1221 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1222 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1223 PMEMORY_BASIC_INFORMATION info =
1224 (PMEMORY_BASIC_INFORMATION)W32S_APP2WINE(stack[2]);
1225 DWORD len = stack[3];
1226 DWORD result;
1228 TRACE("VirtualQuery(%x, %x, %x, %x)\n",
1229 (DWORD)retv, (DWORD)base, (DWORD)info, len);
1231 result = VirtualQuery(base, info, len);
1233 *retv = result;
1234 context->Eax = STATUS_SUCCESS;
1236 break;
1239 case 0x000A: /* SetVirtMemProcess */
1241 * Input: ECX: Process Handle
1243 * EDX: Flat address of region
1245 * Output: EAX: NtStatus
1248 TRACE("[000a] ECX=%x EDX=%x\n",
1249 context->Ecx, context->Edx);
1251 /* FIXME */
1253 context->Eax = STATUS_SUCCESS;
1254 break;
1257 case 0x000B: /* ??? some kind of cleanup */
1259 * Input: ECX: Process Handle
1261 * Output: EAX: NtStatus
1264 TRACE("[000b] ECX=%x\n", context->Ecx);
1266 /* FIXME */
1268 context->Eax = STATUS_SUCCESS;
1269 break;
1272 case 0x000C: /* Set Debug Flags */
1274 * Input: EDX: Debug Flags
1276 * Output: EDX: Previous Debug Flags
1279 FIXME("[000c] EDX=%x\n", context->Edx);
1281 /* FIXME */
1283 context->Edx = 0;
1284 break;
1287 case 0x000D: /* NtCreateSection */
1289 * Input: EDX: Flat address of arguments on stack
1291 * HANDLE32 *retv [out] Handle of Section created
1292 * DWORD flags1 [in] (?? unknown ??)
1293 * DWORD atom [in] Name of Section to create
1294 * LARGE_INTEGER *size [in] Size of Section
1295 * DWORD protect [in] Access protection
1296 * DWORD flags2 [in] (?? unknown ??)
1297 * HFILE32 hFile [in] Handle of file to map
1298 * DWORD psp [in] (Win32s: PSP that hFile belongs to)
1300 * Output: EAX: NtStatus
1303 DWORD *stack = (DWORD *) W32S_APP2WINE(context->Edx);
1304 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]);
1305 DWORD flags1 = stack[1];
1306 DWORD atom = stack[2];
1307 LARGE_INTEGER *size = (LARGE_INTEGER *)W32S_APP2WINE(stack[3]);
1308 DWORD protect = stack[4];
1309 DWORD flags2 = stack[5];
1310 HANDLE hFile = DosFileHandleToWin32Handle(stack[6]);
1311 DWORD psp = stack[7];
1313 HANDLE result = INVALID_HANDLE_VALUE;
1314 char name[128];
1316 TRACE("NtCreateSection(%x, %x, %x, %x, %x, %x, %x, %x)\n",
1317 (DWORD)retv, flags1, atom, (DWORD)size, protect, flags2,
1318 (DWORD)hFile, psp);
1320 if (!atom || GlobalGetAtomNameA(atom, name, sizeof(name)))
1322 TRACE("NtCreateSection: name=%s\n", atom? name : NULL);
1324 result = CreateFileMappingA(hFile, NULL, protect,
1325 size? size->u.HighPart : 0,
1326 size? size->u.LowPart : 0,
1327 atom? name : NULL);
1330 if (result == INVALID_HANDLE_VALUE)
1331 WARN("NtCreateSection: failed!\n");
1332 else
1333 TRACE("NtCreateSection: returned %x\n", (DWORD)result);
1335 if (result != INVALID_HANDLE_VALUE)
1336 *retv = result,
1337 context->Eax = STATUS_SUCCESS;
1338 else
1339 *retv = result,
1340 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1342 break;
1345 case 0x000E: /* NtOpenSection */
1347 * Input: EDX: Flat address of arguments on stack
1349 * HANDLE32 *retv [out] Handle of Section opened
1350 * DWORD protect [in] Access protection
1351 * DWORD atom [in] Name of Section to create
1353 * Output: EAX: NtStatus
1356 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1357 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]);
1358 DWORD protect = stack[1];
1359 DWORD atom = stack[2];
1361 HANDLE result = INVALID_HANDLE_VALUE;
1362 char name[128];
1364 TRACE("NtOpenSection(%x, %x, %x)\n",
1365 (DWORD)retv, protect, atom);
1367 if (atom && GlobalGetAtomNameA(atom, name, sizeof(name)))
1369 TRACE("NtOpenSection: name=%s\n", name);
1371 result = OpenFileMappingA(protect, FALSE, name);
1374 if (result == INVALID_HANDLE_VALUE)
1375 WARN("NtOpenSection: failed!\n");
1376 else
1377 TRACE("NtOpenSection: returned %x\n", (DWORD)result);
1379 if (result != INVALID_HANDLE_VALUE)
1380 *retv = result,
1381 context->Eax = STATUS_SUCCESS;
1382 else
1383 *retv = result,
1384 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1386 break;
1389 case 0x000F: /* NtCloseSection */
1391 * Input: EDX: Flat address of arguments on stack
1393 * HANDLE32 handle [in] Handle of Section to close
1394 * DWORD *id [out] Unique ID (?? unclear ??)
1396 * Output: EAX: NtStatus
1399 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1400 HANDLE handle = (HANDLE)stack[0];
1401 DWORD *id = (DWORD *)W32S_APP2WINE(stack[1]);
1403 TRACE("NtCloseSection(%x, %x)\n", (DWORD)handle, (DWORD)id);
1405 CloseHandle(handle);
1406 if (id) *id = 0; /* FIXME */
1408 context->Eax = STATUS_SUCCESS;
1410 break;
1413 case 0x0010: /* NtDupSection */
1415 * Input: EDX: Flat address of arguments on stack
1417 * HANDLE32 handle [in] Handle of Section to duplicate
1419 * Output: EAX: NtStatus
1422 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1423 HANDLE handle = (HANDLE)stack[0];
1424 HANDLE new_handle;
1426 TRACE("NtDupSection(%x)\n", (DWORD)handle);
1428 DuplicateHandle( GetCurrentProcess(), handle,
1429 GetCurrentProcess(), &new_handle,
1430 0, FALSE, DUPLICATE_SAME_ACCESS );
1431 context->Eax = STATUS_SUCCESS;
1433 break;
1436 case 0x0011: /* NtMapViewOfSection */
1438 * Input: EDX: Flat address of arguments on stack
1440 * HANDLE32 SectionHandle [in] Section to be mapped
1441 * DWORD ProcessHandle [in] Process to be mapped into
1442 * DWORD * BaseAddress [in/out] Address to be mapped at
1443 * DWORD ZeroBits [in] Upper address bits that should be null, starting from bit 31
1444 * DWORD CommitSize [in] (?? unclear ??)
1445 * LARGE_INTEGER *SectionOffset [in] Offset within section
1446 * DWORD * ViewSize [in] Size of view
1447 * DWORD InheritDisposition [in] (?? unclear ??)
1448 * DWORD AllocationType [in] (?? unclear ??)
1449 * DWORD Protect [in] Access protection
1451 * Output: EAX: NtStatus
1454 DWORD * stack = (DWORD *)W32S_APP2WINE(context->Edx);
1455 HANDLE SectionHandle = (HANDLE)stack[0];
1456 DWORD ProcessHandle = stack[1]; /* ignored */
1457 DWORD * BaseAddress = (DWORD *)W32S_APP2WINE(stack[2]);
1458 DWORD ZeroBits = stack[3];
1459 DWORD CommitSize = stack[4];
1460 LARGE_INTEGER *SectionOffset = (LARGE_INTEGER *)W32S_APP2WINE(stack[5]);
1461 DWORD * ViewSize = (DWORD *)W32S_APP2WINE(stack[6]);
1462 DWORD InheritDisposition = stack[7];
1463 DWORD AllocationType = stack[8];
1464 DWORD Protect = stack[9];
1466 LPBYTE address = (LPBYTE)(BaseAddress?
1467 W32S_APP2WINE(*BaseAddress) : 0);
1468 DWORD access = 0, result;
1470 switch (Protect & ~(PAGE_GUARD|PAGE_NOCACHE))
1472 case PAGE_READONLY: access = FILE_MAP_READ; break;
1473 case PAGE_READWRITE: access = FILE_MAP_WRITE; break;
1474 case PAGE_WRITECOPY: access = FILE_MAP_COPY; break;
1476 case PAGE_EXECUTE_READ: access = FILE_MAP_READ; break;
1477 case PAGE_EXECUTE_READWRITE: access = FILE_MAP_WRITE; break;
1478 case PAGE_EXECUTE_WRITECOPY: access = FILE_MAP_COPY; break;
1481 TRACE("NtMapViewOfSection"
1482 "(%x, %x, %x, %x, %x, %x, %x, %x, %x, %x)\n",
1483 (DWORD)SectionHandle, ProcessHandle, (DWORD)BaseAddress,
1484 ZeroBits, CommitSize, (DWORD)SectionOffset, (DWORD)ViewSize,
1485 InheritDisposition, AllocationType, Protect);
1486 TRACE("NtMapViewOfSection: "
1487 "base=%x, offset=%x, size=%x, access=%x\n",
1488 (DWORD)address, SectionOffset? SectionOffset->u.LowPart : 0,
1489 ViewSize? *ViewSize : 0, access);
1491 result = (DWORD)MapViewOfFileEx(SectionHandle, access,
1492 SectionOffset? SectionOffset->u.HighPart : 0,
1493 SectionOffset? SectionOffset->u.LowPart : 0,
1494 ViewSize? *ViewSize : 0, address);
1496 TRACE("NtMapViewOfSection: result=%x\n", result);
1498 if (W32S_WINE2APP(result))
1500 if (BaseAddress) *BaseAddress = W32S_WINE2APP(result);
1501 context->Eax = STATUS_SUCCESS;
1503 else
1504 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1506 break;
1509 case 0x0012: /* NtUnmapViewOfSection */
1511 * Input: EDX: Flat address of arguments on stack
1513 * DWORD ProcessHandle [in] Process (defining address space)
1514 * LPBYTE BaseAddress [in] Base address of view to be unmapped
1516 * Output: EAX: NtStatus
1519 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1520 DWORD ProcessHandle = stack[0]; /* ignored */
1521 LPBYTE BaseAddress = (LPBYTE)W32S_APP2WINE(stack[1]);
1523 TRACE("NtUnmapViewOfSection(%x, %x)\n",
1524 ProcessHandle, (DWORD)BaseAddress);
1526 UnmapViewOfFile(BaseAddress);
1528 context->Eax = STATUS_SUCCESS;
1530 break;
1533 case 0x0013: /* NtFlushVirtualMemory */
1535 * Input: EDX: Flat address of arguments on stack
1537 * DWORD ProcessHandle [in] Process (defining address space)
1538 * LPBYTE *BaseAddress [in?] Base address of range to be flushed
1539 * DWORD *ViewSize [in?] Number of bytes to be flushed
1540 * DWORD *unknown [???] (?? unknown ??)
1542 * Output: EAX: NtStatus
1545 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1546 DWORD ProcessHandle = stack[0]; /* ignored */
1547 DWORD *BaseAddress = (DWORD *)W32S_APP2WINE(stack[1]);
1548 DWORD *ViewSize = (DWORD *)W32S_APP2WINE(stack[2]);
1549 DWORD *unknown = (DWORD *)W32S_APP2WINE(stack[3]);
1551 LPBYTE address = (LPBYTE)(BaseAddress? W32S_APP2WINE(*BaseAddress) : 0);
1552 DWORD size = ViewSize? *ViewSize : 0;
1554 TRACE("NtFlushVirtualMemory(%x, %x, %x, %x)\n",
1555 ProcessHandle, (DWORD)BaseAddress, (DWORD)ViewSize,
1556 (DWORD)unknown);
1557 TRACE("NtFlushVirtualMemory: base=%x, size=%x\n",
1558 (DWORD)address, size);
1560 FlushViewOfFile(address, size);
1562 context->Eax = STATUS_SUCCESS;
1564 break;
1567 case 0x0014: /* Get/Set Debug Registers */
1569 * Input: ECX: 0 if Get, 1 if Set
1571 * EDX: Get: Flat address of buffer to receive values of
1572 * debug registers DR0 .. DR7
1573 * Set: Flat address of buffer containing values of
1574 * debug registers DR0 .. DR7 to be set
1575 * Output: None
1578 FIXME("[0014] ECX=%x EDX=%x\n",
1579 context->Ecx, context->Edx);
1581 /* FIXME */
1582 break;
1585 case 0x0015: /* Set Coprocessor Emulation Flag */
1587 * Input: EDX: 0 to deactivate, 1 to activate coprocessor emulation
1589 * Output: None
1592 TRACE("[0015] EDX=%x\n", context->Edx);
1594 /* We don't care, as we always have a coprocessor anyway */
1595 break;
1598 case 0x0016: /* Init Win32S VxD PSP */
1600 * If called to query required PSP size:
1602 * Input: EBX: 0
1603 * Output: EDX: Required size of Win32s VxD PSP
1605 * If called to initialize allocated PSP:
1607 * Input: EBX: LoWord: Selector of Win32s VxD PSP
1608 * HiWord: Paragraph of Win32s VxD PSP (DOSMEM)
1609 * Output: None
1612 if (context->Ebx == 0)
1613 context->Edx = 0x80;
1614 else
1616 PDB16 *psp = MapSL( MAKESEGPTR( BX_reg(context), 0 ));
1617 psp->nbFiles = 32;
1618 psp->fileHandlesPtr = MAKELONG(HIWORD(context->Ebx), 0x5c);
1619 memset((LPBYTE)psp + 0x5c, '\xFF', 32);
1621 break;
1624 case 0x0017: /* Set Break Point */
1626 * Input: EBX: Offset of Break Point
1627 * CX: Selector of Break Point
1629 * Output: None
1632 FIXME("[0017] EBX=%x CX=%x\n",
1633 context->Ebx, CX_reg(context));
1635 /* FIXME */
1636 break;
1639 case 0x0018: /* VirtualLock */
1641 * Input: ECX: Current Process
1643 * EDX: Flat address of arguments on stack
1645 * DWORD *retv [out] TRUE if success, FALSE if failure
1646 * LPVOID base [in] Flat address of range to lock
1647 * DWORD size [in] Size of range
1649 * Output: EAX: NtStatus
1652 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1653 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1654 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1655 DWORD size = stack[2];
1656 DWORD result;
1658 TRACE("VirtualLock(%x, %x, %x)\n",
1659 (DWORD)retv, (DWORD)base, size);
1661 result = VirtualLock(base, size);
1663 if (result)
1664 *retv = TRUE,
1665 context->Eax = STATUS_SUCCESS;
1666 else
1667 *retv = FALSE,
1668 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1670 break;
1673 case 0x0019: /* VirtualUnlock */
1675 * Input: ECX: Current Process
1677 * EDX: Flat address of arguments on stack
1679 * DWORD *retv [out] TRUE if success, FALSE if failure
1680 * LPVOID base [in] Flat address of range to unlock
1681 * DWORD size [in] Size of range
1683 * Output: EAX: NtStatus
1686 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1687 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1688 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1689 DWORD size = stack[2];
1690 DWORD result;
1692 TRACE("VirtualUnlock(%x, %x, %x)\n",
1693 (DWORD)retv, (DWORD)base, size);
1695 result = VirtualUnlock(base, size);
1697 if (result)
1698 *retv = TRUE,
1699 context->Eax = STATUS_SUCCESS;
1700 else
1701 *retv = FALSE,
1702 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1704 break;
1707 case 0x001A: /* KGetSystemInfo */
1709 * Input: None
1711 * Output: ECX: Start of sparse memory arena
1712 * EDX: End of sparse memory arena
1715 TRACE("KGetSystemInfo()\n");
1718 * Note: Win32s reserves 0GB - 2GB for Win 3.1 and uses 2GB - 4GB as
1719 * sparse memory arena. We do it the other way around, since
1720 * we have to reserve 3GB - 4GB for Linux, and thus use
1721 * 0GB - 3GB as sparse memory arena.
1723 * FIXME: What about other OSes ?
1726 context->Ecx = W32S_WINE2APP(0x00000000);
1727 context->Edx = W32S_WINE2APP(0xbfffffff);
1728 break;
1731 case 0x001B: /* KGlobalMemStat */
1733 * Input: ESI: Flat address of buffer to receive memory info
1735 * Output: None
1738 struct Win32sMemoryInfo
1740 DWORD DIPhys_Count; /* Total physical pages */
1741 DWORD DIFree_Count; /* Free physical pages */
1742 DWORD DILin_Total_Count; /* Total virtual pages (private arena) */
1743 DWORD DILin_Total_Free; /* Free virtual pages (private arena) */
1745 DWORD SparseTotal; /* Total size of sparse arena (bytes ?) */
1746 DWORD SparseFree; /* Free size of sparse arena (bytes ?) */
1749 struct Win32sMemoryInfo *info =
1750 (struct Win32sMemoryInfo *)W32S_APP2WINE(context->Esi);
1752 FIXME("KGlobalMemStat(%x)\n", (DWORD)info);
1754 /* FIXME */
1756 break;
1759 case 0x001C: /* Enable/Disable Exceptions */
1761 * Input: ECX: 0 to disable, 1 to enable exception handling
1763 * Output: None
1766 TRACE("[001c] ECX=%x\n", context->Ecx);
1768 /* FIXME */
1769 break;
1772 case 0x001D: /* VirtualAlloc called from 16-bit code */
1774 * Input: EDX: Segmented address of arguments on stack
1776 * LPVOID base [in] Flat address of region to reserve/commit
1777 * DWORD size [in] Size of region
1778 * DWORD type [in] Type of allocation
1779 * DWORD prot [in] Type of access protection
1781 * Output: EAX: NtStatus
1782 * EDX: Flat base address of allocated region
1785 DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) ));
1786 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]);
1787 DWORD size = stack[1];
1788 DWORD type = stack[2];
1789 DWORD prot = stack[3];
1790 DWORD result;
1792 TRACE("VirtualAlloc16(%x, %x, %x, %x)\n",
1793 (DWORD)base, size, type, prot);
1795 if (type & 0x80000000)
1797 WARN("VirtualAlloc16: strange type %x\n", type);
1798 type &= 0x7fffffff;
1801 result = (DWORD)VirtualAlloc(base, size, type, prot);
1803 if (W32S_WINE2APP(result))
1804 context->Edx = W32S_WINE2APP(result),
1805 context->Eax = STATUS_SUCCESS;
1806 else
1807 context->Edx = 0,
1808 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1809 TRACE("VirtualAlloc16: returning base %x\n", context->Edx);
1811 break;
1814 case 0x001E: /* VirtualFree called from 16-bit code */
1816 * Input: EDX: Segmented address of arguments on stack
1818 * LPVOID base [in] Flat address of region
1819 * DWORD size [in] Size of region
1820 * DWORD type [in] Type of operation
1822 * Output: EAX: NtStatus
1823 * EDX: TRUE if success, FALSE if failure
1826 DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) ));
1827 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]);
1828 DWORD size = stack[1];
1829 DWORD type = stack[2];
1830 DWORD result;
1832 TRACE("VirtualFree16(%x, %x, %x)\n",
1833 (DWORD)base, size, type);
1835 result = VirtualFree(base, size, type);
1837 if (result)
1838 context->Edx = TRUE,
1839 context->Eax = STATUS_SUCCESS;
1840 else
1841 context->Edx = FALSE,
1842 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1844 break;
1847 case 0x001F: /* FWorkingSetSize */
1849 * Input: EDX: 0 if Get, 1 if Set
1851 * ECX: Get: Buffer to receive Working Set Size
1852 * Set: Buffer containing Working Set Size
1854 * Output: NtStatus
1857 DWORD *ptr = (DWORD *)W32S_APP2WINE(context->Ecx);
1858 BOOL set = context->Edx;
1860 TRACE("FWorkingSetSize(%x, %x)\n", (DWORD)ptr, (DWORD)set);
1862 if (set)
1863 /* We do it differently ... */;
1864 else
1865 *ptr = 0x100;
1867 context->Eax = STATUS_SUCCESS;
1869 break;
1871 default:
1872 VXD_BARF( context, "W32S" );