include: Use the hard-float calling convention for Windows APIs on ARM
[wine.git] / dlls / krnl386.exe16 / vxd.c
blob7be5f63b5e0b9c614b114e5f2593d49c6aaaa65e
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( CONTEXT *context )
291 unsigned int i;
292 VxDCallProc proc = NULL;
293 DWORD service = stack32_pop( context );
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 DEFINE_REGS_ENTRYPOINT( VxDCall )
319 /***********************************************************************
320 * __wine_vxd_vmm (WPROCS.401)
322 void WINAPI __wine_vxd_vmm ( CONTEXT *context )
324 unsigned service = AX_reg(context);
326 TRACE("[%04x] VMM\n", (UINT16)service);
328 switch(service)
330 case 0x0000: /* version */
331 SET_AX( context, VXD_WinVersion() );
332 RESET_CFLAG(context);
333 break;
335 case 0x026d: /* Get_Debug_Flag '/m' */
336 case 0x026e: /* Get_Debug_Flag '/n' */
337 SET_AL( context, 0 );
338 RESET_CFLAG(context);
339 break;
341 default:
342 VXD_BARF( context, "VMM" );
346 /***********************************************************************
347 * __wine_vxd_pagefile (WPROCS.433)
349 void WINAPI __wine_vxd_pagefile( CONTEXT *context )
351 unsigned service = AX_reg(context);
353 /* taken from Ralf Brown's Interrupt List */
355 TRACE("[%04x] PageFile\n", (UINT16)service );
357 switch(service)
359 case 0x00: /* get version, is this windows version? */
360 TRACE("returning version\n");
361 SET_AX( context, VXD_WinVersion() );
362 RESET_CFLAG(context);
363 break;
365 case 0x01: /* get swap file info */
366 TRACE("VxD PageFile: returning swap file info\n");
367 SET_AX( context, 0x00 ); /* paging disabled */
368 context->Ecx = 0; /* maximum size of paging file */
369 /* FIXME: do I touch DS:SI or DS:DI? */
370 RESET_CFLAG(context);
371 break;
373 case 0x02: /* delete permanent swap on exit */
374 TRACE("VxD PageFile: supposed to delete swap\n");
375 RESET_CFLAG(context);
376 break;
378 case 0x03: /* current temporary swap file size */
379 TRACE("VxD PageFile: what is current temp. swap size\n");
380 RESET_CFLAG(context);
381 break;
383 case 0x04: /* read or write?? INTERRUP.D */
384 case 0x05: /* cancel?? INTERRUP.D */
385 case 0x06: /* test I/O valid INTERRUP.D */
386 default:
387 VXD_BARF( context, "pagefile" );
388 break;
392 /***********************************************************************
393 * __wine_vxd_reboot (WPROCS.409)
395 void WINAPI __wine_vxd_reboot( CONTEXT *context )
397 unsigned service = AX_reg(context);
399 TRACE("[%04x] Reboot\n", (UINT16)service);
401 switch(service)
403 case 0x0000: /* version */
404 SET_AX( context, VXD_WinVersion() );
405 RESET_CFLAG(context);
406 break;
408 default:
409 VXD_BARF( context, "REBOOT" );
413 /***********************************************************************
414 * __wine_vxd_vdd (WPROCS.410)
416 void WINAPI __wine_vxd_vdd( CONTEXT *context )
418 unsigned service = AX_reg(context);
420 TRACE("[%04x] VDD\n", (UINT16)service);
422 switch(service)
424 case 0x0000: /* version */
425 SET_AX( context, VXD_WinVersion() );
426 RESET_CFLAG(context);
427 break;
429 default:
430 VXD_BARF( context, "VDD" );
434 /***********************************************************************
435 * __wine_vxd_vmd (WPROCS.412)
437 void WINAPI __wine_vxd_vmd( CONTEXT *context )
439 unsigned service = AX_reg(context);
441 TRACE("[%04x] VMD\n", (UINT16)service);
443 switch(service)
445 case 0x0000: /* version */
446 SET_AX( context, VXD_WinVersion() );
447 RESET_CFLAG(context);
448 break;
450 default:
451 VXD_BARF( context, "VMD" );
455 /***********************************************************************
456 * __wine_vxd_vxdloader (WPROCS.439)
458 void WINAPI __wine_vxd_vxdloader( CONTEXT *context )
460 unsigned service = AX_reg(context);
462 TRACE("[%04x] VXDLoader\n", (UINT16)service);
464 switch (service)
466 case 0x0000: /* get version */
467 TRACE("returning version\n");
468 SET_AX( context, 0x0000 );
469 SET_DX( context, VXD_WinVersion() );
470 RESET_CFLAG(context);
471 break;
473 case 0x0001: /* load device */
474 FIXME("load device %04x:%04x (%s)\n",
475 context->SegDs, DX_reg(context),
476 debugstr_a(MapSL(MAKESEGPTR(context->SegDs, DX_reg(context)))));
477 SET_AX( context, 0x0000 );
478 context->SegEs = 0x0000;
479 SET_DI( context, 0x0000 );
480 RESET_CFLAG(context);
481 break;
483 case 0x0002: /* unload device */
484 FIXME("unload device (%08x)\n", context->Ebx);
485 SET_AX( context, 0x0000 );
486 RESET_CFLAG(context);
487 break;
489 default:
490 VXD_BARF( context, "VXDLDR" );
491 SET_AX( context, 0x000B ); /* invalid function number */
492 SET_CFLAG(context);
493 break;
497 /***********************************************************************
498 * __wine_vxd_shell (WPROCS.423)
500 void WINAPI __wine_vxd_shell( CONTEXT *context )
502 unsigned service = DX_reg(context);
504 TRACE("[%04x] Shell\n", (UINT16)service);
506 switch (service) /* Ralf Brown says EDX, but I use DX instead */
508 case 0x0000:
509 TRACE("returning version\n");
510 SET_AX( context, VXD_WinVersion() );
511 context->Ebx = 1; /* system VM Handle */
512 break;
514 case 0x0001:
515 case 0x0002:
516 case 0x0003:
517 /* SHELL_SYSMODAL_Message
518 ebx virtual machine handle
519 eax message box flags
520 ecx address of message
521 edi address of caption
522 return response in eax
524 case 0x0004:
525 /* SHELL_Message
526 ebx virtual machine handle
527 eax message box flags
528 ecx address of message
529 edi address of caption
530 esi address callback
531 edx reference data for callback
532 return response in eax
534 case 0x0005:
535 VXD_BARF( context, "shell" );
536 break;
538 case 0x0006: /* SHELL_Get_VM_State */
539 TRACE("VxD Shell: returning VM state\n");
540 /* Actually we don't, not yet. We have to return a structure
541 * and I am not to sure how to set it up and return it yet,
542 * so for now let's do nothing. I can (hopefully) get this
543 * by the next release
545 /* RESET_CFLAG(context); */
546 break;
548 case 0x0007:
549 case 0x0008:
550 case 0x0009:
551 case 0x000A:
552 case 0x000B:
553 case 0x000C:
554 case 0x000D:
555 case 0x000E:
556 case 0x000F:
557 case 0x0010:
558 case 0x0011:
559 case 0x0012:
560 case 0x0013:
561 case 0x0014:
562 case 0x0015:
563 case 0x0016:
564 VXD_BARF( context, "SHELL" );
565 break;
567 /* the new Win95 shell API */
568 case 0x0100: /* get version */
569 SET_AX( context, VXD_WinVersion() );
570 break;
572 case 0x0104: /* retrieve Hook_Properties list */
573 case 0x0105: /* call Hook_Properties callbacks */
574 VXD_BARF( context, "SHELL" );
575 break;
577 case 0x0106: /* install timeout callback */
578 TRACE("VxD Shell: ignoring shell callback (%d sec.)\n", context->Ebx);
579 SET_CFLAG(context);
580 break;
582 case 0x0107: /* get version of any VxD */
583 default:
584 VXD_BARF( context, "SHELL" );
585 break;
590 /***********************************************************************
591 * __wine_vxd_comm (WPROCS.414)
593 void WINAPI __wine_vxd_comm( CONTEXT *context )
595 unsigned service = AX_reg(context);
597 TRACE("[%04x] Comm\n", (UINT16)service);
599 switch (service)
601 case 0x0000: /* get version */
602 TRACE("returning version\n");
603 SET_AX( context, VXD_WinVersion() );
604 RESET_CFLAG(context);
605 break;
607 case 0x0001: /* set port global */
608 case 0x0002: /* get focus */
609 case 0x0003: /* virtualise port */
610 default:
611 VXD_BARF( context, "comm" );
615 /***********************************************************************
616 * __wine_vxd_timer (WPROCS.405)
618 void WINAPI __wine_vxd_timer( CONTEXT *context )
620 unsigned service = AX_reg(context);
622 TRACE("[%04x] Virtual Timer\n", (UINT16)service);
624 switch(service)
626 case 0x0000: /* version */
627 SET_AX( context, VXD_WinVersion() );
628 RESET_CFLAG(context);
629 break;
631 case 0x0100: /* clock tick time, in 840nsecs */
632 context->Eax = GetTickCount();
634 context->Edx = context->Eax >> 22;
635 context->Eax <<= 10; /* not very precise */
636 break;
638 case 0x0101: /* current Windows time, msecs */
639 case 0x0102: /* current VM time, msecs */
640 context->Eax = GetTickCount();
641 break;
643 default:
644 VXD_BARF( context, "VTD" );
649 /***********************************************************************
650 * timer_thread
652 static DWORD CALLBACK timer_thread( void *arg )
654 DWORD *system_time = arg;
656 for (;;)
658 *system_time = GetTickCount();
659 Sleep( 55 );
662 return 0;
666 /***********************************************************************
667 * __wine_vxd_timerapi (WPROCS.1490)
669 void WINAPI __wine_vxd_timerapi( CONTEXT *context )
671 static WORD System_Time_Selector;
673 unsigned service = AX_reg(context);
675 TRACE("[%04x] TimerAPI\n", (UINT16)service);
677 switch(service)
679 case 0x0000: /* version */
680 SET_AX( context, VXD_WinVersion() );
681 RESET_CFLAG(context);
682 break;
684 case 0x0009: /* get system time selector */
685 if ( !System_Time_Selector )
687 HANDLE16 handle = GlobalAlloc16( GMEM_FIXED, sizeof(DWORD) );
688 System_Time_Selector = handle | 7;
689 CloseHandle( CreateThread( NULL, 0, timer_thread, GlobalLock16(handle), 0, NULL ) );
691 SET_AX( context, System_Time_Selector );
692 RESET_CFLAG(context);
693 break;
695 default:
696 VXD_BARF( context, "VTDAPI" );
700 /***********************************************************************
701 * __wine_vxd_configmg (WPROCS.451)
703 void WINAPI __wine_vxd_configmg( CONTEXT *context )
705 unsigned service = AX_reg(context);
707 TRACE("[%04x] ConfigMG\n", (UINT16)service);
709 switch(service)
711 case 0x0000: /* version */
712 SET_AX( context, VXD_WinVersion() );
713 RESET_CFLAG(context);
714 break;
716 default:
717 VXD_BARF( context, "CONFIGMG" );
721 /***********************************************************************
722 * __wine_vxd_enable (WPROCS.455)
724 void WINAPI __wine_vxd_enable( CONTEXT *context )
726 unsigned service = AX_reg(context);
728 TRACE("[%04x] Enable\n", (UINT16)service);
730 switch(service)
732 case 0x0000: /* version */
733 SET_AX( context, VXD_WinVersion() );
734 RESET_CFLAG(context);
735 break;
737 default:
738 VXD_BARF( context, "ENABLE" );
742 /***********************************************************************
743 * __wine_vxd_apm (WPROCS.438)
745 void WINAPI __wine_vxd_apm( CONTEXT *context )
747 unsigned service = AX_reg(context);
749 TRACE("[%04x] APM\n", (UINT16)service);
751 switch(service)
753 case 0x0000: /* version */
754 SET_AX( context, VXD_WinVersion() );
755 RESET_CFLAG(context);
756 break;
758 default:
759 VXD_BARF( context, "APM" );
763 /***********************************************************************
764 * __wine_vxd_win32s (WPROCS.445)
766 * This is an implementation of the services of the Win32s VxD.
767 * Since official documentation of these does not seem to be available,
768 * certain arguments of some of the services remain unclear.
770 * FIXME: The following services are currently unimplemented:
771 * Exception handling (0x01, 0x1C)
772 * Debugger support (0x0C, 0x14, 0x17)
773 * Low-level memory access (0x02, 0x03, 0x0A, 0x0B)
774 * Memory Statistics (0x1B)
777 * We have a specific problem running Win32s on Linux (and probably also
778 * the other x86 unixes), since Win32s tries to allocate its main 'flat
779 * code/data segment' selectors with a base of 0xffff0000 (and limit 4GB).
780 * The rationale for this seems to be that they want one the one hand to
781 * be able to leave the Win 3.1 memory (starting with the main DOS memory)
782 * at linear address 0, but want at other hand to have offset 0 of the
783 * flat data/code segment point to an unmapped page (to catch NULL pointer
784 * accesses). Hence they allocate the flat segments with a base of 0xffff0000
785 * so that the Win 3.1 memory area at linear address zero shows up in the
786 * flat segments at offset 0x10000 (since linear addresses wrap around at
787 * 4GB). To compensate for that discrepancy between flat segment offsets
788 * and plain linear addresses, all flat pointers passed between the 32-bit
789 * and the 16-bit parts of Win32s are shifted by 0x10000 in the appropriate
790 * direction by the glue code (mainly) in W32SKRNL and WIN32S16.
792 * The problem for us is now that Linux does not allow a LDT selector with
793 * base 0xffff0000 to be created, since it would 'see' a part of the kernel
794 * address space. To address this problem we introduce *another* offset:
795 * We add 0x10000 to every linear address we get as an argument from Win32s.
796 * This means especially that the flat code/data selectors get actually
797 * allocated with base 0x0, so that flat offsets and (real) linear addresses
798 * do again agree! In fact, every call e.g. of a Win32s VxD service now
799 * has all pointer arguments (which are offsets in the flat data segment)
800 * first reduced by 0x10000 by the W32SKRNL glue code, and then again
801 * increased by 0x10000 by *our* code.
803 * Note that to keep everything consistent, this offset has to be applied by
804 * every Wine function that operates on 'linear addresses' passed to it by
805 * Win32s. Fortunately, since Win32s does not directly call any Wine 32-bit
806 * API routines, this affects only two locations: this VxD and the DPMI
807 * handler. (NOTE: Should any Win32s application pass a linear address to
808 * any routine apart from those, e.g. some other VxD handler, that code
809 * would have to take the offset into account as well!)
811 * The offset is set the first time any application calls the GetVersion()
812 * service of the Win32s VxD. (Note that the offset is never reset.)
815 void WINAPI __wine_vxd_win32s( CONTEXT *context )
817 switch (AX_reg(context))
819 case 0x0000: /* Get Version */
821 * Input: None
823 * Output: EAX: LoWord: Win32s Version (1.30)
824 * HiWord: VxD Version (200)
826 * EBX: Build (172)
828 * ECX: ??? (1)
830 * EDX: Debugging Flags
832 * EDI: Error Flag
833 * 0 if OK,
834 * 1 if VMCPD VxD not found
837 TRACE("GetVersion()\n");
839 context->Eax = VXD_WinVersion() | (200 << 16);
840 context->Ebx = 0;
841 context->Ecx = 0;
842 context->Edx = 0;
843 context->Edi = 0;
846 * If this is the first time we are called for this process,
847 * hack the memory image of WIN32S16 so that it doesn't try
848 * to access the GDT directly ...
850 * The first code segment of WIN32S16 (version 1.30) contains
851 * an unexported function somewhere between the exported functions
852 * SetFS and StackLinearToSegmented that tries to find a selector
853 * in the LDT that maps to the memory image of the LDT itself.
854 * If it succeeds, it stores this selector into a global variable
855 * which will be used to speed up execution by using this selector
856 * to modify the LDT directly instead of using the DPMI calls.
858 * To perform this search of the LDT, this function uses the
859 * sgdt and sldt instructions to find the linear address of
860 * the (GDT and then) LDT. While those instructions themselves
861 * execute without problem, the linear address that sgdt returns
862 * points (at least under Linux) to the kernel address space, so
863 * that any subsequent access leads to a segfault.
865 * Fortunately, WIN32S16 still contains as a fallback option the
866 * mechanism of using DPMI calls to modify LDT selectors instead
867 * of direct writes to the LDT. Thus we can circumvent the problem
868 * by simply replacing the first byte of the offending function
869 * with an 'retf' instruction. This means that the global variable
870 * supposed to contain the LDT alias selector will remain zero,
871 * and hence WIN32S16 will fall back to using DPMI calls.
873 * The heuristic we employ to _find_ that function is as follows:
874 * We search between the addresses of the exported symbols SetFS
875 * and StackLinearToSegmented for the byte sequence '0F 01 04'
876 * (this is the opcode of 'sgdt [si]'). We then search backwards
877 * from this address for the last occurrence of 'CB' (retf) that marks
878 * the end of the preceding function. The following byte (which
879 * should now be the first byte of the function we are looking for)
880 * will be replaced by 'CB' (retf).
882 * This heuristic works for the retail as well as the debug version
883 * of Win32s version 1.30. For versions earlier than that this
884 * hack should not be necessary at all, since the whole mechanism
885 * ('PERF130') was introduced only in 1.30 to improve the overall
886 * performance of Win32s.
889 if (!W32S_offset)
891 HMODULE16 hModule = GetModuleHandle16("win32s16");
892 SEGPTR func1 = (SEGPTR)GetProcAddress16(hModule, "SetFS");
893 SEGPTR func2 = (SEGPTR)GetProcAddress16(hModule, "StackLinearToSegmented");
895 if ( hModule && func1 && func2
896 && SELECTOROF(func1) == SELECTOROF(func2))
898 BYTE *start = MapSL(func1);
899 BYTE *end = MapSL(func2);
900 BYTE *p, *retv = NULL;
901 int found = 0;
903 for (p = start; p < end; p++)
904 if (*p == 0xCB) found = 0, retv = p;
905 else if (*p == 0x0F) found = 1;
906 else if (*p == 0x01 && found == 1) found = 2;
907 else if (*p == 0x04 && found == 2) { found = 3; break; }
908 else found = 0;
910 if (found == 3 && retv)
912 TRACE("PERF130 hack: "
913 "Replacing byte %02X at offset %04X:%04X\n",
914 *(retv+1), SELECTOROF(func1),
915 OFFSETOF(func1) + retv+1-start);
917 *(retv+1) = (BYTE)0xCB;
923 * Mark process as Win32s, so that subsequent DPMI calls
924 * will perform the W32S_APP2WINE/W32S_WINE2APP address shift.
926 W32S_offset = 0x10000;
927 break;
930 case 0x0001: /* Install Exception Handling */
932 * Input: EBX: Flat address of W32SKRNL Exception Data
934 * ECX: LoWord: Flat Code Selector
935 * HiWord: Flat Data Selector
937 * EDX: Flat address of W32SKRNL Exception Handler
938 * (this is equal to W32S_BackTo32 + 0x40)
940 * ESI: SEGPTR KERNEL.HASGPHANDLER
942 * EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10)
944 * Output: EAX: 0 if OK
947 TRACE("[0001] EBX=%x ECX=%x EDX=%x ESI=%x EDI=%x\n",
948 context->Ebx, context->Ecx, context->Edx,
949 context->Esi, context->Edi);
951 /* FIXME */
953 context->Eax = 0;
954 break;
957 case 0x0002: /* Set Page Access Flags */
959 * Input: EBX: New access flags
960 * Bit 2: User Page if set, Supervisor Page if clear
961 * Bit 1: Read-Write if set, Read-Only if clear
963 * ECX: Size of memory area to change
965 * EDX: Flat start address of memory area
967 * Output: EAX: Size of area changed
970 TRACE("[0002] EBX=%x ECX=%x EDX=%x\n",
971 context->Ebx, context->Ecx, context->Edx);
973 /* FIXME */
975 context->Eax = context->Ecx;
976 break;
979 case 0x0003: /* Get Page Access Flags */
981 * Input: EDX: Flat address of page to query
983 * Output: EAX: Page access flags
984 * Bit 2: User Page if set, Supervisor Page if clear
985 * Bit 1: Read-Write if set, Read-Only if clear
988 TRACE("[0003] EDX=%x\n", context->Edx);
990 /* FIXME */
992 context->Eax = 6;
993 break;
996 case 0x0004: /* Map Module */
998 * Input: ECX: IMTE (offset in Module Table) of new module
1000 * EDX: Flat address of Win32s Module Table
1002 * Output: EAX: 0 if OK
1005 if (!context->Edx || CX_reg(context) == 0xFFFF)
1007 TRACE("MapModule: Initialization call\n");
1008 context->Eax = 0;
1010 else
1013 * Structure of a Win32s Module Table Entry:
1015 struct Win32sModule
1017 DWORD flags;
1018 DWORD flatBaseAddr;
1019 LPCSTR moduleName;
1020 LPCSTR pathName;
1021 LPCSTR unknown;
1022 LPBYTE baseAddr;
1023 DWORD hModule;
1024 DWORD relocDelta;
1028 * Note: This function should set up a demand-paged memory image
1029 * of the given module. Since mmap does not allow file offsets
1030 * not aligned at 1024 bytes, we simply load the image fully
1031 * into memory.
1034 struct Win32sModule *moduleTable =
1035 (struct Win32sModule *)W32S_APP2WINE(context->Edx);
1036 struct Win32sModule *module = moduleTable + context->Ecx;
1038 IMAGE_NT_HEADERS *nt_header = RtlImageNtHeader( (HMODULE)module->baseAddr );
1039 IMAGE_SECTION_HEADER *pe_seg = (IMAGE_SECTION_HEADER*)((char *)&nt_header->OptionalHeader +
1040 nt_header->FileHeader.SizeOfOptionalHeader);
1043 HFILE image = _lopen(module->pathName, OF_READ);
1044 BOOL error = (image == HFILE_ERROR);
1045 UINT i;
1047 TRACE("MapModule: Loading %s\n", module->pathName);
1049 for (i = 0;
1050 !error && i < nt_header->FileHeader.NumberOfSections;
1051 i++, pe_seg++)
1052 if(!(pe_seg->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA))
1054 DWORD off = pe_seg->PointerToRawData;
1055 DWORD len = pe_seg->SizeOfRawData;
1056 LPBYTE addr = module->baseAddr + pe_seg->VirtualAddress;
1058 TRACE("MapModule: "
1059 "Section %d at %08x from %08x len %08x\n",
1060 i, (DWORD)addr, off, len);
1062 if ( _llseek(image, off, SEEK_SET) != off
1063 || _lread(image, addr, len) != len)
1064 error = TRUE;
1067 _lclose(image);
1069 if (error)
1070 ERR("MapModule: Unable to load %s\n", module->pathName);
1072 else if (module->relocDelta != 0)
1074 IMAGE_DATA_DIRECTORY *dir = nt_header->OptionalHeader.DataDirectory
1075 + IMAGE_DIRECTORY_ENTRY_BASERELOC;
1076 IMAGE_BASE_RELOCATION *r = (IMAGE_BASE_RELOCATION *)
1077 (dir->Size? module->baseAddr + dir->VirtualAddress : 0);
1079 TRACE("MapModule: Reloc delta %08x\n", module->relocDelta);
1081 while (r && r->VirtualAddress)
1083 LPBYTE page = module->baseAddr + r->VirtualAddress;
1084 WORD *TypeOffset = (WORD *)(r + 1);
1085 unsigned int count = (r->SizeOfBlock - sizeof(*r)) / sizeof(*TypeOffset);
1087 TRACE("MapModule: %d relocations for page %08x\n",
1088 count, (DWORD)page);
1090 for(i = 0; i < count; i++)
1092 int offset = TypeOffset[i] & 0xFFF;
1093 int type = TypeOffset[i] >> 12;
1094 switch(type)
1096 case IMAGE_REL_BASED_ABSOLUTE:
1097 break;
1098 case IMAGE_REL_BASED_HIGH:
1099 *(WORD *)(page+offset) += HIWORD(module->relocDelta);
1100 break;
1101 case IMAGE_REL_BASED_LOW:
1102 *(WORD *)(page+offset) += LOWORD(module->relocDelta);
1103 break;
1104 case IMAGE_REL_BASED_HIGHLOW:
1105 *(DWORD*)(page+offset) += module->relocDelta;
1106 break;
1107 default:
1108 WARN("MapModule: Unsupported fixup type\n");
1109 break;
1113 r = (IMAGE_BASE_RELOCATION *)((LPBYTE)r + r->SizeOfBlock);
1117 context->Eax = 0;
1118 RESET_CFLAG(context);
1120 break;
1123 case 0x0005: /* UnMap Module */
1125 * Input: EDX: Flat address of module image
1127 * Output: EAX: 1 if OK
1130 TRACE("UnMapModule: %x\n", W32S_APP2WINE(context->Edx));
1132 /* As we didn't map anything, there's nothing to unmap ... */
1134 context->Eax = 1;
1135 break;
1138 case 0x0006: /* VirtualAlloc */
1140 * Input: ECX: Current Process
1142 * EDX: Flat address of arguments on stack
1144 * DWORD *retv [out] Flat base address of allocated region
1145 * LPVOID base [in] Flat address of region to reserve/commit
1146 * DWORD size [in] Size of region
1147 * DWORD type [in] Type of allocation
1148 * DWORD prot [in] Type of access protection
1150 * Output: EAX: NtStatus
1153 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1154 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1155 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1156 DWORD size = stack[2];
1157 DWORD type = stack[3];
1158 DWORD prot = stack[4];
1159 DWORD result;
1161 TRACE("VirtualAlloc(%x, %x, %x, %x, %x)\n",
1162 (DWORD)retv, (DWORD)base, size, type, prot);
1164 if (type & 0x80000000)
1166 WARN("VirtualAlloc: strange type %x\n", type);
1167 type &= 0x7fffffff;
1170 if (!base && (type & MEM_COMMIT) && prot == PAGE_READONLY)
1172 WARN("VirtualAlloc: NLS hack, allowing write access!\n");
1173 prot = PAGE_READWRITE;
1176 result = (DWORD)VirtualAlloc(base, size, type, prot);
1178 if (W32S_WINE2APP(result))
1179 *retv = W32S_WINE2APP(result),
1180 context->Eax = STATUS_SUCCESS;
1181 else
1182 *retv = 0,
1183 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1185 break;
1188 case 0x0007: /* VirtualFree */
1190 * Input: ECX: Current Process
1192 * EDX: Flat address of arguments on stack
1194 * DWORD *retv [out] TRUE if success, FALSE if failure
1195 * LPVOID base [in] Flat address of region
1196 * DWORD size [in] Size of region
1197 * DWORD type [in] Type of operation
1199 * Output: EAX: NtStatus
1202 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1203 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1204 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1205 DWORD size = stack[2];
1206 DWORD type = stack[3];
1207 DWORD result;
1209 TRACE("VirtualFree(%x, %x, %x, %x)\n",
1210 (DWORD)retv, (DWORD)base, size, type);
1212 result = VirtualFree(base, size, type);
1214 if (result)
1215 *retv = TRUE,
1216 context->Eax = STATUS_SUCCESS;
1217 else
1218 *retv = FALSE,
1219 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1221 break;
1224 case 0x0008: /* VirtualProtect */
1226 * Input: ECX: Current Process
1228 * EDX: Flat address of arguments on stack
1230 * DWORD *retv [out] TRUE if success, FALSE if failure
1231 * LPVOID base [in] Flat address of region
1232 * DWORD size [in] Size of region
1233 * DWORD new_prot [in] Desired access protection
1234 * DWORD *old_prot [out] Previous access protection
1236 * Output: EAX: NtStatus
1239 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1240 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1241 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1242 DWORD size = stack[2];
1243 DWORD new_prot = stack[3];
1244 DWORD *old_prot = (DWORD *)W32S_APP2WINE(stack[4]);
1245 DWORD result;
1247 TRACE("VirtualProtect(%x, %x, %x, %x, %x)\n",
1248 (DWORD)retv, (DWORD)base, size, new_prot, (DWORD)old_prot);
1250 result = VirtualProtect(base, size, new_prot, old_prot);
1252 if (result)
1253 *retv = TRUE,
1254 context->Eax = STATUS_SUCCESS;
1255 else
1256 *retv = FALSE,
1257 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1259 break;
1262 case 0x0009: /* VirtualQuery */
1264 * Input: ECX: Current Process
1266 * EDX: Flat address of arguments on stack
1268 * DWORD *retv [out] Nr. bytes returned
1269 * LPVOID base [in] Flat address of region
1270 * LPMEMORY_BASIC_INFORMATION info [out] Info buffer
1271 * DWORD len [in] Size of buffer
1273 * Output: EAX: NtStatus
1276 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1277 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1278 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1279 PMEMORY_BASIC_INFORMATION info =
1280 (PMEMORY_BASIC_INFORMATION)W32S_APP2WINE(stack[2]);
1281 DWORD len = stack[3];
1282 DWORD result;
1284 TRACE("VirtualQuery(%x, %x, %x, %x)\n",
1285 (DWORD)retv, (DWORD)base, (DWORD)info, len);
1287 result = VirtualQuery(base, info, len);
1289 *retv = result;
1290 context->Eax = STATUS_SUCCESS;
1292 break;
1295 case 0x000A: /* SetVirtMemProcess */
1297 * Input: ECX: Process Handle
1299 * EDX: Flat address of region
1301 * Output: EAX: NtStatus
1304 TRACE("[000a] ECX=%x EDX=%x\n",
1305 context->Ecx, context->Edx);
1307 /* FIXME */
1309 context->Eax = STATUS_SUCCESS;
1310 break;
1313 case 0x000B: /* ??? some kind of cleanup */
1315 * Input: ECX: Process Handle
1317 * Output: EAX: NtStatus
1320 TRACE("[000b] ECX=%x\n", context->Ecx);
1322 /* FIXME */
1324 context->Eax = STATUS_SUCCESS;
1325 break;
1328 case 0x000C: /* Set Debug Flags */
1330 * Input: EDX: Debug Flags
1332 * Output: EDX: Previous Debug Flags
1335 FIXME("[000c] EDX=%x\n", context->Edx);
1337 /* FIXME */
1339 context->Edx = 0;
1340 break;
1343 case 0x000D: /* NtCreateSection */
1345 * Input: EDX: Flat address of arguments on stack
1347 * HANDLE32 *retv [out] Handle of Section created
1348 * DWORD flags1 [in] (?? unknown ??)
1349 * DWORD atom [in] Name of Section to create
1350 * LARGE_INTEGER *size [in] Size of Section
1351 * DWORD protect [in] Access protection
1352 * DWORD flags2 [in] (?? unknown ??)
1353 * HFILE32 hFile [in] Handle of file to map
1354 * DWORD psp [in] (Win32s: PSP that hFile belongs to)
1356 * Output: EAX: NtStatus
1359 DWORD *stack = (DWORD *) W32S_APP2WINE(context->Edx);
1360 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]);
1361 DWORD flags1 = stack[1];
1362 DWORD atom = stack[2];
1363 LARGE_INTEGER *size = (LARGE_INTEGER *)W32S_APP2WINE(stack[3]);
1364 DWORD protect = stack[4];
1365 DWORD flags2 = stack[5];
1366 HANDLE hFile = DosFileHandleToWin32Handle(stack[6]);
1367 DWORD psp = stack[7];
1369 HANDLE result = INVALID_HANDLE_VALUE;
1370 char name[128];
1372 TRACE("NtCreateSection(%x, %x, %x, %x, %x, %x, %x, %x)\n",
1373 (DWORD)retv, flags1, atom, (DWORD)size, protect, flags2,
1374 (DWORD)hFile, psp);
1376 if (!atom || GlobalGetAtomNameA(atom, name, sizeof(name)))
1378 TRACE("NtCreateSection: name=%s\n", atom? name : NULL);
1380 result = CreateFileMappingA(hFile, NULL, protect,
1381 size? size->u.HighPart : 0,
1382 size? size->u.LowPart : 0,
1383 atom? name : NULL);
1386 if (result == INVALID_HANDLE_VALUE)
1387 WARN("NtCreateSection: failed!\n");
1388 else
1389 TRACE("NtCreateSection: returned %x\n", (DWORD)result);
1391 if (result != INVALID_HANDLE_VALUE)
1392 *retv = result,
1393 context->Eax = STATUS_SUCCESS;
1394 else
1395 *retv = result,
1396 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1398 break;
1401 case 0x000E: /* NtOpenSection */
1403 * Input: EDX: Flat address of arguments on stack
1405 * HANDLE32 *retv [out] Handle of Section opened
1406 * DWORD protect [in] Access protection
1407 * DWORD atom [in] Name of Section to create
1409 * Output: EAX: NtStatus
1412 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1413 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]);
1414 DWORD protect = stack[1];
1415 DWORD atom = stack[2];
1417 HANDLE result = INVALID_HANDLE_VALUE;
1418 char name[128];
1420 TRACE("NtOpenSection(%x, %x, %x)\n",
1421 (DWORD)retv, protect, atom);
1423 if (atom && GlobalGetAtomNameA(atom, name, sizeof(name)))
1425 TRACE("NtOpenSection: name=%s\n", name);
1427 result = OpenFileMappingA(protect, FALSE, name);
1430 if (result == INVALID_HANDLE_VALUE)
1431 WARN("NtOpenSection: failed!\n");
1432 else
1433 TRACE("NtOpenSection: returned %x\n", (DWORD)result);
1435 if (result != INVALID_HANDLE_VALUE)
1436 *retv = result,
1437 context->Eax = STATUS_SUCCESS;
1438 else
1439 *retv = result,
1440 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1442 break;
1445 case 0x000F: /* NtCloseSection */
1447 * Input: EDX: Flat address of arguments on stack
1449 * HANDLE32 handle [in] Handle of Section to close
1450 * DWORD *id [out] Unique ID (?? unclear ??)
1452 * Output: EAX: NtStatus
1455 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1456 HANDLE handle = (HANDLE)stack[0];
1457 DWORD *id = (DWORD *)W32S_APP2WINE(stack[1]);
1459 TRACE("NtCloseSection(%x, %x)\n", (DWORD)handle, (DWORD)id);
1461 CloseHandle(handle);
1462 if (id) *id = 0; /* FIXME */
1464 context->Eax = STATUS_SUCCESS;
1466 break;
1469 case 0x0010: /* NtDupSection */
1471 * Input: EDX: Flat address of arguments on stack
1473 * HANDLE32 handle [in] Handle of Section to duplicate
1475 * Output: EAX: NtStatus
1478 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1479 HANDLE handle = (HANDLE)stack[0];
1480 HANDLE new_handle;
1482 TRACE("NtDupSection(%x)\n", (DWORD)handle);
1484 DuplicateHandle( GetCurrentProcess(), handle,
1485 GetCurrentProcess(), &new_handle,
1486 0, FALSE, DUPLICATE_SAME_ACCESS );
1487 context->Eax = STATUS_SUCCESS;
1489 break;
1492 case 0x0011: /* NtMapViewOfSection */
1494 * Input: EDX: Flat address of arguments on stack
1496 * HANDLE32 SectionHandle [in] Section to be mapped
1497 * DWORD ProcessHandle [in] Process to be mapped into
1498 * DWORD * BaseAddress [in/out] Address to be mapped at
1499 * DWORD ZeroBits [in] (?? unclear ??)
1500 * DWORD CommitSize [in] (?? unclear ??)
1501 * LARGE_INTEGER *SectionOffset [in] Offset within section
1502 * DWORD * ViewSize [in] Size of view
1503 * DWORD InheritDisposition [in] (?? unclear ??)
1504 * DWORD AllocationType [in] (?? unclear ??)
1505 * DWORD Protect [in] Access protection
1507 * Output: EAX: NtStatus
1510 DWORD * stack = (DWORD *)W32S_APP2WINE(context->Edx);
1511 HANDLE SectionHandle = (HANDLE)stack[0];
1512 DWORD ProcessHandle = stack[1]; /* ignored */
1513 DWORD * BaseAddress = (DWORD *)W32S_APP2WINE(stack[2]);
1514 DWORD ZeroBits = stack[3];
1515 DWORD CommitSize = stack[4];
1516 LARGE_INTEGER *SectionOffset = (LARGE_INTEGER *)W32S_APP2WINE(stack[5]);
1517 DWORD * ViewSize = (DWORD *)W32S_APP2WINE(stack[6]);
1518 DWORD InheritDisposition = stack[7];
1519 DWORD AllocationType = stack[8];
1520 DWORD Protect = stack[9];
1522 LPBYTE address = (LPBYTE)(BaseAddress?
1523 W32S_APP2WINE(*BaseAddress) : 0);
1524 DWORD access = 0, result;
1526 switch (Protect & ~(PAGE_GUARD|PAGE_NOCACHE))
1528 case PAGE_READONLY: access = FILE_MAP_READ; break;
1529 case PAGE_READWRITE: access = FILE_MAP_WRITE; break;
1530 case PAGE_WRITECOPY: access = FILE_MAP_COPY; break;
1532 case PAGE_EXECUTE_READ: access = FILE_MAP_READ; break;
1533 case PAGE_EXECUTE_READWRITE: access = FILE_MAP_WRITE; break;
1534 case PAGE_EXECUTE_WRITECOPY: access = FILE_MAP_COPY; break;
1537 TRACE("NtMapViewOfSection"
1538 "(%x, %x, %x, %x, %x, %x, %x, %x, %x, %x)\n",
1539 (DWORD)SectionHandle, ProcessHandle, (DWORD)BaseAddress,
1540 ZeroBits, CommitSize, (DWORD)SectionOffset, (DWORD)ViewSize,
1541 InheritDisposition, AllocationType, Protect);
1542 TRACE("NtMapViewOfSection: "
1543 "base=%x, offset=%x, size=%x, access=%x\n",
1544 (DWORD)address, SectionOffset? SectionOffset->u.LowPart : 0,
1545 ViewSize? *ViewSize : 0, access);
1547 result = (DWORD)MapViewOfFileEx(SectionHandle, access,
1548 SectionOffset? SectionOffset->u.HighPart : 0,
1549 SectionOffset? SectionOffset->u.LowPart : 0,
1550 ViewSize? *ViewSize : 0, address);
1552 TRACE("NtMapViewOfSection: result=%x\n", result);
1554 if (W32S_WINE2APP(result))
1556 if (BaseAddress) *BaseAddress = W32S_WINE2APP(result);
1557 context->Eax = STATUS_SUCCESS;
1559 else
1560 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1562 break;
1565 case 0x0012: /* NtUnmapViewOfSection */
1567 * Input: EDX: Flat address of arguments on stack
1569 * DWORD ProcessHandle [in] Process (defining address space)
1570 * LPBYTE BaseAddress [in] Base address of view to be unmapped
1572 * Output: EAX: NtStatus
1575 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1576 DWORD ProcessHandle = stack[0]; /* ignored */
1577 LPBYTE BaseAddress = (LPBYTE)W32S_APP2WINE(stack[1]);
1579 TRACE("NtUnmapViewOfSection(%x, %x)\n",
1580 ProcessHandle, (DWORD)BaseAddress);
1582 UnmapViewOfFile(BaseAddress);
1584 context->Eax = STATUS_SUCCESS;
1586 break;
1589 case 0x0013: /* NtFlushVirtualMemory */
1591 * Input: EDX: Flat address of arguments on stack
1593 * DWORD ProcessHandle [in] Process (defining address space)
1594 * LPBYTE *BaseAddress [in?] Base address of range to be flushed
1595 * DWORD *ViewSize [in?] Number of bytes to be flushed
1596 * DWORD *unknown [???] (?? unknown ??)
1598 * Output: EAX: NtStatus
1601 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1602 DWORD ProcessHandle = stack[0]; /* ignored */
1603 DWORD *BaseAddress = (DWORD *)W32S_APP2WINE(stack[1]);
1604 DWORD *ViewSize = (DWORD *)W32S_APP2WINE(stack[2]);
1605 DWORD *unknown = (DWORD *)W32S_APP2WINE(stack[3]);
1607 LPBYTE address = (LPBYTE)(BaseAddress? W32S_APP2WINE(*BaseAddress) : 0);
1608 DWORD size = ViewSize? *ViewSize : 0;
1610 TRACE("NtFlushVirtualMemory(%x, %x, %x, %x)\n",
1611 ProcessHandle, (DWORD)BaseAddress, (DWORD)ViewSize,
1612 (DWORD)unknown);
1613 TRACE("NtFlushVirtualMemory: base=%x, size=%x\n",
1614 (DWORD)address, size);
1616 FlushViewOfFile(address, size);
1618 context->Eax = STATUS_SUCCESS;
1620 break;
1623 case 0x0014: /* Get/Set Debug Registers */
1625 * Input: ECX: 0 if Get, 1 if Set
1627 * EDX: Get: Flat address of buffer to receive values of
1628 * debug registers DR0 .. DR7
1629 * Set: Flat address of buffer containing values of
1630 * debug registers DR0 .. DR7 to be set
1631 * Output: None
1634 FIXME("[0014] ECX=%x EDX=%x\n",
1635 context->Ecx, context->Edx);
1637 /* FIXME */
1638 break;
1641 case 0x0015: /* Set Coprocessor Emulation Flag */
1643 * Input: EDX: 0 to deactivate, 1 to activate coprocessor emulation
1645 * Output: None
1648 TRACE("[0015] EDX=%x\n", context->Edx);
1650 /* We don't care, as we always have a coprocessor anyway */
1651 break;
1654 case 0x0016: /* Init Win32S VxD PSP */
1656 * If called to query required PSP size:
1658 * Input: EBX: 0
1659 * Output: EDX: Required size of Win32s VxD PSP
1661 * If called to initialize allocated PSP:
1663 * Input: EBX: LoWord: Selector of Win32s VxD PSP
1664 * HiWord: Paragraph of Win32s VxD PSP (DOSMEM)
1665 * Output: None
1668 if (context->Ebx == 0)
1669 context->Edx = 0x80;
1670 else
1672 PDB16 *psp = MapSL( MAKESEGPTR( BX_reg(context), 0 ));
1673 psp->nbFiles = 32;
1674 psp->fileHandlesPtr = MAKELONG(HIWORD(context->Ebx), 0x5c);
1675 memset((LPBYTE)psp + 0x5c, '\xFF', 32);
1677 break;
1680 case 0x0017: /* Set Break Point */
1682 * Input: EBX: Offset of Break Point
1683 * CX: Selector of Break Point
1685 * Output: None
1688 FIXME("[0017] EBX=%x CX=%x\n",
1689 context->Ebx, CX_reg(context));
1691 /* FIXME */
1692 break;
1695 case 0x0018: /* VirtualLock */
1697 * Input: ECX: Current Process
1699 * EDX: Flat address of arguments on stack
1701 * DWORD *retv [out] TRUE if success, FALSE if failure
1702 * LPVOID base [in] Flat address of range to lock
1703 * DWORD size [in] Size of range
1705 * Output: EAX: NtStatus
1708 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1709 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1710 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1711 DWORD size = stack[2];
1712 DWORD result;
1714 TRACE("VirtualLock(%x, %x, %x)\n",
1715 (DWORD)retv, (DWORD)base, size);
1717 result = VirtualLock(base, size);
1719 if (result)
1720 *retv = TRUE,
1721 context->Eax = STATUS_SUCCESS;
1722 else
1723 *retv = FALSE,
1724 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1726 break;
1729 case 0x0019: /* VirtualUnlock */
1731 * Input: ECX: Current Process
1733 * EDX: Flat address of arguments on stack
1735 * DWORD *retv [out] TRUE if success, FALSE if failure
1736 * LPVOID base [in] Flat address of range to unlock
1737 * DWORD size [in] Size of range
1739 * Output: EAX: NtStatus
1742 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1743 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1744 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1745 DWORD size = stack[2];
1746 DWORD result;
1748 TRACE("VirtualUnlock(%x, %x, %x)\n",
1749 (DWORD)retv, (DWORD)base, size);
1751 result = VirtualUnlock(base, size);
1753 if (result)
1754 *retv = TRUE,
1755 context->Eax = STATUS_SUCCESS;
1756 else
1757 *retv = FALSE,
1758 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1760 break;
1763 case 0x001A: /* KGetSystemInfo */
1765 * Input: None
1767 * Output: ECX: Start of sparse memory arena
1768 * EDX: End of sparse memory arena
1771 TRACE("KGetSystemInfo()\n");
1774 * Note: Win32s reserves 0GB - 2GB for Win 3.1 and uses 2GB - 4GB as
1775 * sparse memory arena. We do it the other way around, since
1776 * we have to reserve 3GB - 4GB for Linux, and thus use
1777 * 0GB - 3GB as sparse memory arena.
1779 * FIXME: What about other OSes ?
1782 context->Ecx = W32S_WINE2APP(0x00000000);
1783 context->Edx = W32S_WINE2APP(0xbfffffff);
1784 break;
1787 case 0x001B: /* KGlobalMemStat */
1789 * Input: ESI: Flat address of buffer to receive memory info
1791 * Output: None
1794 struct Win32sMemoryInfo
1796 DWORD DIPhys_Count; /* Total physical pages */
1797 DWORD DIFree_Count; /* Free physical pages */
1798 DWORD DILin_Total_Count; /* Total virtual pages (private arena) */
1799 DWORD DILin_Total_Free; /* Free virtual pages (private arena) */
1801 DWORD SparseTotal; /* Total size of sparse arena (bytes ?) */
1802 DWORD SparseFree; /* Free size of sparse arena (bytes ?) */
1805 struct Win32sMemoryInfo *info =
1806 (struct Win32sMemoryInfo *)W32S_APP2WINE(context->Esi);
1808 FIXME("KGlobalMemStat(%x)\n", (DWORD)info);
1810 /* FIXME */
1812 break;
1815 case 0x001C: /* Enable/Disable Exceptions */
1817 * Input: ECX: 0 to disable, 1 to enable exception handling
1819 * Output: None
1822 TRACE("[001c] ECX=%x\n", context->Ecx);
1824 /* FIXME */
1825 break;
1828 case 0x001D: /* VirtualAlloc called from 16-bit code */
1830 * Input: EDX: Segmented address of arguments on stack
1832 * LPVOID base [in] Flat address of region to reserve/commit
1833 * DWORD size [in] Size of region
1834 * DWORD type [in] Type of allocation
1835 * DWORD prot [in] Type of access protection
1837 * Output: EAX: NtStatus
1838 * EDX: Flat base address of allocated region
1841 DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) ));
1842 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]);
1843 DWORD size = stack[1];
1844 DWORD type = stack[2];
1845 DWORD prot = stack[3];
1846 DWORD result;
1848 TRACE("VirtualAlloc16(%x, %x, %x, %x)\n",
1849 (DWORD)base, size, type, prot);
1851 if (type & 0x80000000)
1853 WARN("VirtualAlloc16: strange type %x\n", type);
1854 type &= 0x7fffffff;
1857 result = (DWORD)VirtualAlloc(base, size, type, prot);
1859 if (W32S_WINE2APP(result))
1860 context->Edx = W32S_WINE2APP(result),
1861 context->Eax = STATUS_SUCCESS;
1862 else
1863 context->Edx = 0,
1864 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1865 TRACE("VirtualAlloc16: returning base %x\n", context->Edx);
1867 break;
1870 case 0x001E: /* VirtualFree called from 16-bit code */
1872 * Input: EDX: Segmented address of arguments on stack
1874 * LPVOID base [in] Flat address of region
1875 * DWORD size [in] Size of region
1876 * DWORD type [in] Type of operation
1878 * Output: EAX: NtStatus
1879 * EDX: TRUE if success, FALSE if failure
1882 DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) ));
1883 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]);
1884 DWORD size = stack[1];
1885 DWORD type = stack[2];
1886 DWORD result;
1888 TRACE("VirtualFree16(%x, %x, %x)\n",
1889 (DWORD)base, size, type);
1891 result = VirtualFree(base, size, type);
1893 if (result)
1894 context->Edx = TRUE,
1895 context->Eax = STATUS_SUCCESS;
1896 else
1897 context->Edx = FALSE,
1898 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1900 break;
1903 case 0x001F: /* FWorkingSetSize */
1905 * Input: EDX: 0 if Get, 1 if Set
1907 * ECX: Get: Buffer to receive Working Set Size
1908 * Set: Buffer containing Working Set Size
1910 * Output: NtStatus
1913 DWORD *ptr = (DWORD *)W32S_APP2WINE(context->Ecx);
1914 BOOL set = context->Edx;
1916 TRACE("FWorkingSetSize(%x, %x)\n", (DWORD)ptr, (DWORD)set);
1918 if (set)
1919 /* We do it differently ... */;
1920 else
1921 *ptr = 0x100;
1923 context->Eax = STATUS_SUCCESS;
1925 break;
1927 default:
1928 VXD_BARF( context, "W32S" );