msvcrt: Simplify platform checks for exception handling functions.
[wine.git] / dlls / krnl386.exe16 / vxd.c
blob966ac272303ad35708e57ba01ca7166c90f96cff
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 #include "windef.h"
31 #include "winbase.h"
32 #include "winerror.h"
33 #include "winternl.h"
34 #include "winioctl.h"
35 #include "kernel16_private.h"
36 #include "dosexe.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(vxd);
41 typedef DWORD (WINAPI *VxDCallProc)(DWORD, CONTEXT *);
42 typedef BOOL (WINAPI *DeviceIoProc)(DWORD, LPVOID, DWORD, LPVOID, DWORD, LPDWORD, LPOVERLAPPED);
44 struct vxd_module
46 LARGE_INTEGER index;
47 HANDLE handle;
48 HMODULE module;
49 DeviceIoProc proc;
52 struct vxdcall_service
54 WCHAR name[12];
55 DWORD service;
56 HMODULE module;
57 VxDCallProc proc;
60 #define MAX_VXD_MODULES 32
62 static struct vxd_module vxd_modules[MAX_VXD_MODULES];
64 static struct vxdcall_service vxd_services[] =
66 { {'v','m','m','.','v','x','d',0}, 0x0001, NULL, NULL },
67 { {'v','w','i','n','3','2','.','v','x','d',0}, 0x002a, NULL, NULL }
70 #define W32S_APP2WINE(addr) ((addr)? (DWORD)(addr) + W32S_offset : 0)
71 #define W32S_WINE2APP(addr) ((addr)? (DWORD)(addr) - W32S_offset : 0)
73 #define VXD_BARF(context,name) \
74 TRACE( "vxd %s: unknown/not implemented parameters:\n" \
75 "vxd %s: AX %04x, BX %04x, CX %04x, DX %04x, " \
76 "SI %04x, DI %04x, DS %04x, ES %04x\n", \
77 (name), (name), AX_reg(context), BX_reg(context), \
78 CX_reg(context), DX_reg(context), SI_reg(context), \
79 DI_reg(context), (WORD)context->SegDs, (WORD)context->SegEs )
81 static CRITICAL_SECTION vxd_section;
82 static CRITICAL_SECTION_DEBUG critsect_debug =
84 0, 0, &vxd_section,
85 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
86 0, 0, { (DWORD_PTR)(__FILE__ ": vxd_section") }
88 static CRITICAL_SECTION vxd_section = { &critsect_debug, -1, 0, 0, 0, 0 };
90 static UINT W32S_offset;
92 static WORD VXD_WinVersion(void)
94 WORD version = LOWORD(GetVersion16());
95 return (version >> 8) | (version << 8);
98 /* retrieve the DeviceIoControl function for a Vxd given a file handle */
99 DeviceIoProc __wine_vxd_get_proc( HANDLE handle )
101 DeviceIoProc ret = NULL;
102 int status, i;
103 IO_STATUS_BLOCK io;
104 FILE_INTERNAL_INFORMATION info;
106 status = NtQueryInformationFile( handle, &io, &info, sizeof(info), FileInternalInformation );
107 if (status)
109 SetLastError( RtlNtStatusToDosError(status) );
110 return NULL;
113 RtlEnterCriticalSection( &vxd_section );
115 for (i = 0; i < MAX_VXD_MODULES; i++)
117 if (!vxd_modules[i].module) break;
118 if (vxd_modules[i].index.QuadPart == info.IndexNumber.QuadPart)
120 if (!(ret = vxd_modules[i].proc)) SetLastError( ERROR_INVALID_FUNCTION );
121 goto done;
124 /* FIXME: Here we could go through the directory to find the VxD name and load it. */
125 /* Let's wait to find out if there are actually apps out there that try to share */
126 /* VxD handles between processes, before we go to the trouble of implementing it. */
127 ERR( "handle %p not found in module list, inherited from another process?\n", handle );
129 done:
130 RtlLeaveCriticalSection( &vxd_section );
131 return ret;
135 /* load a VxD and return a file handle to it */
136 HANDLE __wine_vxd_open( LPCWSTR filenameW, DWORD access, SECURITY_ATTRIBUTES *sa )
138 int i;
139 HANDLE handle;
140 HMODULE module;
141 WCHAR *p, name[13];
143 /* normalize the filename */
145 if (wcschr( filenameW, '/' ) || wcschr( filenameW, '\\' ))
147 SetLastError( ERROR_FILE_NOT_FOUND );
148 return 0;
150 p = wcschr( filenameW, '.' );
151 if (!p && lstrlenW( filenameW ) <= 8)
153 wcscpy( name, filenameW );
154 wcscat( name, L".vxd" );
156 else if (p && !wcsicmp( p, L".vxd" ) && lstrlenW( filenameW ) <= 12) /* existing extension has to be .vxd */
158 wcscpy( name, filenameW );
160 else
162 SetLastError( ERROR_FILE_NOT_FOUND );
163 return 0;
165 wcslwr( name );
167 /* try to load the module first */
169 if (!(module = LoadLibraryW( name )))
171 FIXME( "Unknown/unsupported VxD %s. Try setting Windows version to 'nt40' or 'win31'.\n",
172 debugstr_w(name) );
173 SetLastError( ERROR_FILE_NOT_FOUND );
174 return 0;
177 /* register the module in the global list if necessary */
179 RtlEnterCriticalSection( &vxd_section );
181 for (i = 0; i < MAX_VXD_MODULES; i++)
183 if (vxd_modules[i].module == module)
185 handle = vxd_modules[i].handle;
186 goto done; /* already registered */
188 if (!vxd_modules[i].module) /* new one, register it */
190 WCHAR path[MAX_PATH];
191 IO_STATUS_BLOCK io;
192 FILE_INTERNAL_INFORMATION info;
194 GetModuleFileNameW( module, path, MAX_PATH );
195 handle = CreateFileW( path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 );
196 if (handle == INVALID_HANDLE_VALUE)
198 FreeLibrary( module );
199 goto done;
201 if (!NtQueryInformationFile( handle, &io, &info, sizeof(info), FileInternalInformation ))
202 vxd_modules[i].index = info.IndexNumber;
204 vxd_modules[i].module = module;
205 vxd_modules[i].handle = handle;
206 vxd_modules[i].proc = (DeviceIoProc)GetProcAddress( module, "DeviceIoControl" );
207 goto done;
211 ERR("too many open VxD modules, please report\n" );
212 FreeLibrary( module );
213 handle = 0;
215 done:
216 RtlLeaveCriticalSection( &vxd_section );
217 if (!DuplicateHandle( GetCurrentProcess(), handle, GetCurrentProcess(), &handle, 0,
218 (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle),
219 DUPLICATE_SAME_ACCESS ))
220 handle = 0;
221 return handle;
225 /***********************************************************************
226 * VxDCall0 (KERNEL32.1)
227 * VxDCall1 (KERNEL32.2)
228 * VxDCall2 (KERNEL32.3)
229 * VxDCall3 (KERNEL32.4)
230 * VxDCall4 (KERNEL32.5)
231 * VxDCall5 (KERNEL32.6)
232 * VxDCall6 (KERNEL32.7)
233 * VxDCall7 (KERNEL32.8)
234 * VxDCall8 (KERNEL32.9)
236 void WINAPI __regs_VxDCall( CONTEXT *context )
238 unsigned int i;
239 VxDCallProc proc = NULL;
240 DWORD service = stack32_pop( context );
242 RtlEnterCriticalSection( &vxd_section );
243 for (i = 0; i < ARRAY_SIZE(vxd_services); i++)
245 if (HIWORD(service) != vxd_services[i].service) continue;
246 if (!vxd_services[i].module) /* need to load it */
248 if ((vxd_services[i].module = LoadLibraryW( vxd_services[i].name )))
249 vxd_services[i].proc = (VxDCallProc)GetProcAddress( vxd_services[i].module, "VxDCall" );
251 proc = vxd_services[i].proc;
252 break;
254 RtlLeaveCriticalSection( &vxd_section );
256 if (proc) context->Eax = proc( service, context );
257 else
259 FIXME( "Unknown/unimplemented VxD (%08lx)\n", service);
260 context->Eax = 0xffffffff; /* FIXME */
263 DEFINE_REGS_ENTRYPOINT( VxDCall )
266 /***********************************************************************
267 * __wine_vxd_vmm (WPROCS.401)
269 void WINAPI __wine_vxd_vmm ( CONTEXT *context )
271 unsigned service = AX_reg(context);
273 TRACE("[%04x] VMM\n", (UINT16)service);
275 switch(service)
277 case 0x0000: /* version */
278 SET_AX( context, VXD_WinVersion() );
279 RESET_CFLAG(context);
280 break;
282 case 0x026d: /* Get_Debug_Flag '/m' */
283 case 0x026e: /* Get_Debug_Flag '/n' */
284 SET_AL( context, 0 );
285 RESET_CFLAG(context);
286 break;
288 default:
289 VXD_BARF( context, "VMM" );
293 /***********************************************************************
294 * __wine_vxd_pagefile (WPROCS.433)
296 void WINAPI __wine_vxd_pagefile( CONTEXT *context )
298 unsigned service = AX_reg(context);
300 /* taken from Ralf Brown's Interrupt List */
302 TRACE("[%04x] PageFile\n", (UINT16)service );
304 switch(service)
306 case 0x00: /* get version, is this windows version? */
307 TRACE("returning version\n");
308 SET_AX( context, VXD_WinVersion() );
309 RESET_CFLAG(context);
310 break;
312 case 0x01: /* get swap file info */
313 TRACE("VxD PageFile: returning swap file info\n");
314 SET_AX( context, 0x00 ); /* paging disabled */
315 context->Ecx = 0; /* maximum size of paging file */
316 /* FIXME: do I touch DS:SI or DS:DI? */
317 RESET_CFLAG(context);
318 break;
320 case 0x02: /* delete permanent swap on exit */
321 TRACE("VxD PageFile: supposed to delete swap\n");
322 RESET_CFLAG(context);
323 break;
325 case 0x03: /* current temporary swap file size */
326 TRACE("VxD PageFile: what is current temp. swap size\n");
327 RESET_CFLAG(context);
328 break;
330 case 0x04: /* read or write?? INTERRUP.D */
331 case 0x05: /* cancel?? INTERRUP.D */
332 case 0x06: /* test I/O valid INTERRUP.D */
333 default:
334 VXD_BARF( context, "pagefile" );
335 break;
339 /***********************************************************************
340 * __wine_vxd_reboot (WPROCS.409)
342 void WINAPI __wine_vxd_reboot( CONTEXT *context )
344 unsigned service = AX_reg(context);
346 TRACE("[%04x] Reboot\n", (UINT16)service);
348 switch(service)
350 case 0x0000: /* version */
351 SET_AX( context, VXD_WinVersion() );
352 RESET_CFLAG(context);
353 break;
355 default:
356 VXD_BARF( context, "REBOOT" );
360 /***********************************************************************
361 * __wine_vxd_vdd (WPROCS.410)
363 void WINAPI __wine_vxd_vdd( CONTEXT *context )
365 unsigned service = AX_reg(context);
367 TRACE("[%04x] VDD\n", (UINT16)service);
369 switch(service)
371 case 0x0000: /* version */
372 SET_AX( context, VXD_WinVersion() );
373 RESET_CFLAG(context);
374 break;
376 default:
377 VXD_BARF( context, "VDD" );
381 /***********************************************************************
382 * __wine_vxd_vmd (WPROCS.412)
384 void WINAPI __wine_vxd_vmd( CONTEXT *context )
386 unsigned service = AX_reg(context);
388 TRACE("[%04x] VMD\n", (UINT16)service);
390 switch(service)
392 case 0x0000: /* version */
393 SET_AX( context, VXD_WinVersion() );
394 RESET_CFLAG(context);
395 break;
397 default:
398 VXD_BARF( context, "VMD" );
402 /***********************************************************************
403 * __wine_vxd_vxdloader (WPROCS.439)
405 void WINAPI __wine_vxd_vxdloader( CONTEXT *context )
407 unsigned service = AX_reg(context);
409 TRACE("[%04x] VXDLoader\n", (UINT16)service);
411 switch (service)
413 case 0x0000: /* get version */
414 TRACE("returning version\n");
415 SET_AX( context, 0x0000 );
416 SET_DX( context, VXD_WinVersion() );
417 RESET_CFLAG(context);
418 break;
420 case 0x0001: /* load device */
421 FIXME("load device %04lx:%04x (%s)\n",
422 context->SegDs, DX_reg(context),
423 debugstr_a(MapSL(MAKESEGPTR(context->SegDs, DX_reg(context)))));
424 SET_AX( context, 0x0000 );
425 context->SegEs = 0x0000;
426 SET_DI( context, 0x0000 );
427 RESET_CFLAG(context);
428 break;
430 case 0x0002: /* unload device */
431 FIXME("unload device (%08lx)\n", context->Ebx);
432 SET_AX( context, 0x0000 );
433 RESET_CFLAG(context);
434 break;
436 default:
437 VXD_BARF( context, "VXDLDR" );
438 SET_AX( context, 0x000B ); /* invalid function number */
439 SET_CFLAG(context);
440 break;
444 /***********************************************************************
445 * __wine_vxd_shell (WPROCS.423)
447 void WINAPI __wine_vxd_shell( CONTEXT *context )
449 unsigned service = DX_reg(context);
451 TRACE("[%04x] Shell\n", (UINT16)service);
453 switch (service) /* Ralf Brown says EDX, but I use DX instead */
455 case 0x0000:
456 TRACE("returning version\n");
457 SET_AX( context, VXD_WinVersion() );
458 context->Ebx = 1; /* system VM Handle */
459 break;
461 case 0x0001:
462 case 0x0002:
463 case 0x0003:
464 /* SHELL_SYSMODAL_Message
465 ebx virtual machine handle
466 eax message box flags
467 ecx address of message
468 edi address of caption
469 return response in eax
471 case 0x0004:
472 /* SHELL_Message
473 ebx virtual machine handle
474 eax message box flags
475 ecx address of message
476 edi address of caption
477 esi address callback
478 edx reference data for callback
479 return response in eax
481 case 0x0005:
482 VXD_BARF( context, "shell" );
483 break;
485 case 0x0006: /* SHELL_Get_VM_State */
486 TRACE("VxD Shell: returning VM state\n");
487 /* Actually we don't, not yet. We have to return a structure
488 * and I am not to sure how to set it up and return it yet,
489 * so for now let's do nothing. I can (hopefully) get this
490 * by the next release
492 /* RESET_CFLAG(context); */
493 break;
495 case 0x0007:
496 case 0x0008:
497 case 0x0009:
498 case 0x000A:
499 case 0x000B:
500 case 0x000C:
501 case 0x000D:
502 case 0x000E:
503 case 0x000F:
504 case 0x0010:
505 case 0x0011:
506 case 0x0012:
507 case 0x0013:
508 case 0x0014:
509 case 0x0015:
510 case 0x0016:
511 VXD_BARF( context, "SHELL" );
512 break;
514 /* the new Win95 shell API */
515 case 0x0100: /* get version */
516 SET_AX( context, VXD_WinVersion() );
517 break;
519 case 0x0104: /* retrieve Hook_Properties list */
520 case 0x0105: /* call Hook_Properties callbacks */
521 VXD_BARF( context, "SHELL" );
522 break;
524 case 0x0106: /* install timeout callback */
525 TRACE("VxD Shell: ignoring shell callback (%ld sec.)\n", context->Ebx);
526 SET_CFLAG(context);
527 break;
529 case 0x0107: /* get version of any VxD */
530 default:
531 VXD_BARF( context, "SHELL" );
532 break;
537 /***********************************************************************
538 * __wine_vxd_comm (WPROCS.414)
540 void WINAPI __wine_vxd_comm( CONTEXT *context )
542 unsigned service = AX_reg(context);
544 TRACE("[%04x] Comm\n", (UINT16)service);
546 switch (service)
548 case 0x0000: /* get version */
549 TRACE("returning version\n");
550 SET_AX( context, VXD_WinVersion() );
551 RESET_CFLAG(context);
552 break;
554 case 0x0001: /* set port global */
555 case 0x0002: /* get focus */
556 case 0x0003: /* virtualise port */
557 default:
558 VXD_BARF( context, "comm" );
562 /***********************************************************************
563 * __wine_vxd_timer (WPROCS.405)
565 void WINAPI __wine_vxd_timer( CONTEXT *context )
567 unsigned service = AX_reg(context);
569 TRACE("[%04x] Virtual Timer\n", (UINT16)service);
571 switch(service)
573 case 0x0000: /* version */
574 SET_AX( context, VXD_WinVersion() );
575 RESET_CFLAG(context);
576 break;
578 case 0x0100: /* clock tick time, in 840nsecs */
579 context->Eax = GetTickCount();
581 context->Edx = context->Eax >> 22;
582 context->Eax <<= 10; /* not very precise */
583 break;
585 case 0x0101: /* current Windows time, msecs */
586 case 0x0102: /* current VM time, msecs */
587 context->Eax = GetTickCount();
588 break;
590 default:
591 VXD_BARF( context, "VTD" );
596 /***********************************************************************
597 * timer_thread
599 static DWORD CALLBACK timer_thread( void *arg )
601 DWORD *system_time = arg;
603 for (;;)
605 *system_time = GetTickCount();
606 Sleep( 55 );
609 return 0;
613 /***********************************************************************
614 * __wine_vxd_timerapi (WPROCS.1490)
616 void WINAPI __wine_vxd_timerapi( CONTEXT *context )
618 static WORD System_Time_Selector;
620 unsigned service = AX_reg(context);
622 TRACE("[%04x] TimerAPI\n", (UINT16)service);
624 switch(service)
626 case 0x0000: /* version */
627 SET_AX( context, VXD_WinVersion() );
628 RESET_CFLAG(context);
629 break;
631 case 0x0009: /* get system time selector */
632 if ( !System_Time_Selector )
634 HANDLE16 handle = GlobalAlloc16( GMEM_FIXED, sizeof(DWORD) );
635 System_Time_Selector = handle | 7;
636 CloseHandle( CreateThread( NULL, 0, timer_thread, GlobalLock16(handle), 0, NULL ) );
638 SET_AX( context, System_Time_Selector );
639 RESET_CFLAG(context);
640 break;
642 default:
643 VXD_BARF( context, "VTDAPI" );
647 /***********************************************************************
648 * __wine_vxd_configmg (WPROCS.451)
650 void WINAPI __wine_vxd_configmg( CONTEXT *context )
652 unsigned service = AX_reg(context);
654 TRACE("[%04x] ConfigMG\n", (UINT16)service);
656 switch(service)
658 case 0x0000: /* version */
659 SET_AX( context, VXD_WinVersion() );
660 RESET_CFLAG(context);
661 break;
663 default:
664 VXD_BARF( context, "CONFIGMG" );
668 /***********************************************************************
669 * __wine_vxd_enable (WPROCS.455)
671 void WINAPI __wine_vxd_enable( CONTEXT *context )
673 unsigned service = AX_reg(context);
675 TRACE("[%04x] Enable\n", (UINT16)service);
677 switch(service)
679 case 0x0000: /* version */
680 SET_AX( context, VXD_WinVersion() );
681 RESET_CFLAG(context);
682 break;
684 default:
685 VXD_BARF( context, "ENABLE" );
689 /***********************************************************************
690 * __wine_vxd_apm (WPROCS.438)
692 void WINAPI __wine_vxd_apm( CONTEXT *context )
694 unsigned service = AX_reg(context);
696 TRACE("[%04x] APM\n", (UINT16)service);
698 switch(service)
700 case 0x0000: /* version */
701 SET_AX( context, VXD_WinVersion() );
702 RESET_CFLAG(context);
703 break;
705 default:
706 VXD_BARF( context, "APM" );
710 /***********************************************************************
711 * __wine_vxd_win32s (WPROCS.445)
713 * This is an implementation of the services of the Win32s VxD.
714 * Since official documentation of these does not seem to be available,
715 * certain arguments of some of the services remain unclear.
717 * FIXME: The following services are currently unimplemented:
718 * Exception handling (0x01, 0x1C)
719 * Debugger support (0x0C, 0x14, 0x17)
720 * Low-level memory access (0x02, 0x03, 0x0A, 0x0B)
721 * Memory Statistics (0x1B)
724 * We have a specific problem running Win32s on Linux (and probably also
725 * the other x86 unixes), since Win32s tries to allocate its main 'flat
726 * code/data segment' selectors with a base of 0xffff0000 (and limit 4GB).
727 * The rationale for this seems to be that they want one the one hand to
728 * be able to leave the Win 3.1 memory (starting with the main DOS memory)
729 * at linear address 0, but want at other hand to have offset 0 of the
730 * flat data/code segment point to an unmapped page (to catch NULL pointer
731 * accesses). Hence they allocate the flat segments with a base of 0xffff0000
732 * so that the Win 3.1 memory area at linear address zero shows up in the
733 * flat segments at offset 0x10000 (since linear addresses wrap around at
734 * 4GB). To compensate for that discrepancy between flat segment offsets
735 * and plain linear addresses, all flat pointers passed between the 32-bit
736 * and the 16-bit parts of Win32s are shifted by 0x10000 in the appropriate
737 * direction by the glue code (mainly) in W32SKRNL and WIN32S16.
739 * The problem for us is now that Linux does not allow a LDT selector with
740 * base 0xffff0000 to be created, since it would 'see' a part of the kernel
741 * address space. To address this problem we introduce *another* offset:
742 * We add 0x10000 to every linear address we get as an argument from Win32s.
743 * This means especially that the flat code/data selectors get actually
744 * allocated with base 0x0, so that flat offsets and (real) linear addresses
745 * do again agree! In fact, every call e.g. of a Win32s VxD service now
746 * has all pointer arguments (which are offsets in the flat data segment)
747 * first reduced by 0x10000 by the W32SKRNL glue code, and then again
748 * increased by 0x10000 by *our* code.
750 * Note that to keep everything consistent, this offset has to be applied by
751 * every Wine function that operates on 'linear addresses' passed to it by
752 * Win32s. Fortunately, since Win32s does not directly call any Wine 32-bit
753 * API routines, this affects only two locations: this VxD and the DPMI
754 * handler. (NOTE: Should any Win32s application pass a linear address to
755 * any routine apart from those, e.g. some other VxD handler, that code
756 * would have to take the offset into account as well!)
758 * The offset is set the first time any application calls the GetVersion()
759 * service of the Win32s VxD. (Note that the offset is never reset.)
762 void WINAPI __wine_vxd_win32s( CONTEXT *context )
764 switch (AX_reg(context))
766 case 0x0000: /* Get Version */
768 * Input: None
770 * Output: EAX: LoWord: Win32s Version (1.30)
771 * HiWord: VxD Version (200)
773 * EBX: Build (172)
775 * ECX: ??? (1)
777 * EDX: Debugging Flags
779 * EDI: Error Flag
780 * 0 if OK,
781 * 1 if VMCPD VxD not found
784 TRACE("GetVersion()\n");
786 context->Eax = VXD_WinVersion() | (200 << 16);
787 context->Ebx = 0;
788 context->Ecx = 0;
789 context->Edx = 0;
790 context->Edi = 0;
793 * If this is the first time we are called for this process,
794 * hack the memory image of WIN32S16 so that it doesn't try
795 * to access the GDT directly ...
797 * The first code segment of WIN32S16 (version 1.30) contains
798 * an unexported function somewhere between the exported functions
799 * SetFS and StackLinearToSegmented that tries to find a selector
800 * in the LDT that maps to the memory image of the LDT itself.
801 * If it succeeds, it stores this selector into a global variable
802 * which will be used to speed up execution by using this selector
803 * to modify the LDT directly instead of using the DPMI calls.
805 * To perform this search of the LDT, this function uses the
806 * sgdt and sldt instructions to find the linear address of
807 * the (GDT and then) LDT. While those instructions themselves
808 * execute without problem, the linear address that sgdt returns
809 * points (at least under Linux) to the kernel address space, so
810 * that any subsequent access leads to a segfault.
812 * Fortunately, WIN32S16 still contains as a fallback option the
813 * mechanism of using DPMI calls to modify LDT selectors instead
814 * of direct writes to the LDT. Thus we can circumvent the problem
815 * by simply replacing the first byte of the offending function
816 * with an 'retf' instruction. This means that the global variable
817 * supposed to contain the LDT alias selector will remain zero,
818 * and hence WIN32S16 will fall back to using DPMI calls.
820 * The heuristic we employ to _find_ that function is as follows:
821 * We search between the addresses of the exported symbols SetFS
822 * and StackLinearToSegmented for the byte sequence '0F 01 04'
823 * (this is the opcode of 'sgdt [si]'). We then search backwards
824 * from this address for the last occurrence of 'CB' (retf) that marks
825 * the end of the preceding function. The following byte (which
826 * should now be the first byte of the function we are looking for)
827 * will be replaced by 'CB' (retf).
829 * This heuristic works for the retail as well as the debug version
830 * of Win32s version 1.30. For versions earlier than that this
831 * hack should not be necessary at all, since the whole mechanism
832 * ('PERF130') was introduced only in 1.30 to improve the overall
833 * performance of Win32s.
836 if (!W32S_offset)
838 HMODULE16 hModule = GetModuleHandle16("win32s16");
839 SEGPTR func1 = (SEGPTR)GetProcAddress16(hModule, "SetFS");
840 SEGPTR func2 = (SEGPTR)GetProcAddress16(hModule, "StackLinearToSegmented");
842 if ( hModule && func1 && func2
843 && SELECTOROF(func1) == SELECTOROF(func2))
845 BYTE *start = MapSL(func1);
846 BYTE *end = MapSL(func2);
847 BYTE *p, *retv = NULL;
848 int found = 0;
850 for (p = start; p < end; p++)
851 if (*p == 0xCB) found = 0, retv = p;
852 else if (*p == 0x0F) found = 1;
853 else if (*p == 0x01 && found == 1) found = 2;
854 else if (*p == 0x04 && found == 2) { found = 3; break; }
855 else found = 0;
857 if (found == 3 && retv)
859 TRACE("PERF130 hack: "
860 "Replacing byte %02X at offset %04X:%04X\n",
861 *(retv+1), SELECTOROF(func1),
862 OFFSETOF(func1) + retv+1-start);
864 *(retv+1) = (BYTE)0xCB;
870 * Mark process as Win32s, so that subsequent DPMI calls
871 * will perform the W32S_APP2WINE/W32S_WINE2APP address shift.
873 W32S_offset = 0x10000;
874 break;
877 case 0x0001: /* Install Exception Handling */
879 * Input: EBX: Flat address of W32SKRNL Exception Data
881 * ECX: LoWord: Flat Code Selector
882 * HiWord: Flat Data Selector
884 * EDX: Flat address of W32SKRNL Exception Handler
885 * (this is equal to W32S_BackTo32 + 0x40)
887 * ESI: SEGPTR KERNEL.HASGPHANDLER
889 * EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10)
891 * Output: EAX: 0 if OK
894 TRACE("[0001] EBX=%lx ECX=%lx EDX=%lx ESI=%lx EDI=%lx\n",
895 context->Ebx, context->Ecx, context->Edx,
896 context->Esi, context->Edi);
898 /* FIXME */
900 context->Eax = 0;
901 break;
904 case 0x0002: /* Set Page Access Flags */
906 * Input: EBX: New access flags
907 * Bit 2: User Page if set, Supervisor Page if clear
908 * Bit 1: Read-Write if set, Read-Only if clear
910 * ECX: Size of memory area to change
912 * EDX: Flat start address of memory area
914 * Output: EAX: Size of area changed
917 TRACE("[0002] EBX=%lx ECX=%lx EDX=%lx\n",
918 context->Ebx, context->Ecx, context->Edx);
920 /* FIXME */
922 context->Eax = context->Ecx;
923 break;
926 case 0x0003: /* Get Page Access Flags */
928 * Input: EDX: Flat address of page to query
930 * Output: EAX: Page access flags
931 * Bit 2: User Page if set, Supervisor Page if clear
932 * Bit 1: Read-Write if set, Read-Only if clear
935 TRACE("[0003] EDX=%lx\n", context->Edx);
937 /* FIXME */
939 context->Eax = 6;
940 break;
943 case 0x0004: /* Map Module */
945 * Input: ECX: IMTE (offset in Module Table) of new module
947 * EDX: Flat address of Win32s Module Table
949 * Output: EAX: 0 if OK
952 if (!context->Edx || CX_reg(context) == 0xFFFF)
954 TRACE("MapModule: Initialization call\n");
955 context->Eax = 0;
957 else
960 * Structure of a Win32s Module Table Entry:
962 struct Win32sModule
964 DWORD flags;
965 DWORD flatBaseAddr;
966 LPCSTR moduleName;
967 LPCSTR pathName;
968 LPCSTR unknown;
969 LPBYTE baseAddr;
970 DWORD hModule;
971 DWORD relocDelta;
975 * Note: This function should set up a demand-paged memory image
976 * of the given module. Since mmap does not allow file offsets
977 * not aligned at 1024 bytes, we simply load the image fully
978 * into memory.
981 struct Win32sModule *moduleTable =
982 (struct Win32sModule *)W32S_APP2WINE(context->Edx);
983 struct Win32sModule *module = moduleTable + context->Ecx;
985 IMAGE_NT_HEADERS *nt_header = RtlImageNtHeader( (HMODULE)module->baseAddr );
986 IMAGE_SECTION_HEADER *pe_seg = IMAGE_FIRST_SECTION( nt_header );
987 HFILE image = _lopen(module->pathName, OF_READ);
988 BOOL error = (image == HFILE_ERROR);
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 %08lx from %08lx len %08lx\n",
1004 i, (DWORD)addr, off, len);
1006 if ( _llseek(image, off, SEEK_SET) != off
1007 || _lread(image, addr, len) != len)
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 %08lx\n", module->relocDelta);
1025 while (r && r->VirtualAddress)
1027 LPBYTE page = module->baseAddr + r->VirtualAddress;
1028 WORD *TypeOffset = (WORD *)(r + 1);
1029 unsigned int count = (r->SizeOfBlock - sizeof(*r)) / sizeof(*TypeOffset);
1031 TRACE("MapModule: %d relocations for page %08lx\n",
1032 count, (DWORD)page);
1034 for(i = 0; i < count; i++)
1036 int offset = TypeOffset[i] & 0xFFF;
1037 int type = TypeOffset[i] >> 12;
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: %lx\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(%lx, %lx, %lx, %lx, %lx)\n",
1106 (DWORD)retv, (DWORD)base, size, type, prot);
1108 if (type & 0x80000000)
1110 WARN("VirtualAlloc: strange type %lx\n", type);
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(%lx, %lx, %lx, %lx)\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(%lx, %lx, %lx, %lx, %lx)\n",
1192 (DWORD)retv, (DWORD)base, size, new_prot, (DWORD)old_prot);
1194 result = VirtualProtect(base, size, new_prot, old_prot);
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(%lx, %lx, %lx, %lx)\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=%lx EDX=%lx\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=%lx\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=%lx\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(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\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 : "");
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 %lx\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(%lx, %lx, %lx)\n",
1365 (DWORD)retv, protect, atom);
1367 if (atom && GlobalGetAtomNameA(atom, name, sizeof(name)))
1369 TRACE("NtOpenSection: name=%s\n", name);
1371 result = OpenFileMappingA(protect, FALSE, name);
1374 if (result == INVALID_HANDLE_VALUE)
1375 WARN("NtOpenSection: failed!\n");
1376 else
1377 TRACE("NtOpenSection: returned %lx\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(%lx, %lx)\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(%lx)\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 "(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1483 (DWORD)SectionHandle, ProcessHandle, (DWORD)BaseAddress,
1484 ZeroBits, CommitSize, (DWORD)SectionOffset, (DWORD)ViewSize,
1485 InheritDisposition, AllocationType, Protect);
1486 TRACE("NtMapViewOfSection: "
1487 "base=%lx, offset=%lx, size=%lx, access=%lx\n",
1488 (DWORD)address, SectionOffset? SectionOffset->u.LowPart : 0,
1489 ViewSize? *ViewSize : 0, access);
1491 result = (DWORD)MapViewOfFileEx(SectionHandle, access,
1492 SectionOffset? SectionOffset->u.HighPart : 0,
1493 SectionOffset? SectionOffset->u.LowPart : 0,
1494 ViewSize? *ViewSize : 0, address);
1496 TRACE("NtMapViewOfSection: result=%lx\n", result);
1498 if (W32S_WINE2APP(result))
1500 if (BaseAddress) *BaseAddress = W32S_WINE2APP(result);
1501 context->Eax = STATUS_SUCCESS;
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(%lx, %lx)\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(%lx, %lx, %lx, %lx)\n",
1555 ProcessHandle, (DWORD)BaseAddress, (DWORD)ViewSize,
1556 (DWORD)unknown);
1557 TRACE("NtFlushVirtualMemory: base=%lx, size=%lx\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=%lx EDX=%lx\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=%lx\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=%lx 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(%lx, %lx, %lx)\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(%lx, %lx, %lx)\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(%lx)\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=%lx\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(%lx, %lx, %lx, %lx)\n",
1793 (DWORD)base, size, type, prot);
1795 if (type & 0x80000000)
1797 WARN("VirtualAlloc16: strange type %lx\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 %lx\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(%lx, %lx, %lx)\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(%lx, %lx)\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" );