wined3d: Fix a comment.
[wine/hramrach.git] / dlls / krnl386.exe16 / vxd.c
blobc57f1463cabf92426b04b4a7740510379ea22ca6
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 #define NONAMELESSUNION
38 #define NONAMELESSSTRUCT
39 #include "ntstatus.h"
40 #define WIN32_NO_STATUS
41 #include "windef.h"
42 #include "winbase.h"
43 #include "winerror.h"
44 #include "winternl.h"
45 #include "winioctl.h"
46 #include "kernel16_private.h"
47 #include "dosexe.h"
48 #include "wine/library.h"
49 #include "wine/unicode.h"
50 #include "wine/server.h"
51 #include "wine/debug.h"
53 WINE_DEFAULT_DEBUG_CHANNEL(vxd);
55 typedef DWORD (WINAPI *VxDCallProc)(DWORD, CONTEXT86 *);
56 typedef BOOL (WINAPI *DeviceIoProc)(DWORD, LPVOID, DWORD, LPVOID, DWORD, LPDWORD, LPOVERLAPPED);
58 struct vxd_module
60 LARGE_INTEGER index;
61 HANDLE handle;
62 HMODULE module;
63 DeviceIoProc proc;
66 struct vxdcall_service
68 WCHAR name[12];
69 DWORD service;
70 HMODULE module;
71 VxDCallProc proc;
74 #define MAX_VXD_MODULES 32
76 static struct vxd_module vxd_modules[MAX_VXD_MODULES];
78 static struct vxdcall_service vxd_services[] =
80 { {'v','m','m','.','v','x','d',0}, 0x0001, NULL, NULL },
81 { {'v','w','i','n','3','2','.','v','x','d',0}, 0x002a, NULL, NULL }
84 #define NB_VXD_SERVICES (sizeof(vxd_services)/sizeof(vxd_services[0]))
86 #define W32S_APP2WINE(addr) ((addr)? (DWORD)(addr) + W32S_offset : 0)
87 #define W32S_WINE2APP(addr) ((addr)? (DWORD)(addr) - W32S_offset : 0)
89 #define VXD_BARF(context,name) \
90 TRACE( "vxd %s: unknown/not implemented parameters:\n" \
91 "vxd %s: AX %04x, BX %04x, CX %04x, DX %04x, " \
92 "SI %04x, DI %04x, DS %04x, ES %04x\n", \
93 (name), (name), AX_reg(context), BX_reg(context), \
94 CX_reg(context), DX_reg(context), SI_reg(context), \
95 DI_reg(context), (WORD)context->SegDs, (WORD)context->SegEs )
97 static CRITICAL_SECTION vxd_section;
98 static CRITICAL_SECTION_DEBUG critsect_debug =
100 0, 0, &vxd_section,
101 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
102 0, 0, { (DWORD_PTR)(__FILE__ ": vxd_section") }
104 static CRITICAL_SECTION vxd_section = { &critsect_debug, -1, 0, 0, 0, 0 };
106 static UINT W32S_offset;
108 static WORD VXD_WinVersion(void)
110 WORD version = LOWORD(GetVersion16());
111 return (version >> 8) | (version << 8);
114 /* create a file handle to represent a VxD, by opening a dummy file in the wineserver directory */
115 static HANDLE open_vxd_handle( LPCWSTR name )
117 static const WCHAR prefixW[] = {'\\','?','?','\\','u','n','i','x'};
118 const char *dir = wine_get_server_dir();
119 int len;
120 HANDLE ret;
121 NTSTATUS status;
122 OBJECT_ATTRIBUTES attr;
123 UNICODE_STRING nameW;
124 IO_STATUS_BLOCK io;
126 len = MultiByteToWideChar( CP_UNIXCP, 0, dir, -1, NULL, 0 );
127 nameW.Length = sizeof(prefixW) + (len + strlenW( name )) * sizeof(WCHAR);
128 nameW.MaximumLength = nameW.Length + sizeof(WCHAR);
129 if (!(nameW.Buffer = HeapAlloc( GetProcessHeap(), 0, nameW.MaximumLength )))
131 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
132 return 0;
134 memcpy( nameW.Buffer, prefixW, sizeof(prefixW) );
135 MultiByteToWideChar( CP_UNIXCP, 0, dir, -1, nameW.Buffer + sizeof(prefixW)/sizeof(WCHAR), len );
136 len += sizeof(prefixW) / sizeof(WCHAR);
137 nameW.Buffer[len-1] = '/';
138 strcpyW( nameW.Buffer + len, name );
140 attr.Length = sizeof(attr);
141 attr.RootDirectory = 0;
142 attr.Attributes = 0;
143 attr.ObjectName = &nameW;
144 attr.SecurityDescriptor = NULL;
145 attr.SecurityQualityOfService = NULL;
147 status = NtCreateFile( &ret, 0, &attr, &io, NULL, 0,
148 FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN_IF,
149 FILE_SYNCHRONOUS_IO_ALERT, NULL, 0 );
150 if (status)
152 ret = 0;
153 SetLastError( RtlNtStatusToDosError(status) );
155 RtlFreeUnicodeString( &nameW );
156 return ret;
159 /* retrieve the DeviceIoControl function for a Vxd given a file handle */
160 DeviceIoProc __wine_vxd_get_proc( HANDLE handle )
162 DeviceIoProc ret = NULL;
163 int status, i;
164 IO_STATUS_BLOCK io;
165 FILE_INTERNAL_INFORMATION info;
167 status = NtQueryInformationFile( handle, &io, &info, sizeof(info), FileInternalInformation );
168 if (status)
170 SetLastError( RtlNtStatusToDosError(status) );
171 return NULL;
174 RtlEnterCriticalSection( &vxd_section );
176 for (i = 0; i < MAX_VXD_MODULES; i++)
178 if (!vxd_modules[i].module) break;
179 if (vxd_modules[i].index.QuadPart == info.IndexNumber.QuadPart)
181 if (!(ret = vxd_modules[i].proc)) SetLastError( ERROR_INVALID_FUNCTION );
182 goto done;
185 /* FIXME: Here we could go through the directory to find the VxD name and load it. */
186 /* Let's wait to find out if there are actually apps out there that try to share */
187 /* VxD handles between processes, before we go to the trouble of implementing it. */
188 ERR( "handle %p not found in module list, inherited from another process?\n", handle );
190 done:
191 RtlLeaveCriticalSection( &vxd_section );
192 return ret;
196 /* load a VxD and return a file handle to it */
197 HANDLE __wine_vxd_open( LPCWSTR filenameW, DWORD access, SECURITY_ATTRIBUTES *sa )
199 static const WCHAR dotVxDW[] = {'.','v','x','d',0};
200 int i;
201 HANDLE handle;
202 HMODULE module;
203 WCHAR *p, name[16];
205 /* normalize the filename */
207 if (strlenW( filenameW ) >= sizeof(name)/sizeof(WCHAR) - 4 ||
208 strchrW( filenameW, '/' ) || strchrW( filenameW, '\\' ))
210 SetLastError( ERROR_FILE_NOT_FOUND );
211 return 0;
213 strcpyW( name, filenameW );
214 strlwrW( name );
215 p = strchrW( name, '.' );
216 if (!p) strcatW( name, dotVxDW );
217 else if (strcmpiW( p, dotVxDW )) /* existing extension has to be .vxd */
219 SetLastError( ERROR_FILE_NOT_FOUND );
220 return 0;
223 /* try to load the module first */
225 if (!(module = LoadLibraryW( name )))
227 FIXME( "Unknown/unsupported VxD %s. Try setting Windows version to 'nt40' or 'win31'.\n",
228 debugstr_w(name) );
229 SetLastError( ERROR_FILE_NOT_FOUND );
230 return 0;
233 /* register the module in the global list if necessary */
235 RtlEnterCriticalSection( &vxd_section );
237 for (i = 0; i < MAX_VXD_MODULES; i++)
239 if (vxd_modules[i].module == module)
241 handle = vxd_modules[i].handle;
242 goto done; /* already registered */
244 if (!vxd_modules[i].module) /* new one, register it */
246 IO_STATUS_BLOCK io;
247 FILE_INTERNAL_INFORMATION info;
249 /* get a file handle to the dummy file */
250 if (!(handle = open_vxd_handle( name )))
252 FreeLibrary( module );
253 goto done;
255 if (!NtQueryInformationFile( handle, &io, &info, sizeof(info), FileInternalInformation ))
256 vxd_modules[i].index = info.IndexNumber;
258 vxd_modules[i].module = module;
259 vxd_modules[i].handle = handle;
260 vxd_modules[i].proc = (DeviceIoProc)GetProcAddress( module, "DeviceIoControl" );
261 goto done;
265 ERR("too many open VxD modules, please report\n" );
266 FreeLibrary( module );
267 handle = 0;
269 done:
270 RtlLeaveCriticalSection( &vxd_section );
271 if (!DuplicateHandle( GetCurrentProcess(), handle, GetCurrentProcess(), &handle, 0,
272 (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle),
273 DUP_HANDLE_SAME_ACCESS ))
274 handle = 0;
275 return handle;
279 /***********************************************************************
280 * VxDCall0 (KERNEL32.1)
281 * VxDCall1 (KERNEL32.2)
282 * VxDCall2 (KERNEL32.3)
283 * VxDCall3 (KERNEL32.4)
284 * VxDCall4 (KERNEL32.5)
285 * VxDCall5 (KERNEL32.6)
286 * VxDCall6 (KERNEL32.7)
287 * VxDCall7 (KERNEL32.8)
288 * VxDCall8 (KERNEL32.9)
290 void WINAPI __regs_VxDCall( DWORD service, CONTEXT86 *context )
292 unsigned int i;
293 VxDCallProc proc = NULL;
295 RtlEnterCriticalSection( &vxd_section );
296 for (i = 0; i < NB_VXD_SERVICES; i++)
298 if (HIWORD(service) != vxd_services[i].service) continue;
299 if (!vxd_services[i].module) /* need to load it */
301 if ((vxd_services[i].module = LoadLibraryW( vxd_services[i].name )))
302 vxd_services[i].proc = (VxDCallProc)GetProcAddress( vxd_services[i].module, "VxDCall" );
304 proc = vxd_services[i].proc;
305 break;
307 RtlLeaveCriticalSection( &vxd_section );
309 if (proc) context->Eax = proc( service, context );
310 else
312 FIXME( "Unknown/unimplemented VxD (%08x)\n", service);
313 context->Eax = 0xffffffff; /* FIXME */
316 #ifdef DEFINE_REGS_ENTRYPOINT
317 DEFINE_REGS_ENTRYPOINT( VxDCall, 1 )
318 #endif
321 /***********************************************************************
322 * __wine_vxd_vmm (WPROCS.401)
324 void WINAPI __wine_vxd_vmm ( CONTEXT86 *context )
326 unsigned service = AX_reg(context);
328 TRACE("[%04x] VMM\n", (UINT16)service);
330 switch(service)
332 case 0x0000: /* version */
333 SET_AX( context, VXD_WinVersion() );
334 RESET_CFLAG(context);
335 break;
337 case 0x026d: /* Get_Debug_Flag '/m' */
338 case 0x026e: /* Get_Debug_Flag '/n' */
339 SET_AL( context, 0 );
340 RESET_CFLAG(context);
341 break;
343 default:
344 VXD_BARF( context, "VMM" );
348 /***********************************************************************
349 * __wine_vxd_pagefile (WPROCS.433)
351 void WINAPI __wine_vxd_pagefile( CONTEXT86 *context )
353 unsigned service = AX_reg(context);
355 /* taken from Ralf Brown's Interrupt List */
357 TRACE("[%04x] PageFile\n", (UINT16)service );
359 switch(service)
361 case 0x00: /* get version, is this windows version? */
362 TRACE("returning version\n");
363 SET_AX( context, VXD_WinVersion() );
364 RESET_CFLAG(context);
365 break;
367 case 0x01: /* get swap file info */
368 TRACE("VxD PageFile: returning swap file info\n");
369 SET_AX( context, 0x00 ); /* paging disabled */
370 context->Ecx = 0; /* maximum size of paging file */
371 /* FIXME: do I touch DS:SI or DS:DI? */
372 RESET_CFLAG(context);
373 break;
375 case 0x02: /* delete permanent swap on exit */
376 TRACE("VxD PageFile: supposed to delete swap\n");
377 RESET_CFLAG(context);
378 break;
380 case 0x03: /* current temporary swap file size */
381 TRACE("VxD PageFile: what is current temp. swap size\n");
382 RESET_CFLAG(context);
383 break;
385 case 0x04: /* read or write?? INTERRUP.D */
386 case 0x05: /* cancel?? INTERRUP.D */
387 case 0x06: /* test I/O valid INTERRUP.D */
388 default:
389 VXD_BARF( context, "pagefile" );
390 break;
394 /***********************************************************************
395 * __wine_vxd_reboot (WPROCS.409)
397 void WINAPI __wine_vxd_reboot( CONTEXT86 *context )
399 unsigned service = AX_reg(context);
401 TRACE("[%04x] Reboot\n", (UINT16)service);
403 switch(service)
405 case 0x0000: /* version */
406 SET_AX( context, VXD_WinVersion() );
407 RESET_CFLAG(context);
408 break;
410 default:
411 VXD_BARF( context, "REBOOT" );
415 /***********************************************************************
416 * __wine_vxd_vdd (WPROCS.410)
418 void WINAPI __wine_vxd_vdd( CONTEXT86 *context )
420 unsigned service = AX_reg(context);
422 TRACE("[%04x] VDD\n", (UINT16)service);
424 switch(service)
426 case 0x0000: /* version */
427 SET_AX( context, VXD_WinVersion() );
428 RESET_CFLAG(context);
429 break;
431 default:
432 VXD_BARF( context, "VDD" );
436 /***********************************************************************
437 * __wine_vxd_vmd (WPROCS.412)
439 void WINAPI __wine_vxd_vmd( CONTEXT86 *context )
441 unsigned service = AX_reg(context);
443 TRACE("[%04x] VMD\n", (UINT16)service);
445 switch(service)
447 case 0x0000: /* version */
448 SET_AX( context, VXD_WinVersion() );
449 RESET_CFLAG(context);
450 break;
452 default:
453 VXD_BARF( context, "VMD" );
457 /***********************************************************************
458 * __wine_vxd_vxdloader (WPROCS.439)
460 void WINAPI __wine_vxd_vxdloader( CONTEXT86 *context )
462 unsigned service = AX_reg(context);
464 TRACE("[%04x] VXDLoader\n", (UINT16)service);
466 switch (service)
468 case 0x0000: /* get version */
469 TRACE("returning version\n");
470 SET_AX( context, 0x0000 );
471 SET_DX( context, VXD_WinVersion() );
472 RESET_CFLAG(context);
473 break;
475 case 0x0001: /* load device */
476 FIXME("load device %04x:%04x (%s)\n",
477 context->SegDs, DX_reg(context),
478 debugstr_a(MapSL(MAKESEGPTR(context->SegDs, DX_reg(context)))));
479 SET_AX( context, 0x0000 );
480 context->SegEs = 0x0000;
481 SET_DI( context, 0x0000 );
482 RESET_CFLAG(context);
483 break;
485 case 0x0002: /* unload device */
486 FIXME("unload device (%08x)\n", context->Ebx);
487 SET_AX( context, 0x0000 );
488 RESET_CFLAG(context);
489 break;
491 default:
492 VXD_BARF( context, "VXDLDR" );
493 SET_AX( context, 0x000B ); /* invalid function number */
494 SET_CFLAG(context);
495 break;
499 /***********************************************************************
500 * __wine_vxd_shell (WPROCS.423)
502 void WINAPI __wine_vxd_shell( CONTEXT86 *context )
504 unsigned service = DX_reg(context);
506 TRACE("[%04x] Shell\n", (UINT16)service);
508 switch (service) /* Ralf Brown says EDX, but I use DX instead */
510 case 0x0000:
511 TRACE("returning version\n");
512 SET_AX( context, VXD_WinVersion() );
513 context->Ebx = 1; /* system VM Handle */
514 break;
516 case 0x0001:
517 case 0x0002:
518 case 0x0003:
519 /* SHELL_SYSMODAL_Message
520 ebx virtual machine handle
521 eax message box flags
522 ecx address of message
523 edi address of caption
524 return response in eax
526 case 0x0004:
527 /* SHELL_Message
528 ebx virtual machine handle
529 eax message box flags
530 ecx address of message
531 edi address of caption
532 esi address callback
533 edx reference data for callback
534 return response in eax
536 case 0x0005:
537 VXD_BARF( context, "shell" );
538 break;
540 case 0x0006: /* SHELL_Get_VM_State */
541 TRACE("VxD Shell: returning VM state\n");
542 /* Actually we don't, not yet. We have to return a structure
543 * and I am not to sure how to set it up and return it yet,
544 * so for now let's do nothing. I can (hopefully) get this
545 * by the next release
547 /* RESET_CFLAG(context); */
548 break;
550 case 0x0007:
551 case 0x0008:
552 case 0x0009:
553 case 0x000A:
554 case 0x000B:
555 case 0x000C:
556 case 0x000D:
557 case 0x000E:
558 case 0x000F:
559 case 0x0010:
560 case 0x0011:
561 case 0x0012:
562 case 0x0013:
563 case 0x0014:
564 case 0x0015:
565 case 0x0016:
566 VXD_BARF( context, "SHELL" );
567 break;
569 /* the new Win95 shell API */
570 case 0x0100: /* get version */
571 SET_AX( context, VXD_WinVersion() );
572 break;
574 case 0x0104: /* retrieve Hook_Properties list */
575 case 0x0105: /* call Hook_Properties callbacks */
576 VXD_BARF( context, "SHELL" );
577 break;
579 case 0x0106: /* install timeout callback */
580 TRACE("VxD Shell: ignoring shell callback (%d sec.)\n", context->Ebx);
581 SET_CFLAG(context);
582 break;
584 case 0x0107: /* get version of any VxD */
585 default:
586 VXD_BARF( context, "SHELL" );
587 break;
592 /***********************************************************************
593 * __wine_vxd_comm (WPROCS.414)
595 void WINAPI __wine_vxd_comm( CONTEXT86 *context )
597 unsigned service = AX_reg(context);
599 TRACE("[%04x] Comm\n", (UINT16)service);
601 switch (service)
603 case 0x0000: /* get version */
604 TRACE("returning version\n");
605 SET_AX( context, VXD_WinVersion() );
606 RESET_CFLAG(context);
607 break;
609 case 0x0001: /* set port global */
610 case 0x0002: /* get focus */
611 case 0x0003: /* virtualise port */
612 default:
613 VXD_BARF( context, "comm" );
617 /***********************************************************************
618 * __wine_vxd_timer (WPROCS.405)
620 void WINAPI __wine_vxd_timer( CONTEXT86 *context )
622 unsigned service = AX_reg(context);
624 TRACE("[%04x] Virtual Timer\n", (UINT16)service);
626 switch(service)
628 case 0x0000: /* version */
629 SET_AX( context, VXD_WinVersion() );
630 RESET_CFLAG(context);
631 break;
633 case 0x0100: /* clock tick time, in 840nsecs */
634 context->Eax = GetTickCount();
636 context->Edx = context->Eax >> 22;
637 context->Eax <<= 10; /* not very precise */
638 break;
640 case 0x0101: /* current Windows time, msecs */
641 case 0x0102: /* current VM time, msecs */
642 context->Eax = GetTickCount();
643 break;
645 default:
646 VXD_BARF( context, "VTD" );
651 /***********************************************************************
652 * timer_thread
654 static DWORD CALLBACK timer_thread( void *arg )
656 DWORD *system_time = arg;
658 for (;;)
660 *system_time = GetTickCount();
661 Sleep( 55 );
664 return 0;
668 /***********************************************************************
669 * __wine_vxd_timerapi (WPROCS.1490)
671 void WINAPI __wine_vxd_timerapi( CONTEXT86 *context )
673 static WORD System_Time_Selector;
675 unsigned service = AX_reg(context);
677 TRACE("[%04x] TimerAPI\n", (UINT16)service);
679 switch(service)
681 case 0x0000: /* version */
682 SET_AX( context, VXD_WinVersion() );
683 RESET_CFLAG(context);
684 break;
686 case 0x0009: /* get system time selector */
687 if ( !System_Time_Selector )
689 HANDLE16 handle = GlobalAlloc16( GMEM_FIXED, sizeof(DWORD) );
690 System_Time_Selector = handle | 7;
691 CloseHandle( CreateThread( NULL, 0, timer_thread, GlobalLock16(handle), 0, NULL ) );
693 SET_AX( context, System_Time_Selector );
694 RESET_CFLAG(context);
695 break;
697 default:
698 VXD_BARF( context, "VTDAPI" );
702 /***********************************************************************
703 * __wine_vxd_configmg (WPROCS.451)
705 void WINAPI __wine_vxd_configmg( CONTEXT86 *context )
707 unsigned service = AX_reg(context);
709 TRACE("[%04x] ConfigMG\n", (UINT16)service);
711 switch(service)
713 case 0x0000: /* version */
714 SET_AX( context, VXD_WinVersion() );
715 RESET_CFLAG(context);
716 break;
718 default:
719 VXD_BARF( context, "CONFIGMG" );
723 /***********************************************************************
724 * __wine_vxd_enable (WPROCS.455)
726 void WINAPI __wine_vxd_enable( CONTEXT86 *context )
728 unsigned service = AX_reg(context);
730 TRACE("[%04x] Enable\n", (UINT16)service);
732 switch(service)
734 case 0x0000: /* version */
735 SET_AX( context, VXD_WinVersion() );
736 RESET_CFLAG(context);
737 break;
739 default:
740 VXD_BARF( context, "ENABLE" );
744 /***********************************************************************
745 * __wine_vxd_apm (WPROCS.438)
747 void WINAPI __wine_vxd_apm( CONTEXT86 *context )
749 unsigned service = AX_reg(context);
751 TRACE("[%04x] APM\n", (UINT16)service);
753 switch(service)
755 case 0x0000: /* version */
756 SET_AX( context, VXD_WinVersion() );
757 RESET_CFLAG(context);
758 break;
760 default:
761 VXD_BARF( context, "APM" );
765 /***********************************************************************
766 * __wine_vxd_win32s (WPROCS.445)
768 * This is an implementation of the services of the Win32s VxD.
769 * Since official documentation of these does not seem to be available,
770 * certain arguments of some of the services remain unclear.
772 * FIXME: The following services are currently unimplemented:
773 * Exception handling (0x01, 0x1C)
774 * Debugger support (0x0C, 0x14, 0x17)
775 * Low-level memory access (0x02, 0x03, 0x0A, 0x0B)
776 * Memory Statistics (0x1B)
779 * We have a specific problem running Win32s on Linux (and probably also
780 * the other x86 unixes), since Win32s tries to allocate its main 'flat
781 * code/data segment' selectors with a base of 0xffff0000 (and limit 4GB).
782 * The rationale for this seems to be that they want one the one hand to
783 * be able to leave the Win 3.1 memory (starting with the main DOS memory)
784 * at linear address 0, but want at other hand to have offset 0 of the
785 * flat data/code segment point to an unmapped page (to catch NULL pointer
786 * accesses). Hence they allocate the flat segments with a base of 0xffff0000
787 * so that the Win 3.1 memory area at linear address zero shows up in the
788 * flat segments at offset 0x10000 (since linear addresses wrap around at
789 * 4GB). To compensate for that discrepancy between flat segment offsets
790 * and plain linear addresses, all flat pointers passed between the 32-bit
791 * and the 16-bit parts of Win32s are shifted by 0x10000 in the appropriate
792 * direction by the glue code (mainly) in W32SKRNL and WIN32S16.
794 * The problem for us is now that Linux does not allow a LDT selector with
795 * base 0xffff0000 to be created, since it would 'see' a part of the kernel
796 * address space. To address this problem we introduce *another* offset:
797 * We add 0x10000 to every linear address we get as an argument from Win32s.
798 * This means especially that the flat code/data selectors get actually
799 * allocated with base 0x0, so that flat offsets and (real) linear addresses
800 * do again agree! In fact, every call e.g. of a Win32s VxD service now
801 * has all pointer arguments (which are offsets in the flat data segment)
802 * first reduced by 0x10000 by the W32SKRNL glue code, and then again
803 * increased by 0x10000 by *our* code.
805 * Note that to keep everything consistent, this offset has to be applied by
806 * every Wine function that operates on 'linear addresses' passed to it by
807 * Win32s. Fortunately, since Win32s does not directly call any Wine 32-bit
808 * API routines, this affects only two locations: this VxD and the DPMI
809 * handler. (NOTE: Should any Win32s application pass a linear address to
810 * any routine apart from those, e.g. some other VxD handler, that code
811 * would have to take the offset into account as well!)
813 * The offset is set the first time any application calls the GetVersion()
814 * service of the Win32s VxD. (Note that the offset is never reset.)
817 void WINAPI __wine_vxd_win32s( CONTEXT86 *context )
819 switch (AX_reg(context))
821 case 0x0000: /* Get Version */
823 * Input: None
825 * Output: EAX: LoWord: Win32s Version (1.30)
826 * HiWord: VxD Version (200)
828 * EBX: Build (172)
830 * ECX: ??? (1)
832 * EDX: Debugging Flags
834 * EDI: Error Flag
835 * 0 if OK,
836 * 1 if VMCPD VxD not found
839 TRACE("GetVersion()\n");
841 context->Eax = VXD_WinVersion() | (200 << 16);
842 context->Ebx = 0;
843 context->Ecx = 0;
844 context->Edx = 0;
845 context->Edi = 0;
848 * If this is the first time we are called for this process,
849 * hack the memory image of WIN32S16 so that it doesn't try
850 * to access the GDT directly ...
852 * The first code segment of WIN32S16 (version 1.30) contains
853 * an unexported function somewhere between the exported functions
854 * SetFS and StackLinearToSegmented that tries to find a selector
855 * in the LDT that maps to the memory image of the LDT itself.
856 * If it succeeds, it stores this selector into a global variable
857 * which will be used to speed up execution by using this selector
858 * to modify the LDT directly instead of using the DPMI calls.
860 * To perform this search of the LDT, this function uses the
861 * sgdt and sldt instructions to find the linear address of
862 * the (GDT and then) LDT. While those instructions themselves
863 * execute without problem, the linear address that sgdt returns
864 * points (at least under Linux) to the kernel address space, so
865 * that any subsequent access leads to a segfault.
867 * Fortunately, WIN32S16 still contains as a fallback option the
868 * mechanism of using DPMI calls to modify LDT selectors instead
869 * of direct writes to the LDT. Thus we can circumvent the problem
870 * by simply replacing the first byte of the offending function
871 * with an 'retf' instruction. This means that the global variable
872 * supposed to contain the LDT alias selector will remain zero,
873 * and hence WIN32S16 will fall back to using DPMI calls.
875 * The heuristic we employ to _find_ that function is as follows:
876 * We search between the addresses of the exported symbols SetFS
877 * and StackLinearToSegmented for the byte sequence '0F 01 04'
878 * (this is the opcode of 'sgdt [si]'). We then search backwards
879 * from this address for the last occurrence of 'CB' (retf) that marks
880 * the end of the preceding function. The following byte (which
881 * should now be the first byte of the function we are looking for)
882 * will be replaced by 'CB' (retf).
884 * This heuristic works for the retail as well as the debug version
885 * of Win32s version 1.30. For versions earlier than that this
886 * hack should not be necessary at all, since the whole mechanism
887 * ('PERF130') was introduced only in 1.30 to improve the overall
888 * performance of Win32s.
891 if (!W32S_offset)
893 HMODULE16 hModule = GetModuleHandle16("win32s16");
894 SEGPTR func1 = (SEGPTR)GetProcAddress16(hModule, "SetFS");
895 SEGPTR func2 = (SEGPTR)GetProcAddress16(hModule, "StackLinearToSegmented");
897 if ( hModule && func1 && func2
898 && SELECTOROF(func1) == SELECTOROF(func2))
900 BYTE *start = MapSL(func1);
901 BYTE *end = MapSL(func2);
902 BYTE *p, *retv = NULL;
903 int found = 0;
905 for (p = start; p < end; p++)
906 if (*p == 0xCB) found = 0, retv = p;
907 else if (*p == 0x0F) found = 1;
908 else if (*p == 0x01 && found == 1) found = 2;
909 else if (*p == 0x04 && found == 2) { found = 3; break; }
910 else found = 0;
912 if (found == 3 && retv)
914 TRACE("PERF130 hack: "
915 "Replacing byte %02X at offset %04X:%04X\n",
916 *(retv+1), SELECTOROF(func1),
917 OFFSETOF(func1) + retv+1-start);
919 *(retv+1) = (BYTE)0xCB;
925 * Mark process as Win32s, so that subsequent DPMI calls
926 * will perform the W32S_APP2WINE/W32S_WINE2APP address shift.
928 W32S_offset = 0x10000;
929 break;
932 case 0x0001: /* Install Exception Handling */
934 * Input: EBX: Flat address of W32SKRNL Exception Data
936 * ECX: LoWord: Flat Code Selector
937 * HiWord: Flat Data Selector
939 * EDX: Flat address of W32SKRNL Exception Handler
940 * (this is equal to W32S_BackTo32 + 0x40)
942 * ESI: SEGPTR KERNEL.HASGPHANDLER
944 * EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10)
946 * Output: EAX: 0 if OK
949 TRACE("[0001] EBX=%x ECX=%x EDX=%x ESI=%x EDI=%x\n",
950 context->Ebx, context->Ecx, context->Edx,
951 context->Esi, context->Edi);
953 /* FIXME */
955 context->Eax = 0;
956 break;
959 case 0x0002: /* Set Page Access Flags */
961 * Input: EBX: New access flags
962 * Bit 2: User Page if set, Supervisor Page if clear
963 * Bit 1: Read-Write if set, Read-Only if clear
965 * ECX: Size of memory area to change
967 * EDX: Flat start address of memory area
969 * Output: EAX: Size of area changed
972 TRACE("[0002] EBX=%x ECX=%x EDX=%x\n",
973 context->Ebx, context->Ecx, context->Edx);
975 /* FIXME */
977 context->Eax = context->Ecx;
978 break;
981 case 0x0003: /* Get Page Access Flags */
983 * Input: EDX: Flat address of page to query
985 * Output: EAX: Page access flags
986 * Bit 2: User Page if set, Supervisor Page if clear
987 * Bit 1: Read-Write if set, Read-Only if clear
990 TRACE("[0003] EDX=%x\n", context->Edx);
992 /* FIXME */
994 context->Eax = 6;
995 break;
998 case 0x0004: /* Map Module */
1000 * Input: ECX: IMTE (offset in Module Table) of new module
1002 * EDX: Flat address of Win32s Module Table
1004 * Output: EAX: 0 if OK
1007 if (!context->Edx || CX_reg(context) == 0xFFFF)
1009 TRACE("MapModule: Initialization call\n");
1010 context->Eax = 0;
1012 else
1015 * Structure of a Win32s Module Table Entry:
1017 struct Win32sModule
1019 DWORD flags;
1020 DWORD flatBaseAddr;
1021 LPCSTR moduleName;
1022 LPCSTR pathName;
1023 LPCSTR unknown;
1024 LPBYTE baseAddr;
1025 DWORD hModule;
1026 DWORD relocDelta;
1030 * Note: This function should set up a demand-paged memory image
1031 * of the given module. Since mmap does not allow file offsets
1032 * not aligned at 1024 bytes, we simply load the image fully
1033 * into memory.
1036 struct Win32sModule *moduleTable =
1037 (struct Win32sModule *)W32S_APP2WINE(context->Edx);
1038 struct Win32sModule *module = moduleTable + context->Ecx;
1040 IMAGE_NT_HEADERS *nt_header = RtlImageNtHeader( (HMODULE)module->baseAddr );
1041 IMAGE_SECTION_HEADER *pe_seg = (IMAGE_SECTION_HEADER*)((char *)&nt_header->OptionalHeader +
1042 nt_header->FileHeader.SizeOfOptionalHeader);
1045 HFILE image = _lopen(module->pathName, OF_READ);
1046 BOOL error = (image == HFILE_ERROR);
1047 UINT i;
1049 TRACE("MapModule: Loading %s\n", module->pathName);
1051 for (i = 0;
1052 !error && i < nt_header->FileHeader.NumberOfSections;
1053 i++, pe_seg++)
1054 if(!(pe_seg->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA))
1056 DWORD off = pe_seg->PointerToRawData;
1057 DWORD len = pe_seg->SizeOfRawData;
1058 LPBYTE addr = module->baseAddr + pe_seg->VirtualAddress;
1060 TRACE("MapModule: "
1061 "Section %d at %08x from %08x len %08x\n",
1062 i, (DWORD)addr, off, len);
1064 if ( _llseek(image, off, SEEK_SET) != off
1065 || _lread(image, addr, len) != len)
1066 error = TRUE;
1069 _lclose(image);
1071 if (error)
1072 ERR("MapModule: Unable to load %s\n", module->pathName);
1074 else if (module->relocDelta != 0)
1076 IMAGE_DATA_DIRECTORY *dir = nt_header->OptionalHeader.DataDirectory
1077 + IMAGE_DIRECTORY_ENTRY_BASERELOC;
1078 IMAGE_BASE_RELOCATION *r = (IMAGE_BASE_RELOCATION *)
1079 (dir->Size? module->baseAddr + dir->VirtualAddress : 0);
1081 TRACE("MapModule: Reloc delta %08x\n", module->relocDelta);
1083 while (r && r->VirtualAddress)
1085 LPBYTE page = module->baseAddr + r->VirtualAddress;
1086 WORD *TypeOffset = (WORD *)(r + 1);
1087 unsigned int count = (r->SizeOfBlock - sizeof(*r)) / sizeof(*TypeOffset);
1089 TRACE("MapModule: %d relocations for page %08x\n",
1090 count, (DWORD)page);
1092 for(i = 0; i < count; i++)
1094 int offset = TypeOffset[i] & 0xFFF;
1095 int type = TypeOffset[i] >> 12;
1096 switch(type)
1098 case IMAGE_REL_BASED_ABSOLUTE:
1099 break;
1100 case IMAGE_REL_BASED_HIGH:
1101 *(WORD *)(page+offset) += HIWORD(module->relocDelta);
1102 break;
1103 case IMAGE_REL_BASED_LOW:
1104 *(WORD *)(page+offset) += LOWORD(module->relocDelta);
1105 break;
1106 case IMAGE_REL_BASED_HIGHLOW:
1107 *(DWORD*)(page+offset) += module->relocDelta;
1108 break;
1109 default:
1110 WARN("MapModule: Unsupported fixup type\n");
1111 break;
1115 r = (IMAGE_BASE_RELOCATION *)((LPBYTE)r + r->SizeOfBlock);
1119 context->Eax = 0;
1120 RESET_CFLAG(context);
1122 break;
1125 case 0x0005: /* UnMap Module */
1127 * Input: EDX: Flat address of module image
1129 * Output: EAX: 1 if OK
1132 TRACE("UnMapModule: %x\n", W32S_APP2WINE(context->Edx));
1134 /* As we didn't map anything, there's nothing to unmap ... */
1136 context->Eax = 1;
1137 break;
1140 case 0x0006: /* VirtualAlloc */
1142 * Input: ECX: Current Process
1144 * EDX: Flat address of arguments on stack
1146 * DWORD *retv [out] Flat base address of allocated region
1147 * LPVOID base [in] Flat address of region to reserve/commit
1148 * DWORD size [in] Size of region
1149 * DWORD type [in] Type of allocation
1150 * DWORD prot [in] Type of access protection
1152 * Output: EAX: NtStatus
1155 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1156 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1157 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1158 DWORD size = stack[2];
1159 DWORD type = stack[3];
1160 DWORD prot = stack[4];
1161 DWORD result;
1163 TRACE("VirtualAlloc(%x, %x, %x, %x, %x)\n",
1164 (DWORD)retv, (DWORD)base, size, type, prot);
1166 if (type & 0x80000000)
1168 WARN("VirtualAlloc: strange type %x\n", type);
1169 type &= 0x7fffffff;
1172 if (!base && (type & MEM_COMMIT) && prot == PAGE_READONLY)
1174 WARN("VirtualAlloc: NLS hack, allowing write access!\n");
1175 prot = PAGE_READWRITE;
1178 result = (DWORD)VirtualAlloc(base, size, type, prot);
1180 if (W32S_WINE2APP(result))
1181 *retv = W32S_WINE2APP(result),
1182 context->Eax = STATUS_SUCCESS;
1183 else
1184 *retv = 0,
1185 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1187 break;
1190 case 0x0007: /* VirtualFree */
1192 * Input: ECX: Current Process
1194 * EDX: Flat address of arguments on stack
1196 * DWORD *retv [out] TRUE if success, FALSE if failure
1197 * LPVOID base [in] Flat address of region
1198 * DWORD size [in] Size of region
1199 * DWORD type [in] Type of operation
1201 * Output: EAX: NtStatus
1204 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1205 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1206 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1207 DWORD size = stack[2];
1208 DWORD type = stack[3];
1209 DWORD result;
1211 TRACE("VirtualFree(%x, %x, %x, %x)\n",
1212 (DWORD)retv, (DWORD)base, size, type);
1214 result = VirtualFree(base, size, type);
1216 if (result)
1217 *retv = TRUE,
1218 context->Eax = STATUS_SUCCESS;
1219 else
1220 *retv = FALSE,
1221 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1223 break;
1226 case 0x0008: /* VirtualProtect */
1228 * Input: ECX: Current Process
1230 * EDX: Flat address of arguments on stack
1232 * DWORD *retv [out] TRUE if success, FALSE if failure
1233 * LPVOID base [in] Flat address of region
1234 * DWORD size [in] Size of region
1235 * DWORD new_prot [in] Desired access protection
1236 * DWORD *old_prot [out] Previous access protection
1238 * Output: EAX: NtStatus
1241 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1242 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1243 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1244 DWORD size = stack[2];
1245 DWORD new_prot = stack[3];
1246 DWORD *old_prot = (DWORD *)W32S_APP2WINE(stack[4]);
1247 DWORD result;
1249 TRACE("VirtualProtect(%x, %x, %x, %x, %x)\n",
1250 (DWORD)retv, (DWORD)base, size, new_prot, (DWORD)old_prot);
1252 result = VirtualProtect(base, size, new_prot, old_prot);
1254 if (result)
1255 *retv = TRUE,
1256 context->Eax = STATUS_SUCCESS;
1257 else
1258 *retv = FALSE,
1259 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1261 break;
1264 case 0x0009: /* VirtualQuery */
1266 * Input: ECX: Current Process
1268 * EDX: Flat address of arguments on stack
1270 * DWORD *retv [out] Nr. bytes returned
1271 * LPVOID base [in] Flat address of region
1272 * LPMEMORY_BASIC_INFORMATION info [out] Info buffer
1273 * DWORD len [in] Size of buffer
1275 * Output: EAX: NtStatus
1278 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1279 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1280 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1281 PMEMORY_BASIC_INFORMATION info =
1282 (PMEMORY_BASIC_INFORMATION)W32S_APP2WINE(stack[2]);
1283 DWORD len = stack[3];
1284 DWORD result;
1286 TRACE("VirtualQuery(%x, %x, %x, %x)\n",
1287 (DWORD)retv, (DWORD)base, (DWORD)info, len);
1289 result = VirtualQuery(base, info, len);
1291 *retv = result;
1292 context->Eax = STATUS_SUCCESS;
1294 break;
1297 case 0x000A: /* SetVirtMemProcess */
1299 * Input: ECX: Process Handle
1301 * EDX: Flat address of region
1303 * Output: EAX: NtStatus
1306 TRACE("[000a] ECX=%x EDX=%x\n",
1307 context->Ecx, context->Edx);
1309 /* FIXME */
1311 context->Eax = STATUS_SUCCESS;
1312 break;
1315 case 0x000B: /* ??? some kind of cleanup */
1317 * Input: ECX: Process Handle
1319 * Output: EAX: NtStatus
1322 TRACE("[000b] ECX=%x\n", context->Ecx);
1324 /* FIXME */
1326 context->Eax = STATUS_SUCCESS;
1327 break;
1330 case 0x000C: /* Set Debug Flags */
1332 * Input: EDX: Debug Flags
1334 * Output: EDX: Previous Debug Flags
1337 FIXME("[000c] EDX=%x\n", context->Edx);
1339 /* FIXME */
1341 context->Edx = 0;
1342 break;
1345 case 0x000D: /* NtCreateSection */
1347 * Input: EDX: Flat address of arguments on stack
1349 * HANDLE32 *retv [out] Handle of Section created
1350 * DWORD flags1 [in] (?? unknown ??)
1351 * DWORD atom [in] Name of Section to create
1352 * LARGE_INTEGER *size [in] Size of Section
1353 * DWORD protect [in] Access protection
1354 * DWORD flags2 [in] (?? unknown ??)
1355 * HFILE32 hFile [in] Handle of file to map
1356 * DWORD psp [in] (Win32s: PSP that hFile belongs to)
1358 * Output: EAX: NtStatus
1361 DWORD *stack = (DWORD *) W32S_APP2WINE(context->Edx);
1362 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]);
1363 DWORD flags1 = stack[1];
1364 DWORD atom = stack[2];
1365 LARGE_INTEGER *size = (LARGE_INTEGER *)W32S_APP2WINE(stack[3]);
1366 DWORD protect = stack[4];
1367 DWORD flags2 = stack[5];
1368 HANDLE hFile = DosFileHandleToWin32Handle(stack[6]);
1369 DWORD psp = stack[7];
1371 HANDLE result = INVALID_HANDLE_VALUE;
1372 char name[128];
1374 TRACE("NtCreateSection(%x, %x, %x, %x, %x, %x, %x, %x)\n",
1375 (DWORD)retv, flags1, atom, (DWORD)size, protect, flags2,
1376 (DWORD)hFile, psp);
1378 if (!atom || GlobalGetAtomNameA(atom, name, sizeof(name)))
1380 TRACE("NtCreateSection: name=%s\n", atom? name : NULL);
1382 result = CreateFileMappingA(hFile, NULL, protect,
1383 size? size->u.HighPart : 0,
1384 size? size->u.LowPart : 0,
1385 atom? name : NULL);
1388 if (result == INVALID_HANDLE_VALUE)
1389 WARN("NtCreateSection: failed!\n");
1390 else
1391 TRACE("NtCreateSection: returned %x\n", (DWORD)result);
1393 if (result != INVALID_HANDLE_VALUE)
1394 *retv = result,
1395 context->Eax = STATUS_SUCCESS;
1396 else
1397 *retv = result,
1398 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1400 break;
1403 case 0x000E: /* NtOpenSection */
1405 * Input: EDX: Flat address of arguments on stack
1407 * HANDLE32 *retv [out] Handle of Section opened
1408 * DWORD protect [in] Access protection
1409 * DWORD atom [in] Name of Section to create
1411 * Output: EAX: NtStatus
1414 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1415 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]);
1416 DWORD protect = stack[1];
1417 DWORD atom = stack[2];
1419 HANDLE result = INVALID_HANDLE_VALUE;
1420 char name[128];
1422 TRACE("NtOpenSection(%x, %x, %x)\n",
1423 (DWORD)retv, protect, atom);
1425 if (atom && GlobalGetAtomNameA(atom, name, sizeof(name)))
1427 TRACE("NtOpenSection: name=%s\n", name);
1429 result = OpenFileMappingA(protect, FALSE, name);
1432 if (result == INVALID_HANDLE_VALUE)
1433 WARN("NtOpenSection: failed!\n");
1434 else
1435 TRACE("NtOpenSection: returned %x\n", (DWORD)result);
1437 if (result != INVALID_HANDLE_VALUE)
1438 *retv = result,
1439 context->Eax = STATUS_SUCCESS;
1440 else
1441 *retv = result,
1442 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1444 break;
1447 case 0x000F: /* NtCloseSection */
1449 * Input: EDX: Flat address of arguments on stack
1451 * HANDLE32 handle [in] Handle of Section to close
1452 * DWORD *id [out] Unique ID (?? unclear ??)
1454 * Output: EAX: NtStatus
1457 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1458 HANDLE handle = (HANDLE)stack[0];
1459 DWORD *id = (DWORD *)W32S_APP2WINE(stack[1]);
1461 TRACE("NtCloseSection(%x, %x)\n", (DWORD)handle, (DWORD)id);
1463 CloseHandle(handle);
1464 if (id) *id = 0; /* FIXME */
1466 context->Eax = STATUS_SUCCESS;
1468 break;
1471 case 0x0010: /* NtDupSection */
1473 * Input: EDX: Flat address of arguments on stack
1475 * HANDLE32 handle [in] Handle of Section to duplicate
1477 * Output: EAX: NtStatus
1480 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1481 HANDLE handle = (HANDLE)stack[0];
1482 HANDLE new_handle;
1484 TRACE("NtDupSection(%x)\n", (DWORD)handle);
1486 DuplicateHandle( GetCurrentProcess(), handle,
1487 GetCurrentProcess(), &new_handle,
1488 0, FALSE, DUPLICATE_SAME_ACCESS );
1489 context->Eax = STATUS_SUCCESS;
1491 break;
1494 case 0x0011: /* NtMapViewOfSection */
1496 * Input: EDX: Flat address of arguments on stack
1498 * HANDLE32 SectionHandle [in] Section to be mapped
1499 * DWORD ProcessHandle [in] Process to be mapped into
1500 * DWORD * BaseAddress [in/out] Address to be mapped at
1501 * DWORD ZeroBits [in] (?? unclear ??)
1502 * DWORD CommitSize [in] (?? unclear ??)
1503 * LARGE_INTEGER *SectionOffset [in] Offset within section
1504 * DWORD * ViewSize [in] Size of view
1505 * DWORD InheritDisposition [in] (?? unclear ??)
1506 * DWORD AllocationType [in] (?? unclear ??)
1507 * DWORD Protect [in] Access protection
1509 * Output: EAX: NtStatus
1512 DWORD * stack = (DWORD *)W32S_APP2WINE(context->Edx);
1513 HANDLE SectionHandle = (HANDLE)stack[0];
1514 DWORD ProcessHandle = stack[1]; /* ignored */
1515 DWORD * BaseAddress = (DWORD *)W32S_APP2WINE(stack[2]);
1516 DWORD ZeroBits = stack[3];
1517 DWORD CommitSize = stack[4];
1518 LARGE_INTEGER *SectionOffset = (LARGE_INTEGER *)W32S_APP2WINE(stack[5]);
1519 DWORD * ViewSize = (DWORD *)W32S_APP2WINE(stack[6]);
1520 DWORD InheritDisposition = stack[7];
1521 DWORD AllocationType = stack[8];
1522 DWORD Protect = stack[9];
1524 LPBYTE address = (LPBYTE)(BaseAddress?
1525 W32S_APP2WINE(*BaseAddress) : 0);
1526 DWORD access = 0, result;
1528 switch (Protect & ~(PAGE_GUARD|PAGE_NOCACHE))
1530 case PAGE_READONLY: access = FILE_MAP_READ; break;
1531 case PAGE_READWRITE: access = FILE_MAP_WRITE; break;
1532 case PAGE_WRITECOPY: access = FILE_MAP_COPY; break;
1534 case PAGE_EXECUTE_READ: access = FILE_MAP_READ; break;
1535 case PAGE_EXECUTE_READWRITE: access = FILE_MAP_WRITE; break;
1536 case PAGE_EXECUTE_WRITECOPY: access = FILE_MAP_COPY; break;
1539 TRACE("NtMapViewOfSection"
1540 "(%x, %x, %x, %x, %x, %x, %x, %x, %x, %x)\n",
1541 (DWORD)SectionHandle, ProcessHandle, (DWORD)BaseAddress,
1542 ZeroBits, CommitSize, (DWORD)SectionOffset, (DWORD)ViewSize,
1543 InheritDisposition, AllocationType, Protect);
1544 TRACE("NtMapViewOfSection: "
1545 "base=%x, offset=%x, size=%x, access=%x\n",
1546 (DWORD)address, SectionOffset? SectionOffset->u.LowPart : 0,
1547 ViewSize? *ViewSize : 0, access);
1549 result = (DWORD)MapViewOfFileEx(SectionHandle, access,
1550 SectionOffset? SectionOffset->u.HighPart : 0,
1551 SectionOffset? SectionOffset->u.LowPart : 0,
1552 ViewSize? *ViewSize : 0, address);
1554 TRACE("NtMapViewOfSection: result=%x\n", result);
1556 if (W32S_WINE2APP(result))
1558 if (BaseAddress) *BaseAddress = W32S_WINE2APP(result);
1559 context->Eax = STATUS_SUCCESS;
1561 else
1562 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1564 break;
1567 case 0x0012: /* NtUnmapViewOfSection */
1569 * Input: EDX: Flat address of arguments on stack
1571 * DWORD ProcessHandle [in] Process (defining address space)
1572 * LPBYTE BaseAddress [in] Base address of view to be unmapped
1574 * Output: EAX: NtStatus
1577 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1578 DWORD ProcessHandle = stack[0]; /* ignored */
1579 LPBYTE BaseAddress = (LPBYTE)W32S_APP2WINE(stack[1]);
1581 TRACE("NtUnmapViewOfSection(%x, %x)\n",
1582 ProcessHandle, (DWORD)BaseAddress);
1584 UnmapViewOfFile(BaseAddress);
1586 context->Eax = STATUS_SUCCESS;
1588 break;
1591 case 0x0013: /* NtFlushVirtualMemory */
1593 * Input: EDX: Flat address of arguments on stack
1595 * DWORD ProcessHandle [in] Process (defining address space)
1596 * LPBYTE *BaseAddress [in?] Base address of range to be flushed
1597 * DWORD *ViewSize [in?] Number of bytes to be flushed
1598 * DWORD *unknown [???] (?? unknown ??)
1600 * Output: EAX: NtStatus
1603 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1604 DWORD ProcessHandle = stack[0]; /* ignored */
1605 DWORD *BaseAddress = (DWORD *)W32S_APP2WINE(stack[1]);
1606 DWORD *ViewSize = (DWORD *)W32S_APP2WINE(stack[2]);
1607 DWORD *unknown = (DWORD *)W32S_APP2WINE(stack[3]);
1609 LPBYTE address = (LPBYTE)(BaseAddress? W32S_APP2WINE(*BaseAddress) : 0);
1610 DWORD size = ViewSize? *ViewSize : 0;
1612 TRACE("NtFlushVirtualMemory(%x, %x, %x, %x)\n",
1613 ProcessHandle, (DWORD)BaseAddress, (DWORD)ViewSize,
1614 (DWORD)unknown);
1615 TRACE("NtFlushVirtualMemory: base=%x, size=%x\n",
1616 (DWORD)address, size);
1618 FlushViewOfFile(address, size);
1620 context->Eax = STATUS_SUCCESS;
1622 break;
1625 case 0x0014: /* Get/Set Debug Registers */
1627 * Input: ECX: 0 if Get, 1 if Set
1629 * EDX: Get: Flat address of buffer to receive values of
1630 * debug registers DR0 .. DR7
1631 * Set: Flat address of buffer containing values of
1632 * debug registers DR0 .. DR7 to be set
1633 * Output: None
1636 FIXME("[0014] ECX=%x EDX=%x\n",
1637 context->Ecx, context->Edx);
1639 /* FIXME */
1640 break;
1643 case 0x0015: /* Set Coprocessor Emulation Flag */
1645 * Input: EDX: 0 to deactivate, 1 to activate coprocessor emulation
1647 * Output: None
1650 TRACE("[0015] EDX=%x\n", context->Edx);
1652 /* We don't care, as we always have a coprocessor anyway */
1653 break;
1656 case 0x0016: /* Init Win32S VxD PSP */
1658 * If called to query required PSP size:
1660 * Input: EBX: 0
1661 * Output: EDX: Required size of Win32s VxD PSP
1663 * If called to initialize allocated PSP:
1665 * Input: EBX: LoWord: Selector of Win32s VxD PSP
1666 * HiWord: Paragraph of Win32s VxD PSP (DOSMEM)
1667 * Output: None
1670 if (context->Ebx == 0)
1671 context->Edx = 0x80;
1672 else
1674 PDB16 *psp = MapSL( MAKESEGPTR( BX_reg(context), 0 ));
1675 psp->nbFiles = 32;
1676 psp->fileHandlesPtr = MAKELONG(HIWORD(context->Ebx), 0x5c);
1677 memset((LPBYTE)psp + 0x5c, '\xFF', 32);
1679 break;
1682 case 0x0017: /* Set Break Point */
1684 * Input: EBX: Offset of Break Point
1685 * CX: Selector of Break Point
1687 * Output: None
1690 FIXME("[0017] EBX=%x CX=%x\n",
1691 context->Ebx, CX_reg(context));
1693 /* FIXME */
1694 break;
1697 case 0x0018: /* VirtualLock */
1699 * Input: ECX: Current Process
1701 * EDX: Flat address of arguments on stack
1703 * DWORD *retv [out] TRUE if success, FALSE if failure
1704 * LPVOID base [in] Flat address of range to lock
1705 * DWORD size [in] Size of range
1707 * Output: EAX: NtStatus
1710 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1711 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1712 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1713 DWORD size = stack[2];
1714 DWORD result;
1716 TRACE("VirtualLock(%x, %x, %x)\n",
1717 (DWORD)retv, (DWORD)base, size);
1719 result = VirtualLock(base, size);
1721 if (result)
1722 *retv = TRUE,
1723 context->Eax = STATUS_SUCCESS;
1724 else
1725 *retv = FALSE,
1726 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1728 break;
1731 case 0x0019: /* VirtualUnlock */
1733 * Input: ECX: Current Process
1735 * EDX: Flat address of arguments on stack
1737 * DWORD *retv [out] TRUE if success, FALSE if failure
1738 * LPVOID base [in] Flat address of range to unlock
1739 * DWORD size [in] Size of range
1741 * Output: EAX: NtStatus
1744 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1745 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1746 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1747 DWORD size = stack[2];
1748 DWORD result;
1750 TRACE("VirtualUnlock(%x, %x, %x)\n",
1751 (DWORD)retv, (DWORD)base, size);
1753 result = VirtualUnlock(base, size);
1755 if (result)
1756 *retv = TRUE,
1757 context->Eax = STATUS_SUCCESS;
1758 else
1759 *retv = FALSE,
1760 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1762 break;
1765 case 0x001A: /* KGetSystemInfo */
1767 * Input: None
1769 * Output: ECX: Start of sparse memory arena
1770 * EDX: End of sparse memory arena
1773 TRACE("KGetSystemInfo()\n");
1776 * Note: Win32s reserves 0GB - 2GB for Win 3.1 and uses 2GB - 4GB as
1777 * sparse memory arena. We do it the other way around, since
1778 * we have to reserve 3GB - 4GB for Linux, and thus use
1779 * 0GB - 3GB as sparse memory arena.
1781 * FIXME: What about other OSes ?
1784 context->Ecx = W32S_WINE2APP(0x00000000);
1785 context->Edx = W32S_WINE2APP(0xbfffffff);
1786 break;
1789 case 0x001B: /* KGlobalMemStat */
1791 * Input: ESI: Flat address of buffer to receive memory info
1793 * Output: None
1796 struct Win32sMemoryInfo
1798 DWORD DIPhys_Count; /* Total physical pages */
1799 DWORD DIFree_Count; /* Free physical pages */
1800 DWORD DILin_Total_Count; /* Total virtual pages (private arena) */
1801 DWORD DILin_Total_Free; /* Free virtual pages (private arena) */
1803 DWORD SparseTotal; /* Total size of sparse arena (bytes ?) */
1804 DWORD SparseFree; /* Free size of sparse arena (bytes ?) */
1807 struct Win32sMemoryInfo *info =
1808 (struct Win32sMemoryInfo *)W32S_APP2WINE(context->Esi);
1810 FIXME("KGlobalMemStat(%x)\n", (DWORD)info);
1812 /* FIXME */
1814 break;
1817 case 0x001C: /* Enable/Disable Exceptions */
1819 * Input: ECX: 0 to disable, 1 to enable exception handling
1821 * Output: None
1824 TRACE("[001c] ECX=%x\n", context->Ecx);
1826 /* FIXME */
1827 break;
1830 case 0x001D: /* VirtualAlloc called from 16-bit code */
1832 * Input: EDX: Segmented address of arguments on stack
1834 * LPVOID base [in] Flat address of region to reserve/commit
1835 * DWORD size [in] Size of region
1836 * DWORD type [in] Type of allocation
1837 * DWORD prot [in] Type of access protection
1839 * Output: EAX: NtStatus
1840 * EDX: Flat base address of allocated region
1843 DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) ));
1844 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]);
1845 DWORD size = stack[1];
1846 DWORD type = stack[2];
1847 DWORD prot = stack[3];
1848 DWORD result;
1850 TRACE("VirtualAlloc16(%x, %x, %x, %x)\n",
1851 (DWORD)base, size, type, prot);
1853 if (type & 0x80000000)
1855 WARN("VirtualAlloc16: strange type %x\n", type);
1856 type &= 0x7fffffff;
1859 result = (DWORD)VirtualAlloc(base, size, type, prot);
1861 if (W32S_WINE2APP(result))
1862 context->Edx = W32S_WINE2APP(result),
1863 context->Eax = STATUS_SUCCESS;
1864 else
1865 context->Edx = 0,
1866 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1867 TRACE("VirtualAlloc16: returning base %x\n", context->Edx);
1869 break;
1872 case 0x001E: /* VirtualFree called from 16-bit code */
1874 * Input: EDX: Segmented address of arguments on stack
1876 * LPVOID base [in] Flat address of region
1877 * DWORD size [in] Size of region
1878 * DWORD type [in] Type of operation
1880 * Output: EAX: NtStatus
1881 * EDX: TRUE if success, FALSE if failure
1884 DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) ));
1885 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]);
1886 DWORD size = stack[1];
1887 DWORD type = stack[2];
1888 DWORD result;
1890 TRACE("VirtualFree16(%x, %x, %x)\n",
1891 (DWORD)base, size, type);
1893 result = VirtualFree(base, size, type);
1895 if (result)
1896 context->Edx = TRUE,
1897 context->Eax = STATUS_SUCCESS;
1898 else
1899 context->Edx = FALSE,
1900 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1902 break;
1905 case 0x001F: /* FWorkingSetSize */
1907 * Input: EDX: 0 if Get, 1 if Set
1909 * ECX: Get: Buffer to receive Working Set Size
1910 * Set: Buffer containing Working Set Size
1912 * Output: NtStatus
1915 DWORD *ptr = (DWORD *)W32S_APP2WINE(context->Ecx);
1916 BOOL set = context->Edx;
1918 TRACE("FWorkingSetSize(%x, %x)\n", (DWORD)ptr, (DWORD)set);
1920 if (set)
1921 /* We do it differently ... */;
1922 else
1923 *ptr = 0x100;
1925 context->Eax = STATUS_SUCCESS;
1927 break;
1929 default:
1930 VXD_BARF( context, "W32S" );