kernel32: Update version to Win 10.
[wine.git] / dlls / krnl386.exe16 / vxd.c
blob5d280fb2fdad8702faf39f1a38eaa5dc2c620ae4
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/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(vxd);
42 typedef DWORD (WINAPI *VxDCallProc)(DWORD, CONTEXT *);
43 typedef BOOL (WINAPI *DeviceIoProc)(DWORD, LPVOID, DWORD, LPVOID, DWORD, LPDWORD, LPOVERLAPPED);
45 struct vxd_module
47 LARGE_INTEGER index;
48 HANDLE handle;
49 HMODULE module;
50 DeviceIoProc proc;
53 struct vxdcall_service
55 WCHAR name[12];
56 DWORD service;
57 HMODULE module;
58 VxDCallProc proc;
61 #define MAX_VXD_MODULES 32
63 static struct vxd_module vxd_modules[MAX_VXD_MODULES];
65 static struct vxdcall_service vxd_services[] =
67 { {'v','m','m','.','v','x','d',0}, 0x0001, NULL, NULL },
68 { {'v','w','i','n','3','2','.','v','x','d',0}, 0x002a, NULL, NULL }
71 #define W32S_APP2WINE(addr) ((addr)? (DWORD)(addr) + W32S_offset : 0)
72 #define W32S_WINE2APP(addr) ((addr)? (DWORD)(addr) - W32S_offset : 0)
74 #define VXD_BARF(context,name) \
75 TRACE( "vxd %s: unknown/not implemented parameters:\n" \
76 "vxd %s: AX %04x, BX %04x, CX %04x, DX %04x, " \
77 "SI %04x, DI %04x, DS %04x, ES %04x\n", \
78 (name), (name), AX_reg(context), BX_reg(context), \
79 CX_reg(context), DX_reg(context), SI_reg(context), \
80 DI_reg(context), (WORD)context->SegDs, (WORD)context->SegEs )
82 static CRITICAL_SECTION vxd_section;
83 static CRITICAL_SECTION_DEBUG critsect_debug =
85 0, 0, &vxd_section,
86 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
87 0, 0, { (DWORD_PTR)(__FILE__ ": vxd_section") }
89 static CRITICAL_SECTION vxd_section = { &critsect_debug, -1, 0, 0, 0, 0 };
91 static UINT W32S_offset;
93 static WORD VXD_WinVersion(void)
95 WORD version = LOWORD(GetVersion16());
96 return (version >> 8) | (version << 8);
99 /* retrieve the DeviceIoControl function for a Vxd given a file handle */
100 DeviceIoProc __wine_vxd_get_proc( HANDLE handle )
102 DeviceIoProc ret = NULL;
103 int status, i;
104 IO_STATUS_BLOCK io;
105 FILE_INTERNAL_INFORMATION info;
107 status = NtQueryInformationFile( handle, &io, &info, sizeof(info), FileInternalInformation );
108 if (status)
110 SetLastError( RtlNtStatusToDosError(status) );
111 return NULL;
114 RtlEnterCriticalSection( &vxd_section );
116 for (i = 0; i < MAX_VXD_MODULES; i++)
118 if (!vxd_modules[i].module) break;
119 if (vxd_modules[i].index.QuadPart == info.IndexNumber.QuadPart)
121 if (!(ret = vxd_modules[i].proc)) SetLastError( ERROR_INVALID_FUNCTION );
122 goto done;
125 /* FIXME: Here we could go through the directory to find the VxD name and load it. */
126 /* Let's wait to find out if there are actually apps out there that try to share */
127 /* VxD handles between processes, before we go to the trouble of implementing it. */
128 ERR( "handle %p not found in module list, inherited from another process?\n", handle );
130 done:
131 RtlLeaveCriticalSection( &vxd_section );
132 return ret;
136 /* load a VxD and return a file handle to it */
137 HANDLE __wine_vxd_open( LPCWSTR filenameW, DWORD access, SECURITY_ATTRIBUTES *sa )
139 static const WCHAR dotVxDW[] = {'.','v','x','d',0};
140 int i;
141 HANDLE handle;
142 HMODULE module;
143 WCHAR *p, name[16];
145 /* normalize the filename */
147 if (lstrlenW( filenameW ) >= ARRAY_SIZE(name) - 4 ||
148 wcschr( filenameW, '/' ) || wcschr( filenameW, '\\' ))
150 SetLastError( ERROR_FILE_NOT_FOUND );
151 return 0;
153 lstrcpyW( name, filenameW );
154 wcslwr( name );
155 p = wcschr( name, '.' );
156 if (!p) lstrcatW( name, dotVxDW );
157 else if (wcsicmp( p, dotVxDW )) /* existing extension has to be .vxd */
159 SetLastError( ERROR_FILE_NOT_FOUND );
160 return 0;
163 /* try to load the module first */
165 if (!(module = LoadLibraryW( name )))
167 FIXME( "Unknown/unsupported VxD %s. Try setting Windows version to 'nt40' or 'win31'.\n",
168 debugstr_w(name) );
169 SetLastError( ERROR_FILE_NOT_FOUND );
170 return 0;
173 /* register the module in the global list if necessary */
175 RtlEnterCriticalSection( &vxd_section );
177 for (i = 0; i < MAX_VXD_MODULES; i++)
179 if (vxd_modules[i].module == module)
181 handle = vxd_modules[i].handle;
182 goto done; /* already registered */
184 if (!vxd_modules[i].module) /* new one, register it */
186 WCHAR path[MAX_PATH];
187 IO_STATUS_BLOCK io;
188 FILE_INTERNAL_INFORMATION info;
190 GetModuleFileNameW( module, path, MAX_PATH );
191 handle = CreateFileW( path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 );
192 if (handle == INVALID_HANDLE_VALUE)
194 FreeLibrary( module );
195 goto done;
197 if (!NtQueryInformationFile( handle, &io, &info, sizeof(info), FileInternalInformation ))
198 vxd_modules[i].index = info.IndexNumber;
200 vxd_modules[i].module = module;
201 vxd_modules[i].handle = handle;
202 vxd_modules[i].proc = (DeviceIoProc)GetProcAddress( module, "DeviceIoControl" );
203 goto done;
207 ERR("too many open VxD modules, please report\n" );
208 FreeLibrary( module );
209 handle = 0;
211 done:
212 RtlLeaveCriticalSection( &vxd_section );
213 if (!DuplicateHandle( GetCurrentProcess(), handle, GetCurrentProcess(), &handle, 0,
214 (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle),
215 DUPLICATE_SAME_ACCESS ))
216 handle = 0;
217 return handle;
221 /***********************************************************************
222 * VxDCall0 (KERNEL32.1)
223 * VxDCall1 (KERNEL32.2)
224 * VxDCall2 (KERNEL32.3)
225 * VxDCall3 (KERNEL32.4)
226 * VxDCall4 (KERNEL32.5)
227 * VxDCall5 (KERNEL32.6)
228 * VxDCall6 (KERNEL32.7)
229 * VxDCall7 (KERNEL32.8)
230 * VxDCall8 (KERNEL32.9)
232 void WINAPI DECLSPEC_HIDDEN __regs_VxDCall( CONTEXT *context )
234 unsigned int i;
235 VxDCallProc proc = NULL;
236 DWORD service = stack32_pop( context );
238 RtlEnterCriticalSection( &vxd_section );
239 for (i = 0; i < ARRAY_SIZE(vxd_services); i++)
241 if (HIWORD(service) != vxd_services[i].service) continue;
242 if (!vxd_services[i].module) /* need to load it */
244 if ((vxd_services[i].module = LoadLibraryW( vxd_services[i].name )))
245 vxd_services[i].proc = (VxDCallProc)GetProcAddress( vxd_services[i].module, "VxDCall" );
247 proc = vxd_services[i].proc;
248 break;
250 RtlLeaveCriticalSection( &vxd_section );
252 if (proc) context->Eax = proc( service, context );
253 else
255 FIXME( "Unknown/unimplemented VxD (%08x)\n", service);
256 context->Eax = 0xffffffff; /* FIXME */
259 DEFINE_REGS_ENTRYPOINT( VxDCall )
262 /***********************************************************************
263 * __wine_vxd_vmm (WPROCS.401)
265 void WINAPI __wine_vxd_vmm ( CONTEXT *context )
267 unsigned service = AX_reg(context);
269 TRACE("[%04x] VMM\n", (UINT16)service);
271 switch(service)
273 case 0x0000: /* version */
274 SET_AX( context, VXD_WinVersion() );
275 RESET_CFLAG(context);
276 break;
278 case 0x026d: /* Get_Debug_Flag '/m' */
279 case 0x026e: /* Get_Debug_Flag '/n' */
280 SET_AL( context, 0 );
281 RESET_CFLAG(context);
282 break;
284 default:
285 VXD_BARF( context, "VMM" );
289 /***********************************************************************
290 * __wine_vxd_pagefile (WPROCS.433)
292 void WINAPI __wine_vxd_pagefile( CONTEXT *context )
294 unsigned service = AX_reg(context);
296 /* taken from Ralf Brown's Interrupt List */
298 TRACE("[%04x] PageFile\n", (UINT16)service );
300 switch(service)
302 case 0x00: /* get version, is this windows version? */
303 TRACE("returning version\n");
304 SET_AX( context, VXD_WinVersion() );
305 RESET_CFLAG(context);
306 break;
308 case 0x01: /* get swap file info */
309 TRACE("VxD PageFile: returning swap file info\n");
310 SET_AX( context, 0x00 ); /* paging disabled */
311 context->Ecx = 0; /* maximum size of paging file */
312 /* FIXME: do I touch DS:SI or DS:DI? */
313 RESET_CFLAG(context);
314 break;
316 case 0x02: /* delete permanent swap on exit */
317 TRACE("VxD PageFile: supposed to delete swap\n");
318 RESET_CFLAG(context);
319 break;
321 case 0x03: /* current temporary swap file size */
322 TRACE("VxD PageFile: what is current temp. swap size\n");
323 RESET_CFLAG(context);
324 break;
326 case 0x04: /* read or write?? INTERRUP.D */
327 case 0x05: /* cancel?? INTERRUP.D */
328 case 0x06: /* test I/O valid INTERRUP.D */
329 default:
330 VXD_BARF( context, "pagefile" );
331 break;
335 /***********************************************************************
336 * __wine_vxd_reboot (WPROCS.409)
338 void WINAPI __wine_vxd_reboot( CONTEXT *context )
340 unsigned service = AX_reg(context);
342 TRACE("[%04x] Reboot\n", (UINT16)service);
344 switch(service)
346 case 0x0000: /* version */
347 SET_AX( context, VXD_WinVersion() );
348 RESET_CFLAG(context);
349 break;
351 default:
352 VXD_BARF( context, "REBOOT" );
356 /***********************************************************************
357 * __wine_vxd_vdd (WPROCS.410)
359 void WINAPI __wine_vxd_vdd( CONTEXT *context )
361 unsigned service = AX_reg(context);
363 TRACE("[%04x] VDD\n", (UINT16)service);
365 switch(service)
367 case 0x0000: /* version */
368 SET_AX( context, VXD_WinVersion() );
369 RESET_CFLAG(context);
370 break;
372 default:
373 VXD_BARF( context, "VDD" );
377 /***********************************************************************
378 * __wine_vxd_vmd (WPROCS.412)
380 void WINAPI __wine_vxd_vmd( CONTEXT *context )
382 unsigned service = AX_reg(context);
384 TRACE("[%04x] VMD\n", (UINT16)service);
386 switch(service)
388 case 0x0000: /* version */
389 SET_AX( context, VXD_WinVersion() );
390 RESET_CFLAG(context);
391 break;
393 default:
394 VXD_BARF( context, "VMD" );
398 /***********************************************************************
399 * __wine_vxd_vxdloader (WPROCS.439)
401 void WINAPI __wine_vxd_vxdloader( CONTEXT *context )
403 unsigned service = AX_reg(context);
405 TRACE("[%04x] VXDLoader\n", (UINT16)service);
407 switch (service)
409 case 0x0000: /* get version */
410 TRACE("returning version\n");
411 SET_AX( context, 0x0000 );
412 SET_DX( context, VXD_WinVersion() );
413 RESET_CFLAG(context);
414 break;
416 case 0x0001: /* load device */
417 FIXME("load device %04x:%04x (%s)\n",
418 context->SegDs, DX_reg(context),
419 debugstr_a(MapSL(MAKESEGPTR(context->SegDs, DX_reg(context)))));
420 SET_AX( context, 0x0000 );
421 context->SegEs = 0x0000;
422 SET_DI( context, 0x0000 );
423 RESET_CFLAG(context);
424 break;
426 case 0x0002: /* unload device */
427 FIXME("unload device (%08x)\n", context->Ebx);
428 SET_AX( context, 0x0000 );
429 RESET_CFLAG(context);
430 break;
432 default:
433 VXD_BARF( context, "VXDLDR" );
434 SET_AX( context, 0x000B ); /* invalid function number */
435 SET_CFLAG(context);
436 break;
440 /***********************************************************************
441 * __wine_vxd_shell (WPROCS.423)
443 void WINAPI __wine_vxd_shell( CONTEXT *context )
445 unsigned service = DX_reg(context);
447 TRACE("[%04x] Shell\n", (UINT16)service);
449 switch (service) /* Ralf Brown says EDX, but I use DX instead */
451 case 0x0000:
452 TRACE("returning version\n");
453 SET_AX( context, VXD_WinVersion() );
454 context->Ebx = 1; /* system VM Handle */
455 break;
457 case 0x0001:
458 case 0x0002:
459 case 0x0003:
460 /* SHELL_SYSMODAL_Message
461 ebx virtual machine handle
462 eax message box flags
463 ecx address of message
464 edi address of caption
465 return response in eax
467 case 0x0004:
468 /* SHELL_Message
469 ebx virtual machine handle
470 eax message box flags
471 ecx address of message
472 edi address of caption
473 esi address callback
474 edx reference data for callback
475 return response in eax
477 case 0x0005:
478 VXD_BARF( context, "shell" );
479 break;
481 case 0x0006: /* SHELL_Get_VM_State */
482 TRACE("VxD Shell: returning VM state\n");
483 /* Actually we don't, not yet. We have to return a structure
484 * and I am not to sure how to set it up and return it yet,
485 * so for now let's do nothing. I can (hopefully) get this
486 * by the next release
488 /* RESET_CFLAG(context); */
489 break;
491 case 0x0007:
492 case 0x0008:
493 case 0x0009:
494 case 0x000A:
495 case 0x000B:
496 case 0x000C:
497 case 0x000D:
498 case 0x000E:
499 case 0x000F:
500 case 0x0010:
501 case 0x0011:
502 case 0x0012:
503 case 0x0013:
504 case 0x0014:
505 case 0x0015:
506 case 0x0016:
507 VXD_BARF( context, "SHELL" );
508 break;
510 /* the new Win95 shell API */
511 case 0x0100: /* get version */
512 SET_AX( context, VXD_WinVersion() );
513 break;
515 case 0x0104: /* retrieve Hook_Properties list */
516 case 0x0105: /* call Hook_Properties callbacks */
517 VXD_BARF( context, "SHELL" );
518 break;
520 case 0x0106: /* install timeout callback */
521 TRACE("VxD Shell: ignoring shell callback (%d sec.)\n", context->Ebx);
522 SET_CFLAG(context);
523 break;
525 case 0x0107: /* get version of any VxD */
526 default:
527 VXD_BARF( context, "SHELL" );
528 break;
533 /***********************************************************************
534 * __wine_vxd_comm (WPROCS.414)
536 void WINAPI __wine_vxd_comm( CONTEXT *context )
538 unsigned service = AX_reg(context);
540 TRACE("[%04x] Comm\n", (UINT16)service);
542 switch (service)
544 case 0x0000: /* get version */
545 TRACE("returning version\n");
546 SET_AX( context, VXD_WinVersion() );
547 RESET_CFLAG(context);
548 break;
550 case 0x0001: /* set port global */
551 case 0x0002: /* get focus */
552 case 0x0003: /* virtualise port */
553 default:
554 VXD_BARF( context, "comm" );
558 /***********************************************************************
559 * __wine_vxd_timer (WPROCS.405)
561 void WINAPI __wine_vxd_timer( CONTEXT *context )
563 unsigned service = AX_reg(context);
565 TRACE("[%04x] Virtual Timer\n", (UINT16)service);
567 switch(service)
569 case 0x0000: /* version */
570 SET_AX( context, VXD_WinVersion() );
571 RESET_CFLAG(context);
572 break;
574 case 0x0100: /* clock tick time, in 840nsecs */
575 context->Eax = GetTickCount();
577 context->Edx = context->Eax >> 22;
578 context->Eax <<= 10; /* not very precise */
579 break;
581 case 0x0101: /* current Windows time, msecs */
582 case 0x0102: /* current VM time, msecs */
583 context->Eax = GetTickCount();
584 break;
586 default:
587 VXD_BARF( context, "VTD" );
592 /***********************************************************************
593 * timer_thread
595 static DWORD CALLBACK timer_thread( void *arg )
597 DWORD *system_time = arg;
599 for (;;)
601 *system_time = GetTickCount();
602 Sleep( 55 );
605 return 0;
609 /***********************************************************************
610 * __wine_vxd_timerapi (WPROCS.1490)
612 void WINAPI __wine_vxd_timerapi( CONTEXT *context )
614 static WORD System_Time_Selector;
616 unsigned service = AX_reg(context);
618 TRACE("[%04x] TimerAPI\n", (UINT16)service);
620 switch(service)
622 case 0x0000: /* version */
623 SET_AX( context, VXD_WinVersion() );
624 RESET_CFLAG(context);
625 break;
627 case 0x0009: /* get system time selector */
628 if ( !System_Time_Selector )
630 HANDLE16 handle = GlobalAlloc16( GMEM_FIXED, sizeof(DWORD) );
631 System_Time_Selector = handle | 7;
632 CloseHandle( CreateThread( NULL, 0, timer_thread, GlobalLock16(handle), 0, NULL ) );
634 SET_AX( context, System_Time_Selector );
635 RESET_CFLAG(context);
636 break;
638 default:
639 VXD_BARF( context, "VTDAPI" );
643 /***********************************************************************
644 * __wine_vxd_configmg (WPROCS.451)
646 void WINAPI __wine_vxd_configmg( CONTEXT *context )
648 unsigned service = AX_reg(context);
650 TRACE("[%04x] ConfigMG\n", (UINT16)service);
652 switch(service)
654 case 0x0000: /* version */
655 SET_AX( context, VXD_WinVersion() );
656 RESET_CFLAG(context);
657 break;
659 default:
660 VXD_BARF( context, "CONFIGMG" );
664 /***********************************************************************
665 * __wine_vxd_enable (WPROCS.455)
667 void WINAPI __wine_vxd_enable( CONTEXT *context )
669 unsigned service = AX_reg(context);
671 TRACE("[%04x] Enable\n", (UINT16)service);
673 switch(service)
675 case 0x0000: /* version */
676 SET_AX( context, VXD_WinVersion() );
677 RESET_CFLAG(context);
678 break;
680 default:
681 VXD_BARF( context, "ENABLE" );
685 /***********************************************************************
686 * __wine_vxd_apm (WPROCS.438)
688 void WINAPI __wine_vxd_apm( CONTEXT *context )
690 unsigned service = AX_reg(context);
692 TRACE("[%04x] APM\n", (UINT16)service);
694 switch(service)
696 case 0x0000: /* version */
697 SET_AX( context, VXD_WinVersion() );
698 RESET_CFLAG(context);
699 break;
701 default:
702 VXD_BARF( context, "APM" );
706 /***********************************************************************
707 * __wine_vxd_win32s (WPROCS.445)
709 * This is an implementation of the services of the Win32s VxD.
710 * Since official documentation of these does not seem to be available,
711 * certain arguments of some of the services remain unclear.
713 * FIXME: The following services are currently unimplemented:
714 * Exception handling (0x01, 0x1C)
715 * Debugger support (0x0C, 0x14, 0x17)
716 * Low-level memory access (0x02, 0x03, 0x0A, 0x0B)
717 * Memory Statistics (0x1B)
720 * We have a specific problem running Win32s on Linux (and probably also
721 * the other x86 unixes), since Win32s tries to allocate its main 'flat
722 * code/data segment' selectors with a base of 0xffff0000 (and limit 4GB).
723 * The rationale for this seems to be that they want one the one hand to
724 * be able to leave the Win 3.1 memory (starting with the main DOS memory)
725 * at linear address 0, but want at other hand to have offset 0 of the
726 * flat data/code segment point to an unmapped page (to catch NULL pointer
727 * accesses). Hence they allocate the flat segments with a base of 0xffff0000
728 * so that the Win 3.1 memory area at linear address zero shows up in the
729 * flat segments at offset 0x10000 (since linear addresses wrap around at
730 * 4GB). To compensate for that discrepancy between flat segment offsets
731 * and plain linear addresses, all flat pointers passed between the 32-bit
732 * and the 16-bit parts of Win32s are shifted by 0x10000 in the appropriate
733 * direction by the glue code (mainly) in W32SKRNL and WIN32S16.
735 * The problem for us is now that Linux does not allow a LDT selector with
736 * base 0xffff0000 to be created, since it would 'see' a part of the kernel
737 * address space. To address this problem we introduce *another* offset:
738 * We add 0x10000 to every linear address we get as an argument from Win32s.
739 * This means especially that the flat code/data selectors get actually
740 * allocated with base 0x0, so that flat offsets and (real) linear addresses
741 * do again agree! In fact, every call e.g. of a Win32s VxD service now
742 * has all pointer arguments (which are offsets in the flat data segment)
743 * first reduced by 0x10000 by the W32SKRNL glue code, and then again
744 * increased by 0x10000 by *our* code.
746 * Note that to keep everything consistent, this offset has to be applied by
747 * every Wine function that operates on 'linear addresses' passed to it by
748 * Win32s. Fortunately, since Win32s does not directly call any Wine 32-bit
749 * API routines, this affects only two locations: this VxD and the DPMI
750 * handler. (NOTE: Should any Win32s application pass a linear address to
751 * any routine apart from those, e.g. some other VxD handler, that code
752 * would have to take the offset into account as well!)
754 * The offset is set the first time any application calls the GetVersion()
755 * service of the Win32s VxD. (Note that the offset is never reset.)
758 void WINAPI __wine_vxd_win32s( CONTEXT *context )
760 switch (AX_reg(context))
762 case 0x0000: /* Get Version */
764 * Input: None
766 * Output: EAX: LoWord: Win32s Version (1.30)
767 * HiWord: VxD Version (200)
769 * EBX: Build (172)
771 * ECX: ??? (1)
773 * EDX: Debugging Flags
775 * EDI: Error Flag
776 * 0 if OK,
777 * 1 if VMCPD VxD not found
780 TRACE("GetVersion()\n");
782 context->Eax = VXD_WinVersion() | (200 << 16);
783 context->Ebx = 0;
784 context->Ecx = 0;
785 context->Edx = 0;
786 context->Edi = 0;
789 * If this is the first time we are called for this process,
790 * hack the memory image of WIN32S16 so that it doesn't try
791 * to access the GDT directly ...
793 * The first code segment of WIN32S16 (version 1.30) contains
794 * an unexported function somewhere between the exported functions
795 * SetFS and StackLinearToSegmented that tries to find a selector
796 * in the LDT that maps to the memory image of the LDT itself.
797 * If it succeeds, it stores this selector into a global variable
798 * which will be used to speed up execution by using this selector
799 * to modify the LDT directly instead of using the DPMI calls.
801 * To perform this search of the LDT, this function uses the
802 * sgdt and sldt instructions to find the linear address of
803 * the (GDT and then) LDT. While those instructions themselves
804 * execute without problem, the linear address that sgdt returns
805 * points (at least under Linux) to the kernel address space, so
806 * that any subsequent access leads to a segfault.
808 * Fortunately, WIN32S16 still contains as a fallback option the
809 * mechanism of using DPMI calls to modify LDT selectors instead
810 * of direct writes to the LDT. Thus we can circumvent the problem
811 * by simply replacing the first byte of the offending function
812 * with an 'retf' instruction. This means that the global variable
813 * supposed to contain the LDT alias selector will remain zero,
814 * and hence WIN32S16 will fall back to using DPMI calls.
816 * The heuristic we employ to _find_ that function is as follows:
817 * We search between the addresses of the exported symbols SetFS
818 * and StackLinearToSegmented for the byte sequence '0F 01 04'
819 * (this is the opcode of 'sgdt [si]'). We then search backwards
820 * from this address for the last occurrence of 'CB' (retf) that marks
821 * the end of the preceding function. The following byte (which
822 * should now be the first byte of the function we are looking for)
823 * will be replaced by 'CB' (retf).
825 * This heuristic works for the retail as well as the debug version
826 * of Win32s version 1.30. For versions earlier than that this
827 * hack should not be necessary at all, since the whole mechanism
828 * ('PERF130') was introduced only in 1.30 to improve the overall
829 * performance of Win32s.
832 if (!W32S_offset)
834 HMODULE16 hModule = GetModuleHandle16("win32s16");
835 SEGPTR func1 = (SEGPTR)GetProcAddress16(hModule, "SetFS");
836 SEGPTR func2 = (SEGPTR)GetProcAddress16(hModule, "StackLinearToSegmented");
838 if ( hModule && func1 && func2
839 && SELECTOROF(func1) == SELECTOROF(func2))
841 BYTE *start = MapSL(func1);
842 BYTE *end = MapSL(func2);
843 BYTE *p, *retv = NULL;
844 int found = 0;
846 for (p = start; p < end; p++)
847 if (*p == 0xCB) found = 0, retv = p;
848 else if (*p == 0x0F) found = 1;
849 else if (*p == 0x01 && found == 1) found = 2;
850 else if (*p == 0x04 && found == 2) { found = 3; break; }
851 else found = 0;
853 if (found == 3 && retv)
855 TRACE("PERF130 hack: "
856 "Replacing byte %02X at offset %04X:%04X\n",
857 *(retv+1), SELECTOROF(func1),
858 OFFSETOF(func1) + retv+1-start);
860 *(retv+1) = (BYTE)0xCB;
866 * Mark process as Win32s, so that subsequent DPMI calls
867 * will perform the W32S_APP2WINE/W32S_WINE2APP address shift.
869 W32S_offset = 0x10000;
870 break;
873 case 0x0001: /* Install Exception Handling */
875 * Input: EBX: Flat address of W32SKRNL Exception Data
877 * ECX: LoWord: Flat Code Selector
878 * HiWord: Flat Data Selector
880 * EDX: Flat address of W32SKRNL Exception Handler
881 * (this is equal to W32S_BackTo32 + 0x40)
883 * ESI: SEGPTR KERNEL.HASGPHANDLER
885 * EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10)
887 * Output: EAX: 0 if OK
890 TRACE("[0001] EBX=%x ECX=%x EDX=%x ESI=%x EDI=%x\n",
891 context->Ebx, context->Ecx, context->Edx,
892 context->Esi, context->Edi);
894 /* FIXME */
896 context->Eax = 0;
897 break;
900 case 0x0002: /* Set Page Access Flags */
902 * Input: EBX: New access flags
903 * Bit 2: User Page if set, Supervisor Page if clear
904 * Bit 1: Read-Write if set, Read-Only if clear
906 * ECX: Size of memory area to change
908 * EDX: Flat start address of memory area
910 * Output: EAX: Size of area changed
913 TRACE("[0002] EBX=%x ECX=%x EDX=%x\n",
914 context->Ebx, context->Ecx, context->Edx);
916 /* FIXME */
918 context->Eax = context->Ecx;
919 break;
922 case 0x0003: /* Get Page Access Flags */
924 * Input: EDX: Flat address of page to query
926 * Output: EAX: Page access flags
927 * Bit 2: User Page if set, Supervisor Page if clear
928 * Bit 1: Read-Write if set, Read-Only if clear
931 TRACE("[0003] EDX=%x\n", context->Edx);
933 /* FIXME */
935 context->Eax = 6;
936 break;
939 case 0x0004: /* Map Module */
941 * Input: ECX: IMTE (offset in Module Table) of new module
943 * EDX: Flat address of Win32s Module Table
945 * Output: EAX: 0 if OK
948 if (!context->Edx || CX_reg(context) == 0xFFFF)
950 TRACE("MapModule: Initialization call\n");
951 context->Eax = 0;
953 else
956 * Structure of a Win32s Module Table Entry:
958 struct Win32sModule
960 DWORD flags;
961 DWORD flatBaseAddr;
962 LPCSTR moduleName;
963 LPCSTR pathName;
964 LPCSTR unknown;
965 LPBYTE baseAddr;
966 DWORD hModule;
967 DWORD relocDelta;
971 * Note: This function should set up a demand-paged memory image
972 * of the given module. Since mmap does not allow file offsets
973 * not aligned at 1024 bytes, we simply load the image fully
974 * into memory.
977 struct Win32sModule *moduleTable =
978 (struct Win32sModule *)W32S_APP2WINE(context->Edx);
979 struct Win32sModule *module = moduleTable + context->Ecx;
981 IMAGE_NT_HEADERS *nt_header = RtlImageNtHeader( (HMODULE)module->baseAddr );
982 IMAGE_SECTION_HEADER *pe_seg = (IMAGE_SECTION_HEADER*)((char *)&nt_header->OptionalHeader +
983 nt_header->FileHeader.SizeOfOptionalHeader);
986 HFILE image = _lopen(module->pathName, OF_READ);
987 BOOL error = (image == HFILE_ERROR);
988 UINT i;
990 TRACE("MapModule: Loading %s\n", module->pathName);
992 for (i = 0;
993 !error && i < nt_header->FileHeader.NumberOfSections;
994 i++, pe_seg++)
995 if(!(pe_seg->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA))
997 DWORD off = pe_seg->PointerToRawData;
998 DWORD len = pe_seg->SizeOfRawData;
999 LPBYTE addr = module->baseAddr + pe_seg->VirtualAddress;
1001 TRACE("MapModule: "
1002 "Section %d at %08x from %08x len %08x\n",
1003 i, (DWORD)addr, off, len);
1005 if ( _llseek(image, off, SEEK_SET) != off
1006 || _lread(image, addr, len) != len)
1007 error = TRUE;
1010 _lclose(image);
1012 if (error)
1013 ERR("MapModule: Unable to load %s\n", module->pathName);
1015 else if (module->relocDelta != 0)
1017 IMAGE_DATA_DIRECTORY *dir = nt_header->OptionalHeader.DataDirectory
1018 + IMAGE_DIRECTORY_ENTRY_BASERELOC;
1019 IMAGE_BASE_RELOCATION *r = (IMAGE_BASE_RELOCATION *)
1020 (dir->Size? module->baseAddr + dir->VirtualAddress : 0);
1022 TRACE("MapModule: Reloc delta %08x\n", module->relocDelta);
1024 while (r && r->VirtualAddress)
1026 LPBYTE page = module->baseAddr + r->VirtualAddress;
1027 WORD *TypeOffset = (WORD *)(r + 1);
1028 unsigned int count = (r->SizeOfBlock - sizeof(*r)) / sizeof(*TypeOffset);
1030 TRACE("MapModule: %d relocations for page %08x\n",
1031 count, (DWORD)page);
1033 for(i = 0; i < count; i++)
1035 int offset = TypeOffset[i] & 0xFFF;
1036 int type = TypeOffset[i] >> 12;
1037 switch(type)
1039 case IMAGE_REL_BASED_ABSOLUTE:
1040 break;
1041 case IMAGE_REL_BASED_HIGH:
1042 *(WORD *)(page+offset) += HIWORD(module->relocDelta);
1043 break;
1044 case IMAGE_REL_BASED_LOW:
1045 *(WORD *)(page+offset) += LOWORD(module->relocDelta);
1046 break;
1047 case IMAGE_REL_BASED_HIGHLOW:
1048 *(DWORD*)(page+offset) += module->relocDelta;
1049 break;
1050 default:
1051 WARN("MapModule: Unsupported fixup type\n");
1052 break;
1056 r = (IMAGE_BASE_RELOCATION *)((LPBYTE)r + r->SizeOfBlock);
1060 context->Eax = 0;
1061 RESET_CFLAG(context);
1063 break;
1066 case 0x0005: /* UnMap Module */
1068 * Input: EDX: Flat address of module image
1070 * Output: EAX: 1 if OK
1073 TRACE("UnMapModule: %x\n", W32S_APP2WINE(context->Edx));
1075 /* As we didn't map anything, there's nothing to unmap ... */
1077 context->Eax = 1;
1078 break;
1081 case 0x0006: /* VirtualAlloc */
1083 * Input: ECX: Current Process
1085 * EDX: Flat address of arguments on stack
1087 * DWORD *retv [out] Flat base address of allocated region
1088 * LPVOID base [in] Flat address of region to reserve/commit
1089 * DWORD size [in] Size of region
1090 * DWORD type [in] Type of allocation
1091 * DWORD prot [in] Type of access protection
1093 * Output: EAX: NtStatus
1096 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1097 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1098 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1099 DWORD size = stack[2];
1100 DWORD type = stack[3];
1101 DWORD prot = stack[4];
1102 DWORD result;
1104 TRACE("VirtualAlloc(%x, %x, %x, %x, %x)\n",
1105 (DWORD)retv, (DWORD)base, size, type, prot);
1107 if (type & 0x80000000)
1109 WARN("VirtualAlloc: strange type %x\n", type);
1110 type &= 0x7fffffff;
1113 if (!base && (type & MEM_COMMIT) && prot == PAGE_READONLY)
1115 WARN("VirtualAlloc: NLS hack, allowing write access!\n");
1116 prot = PAGE_READWRITE;
1119 result = (DWORD)VirtualAlloc(base, size, type, prot);
1121 if (W32S_WINE2APP(result))
1122 *retv = W32S_WINE2APP(result),
1123 context->Eax = STATUS_SUCCESS;
1124 else
1125 *retv = 0,
1126 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1128 break;
1131 case 0x0007: /* VirtualFree */
1133 * Input: ECX: Current Process
1135 * EDX: Flat address of arguments on stack
1137 * DWORD *retv [out] TRUE if success, FALSE if failure
1138 * LPVOID base [in] Flat address of region
1139 * DWORD size [in] Size of region
1140 * DWORD type [in] Type of operation
1142 * Output: EAX: NtStatus
1145 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1146 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1147 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1148 DWORD size = stack[2];
1149 DWORD type = stack[3];
1150 DWORD result;
1152 TRACE("VirtualFree(%x, %x, %x, %x)\n",
1153 (DWORD)retv, (DWORD)base, size, type);
1155 result = VirtualFree(base, size, type);
1157 if (result)
1158 *retv = TRUE,
1159 context->Eax = STATUS_SUCCESS;
1160 else
1161 *retv = FALSE,
1162 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1164 break;
1167 case 0x0008: /* VirtualProtect */
1169 * Input: ECX: Current Process
1171 * EDX: Flat address of arguments on stack
1173 * DWORD *retv [out] TRUE if success, FALSE if failure
1174 * LPVOID base [in] Flat address of region
1175 * DWORD size [in] Size of region
1176 * DWORD new_prot [in] Desired access protection
1177 * DWORD *old_prot [out] Previous access protection
1179 * Output: EAX: NtStatus
1182 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1183 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1184 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1185 DWORD size = stack[2];
1186 DWORD new_prot = stack[3];
1187 DWORD *old_prot = (DWORD *)W32S_APP2WINE(stack[4]);
1188 DWORD result;
1190 TRACE("VirtualProtect(%x, %x, %x, %x, %x)\n",
1191 (DWORD)retv, (DWORD)base, size, new_prot, (DWORD)old_prot);
1193 result = VirtualProtect(base, size, new_prot, old_prot);
1195 if (result)
1196 *retv = TRUE,
1197 context->Eax = STATUS_SUCCESS;
1198 else
1199 *retv = FALSE,
1200 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1202 break;
1205 case 0x0009: /* VirtualQuery */
1207 * Input: ECX: Current Process
1209 * EDX: Flat address of arguments on stack
1211 * DWORD *retv [out] Nr. bytes returned
1212 * LPVOID base [in] Flat address of region
1213 * LPMEMORY_BASIC_INFORMATION info [out] Info buffer
1214 * DWORD len [in] Size of buffer
1216 * Output: EAX: NtStatus
1219 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1220 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1221 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1222 PMEMORY_BASIC_INFORMATION info =
1223 (PMEMORY_BASIC_INFORMATION)W32S_APP2WINE(stack[2]);
1224 DWORD len = stack[3];
1225 DWORD result;
1227 TRACE("VirtualQuery(%x, %x, %x, %x)\n",
1228 (DWORD)retv, (DWORD)base, (DWORD)info, len);
1230 result = VirtualQuery(base, info, len);
1232 *retv = result;
1233 context->Eax = STATUS_SUCCESS;
1235 break;
1238 case 0x000A: /* SetVirtMemProcess */
1240 * Input: ECX: Process Handle
1242 * EDX: Flat address of region
1244 * Output: EAX: NtStatus
1247 TRACE("[000a] ECX=%x EDX=%x\n",
1248 context->Ecx, context->Edx);
1250 /* FIXME */
1252 context->Eax = STATUS_SUCCESS;
1253 break;
1256 case 0x000B: /* ??? some kind of cleanup */
1258 * Input: ECX: Process Handle
1260 * Output: EAX: NtStatus
1263 TRACE("[000b] ECX=%x\n", context->Ecx);
1265 /* FIXME */
1267 context->Eax = STATUS_SUCCESS;
1268 break;
1271 case 0x000C: /* Set Debug Flags */
1273 * Input: EDX: Debug Flags
1275 * Output: EDX: Previous Debug Flags
1278 FIXME("[000c] EDX=%x\n", context->Edx);
1280 /* FIXME */
1282 context->Edx = 0;
1283 break;
1286 case 0x000D: /* NtCreateSection */
1288 * Input: EDX: Flat address of arguments on stack
1290 * HANDLE32 *retv [out] Handle of Section created
1291 * DWORD flags1 [in] (?? unknown ??)
1292 * DWORD atom [in] Name of Section to create
1293 * LARGE_INTEGER *size [in] Size of Section
1294 * DWORD protect [in] Access protection
1295 * DWORD flags2 [in] (?? unknown ??)
1296 * HFILE32 hFile [in] Handle of file to map
1297 * DWORD psp [in] (Win32s: PSP that hFile belongs to)
1299 * Output: EAX: NtStatus
1302 DWORD *stack = (DWORD *) W32S_APP2WINE(context->Edx);
1303 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]);
1304 DWORD flags1 = stack[1];
1305 DWORD atom = stack[2];
1306 LARGE_INTEGER *size = (LARGE_INTEGER *)W32S_APP2WINE(stack[3]);
1307 DWORD protect = stack[4];
1308 DWORD flags2 = stack[5];
1309 HANDLE hFile = DosFileHandleToWin32Handle(stack[6]);
1310 DWORD psp = stack[7];
1312 HANDLE result = INVALID_HANDLE_VALUE;
1313 char name[128];
1315 TRACE("NtCreateSection(%x, %x, %x, %x, %x, %x, %x, %x)\n",
1316 (DWORD)retv, flags1, atom, (DWORD)size, protect, flags2,
1317 (DWORD)hFile, psp);
1319 if (!atom || GlobalGetAtomNameA(atom, name, sizeof(name)))
1321 TRACE("NtCreateSection: name=%s\n", atom? name : NULL);
1323 result = CreateFileMappingA(hFile, NULL, protect,
1324 size? size->u.HighPart : 0,
1325 size? size->u.LowPart : 0,
1326 atom? name : NULL);
1329 if (result == INVALID_HANDLE_VALUE)
1330 WARN("NtCreateSection: failed!\n");
1331 else
1332 TRACE("NtCreateSection: returned %x\n", (DWORD)result);
1334 if (result != INVALID_HANDLE_VALUE)
1335 *retv = result,
1336 context->Eax = STATUS_SUCCESS;
1337 else
1338 *retv = result,
1339 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1341 break;
1344 case 0x000E: /* NtOpenSection */
1346 * Input: EDX: Flat address of arguments on stack
1348 * HANDLE32 *retv [out] Handle of Section opened
1349 * DWORD protect [in] Access protection
1350 * DWORD atom [in] Name of Section to create
1352 * Output: EAX: NtStatus
1355 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1356 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]);
1357 DWORD protect = stack[1];
1358 DWORD atom = stack[2];
1360 HANDLE result = INVALID_HANDLE_VALUE;
1361 char name[128];
1363 TRACE("NtOpenSection(%x, %x, %x)\n",
1364 (DWORD)retv, protect, atom);
1366 if (atom && GlobalGetAtomNameA(atom, name, sizeof(name)))
1368 TRACE("NtOpenSection: name=%s\n", name);
1370 result = OpenFileMappingA(protect, FALSE, name);
1373 if (result == INVALID_HANDLE_VALUE)
1374 WARN("NtOpenSection: failed!\n");
1375 else
1376 TRACE("NtOpenSection: returned %x\n", (DWORD)result);
1378 if (result != INVALID_HANDLE_VALUE)
1379 *retv = result,
1380 context->Eax = STATUS_SUCCESS;
1381 else
1382 *retv = result,
1383 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1385 break;
1388 case 0x000F: /* NtCloseSection */
1390 * Input: EDX: Flat address of arguments on stack
1392 * HANDLE32 handle [in] Handle of Section to close
1393 * DWORD *id [out] Unique ID (?? unclear ??)
1395 * Output: EAX: NtStatus
1398 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1399 HANDLE handle = (HANDLE)stack[0];
1400 DWORD *id = (DWORD *)W32S_APP2WINE(stack[1]);
1402 TRACE("NtCloseSection(%x, %x)\n", (DWORD)handle, (DWORD)id);
1404 CloseHandle(handle);
1405 if (id) *id = 0; /* FIXME */
1407 context->Eax = STATUS_SUCCESS;
1409 break;
1412 case 0x0010: /* NtDupSection */
1414 * Input: EDX: Flat address of arguments on stack
1416 * HANDLE32 handle [in] Handle of Section to duplicate
1418 * Output: EAX: NtStatus
1421 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1422 HANDLE handle = (HANDLE)stack[0];
1423 HANDLE new_handle;
1425 TRACE("NtDupSection(%x)\n", (DWORD)handle);
1427 DuplicateHandle( GetCurrentProcess(), handle,
1428 GetCurrentProcess(), &new_handle,
1429 0, FALSE, DUPLICATE_SAME_ACCESS );
1430 context->Eax = STATUS_SUCCESS;
1432 break;
1435 case 0x0011: /* NtMapViewOfSection */
1437 * Input: EDX: Flat address of arguments on stack
1439 * HANDLE32 SectionHandle [in] Section to be mapped
1440 * DWORD ProcessHandle [in] Process to be mapped into
1441 * DWORD * BaseAddress [in/out] Address to be mapped at
1442 * DWORD ZeroBits [in] Upper address bits that should be null, starting from bit 31
1443 * DWORD CommitSize [in] (?? unclear ??)
1444 * LARGE_INTEGER *SectionOffset [in] Offset within section
1445 * DWORD * ViewSize [in] Size of view
1446 * DWORD InheritDisposition [in] (?? unclear ??)
1447 * DWORD AllocationType [in] (?? unclear ??)
1448 * DWORD Protect [in] Access protection
1450 * Output: EAX: NtStatus
1453 DWORD * stack = (DWORD *)W32S_APP2WINE(context->Edx);
1454 HANDLE SectionHandle = (HANDLE)stack[0];
1455 DWORD ProcessHandle = stack[1]; /* ignored */
1456 DWORD * BaseAddress = (DWORD *)W32S_APP2WINE(stack[2]);
1457 DWORD ZeroBits = stack[3];
1458 DWORD CommitSize = stack[4];
1459 LARGE_INTEGER *SectionOffset = (LARGE_INTEGER *)W32S_APP2WINE(stack[5]);
1460 DWORD * ViewSize = (DWORD *)W32S_APP2WINE(stack[6]);
1461 DWORD InheritDisposition = stack[7];
1462 DWORD AllocationType = stack[8];
1463 DWORD Protect = stack[9];
1465 LPBYTE address = (LPBYTE)(BaseAddress?
1466 W32S_APP2WINE(*BaseAddress) : 0);
1467 DWORD access = 0, result;
1469 switch (Protect & ~(PAGE_GUARD|PAGE_NOCACHE))
1471 case PAGE_READONLY: access = FILE_MAP_READ; break;
1472 case PAGE_READWRITE: access = FILE_MAP_WRITE; break;
1473 case PAGE_WRITECOPY: access = FILE_MAP_COPY; break;
1475 case PAGE_EXECUTE_READ: access = FILE_MAP_READ; break;
1476 case PAGE_EXECUTE_READWRITE: access = FILE_MAP_WRITE; break;
1477 case PAGE_EXECUTE_WRITECOPY: access = FILE_MAP_COPY; break;
1480 TRACE("NtMapViewOfSection"
1481 "(%x, %x, %x, %x, %x, %x, %x, %x, %x, %x)\n",
1482 (DWORD)SectionHandle, ProcessHandle, (DWORD)BaseAddress,
1483 ZeroBits, CommitSize, (DWORD)SectionOffset, (DWORD)ViewSize,
1484 InheritDisposition, AllocationType, Protect);
1485 TRACE("NtMapViewOfSection: "
1486 "base=%x, offset=%x, size=%x, access=%x\n",
1487 (DWORD)address, SectionOffset? SectionOffset->u.LowPart : 0,
1488 ViewSize? *ViewSize : 0, access);
1490 result = (DWORD)MapViewOfFileEx(SectionHandle, access,
1491 SectionOffset? SectionOffset->u.HighPart : 0,
1492 SectionOffset? SectionOffset->u.LowPart : 0,
1493 ViewSize? *ViewSize : 0, address);
1495 TRACE("NtMapViewOfSection: result=%x\n", result);
1497 if (W32S_WINE2APP(result))
1499 if (BaseAddress) *BaseAddress = W32S_WINE2APP(result);
1500 context->Eax = STATUS_SUCCESS;
1502 else
1503 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1505 break;
1508 case 0x0012: /* NtUnmapViewOfSection */
1510 * Input: EDX: Flat address of arguments on stack
1512 * DWORD ProcessHandle [in] Process (defining address space)
1513 * LPBYTE BaseAddress [in] Base address of view to be unmapped
1515 * Output: EAX: NtStatus
1518 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1519 DWORD ProcessHandle = stack[0]; /* ignored */
1520 LPBYTE BaseAddress = (LPBYTE)W32S_APP2WINE(stack[1]);
1522 TRACE("NtUnmapViewOfSection(%x, %x)\n",
1523 ProcessHandle, (DWORD)BaseAddress);
1525 UnmapViewOfFile(BaseAddress);
1527 context->Eax = STATUS_SUCCESS;
1529 break;
1532 case 0x0013: /* NtFlushVirtualMemory */
1534 * Input: EDX: Flat address of arguments on stack
1536 * DWORD ProcessHandle [in] Process (defining address space)
1537 * LPBYTE *BaseAddress [in?] Base address of range to be flushed
1538 * DWORD *ViewSize [in?] Number of bytes to be flushed
1539 * DWORD *unknown [???] (?? unknown ??)
1541 * Output: EAX: NtStatus
1544 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1545 DWORD ProcessHandle = stack[0]; /* ignored */
1546 DWORD *BaseAddress = (DWORD *)W32S_APP2WINE(stack[1]);
1547 DWORD *ViewSize = (DWORD *)W32S_APP2WINE(stack[2]);
1548 DWORD *unknown = (DWORD *)W32S_APP2WINE(stack[3]);
1550 LPBYTE address = (LPBYTE)(BaseAddress? W32S_APP2WINE(*BaseAddress) : 0);
1551 DWORD size = ViewSize? *ViewSize : 0;
1553 TRACE("NtFlushVirtualMemory(%x, %x, %x, %x)\n",
1554 ProcessHandle, (DWORD)BaseAddress, (DWORD)ViewSize,
1555 (DWORD)unknown);
1556 TRACE("NtFlushVirtualMemory: base=%x, size=%x\n",
1557 (DWORD)address, size);
1559 FlushViewOfFile(address, size);
1561 context->Eax = STATUS_SUCCESS;
1563 break;
1566 case 0x0014: /* Get/Set Debug Registers */
1568 * Input: ECX: 0 if Get, 1 if Set
1570 * EDX: Get: Flat address of buffer to receive values of
1571 * debug registers DR0 .. DR7
1572 * Set: Flat address of buffer containing values of
1573 * debug registers DR0 .. DR7 to be set
1574 * Output: None
1577 FIXME("[0014] ECX=%x EDX=%x\n",
1578 context->Ecx, context->Edx);
1580 /* FIXME */
1581 break;
1584 case 0x0015: /* Set Coprocessor Emulation Flag */
1586 * Input: EDX: 0 to deactivate, 1 to activate coprocessor emulation
1588 * Output: None
1591 TRACE("[0015] EDX=%x\n", context->Edx);
1593 /* We don't care, as we always have a coprocessor anyway */
1594 break;
1597 case 0x0016: /* Init Win32S VxD PSP */
1599 * If called to query required PSP size:
1601 * Input: EBX: 0
1602 * Output: EDX: Required size of Win32s VxD PSP
1604 * If called to initialize allocated PSP:
1606 * Input: EBX: LoWord: Selector of Win32s VxD PSP
1607 * HiWord: Paragraph of Win32s VxD PSP (DOSMEM)
1608 * Output: None
1611 if (context->Ebx == 0)
1612 context->Edx = 0x80;
1613 else
1615 PDB16 *psp = MapSL( MAKESEGPTR( BX_reg(context), 0 ));
1616 psp->nbFiles = 32;
1617 psp->fileHandlesPtr = MAKELONG(HIWORD(context->Ebx), 0x5c);
1618 memset((LPBYTE)psp + 0x5c, '\xFF', 32);
1620 break;
1623 case 0x0017: /* Set Break Point */
1625 * Input: EBX: Offset of Break Point
1626 * CX: Selector of Break Point
1628 * Output: None
1631 FIXME("[0017] EBX=%x CX=%x\n",
1632 context->Ebx, CX_reg(context));
1634 /* FIXME */
1635 break;
1638 case 0x0018: /* VirtualLock */
1640 * Input: ECX: Current Process
1642 * EDX: Flat address of arguments on stack
1644 * DWORD *retv [out] TRUE if success, FALSE if failure
1645 * LPVOID base [in] Flat address of range to lock
1646 * DWORD size [in] Size of range
1648 * Output: EAX: NtStatus
1651 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1652 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1653 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1654 DWORD size = stack[2];
1655 DWORD result;
1657 TRACE("VirtualLock(%x, %x, %x)\n",
1658 (DWORD)retv, (DWORD)base, size);
1660 result = VirtualLock(base, size);
1662 if (result)
1663 *retv = TRUE,
1664 context->Eax = STATUS_SUCCESS;
1665 else
1666 *retv = FALSE,
1667 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1669 break;
1672 case 0x0019: /* VirtualUnlock */
1674 * Input: ECX: Current Process
1676 * EDX: Flat address of arguments on stack
1678 * DWORD *retv [out] TRUE if success, FALSE if failure
1679 * LPVOID base [in] Flat address of range to unlock
1680 * DWORD size [in] Size of range
1682 * Output: EAX: NtStatus
1685 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1686 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1687 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1688 DWORD size = stack[2];
1689 DWORD result;
1691 TRACE("VirtualUnlock(%x, %x, %x)\n",
1692 (DWORD)retv, (DWORD)base, size);
1694 result = VirtualUnlock(base, size);
1696 if (result)
1697 *retv = TRUE,
1698 context->Eax = STATUS_SUCCESS;
1699 else
1700 *retv = FALSE,
1701 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1703 break;
1706 case 0x001A: /* KGetSystemInfo */
1708 * Input: None
1710 * Output: ECX: Start of sparse memory arena
1711 * EDX: End of sparse memory arena
1714 TRACE("KGetSystemInfo()\n");
1717 * Note: Win32s reserves 0GB - 2GB for Win 3.1 and uses 2GB - 4GB as
1718 * sparse memory arena. We do it the other way around, since
1719 * we have to reserve 3GB - 4GB for Linux, and thus use
1720 * 0GB - 3GB as sparse memory arena.
1722 * FIXME: What about other OSes ?
1725 context->Ecx = W32S_WINE2APP(0x00000000);
1726 context->Edx = W32S_WINE2APP(0xbfffffff);
1727 break;
1730 case 0x001B: /* KGlobalMemStat */
1732 * Input: ESI: Flat address of buffer to receive memory info
1734 * Output: None
1737 struct Win32sMemoryInfo
1739 DWORD DIPhys_Count; /* Total physical pages */
1740 DWORD DIFree_Count; /* Free physical pages */
1741 DWORD DILin_Total_Count; /* Total virtual pages (private arena) */
1742 DWORD DILin_Total_Free; /* Free virtual pages (private arena) */
1744 DWORD SparseTotal; /* Total size of sparse arena (bytes ?) */
1745 DWORD SparseFree; /* Free size of sparse arena (bytes ?) */
1748 struct Win32sMemoryInfo *info =
1749 (struct Win32sMemoryInfo *)W32S_APP2WINE(context->Esi);
1751 FIXME("KGlobalMemStat(%x)\n", (DWORD)info);
1753 /* FIXME */
1755 break;
1758 case 0x001C: /* Enable/Disable Exceptions */
1760 * Input: ECX: 0 to disable, 1 to enable exception handling
1762 * Output: None
1765 TRACE("[001c] ECX=%x\n", context->Ecx);
1767 /* FIXME */
1768 break;
1771 case 0x001D: /* VirtualAlloc called from 16-bit code */
1773 * Input: EDX: Segmented address of arguments on stack
1775 * LPVOID base [in] Flat address of region to reserve/commit
1776 * DWORD size [in] Size of region
1777 * DWORD type [in] Type of allocation
1778 * DWORD prot [in] Type of access protection
1780 * Output: EAX: NtStatus
1781 * EDX: Flat base address of allocated region
1784 DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) ));
1785 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]);
1786 DWORD size = stack[1];
1787 DWORD type = stack[2];
1788 DWORD prot = stack[3];
1789 DWORD result;
1791 TRACE("VirtualAlloc16(%x, %x, %x, %x)\n",
1792 (DWORD)base, size, type, prot);
1794 if (type & 0x80000000)
1796 WARN("VirtualAlloc16: strange type %x\n", type);
1797 type &= 0x7fffffff;
1800 result = (DWORD)VirtualAlloc(base, size, type, prot);
1802 if (W32S_WINE2APP(result))
1803 context->Edx = W32S_WINE2APP(result),
1804 context->Eax = STATUS_SUCCESS;
1805 else
1806 context->Edx = 0,
1807 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1808 TRACE("VirtualAlloc16: returning base %x\n", context->Edx);
1810 break;
1813 case 0x001E: /* VirtualFree called from 16-bit code */
1815 * Input: EDX: Segmented address of arguments on stack
1817 * LPVOID base [in] Flat address of region
1818 * DWORD size [in] Size of region
1819 * DWORD type [in] Type of operation
1821 * Output: EAX: NtStatus
1822 * EDX: TRUE if success, FALSE if failure
1825 DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) ));
1826 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]);
1827 DWORD size = stack[1];
1828 DWORD type = stack[2];
1829 DWORD result;
1831 TRACE("VirtualFree16(%x, %x, %x)\n",
1832 (DWORD)base, size, type);
1834 result = VirtualFree(base, size, type);
1836 if (result)
1837 context->Edx = TRUE,
1838 context->Eax = STATUS_SUCCESS;
1839 else
1840 context->Edx = FALSE,
1841 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1843 break;
1846 case 0x001F: /* FWorkingSetSize */
1848 * Input: EDX: 0 if Get, 1 if Set
1850 * ECX: Get: Buffer to receive Working Set Size
1851 * Set: Buffer containing Working Set Size
1853 * Output: NtStatus
1856 DWORD *ptr = (DWORD *)W32S_APP2WINE(context->Ecx);
1857 BOOL set = context->Edx;
1859 TRACE("FWorkingSetSize(%x, %x)\n", (DWORD)ptr, (DWORD)set);
1861 if (set)
1862 /* We do it differently ... */;
1863 else
1864 *ptr = 0x100;
1866 context->Eax = STATUS_SUCCESS;
1868 break;
1870 default:
1871 VXD_BARF( context, "W32S" );