bcrypt: Make format_gnutls_signature() static.
[wine.git] / dlls / krnl386.exe16 / vxd.c
blob88d43c2d367bd595a1e0001df3e32344d471b91a
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 W32S_APP2WINE(addr) ((addr)? (DWORD)(addr) + W32S_offset : 0)
84 #define W32S_WINE2APP(addr) ((addr)? (DWORD)(addr) - W32S_offset : 0)
86 #define VXD_BARF(context,name) \
87 TRACE( "vxd %s: unknown/not implemented parameters:\n" \
88 "vxd %s: AX %04x, BX %04x, CX %04x, DX %04x, " \
89 "SI %04x, DI %04x, DS %04x, ES %04x\n", \
90 (name), (name), AX_reg(context), BX_reg(context), \
91 CX_reg(context), DX_reg(context), SI_reg(context), \
92 DI_reg(context), (WORD)context->SegDs, (WORD)context->SegEs )
94 static CRITICAL_SECTION vxd_section;
95 static CRITICAL_SECTION_DEBUG critsect_debug =
97 0, 0, &vxd_section,
98 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
99 0, 0, { (DWORD_PTR)(__FILE__ ": vxd_section") }
101 static CRITICAL_SECTION vxd_section = { &critsect_debug, -1, 0, 0, 0, 0 };
103 static UINT W32S_offset;
105 static WORD VXD_WinVersion(void)
107 WORD version = LOWORD(GetVersion16());
108 return (version >> 8) | (version << 8);
111 /* create a file handle to represent a VxD, by opening a dummy file in the wineserver directory */
112 static HANDLE open_vxd_handle( LPCWSTR name )
114 static const WCHAR prefixW[] = {'\\','?','?','\\','u','n','i','x'};
115 const char *dir = wine_get_server_dir();
116 int len;
117 HANDLE ret;
118 NTSTATUS status;
119 OBJECT_ATTRIBUTES attr;
120 UNICODE_STRING nameW;
121 IO_STATUS_BLOCK io;
123 len = MultiByteToWideChar( CP_UNIXCP, 0, dir, -1, NULL, 0 );
124 nameW.Length = sizeof(prefixW) + (len + strlenW( name )) * sizeof(WCHAR);
125 nameW.MaximumLength = nameW.Length + sizeof(WCHAR);
126 if (!(nameW.Buffer = HeapAlloc( GetProcessHeap(), 0, nameW.MaximumLength )))
128 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
129 return 0;
131 memcpy( nameW.Buffer, prefixW, sizeof(prefixW) );
132 MultiByteToWideChar( CP_UNIXCP, 0, dir, -1, nameW.Buffer + ARRAY_SIZE(prefixW), len );
133 len += ARRAY_SIZE(prefixW);
134 nameW.Buffer[len-1] = '/';
135 strcpyW( nameW.Buffer + len, name );
137 attr.Length = sizeof(attr);
138 attr.RootDirectory = 0;
139 attr.Attributes = 0;
140 attr.ObjectName = &nameW;
141 attr.SecurityDescriptor = NULL;
142 attr.SecurityQualityOfService = NULL;
144 status = NtCreateFile( &ret, SYNCHRONIZE, &attr, &io, NULL, 0,
145 FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN_IF,
146 FILE_SYNCHRONOUS_IO_ALERT, NULL, 0 );
147 if (status)
149 ret = 0;
150 SetLastError( RtlNtStatusToDosError(status) );
152 RtlFreeUnicodeString( &nameW );
153 return ret;
156 /* retrieve the DeviceIoControl function for a Vxd given a file handle */
157 DeviceIoProc __wine_vxd_get_proc( HANDLE handle )
159 DeviceIoProc ret = NULL;
160 int status, i;
161 IO_STATUS_BLOCK io;
162 FILE_INTERNAL_INFORMATION info;
164 status = NtQueryInformationFile( handle, &io, &info, sizeof(info), FileInternalInformation );
165 if (status)
167 SetLastError( RtlNtStatusToDosError(status) );
168 return NULL;
171 RtlEnterCriticalSection( &vxd_section );
173 for (i = 0; i < MAX_VXD_MODULES; i++)
175 if (!vxd_modules[i].module) break;
176 if (vxd_modules[i].index.QuadPart == info.IndexNumber.QuadPart)
178 if (!(ret = vxd_modules[i].proc)) SetLastError( ERROR_INVALID_FUNCTION );
179 goto done;
182 /* FIXME: Here we could go through the directory to find the VxD name and load it. */
183 /* Let's wait to find out if there are actually apps out there that try to share */
184 /* VxD handles between processes, before we go to the trouble of implementing it. */
185 ERR( "handle %p not found in module list, inherited from another process?\n", handle );
187 done:
188 RtlLeaveCriticalSection( &vxd_section );
189 return ret;
193 /* load a VxD and return a file handle to it */
194 HANDLE __wine_vxd_open( LPCWSTR filenameW, DWORD access, SECURITY_ATTRIBUTES *sa )
196 static const WCHAR dotVxDW[] = {'.','v','x','d',0};
197 int i;
198 HANDLE handle;
199 HMODULE module;
200 WCHAR *p, name[16];
202 /* normalize the filename */
204 if (strlenW( filenameW ) >= ARRAY_SIZE(name) - 4 ||
205 strchrW( filenameW, '/' ) || strchrW( filenameW, '\\' ))
207 SetLastError( ERROR_FILE_NOT_FOUND );
208 return 0;
210 strcpyW( name, filenameW );
211 strlwrW( name );
212 p = strchrW( name, '.' );
213 if (!p) strcatW( name, dotVxDW );
214 else if (strcmpiW( p, dotVxDW )) /* existing extension has to be .vxd */
216 SetLastError( ERROR_FILE_NOT_FOUND );
217 return 0;
220 /* try to load the module first */
222 if (!(module = LoadLibraryW( name )))
224 FIXME( "Unknown/unsupported VxD %s. Try setting Windows version to 'nt40' or 'win31'.\n",
225 debugstr_w(name) );
226 SetLastError( ERROR_FILE_NOT_FOUND );
227 return 0;
230 /* register the module in the global list if necessary */
232 RtlEnterCriticalSection( &vxd_section );
234 for (i = 0; i < MAX_VXD_MODULES; i++)
236 if (vxd_modules[i].module == module)
238 handle = vxd_modules[i].handle;
239 goto done; /* already registered */
241 if (!vxd_modules[i].module) /* new one, register it */
243 IO_STATUS_BLOCK io;
244 FILE_INTERNAL_INFORMATION info;
246 /* get a file handle to the dummy file */
247 if (!(handle = open_vxd_handle( name )))
249 FreeLibrary( module );
250 goto done;
252 if (!NtQueryInformationFile( handle, &io, &info, sizeof(info), FileInternalInformation ))
253 vxd_modules[i].index = info.IndexNumber;
255 vxd_modules[i].module = module;
256 vxd_modules[i].handle = handle;
257 vxd_modules[i].proc = (DeviceIoProc)GetProcAddress( module, "DeviceIoControl" );
258 goto done;
262 ERR("too many open VxD modules, please report\n" );
263 FreeLibrary( module );
264 handle = 0;
266 done:
267 RtlLeaveCriticalSection( &vxd_section );
268 if (!DuplicateHandle( GetCurrentProcess(), handle, GetCurrentProcess(), &handle, 0,
269 (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle),
270 DUP_HANDLE_SAME_ACCESS ))
271 handle = 0;
272 return handle;
276 /***********************************************************************
277 * VxDCall0 (KERNEL32.1)
278 * VxDCall1 (KERNEL32.2)
279 * VxDCall2 (KERNEL32.3)
280 * VxDCall3 (KERNEL32.4)
281 * VxDCall4 (KERNEL32.5)
282 * VxDCall5 (KERNEL32.6)
283 * VxDCall6 (KERNEL32.7)
284 * VxDCall7 (KERNEL32.8)
285 * VxDCall8 (KERNEL32.9)
287 void WINAPI DECLSPEC_HIDDEN __regs_VxDCall( CONTEXT *context )
289 unsigned int i;
290 VxDCallProc proc = NULL;
291 DWORD service = stack32_pop( context );
293 RtlEnterCriticalSection( &vxd_section );
294 for (i = 0; i < ARRAY_SIZE(vxd_services); i++)
296 if (HIWORD(service) != vxd_services[i].service) continue;
297 if (!vxd_services[i].module) /* need to load it */
299 if ((vxd_services[i].module = LoadLibraryW( vxd_services[i].name )))
300 vxd_services[i].proc = (VxDCallProc)GetProcAddress( vxd_services[i].module, "VxDCall" );
302 proc = vxd_services[i].proc;
303 break;
305 RtlLeaveCriticalSection( &vxd_section );
307 if (proc) context->Eax = proc( service, context );
308 else
310 FIXME( "Unknown/unimplemented VxD (%08x)\n", service);
311 context->Eax = 0xffffffff; /* FIXME */
314 DEFINE_REGS_ENTRYPOINT( VxDCall )
317 /***********************************************************************
318 * __wine_vxd_vmm (WPROCS.401)
320 void WINAPI __wine_vxd_vmm ( CONTEXT *context )
322 unsigned service = AX_reg(context);
324 TRACE("[%04x] VMM\n", (UINT16)service);
326 switch(service)
328 case 0x0000: /* version */
329 SET_AX( context, VXD_WinVersion() );
330 RESET_CFLAG(context);
331 break;
333 case 0x026d: /* Get_Debug_Flag '/m' */
334 case 0x026e: /* Get_Debug_Flag '/n' */
335 SET_AL( context, 0 );
336 RESET_CFLAG(context);
337 break;
339 default:
340 VXD_BARF( context, "VMM" );
344 /***********************************************************************
345 * __wine_vxd_pagefile (WPROCS.433)
347 void WINAPI __wine_vxd_pagefile( CONTEXT *context )
349 unsigned service = AX_reg(context);
351 /* taken from Ralf Brown's Interrupt List */
353 TRACE("[%04x] PageFile\n", (UINT16)service );
355 switch(service)
357 case 0x00: /* get version, is this windows version? */
358 TRACE("returning version\n");
359 SET_AX( context, VXD_WinVersion() );
360 RESET_CFLAG(context);
361 break;
363 case 0x01: /* get swap file info */
364 TRACE("VxD PageFile: returning swap file info\n");
365 SET_AX( context, 0x00 ); /* paging disabled */
366 context->Ecx = 0; /* maximum size of paging file */
367 /* FIXME: do I touch DS:SI or DS:DI? */
368 RESET_CFLAG(context);
369 break;
371 case 0x02: /* delete permanent swap on exit */
372 TRACE("VxD PageFile: supposed to delete swap\n");
373 RESET_CFLAG(context);
374 break;
376 case 0x03: /* current temporary swap file size */
377 TRACE("VxD PageFile: what is current temp. swap size\n");
378 RESET_CFLAG(context);
379 break;
381 case 0x04: /* read or write?? INTERRUP.D */
382 case 0x05: /* cancel?? INTERRUP.D */
383 case 0x06: /* test I/O valid INTERRUP.D */
384 default:
385 VXD_BARF( context, "pagefile" );
386 break;
390 /***********************************************************************
391 * __wine_vxd_reboot (WPROCS.409)
393 void WINAPI __wine_vxd_reboot( CONTEXT *context )
395 unsigned service = AX_reg(context);
397 TRACE("[%04x] Reboot\n", (UINT16)service);
399 switch(service)
401 case 0x0000: /* version */
402 SET_AX( context, VXD_WinVersion() );
403 RESET_CFLAG(context);
404 break;
406 default:
407 VXD_BARF( context, "REBOOT" );
411 /***********************************************************************
412 * __wine_vxd_vdd (WPROCS.410)
414 void WINAPI __wine_vxd_vdd( CONTEXT *context )
416 unsigned service = AX_reg(context);
418 TRACE("[%04x] VDD\n", (UINT16)service);
420 switch(service)
422 case 0x0000: /* version */
423 SET_AX( context, VXD_WinVersion() );
424 RESET_CFLAG(context);
425 break;
427 default:
428 VXD_BARF( context, "VDD" );
432 /***********************************************************************
433 * __wine_vxd_vmd (WPROCS.412)
435 void WINAPI __wine_vxd_vmd( CONTEXT *context )
437 unsigned service = AX_reg(context);
439 TRACE("[%04x] VMD\n", (UINT16)service);
441 switch(service)
443 case 0x0000: /* version */
444 SET_AX( context, VXD_WinVersion() );
445 RESET_CFLAG(context);
446 break;
448 default:
449 VXD_BARF( context, "VMD" );
453 /***********************************************************************
454 * __wine_vxd_vxdloader (WPROCS.439)
456 void WINAPI __wine_vxd_vxdloader( CONTEXT *context )
458 unsigned service = AX_reg(context);
460 TRACE("[%04x] VXDLoader\n", (UINT16)service);
462 switch (service)
464 case 0x0000: /* get version */
465 TRACE("returning version\n");
466 SET_AX( context, 0x0000 );
467 SET_DX( context, VXD_WinVersion() );
468 RESET_CFLAG(context);
469 break;
471 case 0x0001: /* load device */
472 FIXME("load device %04x:%04x (%s)\n",
473 context->SegDs, DX_reg(context),
474 debugstr_a(MapSL(MAKESEGPTR(context->SegDs, DX_reg(context)))));
475 SET_AX( context, 0x0000 );
476 context->SegEs = 0x0000;
477 SET_DI( context, 0x0000 );
478 RESET_CFLAG(context);
479 break;
481 case 0x0002: /* unload device */
482 FIXME("unload device (%08x)\n", context->Ebx);
483 SET_AX( context, 0x0000 );
484 RESET_CFLAG(context);
485 break;
487 default:
488 VXD_BARF( context, "VXDLDR" );
489 SET_AX( context, 0x000B ); /* invalid function number */
490 SET_CFLAG(context);
491 break;
495 /***********************************************************************
496 * __wine_vxd_shell (WPROCS.423)
498 void WINAPI __wine_vxd_shell( CONTEXT *context )
500 unsigned service = DX_reg(context);
502 TRACE("[%04x] Shell\n", (UINT16)service);
504 switch (service) /* Ralf Brown says EDX, but I use DX instead */
506 case 0x0000:
507 TRACE("returning version\n");
508 SET_AX( context, VXD_WinVersion() );
509 context->Ebx = 1; /* system VM Handle */
510 break;
512 case 0x0001:
513 case 0x0002:
514 case 0x0003:
515 /* SHELL_SYSMODAL_Message
516 ebx virtual machine handle
517 eax message box flags
518 ecx address of message
519 edi address of caption
520 return response in eax
522 case 0x0004:
523 /* SHELL_Message
524 ebx virtual machine handle
525 eax message box flags
526 ecx address of message
527 edi address of caption
528 esi address callback
529 edx reference data for callback
530 return response in eax
532 case 0x0005:
533 VXD_BARF( context, "shell" );
534 break;
536 case 0x0006: /* SHELL_Get_VM_State */
537 TRACE("VxD Shell: returning VM state\n");
538 /* Actually we don't, not yet. We have to return a structure
539 * and I am not to sure how to set it up and return it yet,
540 * so for now let's do nothing. I can (hopefully) get this
541 * by the next release
543 /* RESET_CFLAG(context); */
544 break;
546 case 0x0007:
547 case 0x0008:
548 case 0x0009:
549 case 0x000A:
550 case 0x000B:
551 case 0x000C:
552 case 0x000D:
553 case 0x000E:
554 case 0x000F:
555 case 0x0010:
556 case 0x0011:
557 case 0x0012:
558 case 0x0013:
559 case 0x0014:
560 case 0x0015:
561 case 0x0016:
562 VXD_BARF( context, "SHELL" );
563 break;
565 /* the new Win95 shell API */
566 case 0x0100: /* get version */
567 SET_AX( context, VXD_WinVersion() );
568 break;
570 case 0x0104: /* retrieve Hook_Properties list */
571 case 0x0105: /* call Hook_Properties callbacks */
572 VXD_BARF( context, "SHELL" );
573 break;
575 case 0x0106: /* install timeout callback */
576 TRACE("VxD Shell: ignoring shell callback (%d sec.)\n", context->Ebx);
577 SET_CFLAG(context);
578 break;
580 case 0x0107: /* get version of any VxD */
581 default:
582 VXD_BARF( context, "SHELL" );
583 break;
588 /***********************************************************************
589 * __wine_vxd_comm (WPROCS.414)
591 void WINAPI __wine_vxd_comm( CONTEXT *context )
593 unsigned service = AX_reg(context);
595 TRACE("[%04x] Comm\n", (UINT16)service);
597 switch (service)
599 case 0x0000: /* get version */
600 TRACE("returning version\n");
601 SET_AX( context, VXD_WinVersion() );
602 RESET_CFLAG(context);
603 break;
605 case 0x0001: /* set port global */
606 case 0x0002: /* get focus */
607 case 0x0003: /* virtualise port */
608 default:
609 VXD_BARF( context, "comm" );
613 /***********************************************************************
614 * __wine_vxd_timer (WPROCS.405)
616 void WINAPI __wine_vxd_timer( CONTEXT *context )
618 unsigned service = AX_reg(context);
620 TRACE("[%04x] Virtual Timer\n", (UINT16)service);
622 switch(service)
624 case 0x0000: /* version */
625 SET_AX( context, VXD_WinVersion() );
626 RESET_CFLAG(context);
627 break;
629 case 0x0100: /* clock tick time, in 840nsecs */
630 context->Eax = GetTickCount();
632 context->Edx = context->Eax >> 22;
633 context->Eax <<= 10; /* not very precise */
634 break;
636 case 0x0101: /* current Windows time, msecs */
637 case 0x0102: /* current VM time, msecs */
638 context->Eax = GetTickCount();
639 break;
641 default:
642 VXD_BARF( context, "VTD" );
647 /***********************************************************************
648 * timer_thread
650 static DWORD CALLBACK timer_thread( void *arg )
652 DWORD *system_time = arg;
654 for (;;)
656 *system_time = GetTickCount();
657 Sleep( 55 );
660 return 0;
664 /***********************************************************************
665 * __wine_vxd_timerapi (WPROCS.1490)
667 void WINAPI __wine_vxd_timerapi( CONTEXT *context )
669 static WORD System_Time_Selector;
671 unsigned service = AX_reg(context);
673 TRACE("[%04x] TimerAPI\n", (UINT16)service);
675 switch(service)
677 case 0x0000: /* version */
678 SET_AX( context, VXD_WinVersion() );
679 RESET_CFLAG(context);
680 break;
682 case 0x0009: /* get system time selector */
683 if ( !System_Time_Selector )
685 HANDLE16 handle = GlobalAlloc16( GMEM_FIXED, sizeof(DWORD) );
686 System_Time_Selector = handle | 7;
687 CloseHandle( CreateThread( NULL, 0, timer_thread, GlobalLock16(handle), 0, NULL ) );
689 SET_AX( context, System_Time_Selector );
690 RESET_CFLAG(context);
691 break;
693 default:
694 VXD_BARF( context, "VTDAPI" );
698 /***********************************************************************
699 * __wine_vxd_configmg (WPROCS.451)
701 void WINAPI __wine_vxd_configmg( CONTEXT *context )
703 unsigned service = AX_reg(context);
705 TRACE("[%04x] ConfigMG\n", (UINT16)service);
707 switch(service)
709 case 0x0000: /* version */
710 SET_AX( context, VXD_WinVersion() );
711 RESET_CFLAG(context);
712 break;
714 default:
715 VXD_BARF( context, "CONFIGMG" );
719 /***********************************************************************
720 * __wine_vxd_enable (WPROCS.455)
722 void WINAPI __wine_vxd_enable( CONTEXT *context )
724 unsigned service = AX_reg(context);
726 TRACE("[%04x] Enable\n", (UINT16)service);
728 switch(service)
730 case 0x0000: /* version */
731 SET_AX( context, VXD_WinVersion() );
732 RESET_CFLAG(context);
733 break;
735 default:
736 VXD_BARF( context, "ENABLE" );
740 /***********************************************************************
741 * __wine_vxd_apm (WPROCS.438)
743 void WINAPI __wine_vxd_apm( CONTEXT *context )
745 unsigned service = AX_reg(context);
747 TRACE("[%04x] APM\n", (UINT16)service);
749 switch(service)
751 case 0x0000: /* version */
752 SET_AX( context, VXD_WinVersion() );
753 RESET_CFLAG(context);
754 break;
756 default:
757 VXD_BARF( context, "APM" );
761 /***********************************************************************
762 * __wine_vxd_win32s (WPROCS.445)
764 * This is an implementation of the services of the Win32s VxD.
765 * Since official documentation of these does not seem to be available,
766 * certain arguments of some of the services remain unclear.
768 * FIXME: The following services are currently unimplemented:
769 * Exception handling (0x01, 0x1C)
770 * Debugger support (0x0C, 0x14, 0x17)
771 * Low-level memory access (0x02, 0x03, 0x0A, 0x0B)
772 * Memory Statistics (0x1B)
775 * We have a specific problem running Win32s on Linux (and probably also
776 * the other x86 unixes), since Win32s tries to allocate its main 'flat
777 * code/data segment' selectors with a base of 0xffff0000 (and limit 4GB).
778 * The rationale for this seems to be that they want one the one hand to
779 * be able to leave the Win 3.1 memory (starting with the main DOS memory)
780 * at linear address 0, but want at other hand to have offset 0 of the
781 * flat data/code segment point to an unmapped page (to catch NULL pointer
782 * accesses). Hence they allocate the flat segments with a base of 0xffff0000
783 * so that the Win 3.1 memory area at linear address zero shows up in the
784 * flat segments at offset 0x10000 (since linear addresses wrap around at
785 * 4GB). To compensate for that discrepancy between flat segment offsets
786 * and plain linear addresses, all flat pointers passed between the 32-bit
787 * and the 16-bit parts of Win32s are shifted by 0x10000 in the appropriate
788 * direction by the glue code (mainly) in W32SKRNL and WIN32S16.
790 * The problem for us is now that Linux does not allow a LDT selector with
791 * base 0xffff0000 to be created, since it would 'see' a part of the kernel
792 * address space. To address this problem we introduce *another* offset:
793 * We add 0x10000 to every linear address we get as an argument from Win32s.
794 * This means especially that the flat code/data selectors get actually
795 * allocated with base 0x0, so that flat offsets and (real) linear addresses
796 * do again agree! In fact, every call e.g. of a Win32s VxD service now
797 * has all pointer arguments (which are offsets in the flat data segment)
798 * first reduced by 0x10000 by the W32SKRNL glue code, and then again
799 * increased by 0x10000 by *our* code.
801 * Note that to keep everything consistent, this offset has to be applied by
802 * every Wine function that operates on 'linear addresses' passed to it by
803 * Win32s. Fortunately, since Win32s does not directly call any Wine 32-bit
804 * API routines, this affects only two locations: this VxD and the DPMI
805 * handler. (NOTE: Should any Win32s application pass a linear address to
806 * any routine apart from those, e.g. some other VxD handler, that code
807 * would have to take the offset into account as well!)
809 * The offset is set the first time any application calls the GetVersion()
810 * service of the Win32s VxD. (Note that the offset is never reset.)
813 void WINAPI __wine_vxd_win32s( CONTEXT *context )
815 switch (AX_reg(context))
817 case 0x0000: /* Get Version */
819 * Input: None
821 * Output: EAX: LoWord: Win32s Version (1.30)
822 * HiWord: VxD Version (200)
824 * EBX: Build (172)
826 * ECX: ??? (1)
828 * EDX: Debugging Flags
830 * EDI: Error Flag
831 * 0 if OK,
832 * 1 if VMCPD VxD not found
835 TRACE("GetVersion()\n");
837 context->Eax = VXD_WinVersion() | (200 << 16);
838 context->Ebx = 0;
839 context->Ecx = 0;
840 context->Edx = 0;
841 context->Edi = 0;
844 * If this is the first time we are called for this process,
845 * hack the memory image of WIN32S16 so that it doesn't try
846 * to access the GDT directly ...
848 * The first code segment of WIN32S16 (version 1.30) contains
849 * an unexported function somewhere between the exported functions
850 * SetFS and StackLinearToSegmented that tries to find a selector
851 * in the LDT that maps to the memory image of the LDT itself.
852 * If it succeeds, it stores this selector into a global variable
853 * which will be used to speed up execution by using this selector
854 * to modify the LDT directly instead of using the DPMI calls.
856 * To perform this search of the LDT, this function uses the
857 * sgdt and sldt instructions to find the linear address of
858 * the (GDT and then) LDT. While those instructions themselves
859 * execute without problem, the linear address that sgdt returns
860 * points (at least under Linux) to the kernel address space, so
861 * that any subsequent access leads to a segfault.
863 * Fortunately, WIN32S16 still contains as a fallback option the
864 * mechanism of using DPMI calls to modify LDT selectors instead
865 * of direct writes to the LDT. Thus we can circumvent the problem
866 * by simply replacing the first byte of the offending function
867 * with an 'retf' instruction. This means that the global variable
868 * supposed to contain the LDT alias selector will remain zero,
869 * and hence WIN32S16 will fall back to using DPMI calls.
871 * The heuristic we employ to _find_ that function is as follows:
872 * We search between the addresses of the exported symbols SetFS
873 * and StackLinearToSegmented for the byte sequence '0F 01 04'
874 * (this is the opcode of 'sgdt [si]'). We then search backwards
875 * from this address for the last occurrence of 'CB' (retf) that marks
876 * the end of the preceding function. The following byte (which
877 * should now be the first byte of the function we are looking for)
878 * will be replaced by 'CB' (retf).
880 * This heuristic works for the retail as well as the debug version
881 * of Win32s version 1.30. For versions earlier than that this
882 * hack should not be necessary at all, since the whole mechanism
883 * ('PERF130') was introduced only in 1.30 to improve the overall
884 * performance of Win32s.
887 if (!W32S_offset)
889 HMODULE16 hModule = GetModuleHandle16("win32s16");
890 SEGPTR func1 = (SEGPTR)GetProcAddress16(hModule, "SetFS");
891 SEGPTR func2 = (SEGPTR)GetProcAddress16(hModule, "StackLinearToSegmented");
893 if ( hModule && func1 && func2
894 && SELECTOROF(func1) == SELECTOROF(func2))
896 BYTE *start = MapSL(func1);
897 BYTE *end = MapSL(func2);
898 BYTE *p, *retv = NULL;
899 int found = 0;
901 for (p = start; p < end; p++)
902 if (*p == 0xCB) found = 0, retv = p;
903 else if (*p == 0x0F) found = 1;
904 else if (*p == 0x01 && found == 1) found = 2;
905 else if (*p == 0x04 && found == 2) { found = 3; break; }
906 else found = 0;
908 if (found == 3 && retv)
910 TRACE("PERF130 hack: "
911 "Replacing byte %02X at offset %04X:%04X\n",
912 *(retv+1), SELECTOROF(func1),
913 OFFSETOF(func1) + retv+1-start);
915 *(retv+1) = (BYTE)0xCB;
921 * Mark process as Win32s, so that subsequent DPMI calls
922 * will perform the W32S_APP2WINE/W32S_WINE2APP address shift.
924 W32S_offset = 0x10000;
925 break;
928 case 0x0001: /* Install Exception Handling */
930 * Input: EBX: Flat address of W32SKRNL Exception Data
932 * ECX: LoWord: Flat Code Selector
933 * HiWord: Flat Data Selector
935 * EDX: Flat address of W32SKRNL Exception Handler
936 * (this is equal to W32S_BackTo32 + 0x40)
938 * ESI: SEGPTR KERNEL.HASGPHANDLER
940 * EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10)
942 * Output: EAX: 0 if OK
945 TRACE("[0001] EBX=%x ECX=%x EDX=%x ESI=%x EDI=%x\n",
946 context->Ebx, context->Ecx, context->Edx,
947 context->Esi, context->Edi);
949 /* FIXME */
951 context->Eax = 0;
952 break;
955 case 0x0002: /* Set Page Access Flags */
957 * Input: EBX: New access flags
958 * Bit 2: User Page if set, Supervisor Page if clear
959 * Bit 1: Read-Write if set, Read-Only if clear
961 * ECX: Size of memory area to change
963 * EDX: Flat start address of memory area
965 * Output: EAX: Size of area changed
968 TRACE("[0002] EBX=%x ECX=%x EDX=%x\n",
969 context->Ebx, context->Ecx, context->Edx);
971 /* FIXME */
973 context->Eax = context->Ecx;
974 break;
977 case 0x0003: /* Get Page Access Flags */
979 * Input: EDX: Flat address of page to query
981 * Output: EAX: Page access flags
982 * Bit 2: User Page if set, Supervisor Page if clear
983 * Bit 1: Read-Write if set, Read-Only if clear
986 TRACE("[0003] EDX=%x\n", context->Edx);
988 /* FIXME */
990 context->Eax = 6;
991 break;
994 case 0x0004: /* Map Module */
996 * Input: ECX: IMTE (offset in Module Table) of new module
998 * EDX: Flat address of Win32s Module Table
1000 * Output: EAX: 0 if OK
1003 if (!context->Edx || CX_reg(context) == 0xFFFF)
1005 TRACE("MapModule: Initialization call\n");
1006 context->Eax = 0;
1008 else
1011 * Structure of a Win32s Module Table Entry:
1013 struct Win32sModule
1015 DWORD flags;
1016 DWORD flatBaseAddr;
1017 LPCSTR moduleName;
1018 LPCSTR pathName;
1019 LPCSTR unknown;
1020 LPBYTE baseAddr;
1021 DWORD hModule;
1022 DWORD relocDelta;
1026 * Note: This function should set up a demand-paged memory image
1027 * of the given module. Since mmap does not allow file offsets
1028 * not aligned at 1024 bytes, we simply load the image fully
1029 * into memory.
1032 struct Win32sModule *moduleTable =
1033 (struct Win32sModule *)W32S_APP2WINE(context->Edx);
1034 struct Win32sModule *module = moduleTable + context->Ecx;
1036 IMAGE_NT_HEADERS *nt_header = RtlImageNtHeader( (HMODULE)module->baseAddr );
1037 IMAGE_SECTION_HEADER *pe_seg = (IMAGE_SECTION_HEADER*)((char *)&nt_header->OptionalHeader +
1038 nt_header->FileHeader.SizeOfOptionalHeader);
1041 HFILE image = _lopen(module->pathName, OF_READ);
1042 BOOL error = (image == HFILE_ERROR);
1043 UINT i;
1045 TRACE("MapModule: Loading %s\n", module->pathName);
1047 for (i = 0;
1048 !error && i < nt_header->FileHeader.NumberOfSections;
1049 i++, pe_seg++)
1050 if(!(pe_seg->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA))
1052 DWORD off = pe_seg->PointerToRawData;
1053 DWORD len = pe_seg->SizeOfRawData;
1054 LPBYTE addr = module->baseAddr + pe_seg->VirtualAddress;
1056 TRACE("MapModule: "
1057 "Section %d at %08x from %08x len %08x\n",
1058 i, (DWORD)addr, off, len);
1060 if ( _llseek(image, off, SEEK_SET) != off
1061 || _lread(image, addr, len) != len)
1062 error = TRUE;
1065 _lclose(image);
1067 if (error)
1068 ERR("MapModule: Unable to load %s\n", module->pathName);
1070 else if (module->relocDelta != 0)
1072 IMAGE_DATA_DIRECTORY *dir = nt_header->OptionalHeader.DataDirectory
1073 + IMAGE_DIRECTORY_ENTRY_BASERELOC;
1074 IMAGE_BASE_RELOCATION *r = (IMAGE_BASE_RELOCATION *)
1075 (dir->Size? module->baseAddr + dir->VirtualAddress : 0);
1077 TRACE("MapModule: Reloc delta %08x\n", module->relocDelta);
1079 while (r && r->VirtualAddress)
1081 LPBYTE page = module->baseAddr + r->VirtualAddress;
1082 WORD *TypeOffset = (WORD *)(r + 1);
1083 unsigned int count = (r->SizeOfBlock - sizeof(*r)) / sizeof(*TypeOffset);
1085 TRACE("MapModule: %d relocations for page %08x\n",
1086 count, (DWORD)page);
1088 for(i = 0; i < count; i++)
1090 int offset = TypeOffset[i] & 0xFFF;
1091 int type = TypeOffset[i] >> 12;
1092 switch(type)
1094 case IMAGE_REL_BASED_ABSOLUTE:
1095 break;
1096 case IMAGE_REL_BASED_HIGH:
1097 *(WORD *)(page+offset) += HIWORD(module->relocDelta);
1098 break;
1099 case IMAGE_REL_BASED_LOW:
1100 *(WORD *)(page+offset) += LOWORD(module->relocDelta);
1101 break;
1102 case IMAGE_REL_BASED_HIGHLOW:
1103 *(DWORD*)(page+offset) += module->relocDelta;
1104 break;
1105 default:
1106 WARN("MapModule: Unsupported fixup type\n");
1107 break;
1111 r = (IMAGE_BASE_RELOCATION *)((LPBYTE)r + r->SizeOfBlock);
1115 context->Eax = 0;
1116 RESET_CFLAG(context);
1118 break;
1121 case 0x0005: /* UnMap Module */
1123 * Input: EDX: Flat address of module image
1125 * Output: EAX: 1 if OK
1128 TRACE("UnMapModule: %x\n", W32S_APP2WINE(context->Edx));
1130 /* As we didn't map anything, there's nothing to unmap ... */
1132 context->Eax = 1;
1133 break;
1136 case 0x0006: /* VirtualAlloc */
1138 * Input: ECX: Current Process
1140 * EDX: Flat address of arguments on stack
1142 * DWORD *retv [out] Flat base address of allocated region
1143 * LPVOID base [in] Flat address of region to reserve/commit
1144 * DWORD size [in] Size of region
1145 * DWORD type [in] Type of allocation
1146 * DWORD prot [in] Type of access protection
1148 * Output: EAX: NtStatus
1151 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1152 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1153 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1154 DWORD size = stack[2];
1155 DWORD type = stack[3];
1156 DWORD prot = stack[4];
1157 DWORD result;
1159 TRACE("VirtualAlloc(%x, %x, %x, %x, %x)\n",
1160 (DWORD)retv, (DWORD)base, size, type, prot);
1162 if (type & 0x80000000)
1164 WARN("VirtualAlloc: strange type %x\n", type);
1165 type &= 0x7fffffff;
1168 if (!base && (type & MEM_COMMIT) && prot == PAGE_READONLY)
1170 WARN("VirtualAlloc: NLS hack, allowing write access!\n");
1171 prot = PAGE_READWRITE;
1174 result = (DWORD)VirtualAlloc(base, size, type, prot);
1176 if (W32S_WINE2APP(result))
1177 *retv = W32S_WINE2APP(result),
1178 context->Eax = STATUS_SUCCESS;
1179 else
1180 *retv = 0,
1181 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1183 break;
1186 case 0x0007: /* VirtualFree */
1188 * Input: ECX: Current Process
1190 * EDX: Flat address of arguments on stack
1192 * DWORD *retv [out] TRUE if success, FALSE if failure
1193 * LPVOID base [in] Flat address of region
1194 * DWORD size [in] Size of region
1195 * DWORD type [in] Type of operation
1197 * Output: EAX: NtStatus
1200 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1201 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1202 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1203 DWORD size = stack[2];
1204 DWORD type = stack[3];
1205 DWORD result;
1207 TRACE("VirtualFree(%x, %x, %x, %x)\n",
1208 (DWORD)retv, (DWORD)base, size, type);
1210 result = VirtualFree(base, size, type);
1212 if (result)
1213 *retv = TRUE,
1214 context->Eax = STATUS_SUCCESS;
1215 else
1216 *retv = FALSE,
1217 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1219 break;
1222 case 0x0008: /* VirtualProtect */
1224 * Input: ECX: Current Process
1226 * EDX: Flat address of arguments on stack
1228 * DWORD *retv [out] TRUE if success, FALSE if failure
1229 * LPVOID base [in] Flat address of region
1230 * DWORD size [in] Size of region
1231 * DWORD new_prot [in] Desired access protection
1232 * DWORD *old_prot [out] Previous access protection
1234 * Output: EAX: NtStatus
1237 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1238 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1239 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1240 DWORD size = stack[2];
1241 DWORD new_prot = stack[3];
1242 DWORD *old_prot = (DWORD *)W32S_APP2WINE(stack[4]);
1243 DWORD result;
1245 TRACE("VirtualProtect(%x, %x, %x, %x, %x)\n",
1246 (DWORD)retv, (DWORD)base, size, new_prot, (DWORD)old_prot);
1248 result = VirtualProtect(base, size, new_prot, old_prot);
1250 if (result)
1251 *retv = TRUE,
1252 context->Eax = STATUS_SUCCESS;
1253 else
1254 *retv = FALSE,
1255 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1257 break;
1260 case 0x0009: /* VirtualQuery */
1262 * Input: ECX: Current Process
1264 * EDX: Flat address of arguments on stack
1266 * DWORD *retv [out] Nr. bytes returned
1267 * LPVOID base [in] Flat address of region
1268 * LPMEMORY_BASIC_INFORMATION info [out] Info buffer
1269 * DWORD len [in] Size of buffer
1271 * Output: EAX: NtStatus
1274 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1275 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1276 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1277 PMEMORY_BASIC_INFORMATION info =
1278 (PMEMORY_BASIC_INFORMATION)W32S_APP2WINE(stack[2]);
1279 DWORD len = stack[3];
1280 DWORD result;
1282 TRACE("VirtualQuery(%x, %x, %x, %x)\n",
1283 (DWORD)retv, (DWORD)base, (DWORD)info, len);
1285 result = VirtualQuery(base, info, len);
1287 *retv = result;
1288 context->Eax = STATUS_SUCCESS;
1290 break;
1293 case 0x000A: /* SetVirtMemProcess */
1295 * Input: ECX: Process Handle
1297 * EDX: Flat address of region
1299 * Output: EAX: NtStatus
1302 TRACE("[000a] ECX=%x EDX=%x\n",
1303 context->Ecx, context->Edx);
1305 /* FIXME */
1307 context->Eax = STATUS_SUCCESS;
1308 break;
1311 case 0x000B: /* ??? some kind of cleanup */
1313 * Input: ECX: Process Handle
1315 * Output: EAX: NtStatus
1318 TRACE("[000b] ECX=%x\n", context->Ecx);
1320 /* FIXME */
1322 context->Eax = STATUS_SUCCESS;
1323 break;
1326 case 0x000C: /* Set Debug Flags */
1328 * Input: EDX: Debug Flags
1330 * Output: EDX: Previous Debug Flags
1333 FIXME("[000c] EDX=%x\n", context->Edx);
1335 /* FIXME */
1337 context->Edx = 0;
1338 break;
1341 case 0x000D: /* NtCreateSection */
1343 * Input: EDX: Flat address of arguments on stack
1345 * HANDLE32 *retv [out] Handle of Section created
1346 * DWORD flags1 [in] (?? unknown ??)
1347 * DWORD atom [in] Name of Section to create
1348 * LARGE_INTEGER *size [in] Size of Section
1349 * DWORD protect [in] Access protection
1350 * DWORD flags2 [in] (?? unknown ??)
1351 * HFILE32 hFile [in] Handle of file to map
1352 * DWORD psp [in] (Win32s: PSP that hFile belongs to)
1354 * Output: EAX: NtStatus
1357 DWORD *stack = (DWORD *) W32S_APP2WINE(context->Edx);
1358 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]);
1359 DWORD flags1 = stack[1];
1360 DWORD atom = stack[2];
1361 LARGE_INTEGER *size = (LARGE_INTEGER *)W32S_APP2WINE(stack[3]);
1362 DWORD protect = stack[4];
1363 DWORD flags2 = stack[5];
1364 HANDLE hFile = DosFileHandleToWin32Handle(stack[6]);
1365 DWORD psp = stack[7];
1367 HANDLE result = INVALID_HANDLE_VALUE;
1368 char name[128];
1370 TRACE("NtCreateSection(%x, %x, %x, %x, %x, %x, %x, %x)\n",
1371 (DWORD)retv, flags1, atom, (DWORD)size, protect, flags2,
1372 (DWORD)hFile, psp);
1374 if (!atom || GlobalGetAtomNameA(atom, name, sizeof(name)))
1376 TRACE("NtCreateSection: name=%s\n", atom? name : NULL);
1378 result = CreateFileMappingA(hFile, NULL, protect,
1379 size? size->u.HighPart : 0,
1380 size? size->u.LowPart : 0,
1381 atom? name : NULL);
1384 if (result == INVALID_HANDLE_VALUE)
1385 WARN("NtCreateSection: failed!\n");
1386 else
1387 TRACE("NtCreateSection: returned %x\n", (DWORD)result);
1389 if (result != INVALID_HANDLE_VALUE)
1390 *retv = result,
1391 context->Eax = STATUS_SUCCESS;
1392 else
1393 *retv = result,
1394 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1396 break;
1399 case 0x000E: /* NtOpenSection */
1401 * Input: EDX: Flat address of arguments on stack
1403 * HANDLE32 *retv [out] Handle of Section opened
1404 * DWORD protect [in] Access protection
1405 * DWORD atom [in] Name of Section to create
1407 * Output: EAX: NtStatus
1410 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1411 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]);
1412 DWORD protect = stack[1];
1413 DWORD atom = stack[2];
1415 HANDLE result = INVALID_HANDLE_VALUE;
1416 char name[128];
1418 TRACE("NtOpenSection(%x, %x, %x)\n",
1419 (DWORD)retv, protect, atom);
1421 if (atom && GlobalGetAtomNameA(atom, name, sizeof(name)))
1423 TRACE("NtOpenSection: name=%s\n", name);
1425 result = OpenFileMappingA(protect, FALSE, name);
1428 if (result == INVALID_HANDLE_VALUE)
1429 WARN("NtOpenSection: failed!\n");
1430 else
1431 TRACE("NtOpenSection: returned %x\n", (DWORD)result);
1433 if (result != INVALID_HANDLE_VALUE)
1434 *retv = result,
1435 context->Eax = STATUS_SUCCESS;
1436 else
1437 *retv = result,
1438 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1440 break;
1443 case 0x000F: /* NtCloseSection */
1445 * Input: EDX: Flat address of arguments on stack
1447 * HANDLE32 handle [in] Handle of Section to close
1448 * DWORD *id [out] Unique ID (?? unclear ??)
1450 * Output: EAX: NtStatus
1453 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1454 HANDLE handle = (HANDLE)stack[0];
1455 DWORD *id = (DWORD *)W32S_APP2WINE(stack[1]);
1457 TRACE("NtCloseSection(%x, %x)\n", (DWORD)handle, (DWORD)id);
1459 CloseHandle(handle);
1460 if (id) *id = 0; /* FIXME */
1462 context->Eax = STATUS_SUCCESS;
1464 break;
1467 case 0x0010: /* NtDupSection */
1469 * Input: EDX: Flat address of arguments on stack
1471 * HANDLE32 handle [in] Handle of Section to duplicate
1473 * Output: EAX: NtStatus
1476 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1477 HANDLE handle = (HANDLE)stack[0];
1478 HANDLE new_handle;
1480 TRACE("NtDupSection(%x)\n", (DWORD)handle);
1482 DuplicateHandle( GetCurrentProcess(), handle,
1483 GetCurrentProcess(), &new_handle,
1484 0, FALSE, DUPLICATE_SAME_ACCESS );
1485 context->Eax = STATUS_SUCCESS;
1487 break;
1490 case 0x0011: /* NtMapViewOfSection */
1492 * Input: EDX: Flat address of arguments on stack
1494 * HANDLE32 SectionHandle [in] Section to be mapped
1495 * DWORD ProcessHandle [in] Process to be mapped into
1496 * DWORD * BaseAddress [in/out] Address to be mapped at
1497 * DWORD ZeroBits [in] Upper address bits that should be null, starting from bit 31
1498 * DWORD CommitSize [in] (?? unclear ??)
1499 * LARGE_INTEGER *SectionOffset [in] Offset within section
1500 * DWORD * ViewSize [in] Size of view
1501 * DWORD InheritDisposition [in] (?? unclear ??)
1502 * DWORD AllocationType [in] (?? unclear ??)
1503 * DWORD Protect [in] Access protection
1505 * Output: EAX: NtStatus
1508 DWORD * stack = (DWORD *)W32S_APP2WINE(context->Edx);
1509 HANDLE SectionHandle = (HANDLE)stack[0];
1510 DWORD ProcessHandle = stack[1]; /* ignored */
1511 DWORD * BaseAddress = (DWORD *)W32S_APP2WINE(stack[2]);
1512 DWORD ZeroBits = stack[3];
1513 DWORD CommitSize = stack[4];
1514 LARGE_INTEGER *SectionOffset = (LARGE_INTEGER *)W32S_APP2WINE(stack[5]);
1515 DWORD * ViewSize = (DWORD *)W32S_APP2WINE(stack[6]);
1516 DWORD InheritDisposition = stack[7];
1517 DWORD AllocationType = stack[8];
1518 DWORD Protect = stack[9];
1520 LPBYTE address = (LPBYTE)(BaseAddress?
1521 W32S_APP2WINE(*BaseAddress) : 0);
1522 DWORD access = 0, result;
1524 switch (Protect & ~(PAGE_GUARD|PAGE_NOCACHE))
1526 case PAGE_READONLY: access = FILE_MAP_READ; break;
1527 case PAGE_READWRITE: access = FILE_MAP_WRITE; break;
1528 case PAGE_WRITECOPY: access = FILE_MAP_COPY; break;
1530 case PAGE_EXECUTE_READ: access = FILE_MAP_READ; break;
1531 case PAGE_EXECUTE_READWRITE: access = FILE_MAP_WRITE; break;
1532 case PAGE_EXECUTE_WRITECOPY: access = FILE_MAP_COPY; break;
1535 TRACE("NtMapViewOfSection"
1536 "(%x, %x, %x, %x, %x, %x, %x, %x, %x, %x)\n",
1537 (DWORD)SectionHandle, ProcessHandle, (DWORD)BaseAddress,
1538 ZeroBits, CommitSize, (DWORD)SectionOffset, (DWORD)ViewSize,
1539 InheritDisposition, AllocationType, Protect);
1540 TRACE("NtMapViewOfSection: "
1541 "base=%x, offset=%x, size=%x, access=%x\n",
1542 (DWORD)address, SectionOffset? SectionOffset->u.LowPart : 0,
1543 ViewSize? *ViewSize : 0, access);
1545 result = (DWORD)MapViewOfFileEx(SectionHandle, access,
1546 SectionOffset? SectionOffset->u.HighPart : 0,
1547 SectionOffset? SectionOffset->u.LowPart : 0,
1548 ViewSize? *ViewSize : 0, address);
1550 TRACE("NtMapViewOfSection: result=%x\n", result);
1552 if (W32S_WINE2APP(result))
1554 if (BaseAddress) *BaseAddress = W32S_WINE2APP(result);
1555 context->Eax = STATUS_SUCCESS;
1557 else
1558 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1560 break;
1563 case 0x0012: /* NtUnmapViewOfSection */
1565 * Input: EDX: Flat address of arguments on stack
1567 * DWORD ProcessHandle [in] Process (defining address space)
1568 * LPBYTE BaseAddress [in] Base address of view to be unmapped
1570 * Output: EAX: NtStatus
1573 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1574 DWORD ProcessHandle = stack[0]; /* ignored */
1575 LPBYTE BaseAddress = (LPBYTE)W32S_APP2WINE(stack[1]);
1577 TRACE("NtUnmapViewOfSection(%x, %x)\n",
1578 ProcessHandle, (DWORD)BaseAddress);
1580 UnmapViewOfFile(BaseAddress);
1582 context->Eax = STATUS_SUCCESS;
1584 break;
1587 case 0x0013: /* NtFlushVirtualMemory */
1589 * Input: EDX: Flat address of arguments on stack
1591 * DWORD ProcessHandle [in] Process (defining address space)
1592 * LPBYTE *BaseAddress [in?] Base address of range to be flushed
1593 * DWORD *ViewSize [in?] Number of bytes to be flushed
1594 * DWORD *unknown [???] (?? unknown ??)
1596 * Output: EAX: NtStatus
1599 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1600 DWORD ProcessHandle = stack[0]; /* ignored */
1601 DWORD *BaseAddress = (DWORD *)W32S_APP2WINE(stack[1]);
1602 DWORD *ViewSize = (DWORD *)W32S_APP2WINE(stack[2]);
1603 DWORD *unknown = (DWORD *)W32S_APP2WINE(stack[3]);
1605 LPBYTE address = (LPBYTE)(BaseAddress? W32S_APP2WINE(*BaseAddress) : 0);
1606 DWORD size = ViewSize? *ViewSize : 0;
1608 TRACE("NtFlushVirtualMemory(%x, %x, %x, %x)\n",
1609 ProcessHandle, (DWORD)BaseAddress, (DWORD)ViewSize,
1610 (DWORD)unknown);
1611 TRACE("NtFlushVirtualMemory: base=%x, size=%x\n",
1612 (DWORD)address, size);
1614 FlushViewOfFile(address, size);
1616 context->Eax = STATUS_SUCCESS;
1618 break;
1621 case 0x0014: /* Get/Set Debug Registers */
1623 * Input: ECX: 0 if Get, 1 if Set
1625 * EDX: Get: Flat address of buffer to receive values of
1626 * debug registers DR0 .. DR7
1627 * Set: Flat address of buffer containing values of
1628 * debug registers DR0 .. DR7 to be set
1629 * Output: None
1632 FIXME("[0014] ECX=%x EDX=%x\n",
1633 context->Ecx, context->Edx);
1635 /* FIXME */
1636 break;
1639 case 0x0015: /* Set Coprocessor Emulation Flag */
1641 * Input: EDX: 0 to deactivate, 1 to activate coprocessor emulation
1643 * Output: None
1646 TRACE("[0015] EDX=%x\n", context->Edx);
1648 /* We don't care, as we always have a coprocessor anyway */
1649 break;
1652 case 0x0016: /* Init Win32S VxD PSP */
1654 * If called to query required PSP size:
1656 * Input: EBX: 0
1657 * Output: EDX: Required size of Win32s VxD PSP
1659 * If called to initialize allocated PSP:
1661 * Input: EBX: LoWord: Selector of Win32s VxD PSP
1662 * HiWord: Paragraph of Win32s VxD PSP (DOSMEM)
1663 * Output: None
1666 if (context->Ebx == 0)
1667 context->Edx = 0x80;
1668 else
1670 PDB16 *psp = MapSL( MAKESEGPTR( BX_reg(context), 0 ));
1671 psp->nbFiles = 32;
1672 psp->fileHandlesPtr = MAKELONG(HIWORD(context->Ebx), 0x5c);
1673 memset((LPBYTE)psp + 0x5c, '\xFF', 32);
1675 break;
1678 case 0x0017: /* Set Break Point */
1680 * Input: EBX: Offset of Break Point
1681 * CX: Selector of Break Point
1683 * Output: None
1686 FIXME("[0017] EBX=%x CX=%x\n",
1687 context->Ebx, CX_reg(context));
1689 /* FIXME */
1690 break;
1693 case 0x0018: /* VirtualLock */
1695 * Input: ECX: Current Process
1697 * EDX: Flat address of arguments on stack
1699 * DWORD *retv [out] TRUE if success, FALSE if failure
1700 * LPVOID base [in] Flat address of range to lock
1701 * DWORD size [in] Size of range
1703 * Output: EAX: NtStatus
1706 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1707 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1708 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1709 DWORD size = stack[2];
1710 DWORD result;
1712 TRACE("VirtualLock(%x, %x, %x)\n",
1713 (DWORD)retv, (DWORD)base, size);
1715 result = VirtualLock(base, size);
1717 if (result)
1718 *retv = TRUE,
1719 context->Eax = STATUS_SUCCESS;
1720 else
1721 *retv = FALSE,
1722 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1724 break;
1727 case 0x0019: /* VirtualUnlock */
1729 * Input: ECX: Current Process
1731 * EDX: Flat address of arguments on stack
1733 * DWORD *retv [out] TRUE if success, FALSE if failure
1734 * LPVOID base [in] Flat address of range to unlock
1735 * DWORD size [in] Size of range
1737 * Output: EAX: NtStatus
1740 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1741 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1742 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1743 DWORD size = stack[2];
1744 DWORD result;
1746 TRACE("VirtualUnlock(%x, %x, %x)\n",
1747 (DWORD)retv, (DWORD)base, size);
1749 result = VirtualUnlock(base, size);
1751 if (result)
1752 *retv = TRUE,
1753 context->Eax = STATUS_SUCCESS;
1754 else
1755 *retv = FALSE,
1756 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1758 break;
1761 case 0x001A: /* KGetSystemInfo */
1763 * Input: None
1765 * Output: ECX: Start of sparse memory arena
1766 * EDX: End of sparse memory arena
1769 TRACE("KGetSystemInfo()\n");
1772 * Note: Win32s reserves 0GB - 2GB for Win 3.1 and uses 2GB - 4GB as
1773 * sparse memory arena. We do it the other way around, since
1774 * we have to reserve 3GB - 4GB for Linux, and thus use
1775 * 0GB - 3GB as sparse memory arena.
1777 * FIXME: What about other OSes ?
1780 context->Ecx = W32S_WINE2APP(0x00000000);
1781 context->Edx = W32S_WINE2APP(0xbfffffff);
1782 break;
1785 case 0x001B: /* KGlobalMemStat */
1787 * Input: ESI: Flat address of buffer to receive memory info
1789 * Output: None
1792 struct Win32sMemoryInfo
1794 DWORD DIPhys_Count; /* Total physical pages */
1795 DWORD DIFree_Count; /* Free physical pages */
1796 DWORD DILin_Total_Count; /* Total virtual pages (private arena) */
1797 DWORD DILin_Total_Free; /* Free virtual pages (private arena) */
1799 DWORD SparseTotal; /* Total size of sparse arena (bytes ?) */
1800 DWORD SparseFree; /* Free size of sparse arena (bytes ?) */
1803 struct Win32sMemoryInfo *info =
1804 (struct Win32sMemoryInfo *)W32S_APP2WINE(context->Esi);
1806 FIXME("KGlobalMemStat(%x)\n", (DWORD)info);
1808 /* FIXME */
1810 break;
1813 case 0x001C: /* Enable/Disable Exceptions */
1815 * Input: ECX: 0 to disable, 1 to enable exception handling
1817 * Output: None
1820 TRACE("[001c] ECX=%x\n", context->Ecx);
1822 /* FIXME */
1823 break;
1826 case 0x001D: /* VirtualAlloc called from 16-bit code */
1828 * Input: EDX: Segmented address of arguments on stack
1830 * LPVOID base [in] Flat address of region to reserve/commit
1831 * DWORD size [in] Size of region
1832 * DWORD type [in] Type of allocation
1833 * DWORD prot [in] Type of access protection
1835 * Output: EAX: NtStatus
1836 * EDX: Flat base address of allocated region
1839 DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) ));
1840 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]);
1841 DWORD size = stack[1];
1842 DWORD type = stack[2];
1843 DWORD prot = stack[3];
1844 DWORD result;
1846 TRACE("VirtualAlloc16(%x, %x, %x, %x)\n",
1847 (DWORD)base, size, type, prot);
1849 if (type & 0x80000000)
1851 WARN("VirtualAlloc16: strange type %x\n", type);
1852 type &= 0x7fffffff;
1855 result = (DWORD)VirtualAlloc(base, size, type, prot);
1857 if (W32S_WINE2APP(result))
1858 context->Edx = W32S_WINE2APP(result),
1859 context->Eax = STATUS_SUCCESS;
1860 else
1861 context->Edx = 0,
1862 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1863 TRACE("VirtualAlloc16: returning base %x\n", context->Edx);
1865 break;
1868 case 0x001E: /* VirtualFree called from 16-bit code */
1870 * Input: EDX: Segmented address of arguments on stack
1872 * LPVOID base [in] Flat address of region
1873 * DWORD size [in] Size of region
1874 * DWORD type [in] Type of operation
1876 * Output: EAX: NtStatus
1877 * EDX: TRUE if success, FALSE if failure
1880 DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) ));
1881 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]);
1882 DWORD size = stack[1];
1883 DWORD type = stack[2];
1884 DWORD result;
1886 TRACE("VirtualFree16(%x, %x, %x)\n",
1887 (DWORD)base, size, type);
1889 result = VirtualFree(base, size, type);
1891 if (result)
1892 context->Edx = TRUE,
1893 context->Eax = STATUS_SUCCESS;
1894 else
1895 context->Edx = FALSE,
1896 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1898 break;
1901 case 0x001F: /* FWorkingSetSize */
1903 * Input: EDX: 0 if Get, 1 if Set
1905 * ECX: Get: Buffer to receive Working Set Size
1906 * Set: Buffer containing Working Set Size
1908 * Output: NtStatus
1911 DWORD *ptr = (DWORD *)W32S_APP2WINE(context->Ecx);
1912 BOOL set = context->Edx;
1914 TRACE("FWorkingSetSize(%x, %x)\n", (DWORD)ptr, (DWORD)set);
1916 if (set)
1917 /* We do it differently ... */;
1918 else
1919 *ptr = 0x100;
1921 context->Eax = STATUS_SUCCESS;
1923 break;
1925 default:
1926 VXD_BARF( context, "W32S" );