krnl386: Mark function that are only called from assembly as hidden.
[wine.git] / dlls / krnl386.exe16 / vxd.c
blob6cb7d70b7a42ab2ffa6f1646178f3abbd0f2286b
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 "config.h"
24 #include "wine/port.h"
26 #include <stdlib.h>
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30 #include <sys/types.h>
31 #ifdef HAVE_SYS_STAT_H
32 # include <sys/stat.h>
33 #endif
34 #include <string.h>
35 #include <stdarg.h>
37 #include "ntstatus.h"
38 #define WIN32_NO_STATUS
39 #define NONAMELESSUNION
40 #include "windef.h"
41 #include "winbase.h"
42 #include "winerror.h"
43 #include "winternl.h"
44 #include "winioctl.h"
45 #include "kernel16_private.h"
46 #include "dosexe.h"
47 #include "wine/library.h"
48 #include "wine/unicode.h"
49 #include "wine/server.h"
50 #include "wine/debug.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(vxd);
54 typedef DWORD (WINAPI *VxDCallProc)(DWORD, CONTEXT *);
55 typedef BOOL (WINAPI *DeviceIoProc)(DWORD, LPVOID, DWORD, LPVOID, DWORD, LPDWORD, LPOVERLAPPED);
57 struct vxd_module
59 LARGE_INTEGER index;
60 HANDLE handle;
61 HMODULE module;
62 DeviceIoProc proc;
65 struct vxdcall_service
67 WCHAR name[12];
68 DWORD service;
69 HMODULE module;
70 VxDCallProc proc;
73 #define MAX_VXD_MODULES 32
75 static struct vxd_module vxd_modules[MAX_VXD_MODULES];
77 static struct vxdcall_service vxd_services[] =
79 { {'v','m','m','.','v','x','d',0}, 0x0001, NULL, NULL },
80 { {'v','w','i','n','3','2','.','v','x','d',0}, 0x002a, NULL, NULL }
83 #define NB_VXD_SERVICES (sizeof(vxd_services)/sizeof(vxd_services[0]))
85 #define W32S_APP2WINE(addr) ((addr)? (DWORD)(addr) + W32S_offset : 0)
86 #define W32S_WINE2APP(addr) ((addr)? (DWORD)(addr) - W32S_offset : 0)
88 #define VXD_BARF(context,name) \
89 TRACE( "vxd %s: unknown/not implemented parameters:\n" \
90 "vxd %s: AX %04x, BX %04x, CX %04x, DX %04x, " \
91 "SI %04x, DI %04x, DS %04x, ES %04x\n", \
92 (name), (name), AX_reg(context), BX_reg(context), \
93 CX_reg(context), DX_reg(context), SI_reg(context), \
94 DI_reg(context), (WORD)context->SegDs, (WORD)context->SegEs )
96 static CRITICAL_SECTION vxd_section;
97 static CRITICAL_SECTION_DEBUG critsect_debug =
99 0, 0, &vxd_section,
100 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
101 0, 0, { (DWORD_PTR)(__FILE__ ": vxd_section") }
103 static CRITICAL_SECTION vxd_section = { &critsect_debug, -1, 0, 0, 0, 0 };
105 static UINT W32S_offset;
107 static WORD VXD_WinVersion(void)
109 WORD version = LOWORD(GetVersion16());
110 return (version >> 8) | (version << 8);
113 /* create a file handle to represent a VxD, by opening a dummy file in the wineserver directory */
114 static HANDLE open_vxd_handle( LPCWSTR name )
116 static const WCHAR prefixW[] = {'\\','?','?','\\','u','n','i','x'};
117 const char *dir = wine_get_server_dir();
118 int len;
119 HANDLE ret;
120 NTSTATUS status;
121 OBJECT_ATTRIBUTES attr;
122 UNICODE_STRING nameW;
123 IO_STATUS_BLOCK io;
125 len = MultiByteToWideChar( CP_UNIXCP, 0, dir, -1, NULL, 0 );
126 nameW.Length = sizeof(prefixW) + (len + strlenW( name )) * sizeof(WCHAR);
127 nameW.MaximumLength = nameW.Length + sizeof(WCHAR);
128 if (!(nameW.Buffer = HeapAlloc( GetProcessHeap(), 0, nameW.MaximumLength )))
130 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
131 return 0;
133 memcpy( nameW.Buffer, prefixW, sizeof(prefixW) );
134 MultiByteToWideChar( CP_UNIXCP, 0, dir, -1, nameW.Buffer + sizeof(prefixW)/sizeof(WCHAR), len );
135 len += sizeof(prefixW) / sizeof(WCHAR);
136 nameW.Buffer[len-1] = '/';
137 strcpyW( nameW.Buffer + len, name );
139 attr.Length = sizeof(attr);
140 attr.RootDirectory = 0;
141 attr.Attributes = 0;
142 attr.ObjectName = &nameW;
143 attr.SecurityDescriptor = NULL;
144 attr.SecurityQualityOfService = NULL;
146 status = NtCreateFile( &ret, SYNCHRONIZE, &attr, &io, NULL, 0,
147 FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN_IF,
148 FILE_SYNCHRONOUS_IO_ALERT, NULL, 0 );
149 if (status)
151 ret = 0;
152 SetLastError( RtlNtStatusToDosError(status) );
154 RtlFreeUnicodeString( &nameW );
155 return ret;
158 /* retrieve the DeviceIoControl function for a Vxd given a file handle */
159 DeviceIoProc __wine_vxd_get_proc( HANDLE handle )
161 DeviceIoProc ret = NULL;
162 int status, i;
163 IO_STATUS_BLOCK io;
164 FILE_INTERNAL_INFORMATION info;
166 status = NtQueryInformationFile( handle, &io, &info, sizeof(info), FileInternalInformation );
167 if (status)
169 SetLastError( RtlNtStatusToDosError(status) );
170 return NULL;
173 RtlEnterCriticalSection( &vxd_section );
175 for (i = 0; i < MAX_VXD_MODULES; i++)
177 if (!vxd_modules[i].module) break;
178 if (vxd_modules[i].index.QuadPart == info.IndexNumber.QuadPart)
180 if (!(ret = vxd_modules[i].proc)) SetLastError( ERROR_INVALID_FUNCTION );
181 goto done;
184 /* FIXME: Here we could go through the directory to find the VxD name and load it. */
185 /* Let's wait to find out if there are actually apps out there that try to share */
186 /* VxD handles between processes, before we go to the trouble of implementing it. */
187 ERR( "handle %p not found in module list, inherited from another process?\n", handle );
189 done:
190 RtlLeaveCriticalSection( &vxd_section );
191 return ret;
195 /* load a VxD and return a file handle to it */
196 HANDLE __wine_vxd_open( LPCWSTR filenameW, DWORD access, SECURITY_ATTRIBUTES *sa )
198 static const WCHAR dotVxDW[] = {'.','v','x','d',0};
199 int i;
200 HANDLE handle;
201 HMODULE module;
202 WCHAR *p, name[16];
204 /* normalize the filename */
206 if (strlenW( filenameW ) >= sizeof(name)/sizeof(WCHAR) - 4 ||
207 strchrW( filenameW, '/' ) || strchrW( filenameW, '\\' ))
209 SetLastError( ERROR_FILE_NOT_FOUND );
210 return 0;
212 strcpyW( name, filenameW );
213 strlwrW( name );
214 p = strchrW( name, '.' );
215 if (!p) strcatW( name, dotVxDW );
216 else if (strcmpiW( p, dotVxDW )) /* existing extension has to be .vxd */
218 SetLastError( ERROR_FILE_NOT_FOUND );
219 return 0;
222 /* try to load the module first */
224 if (!(module = LoadLibraryW( name )))
226 FIXME( "Unknown/unsupported VxD %s. Try setting Windows version to 'nt40' or 'win31'.\n",
227 debugstr_w(name) );
228 SetLastError( ERROR_FILE_NOT_FOUND );
229 return 0;
232 /* register the module in the global list if necessary */
234 RtlEnterCriticalSection( &vxd_section );
236 for (i = 0; i < MAX_VXD_MODULES; i++)
238 if (vxd_modules[i].module == module)
240 handle = vxd_modules[i].handle;
241 goto done; /* already registered */
243 if (!vxd_modules[i].module) /* new one, register it */
245 IO_STATUS_BLOCK io;
246 FILE_INTERNAL_INFORMATION info;
248 /* get a file handle to the dummy file */
249 if (!(handle = open_vxd_handle( name )))
251 FreeLibrary( module );
252 goto done;
254 if (!NtQueryInformationFile( handle, &io, &info, sizeof(info), FileInternalInformation ))
255 vxd_modules[i].index = info.IndexNumber;
257 vxd_modules[i].module = module;
258 vxd_modules[i].handle = handle;
259 vxd_modules[i].proc = (DeviceIoProc)GetProcAddress( module, "DeviceIoControl" );
260 goto done;
264 ERR("too many open VxD modules, please report\n" );
265 FreeLibrary( module );
266 handle = 0;
268 done:
269 RtlLeaveCriticalSection( &vxd_section );
270 if (!DuplicateHandle( GetCurrentProcess(), handle, GetCurrentProcess(), &handle, 0,
271 (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle),
272 DUP_HANDLE_SAME_ACCESS ))
273 handle = 0;
274 return handle;
278 /***********************************************************************
279 * VxDCall0 (KERNEL32.1)
280 * VxDCall1 (KERNEL32.2)
281 * VxDCall2 (KERNEL32.3)
282 * VxDCall3 (KERNEL32.4)
283 * VxDCall4 (KERNEL32.5)
284 * VxDCall5 (KERNEL32.6)
285 * VxDCall6 (KERNEL32.7)
286 * VxDCall7 (KERNEL32.8)
287 * VxDCall8 (KERNEL32.9)
289 void WINAPI DECLSPEC_HIDDEN __regs_VxDCall( DWORD service, CONTEXT *context )
291 unsigned int i;
292 VxDCallProc proc = NULL;
294 RtlEnterCriticalSection( &vxd_section );
295 for (i = 0; i < NB_VXD_SERVICES; i++)
297 if (HIWORD(service) != vxd_services[i].service) continue;
298 if (!vxd_services[i].module) /* need to load it */
300 if ((vxd_services[i].module = LoadLibraryW( vxd_services[i].name )))
301 vxd_services[i].proc = (VxDCallProc)GetProcAddress( vxd_services[i].module, "VxDCall" );
303 proc = vxd_services[i].proc;
304 break;
306 RtlLeaveCriticalSection( &vxd_section );
308 if (proc) context->Eax = proc( service, context );
309 else
311 FIXME( "Unknown/unimplemented VxD (%08x)\n", service);
312 context->Eax = 0xffffffff; /* FIXME */
315 #ifdef DEFINE_REGS_ENTRYPOINT
316 DEFINE_REGS_ENTRYPOINT( VxDCall, 1 )
317 #endif
320 /***********************************************************************
321 * __wine_vxd_vmm (WPROCS.401)
323 void WINAPI __wine_vxd_vmm ( CONTEXT *context )
325 unsigned service = AX_reg(context);
327 TRACE("[%04x] VMM\n", (UINT16)service);
329 switch(service)
331 case 0x0000: /* version */
332 SET_AX( context, VXD_WinVersion() );
333 RESET_CFLAG(context);
334 break;
336 case 0x026d: /* Get_Debug_Flag '/m' */
337 case 0x026e: /* Get_Debug_Flag '/n' */
338 SET_AL( context, 0 );
339 RESET_CFLAG(context);
340 break;
342 default:
343 VXD_BARF( context, "VMM" );
347 /***********************************************************************
348 * __wine_vxd_pagefile (WPROCS.433)
350 void WINAPI __wine_vxd_pagefile( CONTEXT *context )
352 unsigned service = AX_reg(context);
354 /* taken from Ralf Brown's Interrupt List */
356 TRACE("[%04x] PageFile\n", (UINT16)service );
358 switch(service)
360 case 0x00: /* get version, is this windows version? */
361 TRACE("returning version\n");
362 SET_AX( context, VXD_WinVersion() );
363 RESET_CFLAG(context);
364 break;
366 case 0x01: /* get swap file info */
367 TRACE("VxD PageFile: returning swap file info\n");
368 SET_AX( context, 0x00 ); /* paging disabled */
369 context->Ecx = 0; /* maximum size of paging file */
370 /* FIXME: do I touch DS:SI or DS:DI? */
371 RESET_CFLAG(context);
372 break;
374 case 0x02: /* delete permanent swap on exit */
375 TRACE("VxD PageFile: supposed to delete swap\n");
376 RESET_CFLAG(context);
377 break;
379 case 0x03: /* current temporary swap file size */
380 TRACE("VxD PageFile: what is current temp. swap size\n");
381 RESET_CFLAG(context);
382 break;
384 case 0x04: /* read or write?? INTERRUP.D */
385 case 0x05: /* cancel?? INTERRUP.D */
386 case 0x06: /* test I/O valid INTERRUP.D */
387 default:
388 VXD_BARF( context, "pagefile" );
389 break;
393 /***********************************************************************
394 * __wine_vxd_reboot (WPROCS.409)
396 void WINAPI __wine_vxd_reboot( CONTEXT *context )
398 unsigned service = AX_reg(context);
400 TRACE("[%04x] Reboot\n", (UINT16)service);
402 switch(service)
404 case 0x0000: /* version */
405 SET_AX( context, VXD_WinVersion() );
406 RESET_CFLAG(context);
407 break;
409 default:
410 VXD_BARF( context, "REBOOT" );
414 /***********************************************************************
415 * __wine_vxd_vdd (WPROCS.410)
417 void WINAPI __wine_vxd_vdd( CONTEXT *context )
419 unsigned service = AX_reg(context);
421 TRACE("[%04x] VDD\n", (UINT16)service);
423 switch(service)
425 case 0x0000: /* version */
426 SET_AX( context, VXD_WinVersion() );
427 RESET_CFLAG(context);
428 break;
430 default:
431 VXD_BARF( context, "VDD" );
435 /***********************************************************************
436 * __wine_vxd_vmd (WPROCS.412)
438 void WINAPI __wine_vxd_vmd( CONTEXT *context )
440 unsigned service = AX_reg(context);
442 TRACE("[%04x] VMD\n", (UINT16)service);
444 switch(service)
446 case 0x0000: /* version */
447 SET_AX( context, VXD_WinVersion() );
448 RESET_CFLAG(context);
449 break;
451 default:
452 VXD_BARF( context, "VMD" );
456 /***********************************************************************
457 * __wine_vxd_vxdloader (WPROCS.439)
459 void WINAPI __wine_vxd_vxdloader( CONTEXT *context )
461 unsigned service = AX_reg(context);
463 TRACE("[%04x] VXDLoader\n", (UINT16)service);
465 switch (service)
467 case 0x0000: /* get version */
468 TRACE("returning version\n");
469 SET_AX( context, 0x0000 );
470 SET_DX( context, VXD_WinVersion() );
471 RESET_CFLAG(context);
472 break;
474 case 0x0001: /* load device */
475 FIXME("load device %04x:%04x (%s)\n",
476 context->SegDs, DX_reg(context),
477 debugstr_a(MapSL(MAKESEGPTR(context->SegDs, DX_reg(context)))));
478 SET_AX( context, 0x0000 );
479 context->SegEs = 0x0000;
480 SET_DI( context, 0x0000 );
481 RESET_CFLAG(context);
482 break;
484 case 0x0002: /* unload device */
485 FIXME("unload device (%08x)\n", context->Ebx);
486 SET_AX( context, 0x0000 );
487 RESET_CFLAG(context);
488 break;
490 default:
491 VXD_BARF( context, "VXDLDR" );
492 SET_AX( context, 0x000B ); /* invalid function number */
493 SET_CFLAG(context);
494 break;
498 /***********************************************************************
499 * __wine_vxd_shell (WPROCS.423)
501 void WINAPI __wine_vxd_shell( CONTEXT *context )
503 unsigned service = DX_reg(context);
505 TRACE("[%04x] Shell\n", (UINT16)service);
507 switch (service) /* Ralf Brown says EDX, but I use DX instead */
509 case 0x0000:
510 TRACE("returning version\n");
511 SET_AX( context, VXD_WinVersion() );
512 context->Ebx = 1; /* system VM Handle */
513 break;
515 case 0x0001:
516 case 0x0002:
517 case 0x0003:
518 /* SHELL_SYSMODAL_Message
519 ebx virtual machine handle
520 eax message box flags
521 ecx address of message
522 edi address of caption
523 return response in eax
525 case 0x0004:
526 /* SHELL_Message
527 ebx virtual machine handle
528 eax message box flags
529 ecx address of message
530 edi address of caption
531 esi address callback
532 edx reference data for callback
533 return response in eax
535 case 0x0005:
536 VXD_BARF( context, "shell" );
537 break;
539 case 0x0006: /* SHELL_Get_VM_State */
540 TRACE("VxD Shell: returning VM state\n");
541 /* Actually we don't, not yet. We have to return a structure
542 * and I am not to sure how to set it up and return it yet,
543 * so for now let's do nothing. I can (hopefully) get this
544 * by the next release
546 /* RESET_CFLAG(context); */
547 break;
549 case 0x0007:
550 case 0x0008:
551 case 0x0009:
552 case 0x000A:
553 case 0x000B:
554 case 0x000C:
555 case 0x000D:
556 case 0x000E:
557 case 0x000F:
558 case 0x0010:
559 case 0x0011:
560 case 0x0012:
561 case 0x0013:
562 case 0x0014:
563 case 0x0015:
564 case 0x0016:
565 VXD_BARF( context, "SHELL" );
566 break;
568 /* the new Win95 shell API */
569 case 0x0100: /* get version */
570 SET_AX( context, VXD_WinVersion() );
571 break;
573 case 0x0104: /* retrieve Hook_Properties list */
574 case 0x0105: /* call Hook_Properties callbacks */
575 VXD_BARF( context, "SHELL" );
576 break;
578 case 0x0106: /* install timeout callback */
579 TRACE("VxD Shell: ignoring shell callback (%d sec.)\n", context->Ebx);
580 SET_CFLAG(context);
581 break;
583 case 0x0107: /* get version of any VxD */
584 default:
585 VXD_BARF( context, "SHELL" );
586 break;
591 /***********************************************************************
592 * __wine_vxd_comm (WPROCS.414)
594 void WINAPI __wine_vxd_comm( CONTEXT *context )
596 unsigned service = AX_reg(context);
598 TRACE("[%04x] Comm\n", (UINT16)service);
600 switch (service)
602 case 0x0000: /* get version */
603 TRACE("returning version\n");
604 SET_AX( context, VXD_WinVersion() );
605 RESET_CFLAG(context);
606 break;
608 case 0x0001: /* set port global */
609 case 0x0002: /* get focus */
610 case 0x0003: /* virtualise port */
611 default:
612 VXD_BARF( context, "comm" );
616 /***********************************************************************
617 * __wine_vxd_timer (WPROCS.405)
619 void WINAPI __wine_vxd_timer( CONTEXT *context )
621 unsigned service = AX_reg(context);
623 TRACE("[%04x] Virtual Timer\n", (UINT16)service);
625 switch(service)
627 case 0x0000: /* version */
628 SET_AX( context, VXD_WinVersion() );
629 RESET_CFLAG(context);
630 break;
632 case 0x0100: /* clock tick time, in 840nsecs */
633 context->Eax = GetTickCount();
635 context->Edx = context->Eax >> 22;
636 context->Eax <<= 10; /* not very precise */
637 break;
639 case 0x0101: /* current Windows time, msecs */
640 case 0x0102: /* current VM time, msecs */
641 context->Eax = GetTickCount();
642 break;
644 default:
645 VXD_BARF( context, "VTD" );
650 /***********************************************************************
651 * timer_thread
653 static DWORD CALLBACK timer_thread( void *arg )
655 DWORD *system_time = arg;
657 for (;;)
659 *system_time = GetTickCount();
660 Sleep( 55 );
663 return 0;
667 /***********************************************************************
668 * __wine_vxd_timerapi (WPROCS.1490)
670 void WINAPI __wine_vxd_timerapi( CONTEXT *context )
672 static WORD System_Time_Selector;
674 unsigned service = AX_reg(context);
676 TRACE("[%04x] TimerAPI\n", (UINT16)service);
678 switch(service)
680 case 0x0000: /* version */
681 SET_AX( context, VXD_WinVersion() );
682 RESET_CFLAG(context);
683 break;
685 case 0x0009: /* get system time selector */
686 if ( !System_Time_Selector )
688 HANDLE16 handle = GlobalAlloc16( GMEM_FIXED, sizeof(DWORD) );
689 System_Time_Selector = handle | 7;
690 CloseHandle( CreateThread( NULL, 0, timer_thread, GlobalLock16(handle), 0, NULL ) );
692 SET_AX( context, System_Time_Selector );
693 RESET_CFLAG(context);
694 break;
696 default:
697 VXD_BARF( context, "VTDAPI" );
701 /***********************************************************************
702 * __wine_vxd_configmg (WPROCS.451)
704 void WINAPI __wine_vxd_configmg( CONTEXT *context )
706 unsigned service = AX_reg(context);
708 TRACE("[%04x] ConfigMG\n", (UINT16)service);
710 switch(service)
712 case 0x0000: /* version */
713 SET_AX( context, VXD_WinVersion() );
714 RESET_CFLAG(context);
715 break;
717 default:
718 VXD_BARF( context, "CONFIGMG" );
722 /***********************************************************************
723 * __wine_vxd_enable (WPROCS.455)
725 void WINAPI __wine_vxd_enable( CONTEXT *context )
727 unsigned service = AX_reg(context);
729 TRACE("[%04x] Enable\n", (UINT16)service);
731 switch(service)
733 case 0x0000: /* version */
734 SET_AX( context, VXD_WinVersion() );
735 RESET_CFLAG(context);
736 break;
738 default:
739 VXD_BARF( context, "ENABLE" );
743 /***********************************************************************
744 * __wine_vxd_apm (WPROCS.438)
746 void WINAPI __wine_vxd_apm( CONTEXT *context )
748 unsigned service = AX_reg(context);
750 TRACE("[%04x] APM\n", (UINT16)service);
752 switch(service)
754 case 0x0000: /* version */
755 SET_AX( context, VXD_WinVersion() );
756 RESET_CFLAG(context);
757 break;
759 default:
760 VXD_BARF( context, "APM" );
764 /***********************************************************************
765 * __wine_vxd_win32s (WPROCS.445)
767 * This is an implementation of the services of the Win32s VxD.
768 * Since official documentation of these does not seem to be available,
769 * certain arguments of some of the services remain unclear.
771 * FIXME: The following services are currently unimplemented:
772 * Exception handling (0x01, 0x1C)
773 * Debugger support (0x0C, 0x14, 0x17)
774 * Low-level memory access (0x02, 0x03, 0x0A, 0x0B)
775 * Memory Statistics (0x1B)
778 * We have a specific problem running Win32s on Linux (and probably also
779 * the other x86 unixes), since Win32s tries to allocate its main 'flat
780 * code/data segment' selectors with a base of 0xffff0000 (and limit 4GB).
781 * The rationale for this seems to be that they want one the one hand to
782 * be able to leave the Win 3.1 memory (starting with the main DOS memory)
783 * at linear address 0, but want at other hand to have offset 0 of the
784 * flat data/code segment point to an unmapped page (to catch NULL pointer
785 * accesses). Hence they allocate the flat segments with a base of 0xffff0000
786 * so that the Win 3.1 memory area at linear address zero shows up in the
787 * flat segments at offset 0x10000 (since linear addresses wrap around at
788 * 4GB). To compensate for that discrepancy between flat segment offsets
789 * and plain linear addresses, all flat pointers passed between the 32-bit
790 * and the 16-bit parts of Win32s are shifted by 0x10000 in the appropriate
791 * direction by the glue code (mainly) in W32SKRNL and WIN32S16.
793 * The problem for us is now that Linux does not allow a LDT selector with
794 * base 0xffff0000 to be created, since it would 'see' a part of the kernel
795 * address space. To address this problem we introduce *another* offset:
796 * We add 0x10000 to every linear address we get as an argument from Win32s.
797 * This means especially that the flat code/data selectors get actually
798 * allocated with base 0x0, so that flat offsets and (real) linear addresses
799 * do again agree! In fact, every call e.g. of a Win32s VxD service now
800 * has all pointer arguments (which are offsets in the flat data segment)
801 * first reduced by 0x10000 by the W32SKRNL glue code, and then again
802 * increased by 0x10000 by *our* code.
804 * Note that to keep everything consistent, this offset has to be applied by
805 * every Wine function that operates on 'linear addresses' passed to it by
806 * Win32s. Fortunately, since Win32s does not directly call any Wine 32-bit
807 * API routines, this affects only two locations: this VxD and the DPMI
808 * handler. (NOTE: Should any Win32s application pass a linear address to
809 * any routine apart from those, e.g. some other VxD handler, that code
810 * would have to take the offset into account as well!)
812 * The offset is set the first time any application calls the GetVersion()
813 * service of the Win32s VxD. (Note that the offset is never reset.)
816 void WINAPI __wine_vxd_win32s( CONTEXT *context )
818 switch (AX_reg(context))
820 case 0x0000: /* Get Version */
822 * Input: None
824 * Output: EAX: LoWord: Win32s Version (1.30)
825 * HiWord: VxD Version (200)
827 * EBX: Build (172)
829 * ECX: ??? (1)
831 * EDX: Debugging Flags
833 * EDI: Error Flag
834 * 0 if OK,
835 * 1 if VMCPD VxD not found
838 TRACE("GetVersion()\n");
840 context->Eax = VXD_WinVersion() | (200 << 16);
841 context->Ebx = 0;
842 context->Ecx = 0;
843 context->Edx = 0;
844 context->Edi = 0;
847 * If this is the first time we are called for this process,
848 * hack the memory image of WIN32S16 so that it doesn't try
849 * to access the GDT directly ...
851 * The first code segment of WIN32S16 (version 1.30) contains
852 * an unexported function somewhere between the exported functions
853 * SetFS and StackLinearToSegmented that tries to find a selector
854 * in the LDT that maps to the memory image of the LDT itself.
855 * If it succeeds, it stores this selector into a global variable
856 * which will be used to speed up execution by using this selector
857 * to modify the LDT directly instead of using the DPMI calls.
859 * To perform this search of the LDT, this function uses the
860 * sgdt and sldt instructions to find the linear address of
861 * the (GDT and then) LDT. While those instructions themselves
862 * execute without problem, the linear address that sgdt returns
863 * points (at least under Linux) to the kernel address space, so
864 * that any subsequent access leads to a segfault.
866 * Fortunately, WIN32S16 still contains as a fallback option the
867 * mechanism of using DPMI calls to modify LDT selectors instead
868 * of direct writes to the LDT. Thus we can circumvent the problem
869 * by simply replacing the first byte of the offending function
870 * with an 'retf' instruction. This means that the global variable
871 * supposed to contain the LDT alias selector will remain zero,
872 * and hence WIN32S16 will fall back to using DPMI calls.
874 * The heuristic we employ to _find_ that function is as follows:
875 * We search between the addresses of the exported symbols SetFS
876 * and StackLinearToSegmented for the byte sequence '0F 01 04'
877 * (this is the opcode of 'sgdt [si]'). We then search backwards
878 * from this address for the last occurrence of 'CB' (retf) that marks
879 * the end of the preceding function. The following byte (which
880 * should now be the first byte of the function we are looking for)
881 * will be replaced by 'CB' (retf).
883 * This heuristic works for the retail as well as the debug version
884 * of Win32s version 1.30. For versions earlier than that this
885 * hack should not be necessary at all, since the whole mechanism
886 * ('PERF130') was introduced only in 1.30 to improve the overall
887 * performance of Win32s.
890 if (!W32S_offset)
892 HMODULE16 hModule = GetModuleHandle16("win32s16");
893 SEGPTR func1 = (SEGPTR)GetProcAddress16(hModule, "SetFS");
894 SEGPTR func2 = (SEGPTR)GetProcAddress16(hModule, "StackLinearToSegmented");
896 if ( hModule && func1 && func2
897 && SELECTOROF(func1) == SELECTOROF(func2))
899 BYTE *start = MapSL(func1);
900 BYTE *end = MapSL(func2);
901 BYTE *p, *retv = NULL;
902 int found = 0;
904 for (p = start; p < end; p++)
905 if (*p == 0xCB) found = 0, retv = p;
906 else if (*p == 0x0F) found = 1;
907 else if (*p == 0x01 && found == 1) found = 2;
908 else if (*p == 0x04 && found == 2) { found = 3; break; }
909 else found = 0;
911 if (found == 3 && retv)
913 TRACE("PERF130 hack: "
914 "Replacing byte %02X at offset %04X:%04X\n",
915 *(retv+1), SELECTOROF(func1),
916 OFFSETOF(func1) + retv+1-start);
918 *(retv+1) = (BYTE)0xCB;
924 * Mark process as Win32s, so that subsequent DPMI calls
925 * will perform the W32S_APP2WINE/W32S_WINE2APP address shift.
927 W32S_offset = 0x10000;
928 break;
931 case 0x0001: /* Install Exception Handling */
933 * Input: EBX: Flat address of W32SKRNL Exception Data
935 * ECX: LoWord: Flat Code Selector
936 * HiWord: Flat Data Selector
938 * EDX: Flat address of W32SKRNL Exception Handler
939 * (this is equal to W32S_BackTo32 + 0x40)
941 * ESI: SEGPTR KERNEL.HASGPHANDLER
943 * EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10)
945 * Output: EAX: 0 if OK
948 TRACE("[0001] EBX=%x ECX=%x EDX=%x ESI=%x EDI=%x\n",
949 context->Ebx, context->Ecx, context->Edx,
950 context->Esi, context->Edi);
952 /* FIXME */
954 context->Eax = 0;
955 break;
958 case 0x0002: /* Set Page Access Flags */
960 * Input: EBX: New access flags
961 * Bit 2: User Page if set, Supervisor Page if clear
962 * Bit 1: Read-Write if set, Read-Only if clear
964 * ECX: Size of memory area to change
966 * EDX: Flat start address of memory area
968 * Output: EAX: Size of area changed
971 TRACE("[0002] EBX=%x ECX=%x EDX=%x\n",
972 context->Ebx, context->Ecx, context->Edx);
974 /* FIXME */
976 context->Eax = context->Ecx;
977 break;
980 case 0x0003: /* Get Page Access Flags */
982 * Input: EDX: Flat address of page to query
984 * Output: EAX: Page access flags
985 * Bit 2: User Page if set, Supervisor Page if clear
986 * Bit 1: Read-Write if set, Read-Only if clear
989 TRACE("[0003] EDX=%x\n", context->Edx);
991 /* FIXME */
993 context->Eax = 6;
994 break;
997 case 0x0004: /* Map Module */
999 * Input: ECX: IMTE (offset in Module Table) of new module
1001 * EDX: Flat address of Win32s Module Table
1003 * Output: EAX: 0 if OK
1006 if (!context->Edx || CX_reg(context) == 0xFFFF)
1008 TRACE("MapModule: Initialization call\n");
1009 context->Eax = 0;
1011 else
1014 * Structure of a Win32s Module Table Entry:
1016 struct Win32sModule
1018 DWORD flags;
1019 DWORD flatBaseAddr;
1020 LPCSTR moduleName;
1021 LPCSTR pathName;
1022 LPCSTR unknown;
1023 LPBYTE baseAddr;
1024 DWORD hModule;
1025 DWORD relocDelta;
1029 * Note: This function should set up a demand-paged memory image
1030 * of the given module. Since mmap does not allow file offsets
1031 * not aligned at 1024 bytes, we simply load the image fully
1032 * into memory.
1035 struct Win32sModule *moduleTable =
1036 (struct Win32sModule *)W32S_APP2WINE(context->Edx);
1037 struct Win32sModule *module = moduleTable + context->Ecx;
1039 IMAGE_NT_HEADERS *nt_header = RtlImageNtHeader( (HMODULE)module->baseAddr );
1040 IMAGE_SECTION_HEADER *pe_seg = (IMAGE_SECTION_HEADER*)((char *)&nt_header->OptionalHeader +
1041 nt_header->FileHeader.SizeOfOptionalHeader);
1044 HFILE image = _lopen(module->pathName, OF_READ);
1045 BOOL error = (image == HFILE_ERROR);
1046 UINT i;
1048 TRACE("MapModule: Loading %s\n", module->pathName);
1050 for (i = 0;
1051 !error && i < nt_header->FileHeader.NumberOfSections;
1052 i++, pe_seg++)
1053 if(!(pe_seg->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA))
1055 DWORD off = pe_seg->PointerToRawData;
1056 DWORD len = pe_seg->SizeOfRawData;
1057 LPBYTE addr = module->baseAddr + pe_seg->VirtualAddress;
1059 TRACE("MapModule: "
1060 "Section %d at %08x from %08x len %08x\n",
1061 i, (DWORD)addr, off, len);
1063 if ( _llseek(image, off, SEEK_SET) != off
1064 || _lread(image, addr, len) != len)
1065 error = TRUE;
1068 _lclose(image);
1070 if (error)
1071 ERR("MapModule: Unable to load %s\n", module->pathName);
1073 else if (module->relocDelta != 0)
1075 IMAGE_DATA_DIRECTORY *dir = nt_header->OptionalHeader.DataDirectory
1076 + IMAGE_DIRECTORY_ENTRY_BASERELOC;
1077 IMAGE_BASE_RELOCATION *r = (IMAGE_BASE_RELOCATION *)
1078 (dir->Size? module->baseAddr + dir->VirtualAddress : 0);
1080 TRACE("MapModule: Reloc delta %08x\n", module->relocDelta);
1082 while (r && r->VirtualAddress)
1084 LPBYTE page = module->baseAddr + r->VirtualAddress;
1085 WORD *TypeOffset = (WORD *)(r + 1);
1086 unsigned int count = (r->SizeOfBlock - sizeof(*r)) / sizeof(*TypeOffset);
1088 TRACE("MapModule: %d relocations for page %08x\n",
1089 count, (DWORD)page);
1091 for(i = 0; i < count; i++)
1093 int offset = TypeOffset[i] & 0xFFF;
1094 int type = TypeOffset[i] >> 12;
1095 switch(type)
1097 case IMAGE_REL_BASED_ABSOLUTE:
1098 break;
1099 case IMAGE_REL_BASED_HIGH:
1100 *(WORD *)(page+offset) += HIWORD(module->relocDelta);
1101 break;
1102 case IMAGE_REL_BASED_LOW:
1103 *(WORD *)(page+offset) += LOWORD(module->relocDelta);
1104 break;
1105 case IMAGE_REL_BASED_HIGHLOW:
1106 *(DWORD*)(page+offset) += module->relocDelta;
1107 break;
1108 default:
1109 WARN("MapModule: Unsupported fixup type\n");
1110 break;
1114 r = (IMAGE_BASE_RELOCATION *)((LPBYTE)r + r->SizeOfBlock);
1118 context->Eax = 0;
1119 RESET_CFLAG(context);
1121 break;
1124 case 0x0005: /* UnMap Module */
1126 * Input: EDX: Flat address of module image
1128 * Output: EAX: 1 if OK
1131 TRACE("UnMapModule: %x\n", W32S_APP2WINE(context->Edx));
1133 /* As we didn't map anything, there's nothing to unmap ... */
1135 context->Eax = 1;
1136 break;
1139 case 0x0006: /* VirtualAlloc */
1141 * Input: ECX: Current Process
1143 * EDX: Flat address of arguments on stack
1145 * DWORD *retv [out] Flat base address of allocated region
1146 * LPVOID base [in] Flat address of region to reserve/commit
1147 * DWORD size [in] Size of region
1148 * DWORD type [in] Type of allocation
1149 * DWORD prot [in] Type of access protection
1151 * Output: EAX: NtStatus
1154 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1155 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1156 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1157 DWORD size = stack[2];
1158 DWORD type = stack[3];
1159 DWORD prot = stack[4];
1160 DWORD result;
1162 TRACE("VirtualAlloc(%x, %x, %x, %x, %x)\n",
1163 (DWORD)retv, (DWORD)base, size, type, prot);
1165 if (type & 0x80000000)
1167 WARN("VirtualAlloc: strange type %x\n", type);
1168 type &= 0x7fffffff;
1171 if (!base && (type & MEM_COMMIT) && prot == PAGE_READONLY)
1173 WARN("VirtualAlloc: NLS hack, allowing write access!\n");
1174 prot = PAGE_READWRITE;
1177 result = (DWORD)VirtualAlloc(base, size, type, prot);
1179 if (W32S_WINE2APP(result))
1180 *retv = W32S_WINE2APP(result),
1181 context->Eax = STATUS_SUCCESS;
1182 else
1183 *retv = 0,
1184 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1186 break;
1189 case 0x0007: /* VirtualFree */
1191 * Input: ECX: Current Process
1193 * EDX: Flat address of arguments on stack
1195 * DWORD *retv [out] TRUE if success, FALSE if failure
1196 * LPVOID base [in] Flat address of region
1197 * DWORD size [in] Size of region
1198 * DWORD type [in] Type of operation
1200 * Output: EAX: NtStatus
1203 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1204 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1205 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1206 DWORD size = stack[2];
1207 DWORD type = stack[3];
1208 DWORD result;
1210 TRACE("VirtualFree(%x, %x, %x, %x)\n",
1211 (DWORD)retv, (DWORD)base, size, type);
1213 result = VirtualFree(base, size, type);
1215 if (result)
1216 *retv = TRUE,
1217 context->Eax = STATUS_SUCCESS;
1218 else
1219 *retv = FALSE,
1220 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1222 break;
1225 case 0x0008: /* VirtualProtect */
1227 * Input: ECX: Current Process
1229 * EDX: Flat address of arguments on stack
1231 * DWORD *retv [out] TRUE if success, FALSE if failure
1232 * LPVOID base [in] Flat address of region
1233 * DWORD size [in] Size of region
1234 * DWORD new_prot [in] Desired access protection
1235 * DWORD *old_prot [out] Previous access protection
1237 * Output: EAX: NtStatus
1240 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1241 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1242 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1243 DWORD size = stack[2];
1244 DWORD new_prot = stack[3];
1245 DWORD *old_prot = (DWORD *)W32S_APP2WINE(stack[4]);
1246 DWORD result;
1248 TRACE("VirtualProtect(%x, %x, %x, %x, %x)\n",
1249 (DWORD)retv, (DWORD)base, size, new_prot, (DWORD)old_prot);
1251 result = VirtualProtect(base, size, new_prot, old_prot);
1253 if (result)
1254 *retv = TRUE,
1255 context->Eax = STATUS_SUCCESS;
1256 else
1257 *retv = FALSE,
1258 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1260 break;
1263 case 0x0009: /* VirtualQuery */
1265 * Input: ECX: Current Process
1267 * EDX: Flat address of arguments on stack
1269 * DWORD *retv [out] Nr. bytes returned
1270 * LPVOID base [in] Flat address of region
1271 * LPMEMORY_BASIC_INFORMATION info [out] Info buffer
1272 * DWORD len [in] Size of buffer
1274 * Output: EAX: NtStatus
1277 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1278 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1279 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1280 PMEMORY_BASIC_INFORMATION info =
1281 (PMEMORY_BASIC_INFORMATION)W32S_APP2WINE(stack[2]);
1282 DWORD len = stack[3];
1283 DWORD result;
1285 TRACE("VirtualQuery(%x, %x, %x, %x)\n",
1286 (DWORD)retv, (DWORD)base, (DWORD)info, len);
1288 result = VirtualQuery(base, info, len);
1290 *retv = result;
1291 context->Eax = STATUS_SUCCESS;
1293 break;
1296 case 0x000A: /* SetVirtMemProcess */
1298 * Input: ECX: Process Handle
1300 * EDX: Flat address of region
1302 * Output: EAX: NtStatus
1305 TRACE("[000a] ECX=%x EDX=%x\n",
1306 context->Ecx, context->Edx);
1308 /* FIXME */
1310 context->Eax = STATUS_SUCCESS;
1311 break;
1314 case 0x000B: /* ??? some kind of cleanup */
1316 * Input: ECX: Process Handle
1318 * Output: EAX: NtStatus
1321 TRACE("[000b] ECX=%x\n", context->Ecx);
1323 /* FIXME */
1325 context->Eax = STATUS_SUCCESS;
1326 break;
1329 case 0x000C: /* Set Debug Flags */
1331 * Input: EDX: Debug Flags
1333 * Output: EDX: Previous Debug Flags
1336 FIXME("[000c] EDX=%x\n", context->Edx);
1338 /* FIXME */
1340 context->Edx = 0;
1341 break;
1344 case 0x000D: /* NtCreateSection */
1346 * Input: EDX: Flat address of arguments on stack
1348 * HANDLE32 *retv [out] Handle of Section created
1349 * DWORD flags1 [in] (?? unknown ??)
1350 * DWORD atom [in] Name of Section to create
1351 * LARGE_INTEGER *size [in] Size of Section
1352 * DWORD protect [in] Access protection
1353 * DWORD flags2 [in] (?? unknown ??)
1354 * HFILE32 hFile [in] Handle of file to map
1355 * DWORD psp [in] (Win32s: PSP that hFile belongs to)
1357 * Output: EAX: NtStatus
1360 DWORD *stack = (DWORD *) W32S_APP2WINE(context->Edx);
1361 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]);
1362 DWORD flags1 = stack[1];
1363 DWORD atom = stack[2];
1364 LARGE_INTEGER *size = (LARGE_INTEGER *)W32S_APP2WINE(stack[3]);
1365 DWORD protect = stack[4];
1366 DWORD flags2 = stack[5];
1367 HANDLE hFile = DosFileHandleToWin32Handle(stack[6]);
1368 DWORD psp = stack[7];
1370 HANDLE result = INVALID_HANDLE_VALUE;
1371 char name[128];
1373 TRACE("NtCreateSection(%x, %x, %x, %x, %x, %x, %x, %x)\n",
1374 (DWORD)retv, flags1, atom, (DWORD)size, protect, flags2,
1375 (DWORD)hFile, psp);
1377 if (!atom || GlobalGetAtomNameA(atom, name, sizeof(name)))
1379 TRACE("NtCreateSection: name=%s\n", atom? name : NULL);
1381 result = CreateFileMappingA(hFile, NULL, protect,
1382 size? size->u.HighPart : 0,
1383 size? size->u.LowPart : 0,
1384 atom? name : NULL);
1387 if (result == INVALID_HANDLE_VALUE)
1388 WARN("NtCreateSection: failed!\n");
1389 else
1390 TRACE("NtCreateSection: returned %x\n", (DWORD)result);
1392 if (result != INVALID_HANDLE_VALUE)
1393 *retv = result,
1394 context->Eax = STATUS_SUCCESS;
1395 else
1396 *retv = result,
1397 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1399 break;
1402 case 0x000E: /* NtOpenSection */
1404 * Input: EDX: Flat address of arguments on stack
1406 * HANDLE32 *retv [out] Handle of Section opened
1407 * DWORD protect [in] Access protection
1408 * DWORD atom [in] Name of Section to create
1410 * Output: EAX: NtStatus
1413 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1414 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]);
1415 DWORD protect = stack[1];
1416 DWORD atom = stack[2];
1418 HANDLE result = INVALID_HANDLE_VALUE;
1419 char name[128];
1421 TRACE("NtOpenSection(%x, %x, %x)\n",
1422 (DWORD)retv, protect, atom);
1424 if (atom && GlobalGetAtomNameA(atom, name, sizeof(name)))
1426 TRACE("NtOpenSection: name=%s\n", name);
1428 result = OpenFileMappingA(protect, FALSE, name);
1431 if (result == INVALID_HANDLE_VALUE)
1432 WARN("NtOpenSection: failed!\n");
1433 else
1434 TRACE("NtOpenSection: returned %x\n", (DWORD)result);
1436 if (result != INVALID_HANDLE_VALUE)
1437 *retv = result,
1438 context->Eax = STATUS_SUCCESS;
1439 else
1440 *retv = result,
1441 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1443 break;
1446 case 0x000F: /* NtCloseSection */
1448 * Input: EDX: Flat address of arguments on stack
1450 * HANDLE32 handle [in] Handle of Section to close
1451 * DWORD *id [out] Unique ID (?? unclear ??)
1453 * Output: EAX: NtStatus
1456 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1457 HANDLE handle = (HANDLE)stack[0];
1458 DWORD *id = (DWORD *)W32S_APP2WINE(stack[1]);
1460 TRACE("NtCloseSection(%x, %x)\n", (DWORD)handle, (DWORD)id);
1462 CloseHandle(handle);
1463 if (id) *id = 0; /* FIXME */
1465 context->Eax = STATUS_SUCCESS;
1467 break;
1470 case 0x0010: /* NtDupSection */
1472 * Input: EDX: Flat address of arguments on stack
1474 * HANDLE32 handle [in] Handle of Section to duplicate
1476 * Output: EAX: NtStatus
1479 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1480 HANDLE handle = (HANDLE)stack[0];
1481 HANDLE new_handle;
1483 TRACE("NtDupSection(%x)\n", (DWORD)handle);
1485 DuplicateHandle( GetCurrentProcess(), handle,
1486 GetCurrentProcess(), &new_handle,
1487 0, FALSE, DUPLICATE_SAME_ACCESS );
1488 context->Eax = STATUS_SUCCESS;
1490 break;
1493 case 0x0011: /* NtMapViewOfSection */
1495 * Input: EDX: Flat address of arguments on stack
1497 * HANDLE32 SectionHandle [in] Section to be mapped
1498 * DWORD ProcessHandle [in] Process to be mapped into
1499 * DWORD * BaseAddress [in/out] Address to be mapped at
1500 * DWORD ZeroBits [in] (?? unclear ??)
1501 * DWORD CommitSize [in] (?? unclear ??)
1502 * LARGE_INTEGER *SectionOffset [in] Offset within section
1503 * DWORD * ViewSize [in] Size of view
1504 * DWORD InheritDisposition [in] (?? unclear ??)
1505 * DWORD AllocationType [in] (?? unclear ??)
1506 * DWORD Protect [in] Access protection
1508 * Output: EAX: NtStatus
1511 DWORD * stack = (DWORD *)W32S_APP2WINE(context->Edx);
1512 HANDLE SectionHandle = (HANDLE)stack[0];
1513 DWORD ProcessHandle = stack[1]; /* ignored */
1514 DWORD * BaseAddress = (DWORD *)W32S_APP2WINE(stack[2]);
1515 DWORD ZeroBits = stack[3];
1516 DWORD CommitSize = stack[4];
1517 LARGE_INTEGER *SectionOffset = (LARGE_INTEGER *)W32S_APP2WINE(stack[5]);
1518 DWORD * ViewSize = (DWORD *)W32S_APP2WINE(stack[6]);
1519 DWORD InheritDisposition = stack[7];
1520 DWORD AllocationType = stack[8];
1521 DWORD Protect = stack[9];
1523 LPBYTE address = (LPBYTE)(BaseAddress?
1524 W32S_APP2WINE(*BaseAddress) : 0);
1525 DWORD access = 0, result;
1527 switch (Protect & ~(PAGE_GUARD|PAGE_NOCACHE))
1529 case PAGE_READONLY: access = FILE_MAP_READ; break;
1530 case PAGE_READWRITE: access = FILE_MAP_WRITE; break;
1531 case PAGE_WRITECOPY: access = FILE_MAP_COPY; break;
1533 case PAGE_EXECUTE_READ: access = FILE_MAP_READ; break;
1534 case PAGE_EXECUTE_READWRITE: access = FILE_MAP_WRITE; break;
1535 case PAGE_EXECUTE_WRITECOPY: access = FILE_MAP_COPY; break;
1538 TRACE("NtMapViewOfSection"
1539 "(%x, %x, %x, %x, %x, %x, %x, %x, %x, %x)\n",
1540 (DWORD)SectionHandle, ProcessHandle, (DWORD)BaseAddress,
1541 ZeroBits, CommitSize, (DWORD)SectionOffset, (DWORD)ViewSize,
1542 InheritDisposition, AllocationType, Protect);
1543 TRACE("NtMapViewOfSection: "
1544 "base=%x, offset=%x, size=%x, access=%x\n",
1545 (DWORD)address, SectionOffset? SectionOffset->u.LowPart : 0,
1546 ViewSize? *ViewSize : 0, access);
1548 result = (DWORD)MapViewOfFileEx(SectionHandle, access,
1549 SectionOffset? SectionOffset->u.HighPart : 0,
1550 SectionOffset? SectionOffset->u.LowPart : 0,
1551 ViewSize? *ViewSize : 0, address);
1553 TRACE("NtMapViewOfSection: result=%x\n", result);
1555 if (W32S_WINE2APP(result))
1557 if (BaseAddress) *BaseAddress = W32S_WINE2APP(result);
1558 context->Eax = STATUS_SUCCESS;
1560 else
1561 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1563 break;
1566 case 0x0012: /* NtUnmapViewOfSection */
1568 * Input: EDX: Flat address of arguments on stack
1570 * DWORD ProcessHandle [in] Process (defining address space)
1571 * LPBYTE BaseAddress [in] Base address of view to be unmapped
1573 * Output: EAX: NtStatus
1576 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1577 DWORD ProcessHandle = stack[0]; /* ignored */
1578 LPBYTE BaseAddress = (LPBYTE)W32S_APP2WINE(stack[1]);
1580 TRACE("NtUnmapViewOfSection(%x, %x)\n",
1581 ProcessHandle, (DWORD)BaseAddress);
1583 UnmapViewOfFile(BaseAddress);
1585 context->Eax = STATUS_SUCCESS;
1587 break;
1590 case 0x0013: /* NtFlushVirtualMemory */
1592 * Input: EDX: Flat address of arguments on stack
1594 * DWORD ProcessHandle [in] Process (defining address space)
1595 * LPBYTE *BaseAddress [in?] Base address of range to be flushed
1596 * DWORD *ViewSize [in?] Number of bytes to be flushed
1597 * DWORD *unknown [???] (?? unknown ??)
1599 * Output: EAX: NtStatus
1602 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1603 DWORD ProcessHandle = stack[0]; /* ignored */
1604 DWORD *BaseAddress = (DWORD *)W32S_APP2WINE(stack[1]);
1605 DWORD *ViewSize = (DWORD *)W32S_APP2WINE(stack[2]);
1606 DWORD *unknown = (DWORD *)W32S_APP2WINE(stack[3]);
1608 LPBYTE address = (LPBYTE)(BaseAddress? W32S_APP2WINE(*BaseAddress) : 0);
1609 DWORD size = ViewSize? *ViewSize : 0;
1611 TRACE("NtFlushVirtualMemory(%x, %x, %x, %x)\n",
1612 ProcessHandle, (DWORD)BaseAddress, (DWORD)ViewSize,
1613 (DWORD)unknown);
1614 TRACE("NtFlushVirtualMemory: base=%x, size=%x\n",
1615 (DWORD)address, size);
1617 FlushViewOfFile(address, size);
1619 context->Eax = STATUS_SUCCESS;
1621 break;
1624 case 0x0014: /* Get/Set Debug Registers */
1626 * Input: ECX: 0 if Get, 1 if Set
1628 * EDX: Get: Flat address of buffer to receive values of
1629 * debug registers DR0 .. DR7
1630 * Set: Flat address of buffer containing values of
1631 * debug registers DR0 .. DR7 to be set
1632 * Output: None
1635 FIXME("[0014] ECX=%x EDX=%x\n",
1636 context->Ecx, context->Edx);
1638 /* FIXME */
1639 break;
1642 case 0x0015: /* Set Coprocessor Emulation Flag */
1644 * Input: EDX: 0 to deactivate, 1 to activate coprocessor emulation
1646 * Output: None
1649 TRACE("[0015] EDX=%x\n", context->Edx);
1651 /* We don't care, as we always have a coprocessor anyway */
1652 break;
1655 case 0x0016: /* Init Win32S VxD PSP */
1657 * If called to query required PSP size:
1659 * Input: EBX: 0
1660 * Output: EDX: Required size of Win32s VxD PSP
1662 * If called to initialize allocated PSP:
1664 * Input: EBX: LoWord: Selector of Win32s VxD PSP
1665 * HiWord: Paragraph of Win32s VxD PSP (DOSMEM)
1666 * Output: None
1669 if (context->Ebx == 0)
1670 context->Edx = 0x80;
1671 else
1673 PDB16 *psp = MapSL( MAKESEGPTR( BX_reg(context), 0 ));
1674 psp->nbFiles = 32;
1675 psp->fileHandlesPtr = MAKELONG(HIWORD(context->Ebx), 0x5c);
1676 memset((LPBYTE)psp + 0x5c, '\xFF', 32);
1678 break;
1681 case 0x0017: /* Set Break Point */
1683 * Input: EBX: Offset of Break Point
1684 * CX: Selector of Break Point
1686 * Output: None
1689 FIXME("[0017] EBX=%x CX=%x\n",
1690 context->Ebx, CX_reg(context));
1692 /* FIXME */
1693 break;
1696 case 0x0018: /* VirtualLock */
1698 * Input: ECX: Current Process
1700 * EDX: Flat address of arguments on stack
1702 * DWORD *retv [out] TRUE if success, FALSE if failure
1703 * LPVOID base [in] Flat address of range to lock
1704 * DWORD size [in] Size of range
1706 * Output: EAX: NtStatus
1709 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1710 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1711 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1712 DWORD size = stack[2];
1713 DWORD result;
1715 TRACE("VirtualLock(%x, %x, %x)\n",
1716 (DWORD)retv, (DWORD)base, size);
1718 result = VirtualLock(base, size);
1720 if (result)
1721 *retv = TRUE,
1722 context->Eax = STATUS_SUCCESS;
1723 else
1724 *retv = FALSE,
1725 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1727 break;
1730 case 0x0019: /* VirtualUnlock */
1732 * Input: ECX: Current Process
1734 * EDX: Flat address of arguments on stack
1736 * DWORD *retv [out] TRUE if success, FALSE if failure
1737 * LPVOID base [in] Flat address of range to unlock
1738 * DWORD size [in] Size of range
1740 * Output: EAX: NtStatus
1743 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1744 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1745 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1746 DWORD size = stack[2];
1747 DWORD result;
1749 TRACE("VirtualUnlock(%x, %x, %x)\n",
1750 (DWORD)retv, (DWORD)base, size);
1752 result = VirtualUnlock(base, size);
1754 if (result)
1755 *retv = TRUE,
1756 context->Eax = STATUS_SUCCESS;
1757 else
1758 *retv = FALSE,
1759 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1761 break;
1764 case 0x001A: /* KGetSystemInfo */
1766 * Input: None
1768 * Output: ECX: Start of sparse memory arena
1769 * EDX: End of sparse memory arena
1772 TRACE("KGetSystemInfo()\n");
1775 * Note: Win32s reserves 0GB - 2GB for Win 3.1 and uses 2GB - 4GB as
1776 * sparse memory arena. We do it the other way around, since
1777 * we have to reserve 3GB - 4GB for Linux, and thus use
1778 * 0GB - 3GB as sparse memory arena.
1780 * FIXME: What about other OSes ?
1783 context->Ecx = W32S_WINE2APP(0x00000000);
1784 context->Edx = W32S_WINE2APP(0xbfffffff);
1785 break;
1788 case 0x001B: /* KGlobalMemStat */
1790 * Input: ESI: Flat address of buffer to receive memory info
1792 * Output: None
1795 struct Win32sMemoryInfo
1797 DWORD DIPhys_Count; /* Total physical pages */
1798 DWORD DIFree_Count; /* Free physical pages */
1799 DWORD DILin_Total_Count; /* Total virtual pages (private arena) */
1800 DWORD DILin_Total_Free; /* Free virtual pages (private arena) */
1802 DWORD SparseTotal; /* Total size of sparse arena (bytes ?) */
1803 DWORD SparseFree; /* Free size of sparse arena (bytes ?) */
1806 struct Win32sMemoryInfo *info =
1807 (struct Win32sMemoryInfo *)W32S_APP2WINE(context->Esi);
1809 FIXME("KGlobalMemStat(%x)\n", (DWORD)info);
1811 /* FIXME */
1813 break;
1816 case 0x001C: /* Enable/Disable Exceptions */
1818 * Input: ECX: 0 to disable, 1 to enable exception handling
1820 * Output: None
1823 TRACE("[001c] ECX=%x\n", context->Ecx);
1825 /* FIXME */
1826 break;
1829 case 0x001D: /* VirtualAlloc called from 16-bit code */
1831 * Input: EDX: Segmented address of arguments on stack
1833 * LPVOID base [in] Flat address of region to reserve/commit
1834 * DWORD size [in] Size of region
1835 * DWORD type [in] Type of allocation
1836 * DWORD prot [in] Type of access protection
1838 * Output: EAX: NtStatus
1839 * EDX: Flat base address of allocated region
1842 DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) ));
1843 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]);
1844 DWORD size = stack[1];
1845 DWORD type = stack[2];
1846 DWORD prot = stack[3];
1847 DWORD result;
1849 TRACE("VirtualAlloc16(%x, %x, %x, %x)\n",
1850 (DWORD)base, size, type, prot);
1852 if (type & 0x80000000)
1854 WARN("VirtualAlloc16: strange type %x\n", type);
1855 type &= 0x7fffffff;
1858 result = (DWORD)VirtualAlloc(base, size, type, prot);
1860 if (W32S_WINE2APP(result))
1861 context->Edx = W32S_WINE2APP(result),
1862 context->Eax = STATUS_SUCCESS;
1863 else
1864 context->Edx = 0,
1865 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1866 TRACE("VirtualAlloc16: returning base %x\n", context->Edx);
1868 break;
1871 case 0x001E: /* VirtualFree called from 16-bit code */
1873 * Input: EDX: Segmented address of arguments on stack
1875 * LPVOID base [in] Flat address of region
1876 * DWORD size [in] Size of region
1877 * DWORD type [in] Type of operation
1879 * Output: EAX: NtStatus
1880 * EDX: TRUE if success, FALSE if failure
1883 DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) ));
1884 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]);
1885 DWORD size = stack[1];
1886 DWORD type = stack[2];
1887 DWORD result;
1889 TRACE("VirtualFree16(%x, %x, %x)\n",
1890 (DWORD)base, size, type);
1892 result = VirtualFree(base, size, type);
1894 if (result)
1895 context->Edx = TRUE,
1896 context->Eax = STATUS_SUCCESS;
1897 else
1898 context->Edx = FALSE,
1899 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1901 break;
1904 case 0x001F: /* FWorkingSetSize */
1906 * Input: EDX: 0 if Get, 1 if Set
1908 * ECX: Get: Buffer to receive Working Set Size
1909 * Set: Buffer containing Working Set Size
1911 * Output: NtStatus
1914 DWORD *ptr = (DWORD *)W32S_APP2WINE(context->Ecx);
1915 BOOL set = context->Edx;
1917 TRACE("FWorkingSetSize(%x, %x)\n", (DWORD)ptr, (DWORD)set);
1919 if (set)
1920 /* We do it differently ... */;
1921 else
1922 *ptr = 0x100;
1924 context->Eax = STATUS_SUCCESS;
1926 break;
1928 default:
1929 VXD_BARF( context, "W32S" );