ntdll: Use a separate memory allocation for the kernel stack.
[wine.git] / dlls / krnl386.exe16 / vxd.c
bloba707fc36043a7a96c39ea9d7bbb4805a08ccc378
1 /*
2 * Win32 VxD functions
4 * Copyright 1998 Marcus Meissner
5 * Copyright 1998 Ulrich Weigand
6 * Copyright 1998 Patrik Stridvall
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <stdlib.h>
24 #include <sys/types.h>
25 #include <string.h>
26 #include <stdarg.h>
28 #include "ntstatus.h"
29 #define WIN32_NO_STATUS
30 #define NONAMELESSUNION
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winerror.h"
34 #include "winternl.h"
35 #include "winioctl.h"
36 #include "kernel16_private.h"
37 #include "dosexe.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(vxd);
42 typedef DWORD (WINAPI *VxDCallProc)(DWORD, CONTEXT *);
43 typedef BOOL (WINAPI *DeviceIoProc)(DWORD, LPVOID, DWORD, LPVOID, DWORD, LPDWORD, LPOVERLAPPED);
45 struct vxd_module
47 LARGE_INTEGER index;
48 HANDLE handle;
49 HMODULE module;
50 DeviceIoProc proc;
53 struct vxdcall_service
55 WCHAR name[12];
56 DWORD service;
57 HMODULE module;
58 VxDCallProc proc;
61 #define MAX_VXD_MODULES 32
63 static struct vxd_module vxd_modules[MAX_VXD_MODULES];
65 static struct vxdcall_service vxd_services[] =
67 { {'v','m','m','.','v','x','d',0}, 0x0001, NULL, NULL },
68 { {'v','w','i','n','3','2','.','v','x','d',0}, 0x002a, NULL, NULL }
71 #define W32S_APP2WINE(addr) ((addr)? (DWORD)(addr) + W32S_offset : 0)
72 #define W32S_WINE2APP(addr) ((addr)? (DWORD)(addr) - W32S_offset : 0)
74 #define VXD_BARF(context,name) \
75 TRACE( "vxd %s: unknown/not implemented parameters:\n" \
76 "vxd %s: AX %04x, BX %04x, CX %04x, DX %04x, " \
77 "SI %04x, DI %04x, DS %04x, ES %04x\n", \
78 (name), (name), AX_reg(context), BX_reg(context), \
79 CX_reg(context), DX_reg(context), SI_reg(context), \
80 DI_reg(context), (WORD)context->SegDs, (WORD)context->SegEs )
82 static CRITICAL_SECTION vxd_section;
83 static CRITICAL_SECTION_DEBUG critsect_debug =
85 0, 0, &vxd_section,
86 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
87 0, 0, { (DWORD_PTR)(__FILE__ ": vxd_section") }
89 static CRITICAL_SECTION vxd_section = { &critsect_debug, -1, 0, 0, 0, 0 };
91 static UINT W32S_offset;
93 static WORD VXD_WinVersion(void)
95 WORD version = LOWORD(GetVersion16());
96 return (version >> 8) | (version << 8);
99 /* retrieve the DeviceIoControl function for a Vxd given a file handle */
100 DeviceIoProc __wine_vxd_get_proc( HANDLE handle )
102 DeviceIoProc ret = NULL;
103 int status, i;
104 IO_STATUS_BLOCK io;
105 FILE_INTERNAL_INFORMATION info;
107 status = NtQueryInformationFile( handle, &io, &info, sizeof(info), FileInternalInformation );
108 if (status)
110 SetLastError( RtlNtStatusToDosError(status) );
111 return NULL;
114 RtlEnterCriticalSection( &vxd_section );
116 for (i = 0; i < MAX_VXD_MODULES; i++)
118 if (!vxd_modules[i].module) break;
119 if (vxd_modules[i].index.QuadPart == info.IndexNumber.QuadPart)
121 if (!(ret = vxd_modules[i].proc)) SetLastError( ERROR_INVALID_FUNCTION );
122 goto done;
125 /* FIXME: Here we could go through the directory to find the VxD name and load it. */
126 /* Let's wait to find out if there are actually apps out there that try to share */
127 /* VxD handles between processes, before we go to the trouble of implementing it. */
128 ERR( "handle %p not found in module list, inherited from another process?\n", handle );
130 done:
131 RtlLeaveCriticalSection( &vxd_section );
132 return ret;
136 /* load a VxD and return a file handle to it */
137 HANDLE __wine_vxd_open( LPCWSTR filenameW, DWORD access, SECURITY_ATTRIBUTES *sa )
139 int i;
140 HANDLE handle;
141 HMODULE module;
142 WCHAR *p, name[13];
144 /* normalize the filename */
146 if (wcschr( filenameW, '/' ) || wcschr( filenameW, '\\' ))
148 SetLastError( ERROR_FILE_NOT_FOUND );
149 return 0;
151 p = wcschr( filenameW, '.' );
152 if (!p && lstrlenW( filenameW ) <= 8)
154 wcscpy( name, filenameW );
155 wcscat( name, L".vxd" );
157 else if (p && !wcsicmp( p, L".vxd" ) && lstrlenW( filenameW ) <= 12) /* existing extension has to be .vxd */
159 wcscpy( name, filenameW );
161 else
163 SetLastError( ERROR_FILE_NOT_FOUND );
164 return 0;
166 wcslwr( name );
168 /* try to load the module first */
170 if (!(module = LoadLibraryW( name )))
172 FIXME( "Unknown/unsupported VxD %s. Try setting Windows version to 'nt40' or 'win31'.\n",
173 debugstr_w(name) );
174 SetLastError( ERROR_FILE_NOT_FOUND );
175 return 0;
178 /* register the module in the global list if necessary */
180 RtlEnterCriticalSection( &vxd_section );
182 for (i = 0; i < MAX_VXD_MODULES; i++)
184 if (vxd_modules[i].module == module)
186 handle = vxd_modules[i].handle;
187 goto done; /* already registered */
189 if (!vxd_modules[i].module) /* new one, register it */
191 WCHAR path[MAX_PATH];
192 IO_STATUS_BLOCK io;
193 FILE_INTERNAL_INFORMATION info;
195 GetModuleFileNameW( module, path, MAX_PATH );
196 handle = CreateFileW( path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 );
197 if (handle == INVALID_HANDLE_VALUE)
199 FreeLibrary( module );
200 goto done;
202 if (!NtQueryInformationFile( handle, &io, &info, sizeof(info), FileInternalInformation ))
203 vxd_modules[i].index = info.IndexNumber;
205 vxd_modules[i].module = module;
206 vxd_modules[i].handle = handle;
207 vxd_modules[i].proc = (DeviceIoProc)GetProcAddress( module, "DeviceIoControl" );
208 goto done;
212 ERR("too many open VxD modules, please report\n" );
213 FreeLibrary( module );
214 handle = 0;
216 done:
217 RtlLeaveCriticalSection( &vxd_section );
218 if (!DuplicateHandle( GetCurrentProcess(), handle, GetCurrentProcess(), &handle, 0,
219 (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle),
220 DUPLICATE_SAME_ACCESS ))
221 handle = 0;
222 return handle;
226 /***********************************************************************
227 * VxDCall0 (KERNEL32.1)
228 * VxDCall1 (KERNEL32.2)
229 * VxDCall2 (KERNEL32.3)
230 * VxDCall3 (KERNEL32.4)
231 * VxDCall4 (KERNEL32.5)
232 * VxDCall5 (KERNEL32.6)
233 * VxDCall6 (KERNEL32.7)
234 * VxDCall7 (KERNEL32.8)
235 * VxDCall8 (KERNEL32.9)
237 void WINAPI DECLSPEC_HIDDEN __regs_VxDCall( CONTEXT *context )
239 unsigned int i;
240 VxDCallProc proc = NULL;
241 DWORD service = stack32_pop( context );
243 RtlEnterCriticalSection( &vxd_section );
244 for (i = 0; i < ARRAY_SIZE(vxd_services); i++)
246 if (HIWORD(service) != vxd_services[i].service) continue;
247 if (!vxd_services[i].module) /* need to load it */
249 if ((vxd_services[i].module = LoadLibraryW( vxd_services[i].name )))
250 vxd_services[i].proc = (VxDCallProc)GetProcAddress( vxd_services[i].module, "VxDCall" );
252 proc = vxd_services[i].proc;
253 break;
255 RtlLeaveCriticalSection( &vxd_section );
257 if (proc) context->Eax = proc( service, context );
258 else
260 FIXME( "Unknown/unimplemented VxD (%08lx)\n", service);
261 context->Eax = 0xffffffff; /* FIXME */
264 DEFINE_REGS_ENTRYPOINT( VxDCall )
267 /***********************************************************************
268 * __wine_vxd_vmm (WPROCS.401)
270 void WINAPI __wine_vxd_vmm ( CONTEXT *context )
272 unsigned service = AX_reg(context);
274 TRACE("[%04x] VMM\n", (UINT16)service);
276 switch(service)
278 case 0x0000: /* version */
279 SET_AX( context, VXD_WinVersion() );
280 RESET_CFLAG(context);
281 break;
283 case 0x026d: /* Get_Debug_Flag '/m' */
284 case 0x026e: /* Get_Debug_Flag '/n' */
285 SET_AL( context, 0 );
286 RESET_CFLAG(context);
287 break;
289 default:
290 VXD_BARF( context, "VMM" );
294 /***********************************************************************
295 * __wine_vxd_pagefile (WPROCS.433)
297 void WINAPI __wine_vxd_pagefile( CONTEXT *context )
299 unsigned service = AX_reg(context);
301 /* taken from Ralf Brown's Interrupt List */
303 TRACE("[%04x] PageFile\n", (UINT16)service );
305 switch(service)
307 case 0x00: /* get version, is this windows version? */
308 TRACE("returning version\n");
309 SET_AX( context, VXD_WinVersion() );
310 RESET_CFLAG(context);
311 break;
313 case 0x01: /* get swap file info */
314 TRACE("VxD PageFile: returning swap file info\n");
315 SET_AX( context, 0x00 ); /* paging disabled */
316 context->Ecx = 0; /* maximum size of paging file */
317 /* FIXME: do I touch DS:SI or DS:DI? */
318 RESET_CFLAG(context);
319 break;
321 case 0x02: /* delete permanent swap on exit */
322 TRACE("VxD PageFile: supposed to delete swap\n");
323 RESET_CFLAG(context);
324 break;
326 case 0x03: /* current temporary swap file size */
327 TRACE("VxD PageFile: what is current temp. swap size\n");
328 RESET_CFLAG(context);
329 break;
331 case 0x04: /* read or write?? INTERRUP.D */
332 case 0x05: /* cancel?? INTERRUP.D */
333 case 0x06: /* test I/O valid INTERRUP.D */
334 default:
335 VXD_BARF( context, "pagefile" );
336 break;
340 /***********************************************************************
341 * __wine_vxd_reboot (WPROCS.409)
343 void WINAPI __wine_vxd_reboot( CONTEXT *context )
345 unsigned service = AX_reg(context);
347 TRACE("[%04x] Reboot\n", (UINT16)service);
349 switch(service)
351 case 0x0000: /* version */
352 SET_AX( context, VXD_WinVersion() );
353 RESET_CFLAG(context);
354 break;
356 default:
357 VXD_BARF( context, "REBOOT" );
361 /***********************************************************************
362 * __wine_vxd_vdd (WPROCS.410)
364 void WINAPI __wine_vxd_vdd( CONTEXT *context )
366 unsigned service = AX_reg(context);
368 TRACE("[%04x] VDD\n", (UINT16)service);
370 switch(service)
372 case 0x0000: /* version */
373 SET_AX( context, VXD_WinVersion() );
374 RESET_CFLAG(context);
375 break;
377 default:
378 VXD_BARF( context, "VDD" );
382 /***********************************************************************
383 * __wine_vxd_vmd (WPROCS.412)
385 void WINAPI __wine_vxd_vmd( CONTEXT *context )
387 unsigned service = AX_reg(context);
389 TRACE("[%04x] VMD\n", (UINT16)service);
391 switch(service)
393 case 0x0000: /* version */
394 SET_AX( context, VXD_WinVersion() );
395 RESET_CFLAG(context);
396 break;
398 default:
399 VXD_BARF( context, "VMD" );
403 /***********************************************************************
404 * __wine_vxd_vxdloader (WPROCS.439)
406 void WINAPI __wine_vxd_vxdloader( CONTEXT *context )
408 unsigned service = AX_reg(context);
410 TRACE("[%04x] VXDLoader\n", (UINT16)service);
412 switch (service)
414 case 0x0000: /* get version */
415 TRACE("returning version\n");
416 SET_AX( context, 0x0000 );
417 SET_DX( context, VXD_WinVersion() );
418 RESET_CFLAG(context);
419 break;
421 case 0x0001: /* load device */
422 FIXME("load device %04lx:%04x (%s)\n",
423 context->SegDs, DX_reg(context),
424 debugstr_a(MapSL(MAKESEGPTR(context->SegDs, DX_reg(context)))));
425 SET_AX( context, 0x0000 );
426 context->SegEs = 0x0000;
427 SET_DI( context, 0x0000 );
428 RESET_CFLAG(context);
429 break;
431 case 0x0002: /* unload device */
432 FIXME("unload device (%08lx)\n", context->Ebx);
433 SET_AX( context, 0x0000 );
434 RESET_CFLAG(context);
435 break;
437 default:
438 VXD_BARF( context, "VXDLDR" );
439 SET_AX( context, 0x000B ); /* invalid function number */
440 SET_CFLAG(context);
441 break;
445 /***********************************************************************
446 * __wine_vxd_shell (WPROCS.423)
448 void WINAPI __wine_vxd_shell( CONTEXT *context )
450 unsigned service = DX_reg(context);
452 TRACE("[%04x] Shell\n", (UINT16)service);
454 switch (service) /* Ralf Brown says EDX, but I use DX instead */
456 case 0x0000:
457 TRACE("returning version\n");
458 SET_AX( context, VXD_WinVersion() );
459 context->Ebx = 1; /* system VM Handle */
460 break;
462 case 0x0001:
463 case 0x0002:
464 case 0x0003:
465 /* SHELL_SYSMODAL_Message
466 ebx virtual machine handle
467 eax message box flags
468 ecx address of message
469 edi address of caption
470 return response in eax
472 case 0x0004:
473 /* SHELL_Message
474 ebx virtual machine handle
475 eax message box flags
476 ecx address of message
477 edi address of caption
478 esi address callback
479 edx reference data for callback
480 return response in eax
482 case 0x0005:
483 VXD_BARF( context, "shell" );
484 break;
486 case 0x0006: /* SHELL_Get_VM_State */
487 TRACE("VxD Shell: returning VM state\n");
488 /* Actually we don't, not yet. We have to return a structure
489 * and I am not to sure how to set it up and return it yet,
490 * so for now let's do nothing. I can (hopefully) get this
491 * by the next release
493 /* RESET_CFLAG(context); */
494 break;
496 case 0x0007:
497 case 0x0008:
498 case 0x0009:
499 case 0x000A:
500 case 0x000B:
501 case 0x000C:
502 case 0x000D:
503 case 0x000E:
504 case 0x000F:
505 case 0x0010:
506 case 0x0011:
507 case 0x0012:
508 case 0x0013:
509 case 0x0014:
510 case 0x0015:
511 case 0x0016:
512 VXD_BARF( context, "SHELL" );
513 break;
515 /* the new Win95 shell API */
516 case 0x0100: /* get version */
517 SET_AX( context, VXD_WinVersion() );
518 break;
520 case 0x0104: /* retrieve Hook_Properties list */
521 case 0x0105: /* call Hook_Properties callbacks */
522 VXD_BARF( context, "SHELL" );
523 break;
525 case 0x0106: /* install timeout callback */
526 TRACE("VxD Shell: ignoring shell callback (%ld sec.)\n", context->Ebx);
527 SET_CFLAG(context);
528 break;
530 case 0x0107: /* get version of any VxD */
531 default:
532 VXD_BARF( context, "SHELL" );
533 break;
538 /***********************************************************************
539 * __wine_vxd_comm (WPROCS.414)
541 void WINAPI __wine_vxd_comm( CONTEXT *context )
543 unsigned service = AX_reg(context);
545 TRACE("[%04x] Comm\n", (UINT16)service);
547 switch (service)
549 case 0x0000: /* get version */
550 TRACE("returning version\n");
551 SET_AX( context, VXD_WinVersion() );
552 RESET_CFLAG(context);
553 break;
555 case 0x0001: /* set port global */
556 case 0x0002: /* get focus */
557 case 0x0003: /* virtualise port */
558 default:
559 VXD_BARF( context, "comm" );
563 /***********************************************************************
564 * __wine_vxd_timer (WPROCS.405)
566 void WINAPI __wine_vxd_timer( CONTEXT *context )
568 unsigned service = AX_reg(context);
570 TRACE("[%04x] Virtual Timer\n", (UINT16)service);
572 switch(service)
574 case 0x0000: /* version */
575 SET_AX( context, VXD_WinVersion() );
576 RESET_CFLAG(context);
577 break;
579 case 0x0100: /* clock tick time, in 840nsecs */
580 context->Eax = GetTickCount();
582 context->Edx = context->Eax >> 22;
583 context->Eax <<= 10; /* not very precise */
584 break;
586 case 0x0101: /* current Windows time, msecs */
587 case 0x0102: /* current VM time, msecs */
588 context->Eax = GetTickCount();
589 break;
591 default:
592 VXD_BARF( context, "VTD" );
597 /***********************************************************************
598 * timer_thread
600 static DWORD CALLBACK timer_thread( void *arg )
602 DWORD *system_time = arg;
604 for (;;)
606 *system_time = GetTickCount();
607 Sleep( 55 );
610 return 0;
614 /***********************************************************************
615 * __wine_vxd_timerapi (WPROCS.1490)
617 void WINAPI __wine_vxd_timerapi( CONTEXT *context )
619 static WORD System_Time_Selector;
621 unsigned service = AX_reg(context);
623 TRACE("[%04x] TimerAPI\n", (UINT16)service);
625 switch(service)
627 case 0x0000: /* version */
628 SET_AX( context, VXD_WinVersion() );
629 RESET_CFLAG(context);
630 break;
632 case 0x0009: /* get system time selector */
633 if ( !System_Time_Selector )
635 HANDLE16 handle = GlobalAlloc16( GMEM_FIXED, sizeof(DWORD) );
636 System_Time_Selector = handle | 7;
637 CloseHandle( CreateThread( NULL, 0, timer_thread, GlobalLock16(handle), 0, NULL ) );
639 SET_AX( context, System_Time_Selector );
640 RESET_CFLAG(context);
641 break;
643 default:
644 VXD_BARF( context, "VTDAPI" );
648 /***********************************************************************
649 * __wine_vxd_configmg (WPROCS.451)
651 void WINAPI __wine_vxd_configmg( CONTEXT *context )
653 unsigned service = AX_reg(context);
655 TRACE("[%04x] ConfigMG\n", (UINT16)service);
657 switch(service)
659 case 0x0000: /* version */
660 SET_AX( context, VXD_WinVersion() );
661 RESET_CFLAG(context);
662 break;
664 default:
665 VXD_BARF( context, "CONFIGMG" );
669 /***********************************************************************
670 * __wine_vxd_enable (WPROCS.455)
672 void WINAPI __wine_vxd_enable( CONTEXT *context )
674 unsigned service = AX_reg(context);
676 TRACE("[%04x] Enable\n", (UINT16)service);
678 switch(service)
680 case 0x0000: /* version */
681 SET_AX( context, VXD_WinVersion() );
682 RESET_CFLAG(context);
683 break;
685 default:
686 VXD_BARF( context, "ENABLE" );
690 /***********************************************************************
691 * __wine_vxd_apm (WPROCS.438)
693 void WINAPI __wine_vxd_apm( CONTEXT *context )
695 unsigned service = AX_reg(context);
697 TRACE("[%04x] APM\n", (UINT16)service);
699 switch(service)
701 case 0x0000: /* version */
702 SET_AX( context, VXD_WinVersion() );
703 RESET_CFLAG(context);
704 break;
706 default:
707 VXD_BARF( context, "APM" );
711 /***********************************************************************
712 * __wine_vxd_win32s (WPROCS.445)
714 * This is an implementation of the services of the Win32s VxD.
715 * Since official documentation of these does not seem to be available,
716 * certain arguments of some of the services remain unclear.
718 * FIXME: The following services are currently unimplemented:
719 * Exception handling (0x01, 0x1C)
720 * Debugger support (0x0C, 0x14, 0x17)
721 * Low-level memory access (0x02, 0x03, 0x0A, 0x0B)
722 * Memory Statistics (0x1B)
725 * We have a specific problem running Win32s on Linux (and probably also
726 * the other x86 unixes), since Win32s tries to allocate its main 'flat
727 * code/data segment' selectors with a base of 0xffff0000 (and limit 4GB).
728 * The rationale for this seems to be that they want one the one hand to
729 * be able to leave the Win 3.1 memory (starting with the main DOS memory)
730 * at linear address 0, but want at other hand to have offset 0 of the
731 * flat data/code segment point to an unmapped page (to catch NULL pointer
732 * accesses). Hence they allocate the flat segments with a base of 0xffff0000
733 * so that the Win 3.1 memory area at linear address zero shows up in the
734 * flat segments at offset 0x10000 (since linear addresses wrap around at
735 * 4GB). To compensate for that discrepancy between flat segment offsets
736 * and plain linear addresses, all flat pointers passed between the 32-bit
737 * and the 16-bit parts of Win32s are shifted by 0x10000 in the appropriate
738 * direction by the glue code (mainly) in W32SKRNL and WIN32S16.
740 * The problem for us is now that Linux does not allow a LDT selector with
741 * base 0xffff0000 to be created, since it would 'see' a part of the kernel
742 * address space. To address this problem we introduce *another* offset:
743 * We add 0x10000 to every linear address we get as an argument from Win32s.
744 * This means especially that the flat code/data selectors get actually
745 * allocated with base 0x0, so that flat offsets and (real) linear addresses
746 * do again agree! In fact, every call e.g. of a Win32s VxD service now
747 * has all pointer arguments (which are offsets in the flat data segment)
748 * first reduced by 0x10000 by the W32SKRNL glue code, and then again
749 * increased by 0x10000 by *our* code.
751 * Note that to keep everything consistent, this offset has to be applied by
752 * every Wine function that operates on 'linear addresses' passed to it by
753 * Win32s. Fortunately, since Win32s does not directly call any Wine 32-bit
754 * API routines, this affects only two locations: this VxD and the DPMI
755 * handler. (NOTE: Should any Win32s application pass a linear address to
756 * any routine apart from those, e.g. some other VxD handler, that code
757 * would have to take the offset into account as well!)
759 * The offset is set the first time any application calls the GetVersion()
760 * service of the Win32s VxD. (Note that the offset is never reset.)
763 void WINAPI __wine_vxd_win32s( CONTEXT *context )
765 switch (AX_reg(context))
767 case 0x0000: /* Get Version */
769 * Input: None
771 * Output: EAX: LoWord: Win32s Version (1.30)
772 * HiWord: VxD Version (200)
774 * EBX: Build (172)
776 * ECX: ??? (1)
778 * EDX: Debugging Flags
780 * EDI: Error Flag
781 * 0 if OK,
782 * 1 if VMCPD VxD not found
785 TRACE("GetVersion()\n");
787 context->Eax = VXD_WinVersion() | (200 << 16);
788 context->Ebx = 0;
789 context->Ecx = 0;
790 context->Edx = 0;
791 context->Edi = 0;
794 * If this is the first time we are called for this process,
795 * hack the memory image of WIN32S16 so that it doesn't try
796 * to access the GDT directly ...
798 * The first code segment of WIN32S16 (version 1.30) contains
799 * an unexported function somewhere between the exported functions
800 * SetFS and StackLinearToSegmented that tries to find a selector
801 * in the LDT that maps to the memory image of the LDT itself.
802 * If it succeeds, it stores this selector into a global variable
803 * which will be used to speed up execution by using this selector
804 * to modify the LDT directly instead of using the DPMI calls.
806 * To perform this search of the LDT, this function uses the
807 * sgdt and sldt instructions to find the linear address of
808 * the (GDT and then) LDT. While those instructions themselves
809 * execute without problem, the linear address that sgdt returns
810 * points (at least under Linux) to the kernel address space, so
811 * that any subsequent access leads to a segfault.
813 * Fortunately, WIN32S16 still contains as a fallback option the
814 * mechanism of using DPMI calls to modify LDT selectors instead
815 * of direct writes to the LDT. Thus we can circumvent the problem
816 * by simply replacing the first byte of the offending function
817 * with an 'retf' instruction. This means that the global variable
818 * supposed to contain the LDT alias selector will remain zero,
819 * and hence WIN32S16 will fall back to using DPMI calls.
821 * The heuristic we employ to _find_ that function is as follows:
822 * We search between the addresses of the exported symbols SetFS
823 * and StackLinearToSegmented for the byte sequence '0F 01 04'
824 * (this is the opcode of 'sgdt [si]'). We then search backwards
825 * from this address for the last occurrence of 'CB' (retf) that marks
826 * the end of the preceding function. The following byte (which
827 * should now be the first byte of the function we are looking for)
828 * will be replaced by 'CB' (retf).
830 * This heuristic works for the retail as well as the debug version
831 * of Win32s version 1.30. For versions earlier than that this
832 * hack should not be necessary at all, since the whole mechanism
833 * ('PERF130') was introduced only in 1.30 to improve the overall
834 * performance of Win32s.
837 if (!W32S_offset)
839 HMODULE16 hModule = GetModuleHandle16("win32s16");
840 SEGPTR func1 = (SEGPTR)GetProcAddress16(hModule, "SetFS");
841 SEGPTR func2 = (SEGPTR)GetProcAddress16(hModule, "StackLinearToSegmented");
843 if ( hModule && func1 && func2
844 && SELECTOROF(func1) == SELECTOROF(func2))
846 BYTE *start = MapSL(func1);
847 BYTE *end = MapSL(func2);
848 BYTE *p, *retv = NULL;
849 int found = 0;
851 for (p = start; p < end; p++)
852 if (*p == 0xCB) found = 0, retv = p;
853 else if (*p == 0x0F) found = 1;
854 else if (*p == 0x01 && found == 1) found = 2;
855 else if (*p == 0x04 && found == 2) { found = 3; break; }
856 else found = 0;
858 if (found == 3 && retv)
860 TRACE("PERF130 hack: "
861 "Replacing byte %02X at offset %04X:%04X\n",
862 *(retv+1), SELECTOROF(func1),
863 OFFSETOF(func1) + retv+1-start);
865 *(retv+1) = (BYTE)0xCB;
871 * Mark process as Win32s, so that subsequent DPMI calls
872 * will perform the W32S_APP2WINE/W32S_WINE2APP address shift.
874 W32S_offset = 0x10000;
875 break;
878 case 0x0001: /* Install Exception Handling */
880 * Input: EBX: Flat address of W32SKRNL Exception Data
882 * ECX: LoWord: Flat Code Selector
883 * HiWord: Flat Data Selector
885 * EDX: Flat address of W32SKRNL Exception Handler
886 * (this is equal to W32S_BackTo32 + 0x40)
888 * ESI: SEGPTR KERNEL.HASGPHANDLER
890 * EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10)
892 * Output: EAX: 0 if OK
895 TRACE("[0001] EBX=%lx ECX=%lx EDX=%lx ESI=%lx EDI=%lx\n",
896 context->Ebx, context->Ecx, context->Edx,
897 context->Esi, context->Edi);
899 /* FIXME */
901 context->Eax = 0;
902 break;
905 case 0x0002: /* Set Page Access Flags */
907 * Input: EBX: New access flags
908 * Bit 2: User Page if set, Supervisor Page if clear
909 * Bit 1: Read-Write if set, Read-Only if clear
911 * ECX: Size of memory area to change
913 * EDX: Flat start address of memory area
915 * Output: EAX: Size of area changed
918 TRACE("[0002] EBX=%lx ECX=%lx EDX=%lx\n",
919 context->Ebx, context->Ecx, context->Edx);
921 /* FIXME */
923 context->Eax = context->Ecx;
924 break;
927 case 0x0003: /* Get Page Access Flags */
929 * Input: EDX: Flat address of page to query
931 * Output: EAX: Page access flags
932 * Bit 2: User Page if set, Supervisor Page if clear
933 * Bit 1: Read-Write if set, Read-Only if clear
936 TRACE("[0003] EDX=%lx\n", context->Edx);
938 /* FIXME */
940 context->Eax = 6;
941 break;
944 case 0x0004: /* Map Module */
946 * Input: ECX: IMTE (offset in Module Table) of new module
948 * EDX: Flat address of Win32s Module Table
950 * Output: EAX: 0 if OK
953 if (!context->Edx || CX_reg(context) == 0xFFFF)
955 TRACE("MapModule: Initialization call\n");
956 context->Eax = 0;
958 else
961 * Structure of a Win32s Module Table Entry:
963 struct Win32sModule
965 DWORD flags;
966 DWORD flatBaseAddr;
967 LPCSTR moduleName;
968 LPCSTR pathName;
969 LPCSTR unknown;
970 LPBYTE baseAddr;
971 DWORD hModule;
972 DWORD relocDelta;
976 * Note: This function should set up a demand-paged memory image
977 * of the given module. Since mmap does not allow file offsets
978 * not aligned at 1024 bytes, we simply load the image fully
979 * into memory.
982 struct Win32sModule *moduleTable =
983 (struct Win32sModule *)W32S_APP2WINE(context->Edx);
984 struct Win32sModule *module = moduleTable + context->Ecx;
986 IMAGE_NT_HEADERS *nt_header = RtlImageNtHeader( (HMODULE)module->baseAddr );
987 IMAGE_SECTION_HEADER *pe_seg = (IMAGE_SECTION_HEADER*)((char *)&nt_header->OptionalHeader +
988 nt_header->FileHeader.SizeOfOptionalHeader);
991 HFILE image = _lopen(module->pathName, OF_READ);
992 BOOL error = (image == HFILE_ERROR);
993 UINT i;
995 TRACE("MapModule: Loading %s\n", module->pathName);
997 for (i = 0;
998 !error && i < nt_header->FileHeader.NumberOfSections;
999 i++, pe_seg++)
1000 if(!(pe_seg->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA))
1002 DWORD off = pe_seg->PointerToRawData;
1003 DWORD len = pe_seg->SizeOfRawData;
1004 LPBYTE addr = module->baseAddr + pe_seg->VirtualAddress;
1006 TRACE("MapModule: "
1007 "Section %d at %08lx from %08lx len %08lx\n",
1008 i, (DWORD)addr, off, len);
1010 if ( _llseek(image, off, SEEK_SET) != off
1011 || _lread(image, addr, len) != len)
1012 error = TRUE;
1015 _lclose(image);
1017 if (error)
1018 ERR("MapModule: Unable to load %s\n", module->pathName);
1020 else if (module->relocDelta != 0)
1022 IMAGE_DATA_DIRECTORY *dir = nt_header->OptionalHeader.DataDirectory
1023 + IMAGE_DIRECTORY_ENTRY_BASERELOC;
1024 IMAGE_BASE_RELOCATION *r = (IMAGE_BASE_RELOCATION *)
1025 (dir->Size? module->baseAddr + dir->VirtualAddress : 0);
1027 TRACE("MapModule: Reloc delta %08lx\n", module->relocDelta);
1029 while (r && r->VirtualAddress)
1031 LPBYTE page = module->baseAddr + r->VirtualAddress;
1032 WORD *TypeOffset = (WORD *)(r + 1);
1033 unsigned int count = (r->SizeOfBlock - sizeof(*r)) / sizeof(*TypeOffset);
1035 TRACE("MapModule: %d relocations for page %08lx\n",
1036 count, (DWORD)page);
1038 for(i = 0; i < count; i++)
1040 int offset = TypeOffset[i] & 0xFFF;
1041 int type = TypeOffset[i] >> 12;
1042 switch(type)
1044 case IMAGE_REL_BASED_ABSOLUTE:
1045 break;
1046 case IMAGE_REL_BASED_HIGH:
1047 *(WORD *)(page+offset) += HIWORD(module->relocDelta);
1048 break;
1049 case IMAGE_REL_BASED_LOW:
1050 *(WORD *)(page+offset) += LOWORD(module->relocDelta);
1051 break;
1052 case IMAGE_REL_BASED_HIGHLOW:
1053 *(DWORD*)(page+offset) += module->relocDelta;
1054 break;
1055 default:
1056 WARN("MapModule: Unsupported fixup type\n");
1057 break;
1061 r = (IMAGE_BASE_RELOCATION *)((LPBYTE)r + r->SizeOfBlock);
1065 context->Eax = 0;
1066 RESET_CFLAG(context);
1068 break;
1071 case 0x0005: /* UnMap Module */
1073 * Input: EDX: Flat address of module image
1075 * Output: EAX: 1 if OK
1078 TRACE("UnMapModule: %lx\n", W32S_APP2WINE(context->Edx));
1080 /* As we didn't map anything, there's nothing to unmap ... */
1082 context->Eax = 1;
1083 break;
1086 case 0x0006: /* VirtualAlloc */
1088 * Input: ECX: Current Process
1090 * EDX: Flat address of arguments on stack
1092 * DWORD *retv [out] Flat base address of allocated region
1093 * LPVOID base [in] Flat address of region to reserve/commit
1094 * DWORD size [in] Size of region
1095 * DWORD type [in] Type of allocation
1096 * DWORD prot [in] Type of access protection
1098 * Output: EAX: NtStatus
1101 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1102 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1103 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1104 DWORD size = stack[2];
1105 DWORD type = stack[3];
1106 DWORD prot = stack[4];
1107 DWORD result;
1109 TRACE("VirtualAlloc(%lx, %lx, %lx, %lx, %lx)\n",
1110 (DWORD)retv, (DWORD)base, size, type, prot);
1112 if (type & 0x80000000)
1114 WARN("VirtualAlloc: strange type %lx\n", type);
1115 type &= 0x7fffffff;
1118 if (!base && (type & MEM_COMMIT) && prot == PAGE_READONLY)
1120 WARN("VirtualAlloc: NLS hack, allowing write access!\n");
1121 prot = PAGE_READWRITE;
1124 result = (DWORD)VirtualAlloc(base, size, type, prot);
1126 if (W32S_WINE2APP(result))
1127 *retv = W32S_WINE2APP(result),
1128 context->Eax = STATUS_SUCCESS;
1129 else
1130 *retv = 0,
1131 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1133 break;
1136 case 0x0007: /* VirtualFree */
1138 * Input: ECX: Current Process
1140 * EDX: Flat address of arguments on stack
1142 * DWORD *retv [out] TRUE if success, FALSE if failure
1143 * LPVOID base [in] Flat address of region
1144 * DWORD size [in] Size of region
1145 * DWORD type [in] Type of operation
1147 * Output: EAX: NtStatus
1150 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1151 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1152 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1153 DWORD size = stack[2];
1154 DWORD type = stack[3];
1155 DWORD result;
1157 TRACE("VirtualFree(%lx, %lx, %lx, %lx)\n",
1158 (DWORD)retv, (DWORD)base, size, type);
1160 result = VirtualFree(base, size, type);
1162 if (result)
1163 *retv = TRUE,
1164 context->Eax = STATUS_SUCCESS;
1165 else
1166 *retv = FALSE,
1167 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1169 break;
1172 case 0x0008: /* VirtualProtect */
1174 * Input: ECX: Current Process
1176 * EDX: Flat address of arguments on stack
1178 * DWORD *retv [out] TRUE if success, FALSE if failure
1179 * LPVOID base [in] Flat address of region
1180 * DWORD size [in] Size of region
1181 * DWORD new_prot [in] Desired access protection
1182 * DWORD *old_prot [out] Previous access protection
1184 * Output: EAX: NtStatus
1187 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1188 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1189 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1190 DWORD size = stack[2];
1191 DWORD new_prot = stack[3];
1192 DWORD *old_prot = (DWORD *)W32S_APP2WINE(stack[4]);
1193 DWORD result;
1195 TRACE("VirtualProtect(%lx, %lx, %lx, %lx, %lx)\n",
1196 (DWORD)retv, (DWORD)base, size, new_prot, (DWORD)old_prot);
1198 result = VirtualProtect(base, size, new_prot, old_prot);
1200 if (result)
1201 *retv = TRUE,
1202 context->Eax = STATUS_SUCCESS;
1203 else
1204 *retv = FALSE,
1205 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1207 break;
1210 case 0x0009: /* VirtualQuery */
1212 * Input: ECX: Current Process
1214 * EDX: Flat address of arguments on stack
1216 * DWORD *retv [out] Nr. bytes returned
1217 * LPVOID base [in] Flat address of region
1218 * LPMEMORY_BASIC_INFORMATION info [out] Info buffer
1219 * DWORD len [in] Size of buffer
1221 * Output: EAX: NtStatus
1224 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1225 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1226 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1227 PMEMORY_BASIC_INFORMATION info =
1228 (PMEMORY_BASIC_INFORMATION)W32S_APP2WINE(stack[2]);
1229 DWORD len = stack[3];
1230 DWORD result;
1232 TRACE("VirtualQuery(%lx, %lx, %lx, %lx)\n",
1233 (DWORD)retv, (DWORD)base, (DWORD)info, len);
1235 result = VirtualQuery(base, info, len);
1237 *retv = result;
1238 context->Eax = STATUS_SUCCESS;
1240 break;
1243 case 0x000A: /* SetVirtMemProcess */
1245 * Input: ECX: Process Handle
1247 * EDX: Flat address of region
1249 * Output: EAX: NtStatus
1252 TRACE("[000a] ECX=%lx EDX=%lx\n",
1253 context->Ecx, context->Edx);
1255 /* FIXME */
1257 context->Eax = STATUS_SUCCESS;
1258 break;
1261 case 0x000B: /* ??? some kind of cleanup */
1263 * Input: ECX: Process Handle
1265 * Output: EAX: NtStatus
1268 TRACE("[000b] ECX=%lx\n", context->Ecx);
1270 /* FIXME */
1272 context->Eax = STATUS_SUCCESS;
1273 break;
1276 case 0x000C: /* Set Debug Flags */
1278 * Input: EDX: Debug Flags
1280 * Output: EDX: Previous Debug Flags
1283 FIXME("[000c] EDX=%lx\n", context->Edx);
1285 /* FIXME */
1287 context->Edx = 0;
1288 break;
1291 case 0x000D: /* NtCreateSection */
1293 * Input: EDX: Flat address of arguments on stack
1295 * HANDLE32 *retv [out] Handle of Section created
1296 * DWORD flags1 [in] (?? unknown ??)
1297 * DWORD atom [in] Name of Section to create
1298 * LARGE_INTEGER *size [in] Size of Section
1299 * DWORD protect [in] Access protection
1300 * DWORD flags2 [in] (?? unknown ??)
1301 * HFILE32 hFile [in] Handle of file to map
1302 * DWORD psp [in] (Win32s: PSP that hFile belongs to)
1304 * Output: EAX: NtStatus
1307 DWORD *stack = (DWORD *) W32S_APP2WINE(context->Edx);
1308 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]);
1309 DWORD flags1 = stack[1];
1310 DWORD atom = stack[2];
1311 LARGE_INTEGER *size = (LARGE_INTEGER *)W32S_APP2WINE(stack[3]);
1312 DWORD protect = stack[4];
1313 DWORD flags2 = stack[5];
1314 HANDLE hFile = DosFileHandleToWin32Handle(stack[6]);
1315 DWORD psp = stack[7];
1317 HANDLE result = INVALID_HANDLE_VALUE;
1318 char name[128];
1320 TRACE("NtCreateSection(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1321 (DWORD)retv, flags1, atom, (DWORD)size, protect, flags2,
1322 (DWORD)hFile, psp);
1324 if (!atom || GlobalGetAtomNameA(atom, name, sizeof(name)))
1326 TRACE("NtCreateSection: name=%s\n", atom? name : "");
1328 result = CreateFileMappingA(hFile, NULL, protect,
1329 size? size->u.HighPart : 0,
1330 size? size->u.LowPart : 0,
1331 atom? name : NULL);
1334 if (result == INVALID_HANDLE_VALUE)
1335 WARN("NtCreateSection: failed!\n");
1336 else
1337 TRACE("NtCreateSection: returned %lx\n", (DWORD)result);
1339 if (result != INVALID_HANDLE_VALUE)
1340 *retv = result,
1341 context->Eax = STATUS_SUCCESS;
1342 else
1343 *retv = result,
1344 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1346 break;
1349 case 0x000E: /* NtOpenSection */
1351 * Input: EDX: Flat address of arguments on stack
1353 * HANDLE32 *retv [out] Handle of Section opened
1354 * DWORD protect [in] Access protection
1355 * DWORD atom [in] Name of Section to create
1357 * Output: EAX: NtStatus
1360 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1361 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]);
1362 DWORD protect = stack[1];
1363 DWORD atom = stack[2];
1365 HANDLE result = INVALID_HANDLE_VALUE;
1366 char name[128];
1368 TRACE("NtOpenSection(%lx, %lx, %lx)\n",
1369 (DWORD)retv, protect, atom);
1371 if (atom && GlobalGetAtomNameA(atom, name, sizeof(name)))
1373 TRACE("NtOpenSection: name=%s\n", name);
1375 result = OpenFileMappingA(protect, FALSE, name);
1378 if (result == INVALID_HANDLE_VALUE)
1379 WARN("NtOpenSection: failed!\n");
1380 else
1381 TRACE("NtOpenSection: returned %lx\n", (DWORD)result);
1383 if (result != INVALID_HANDLE_VALUE)
1384 *retv = result,
1385 context->Eax = STATUS_SUCCESS;
1386 else
1387 *retv = result,
1388 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1390 break;
1393 case 0x000F: /* NtCloseSection */
1395 * Input: EDX: Flat address of arguments on stack
1397 * HANDLE32 handle [in] Handle of Section to close
1398 * DWORD *id [out] Unique ID (?? unclear ??)
1400 * Output: EAX: NtStatus
1403 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1404 HANDLE handle = (HANDLE)stack[0];
1405 DWORD *id = (DWORD *)W32S_APP2WINE(stack[1]);
1407 TRACE("NtCloseSection(%lx, %lx)\n", (DWORD)handle, (DWORD)id);
1409 CloseHandle(handle);
1410 if (id) *id = 0; /* FIXME */
1412 context->Eax = STATUS_SUCCESS;
1414 break;
1417 case 0x0010: /* NtDupSection */
1419 * Input: EDX: Flat address of arguments on stack
1421 * HANDLE32 handle [in] Handle of Section to duplicate
1423 * Output: EAX: NtStatus
1426 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1427 HANDLE handle = (HANDLE)stack[0];
1428 HANDLE new_handle;
1430 TRACE("NtDupSection(%lx)\n", (DWORD)handle);
1432 DuplicateHandle( GetCurrentProcess(), handle,
1433 GetCurrentProcess(), &new_handle,
1434 0, FALSE, DUPLICATE_SAME_ACCESS );
1435 context->Eax = STATUS_SUCCESS;
1437 break;
1440 case 0x0011: /* NtMapViewOfSection */
1442 * Input: EDX: Flat address of arguments on stack
1444 * HANDLE32 SectionHandle [in] Section to be mapped
1445 * DWORD ProcessHandle [in] Process to be mapped into
1446 * DWORD * BaseAddress [in/out] Address to be mapped at
1447 * DWORD ZeroBits [in] Upper address bits that should be null, starting from bit 31
1448 * DWORD CommitSize [in] (?? unclear ??)
1449 * LARGE_INTEGER *SectionOffset [in] Offset within section
1450 * DWORD * ViewSize [in] Size of view
1451 * DWORD InheritDisposition [in] (?? unclear ??)
1452 * DWORD AllocationType [in] (?? unclear ??)
1453 * DWORD Protect [in] Access protection
1455 * Output: EAX: NtStatus
1458 DWORD * stack = (DWORD *)W32S_APP2WINE(context->Edx);
1459 HANDLE SectionHandle = (HANDLE)stack[0];
1460 DWORD ProcessHandle = stack[1]; /* ignored */
1461 DWORD * BaseAddress = (DWORD *)W32S_APP2WINE(stack[2]);
1462 DWORD ZeroBits = stack[3];
1463 DWORD CommitSize = stack[4];
1464 LARGE_INTEGER *SectionOffset = (LARGE_INTEGER *)W32S_APP2WINE(stack[5]);
1465 DWORD * ViewSize = (DWORD *)W32S_APP2WINE(stack[6]);
1466 DWORD InheritDisposition = stack[7];
1467 DWORD AllocationType = stack[8];
1468 DWORD Protect = stack[9];
1470 LPBYTE address = (LPBYTE)(BaseAddress?
1471 W32S_APP2WINE(*BaseAddress) : 0);
1472 DWORD access = 0, result;
1474 switch (Protect & ~(PAGE_GUARD|PAGE_NOCACHE))
1476 case PAGE_READONLY: access = FILE_MAP_READ; break;
1477 case PAGE_READWRITE: access = FILE_MAP_WRITE; break;
1478 case PAGE_WRITECOPY: access = FILE_MAP_COPY; break;
1480 case PAGE_EXECUTE_READ: access = FILE_MAP_READ; break;
1481 case PAGE_EXECUTE_READWRITE: access = FILE_MAP_WRITE; break;
1482 case PAGE_EXECUTE_WRITECOPY: access = FILE_MAP_COPY; break;
1485 TRACE("NtMapViewOfSection"
1486 "(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1487 (DWORD)SectionHandle, ProcessHandle, (DWORD)BaseAddress,
1488 ZeroBits, CommitSize, (DWORD)SectionOffset, (DWORD)ViewSize,
1489 InheritDisposition, AllocationType, Protect);
1490 TRACE("NtMapViewOfSection: "
1491 "base=%lx, offset=%lx, size=%lx, access=%lx\n",
1492 (DWORD)address, SectionOffset? SectionOffset->u.LowPart : 0,
1493 ViewSize? *ViewSize : 0, access);
1495 result = (DWORD)MapViewOfFileEx(SectionHandle, access,
1496 SectionOffset? SectionOffset->u.HighPart : 0,
1497 SectionOffset? SectionOffset->u.LowPart : 0,
1498 ViewSize? *ViewSize : 0, address);
1500 TRACE("NtMapViewOfSection: result=%lx\n", result);
1502 if (W32S_WINE2APP(result))
1504 if (BaseAddress) *BaseAddress = W32S_WINE2APP(result);
1505 context->Eax = STATUS_SUCCESS;
1507 else
1508 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1510 break;
1513 case 0x0012: /* NtUnmapViewOfSection */
1515 * Input: EDX: Flat address of arguments on stack
1517 * DWORD ProcessHandle [in] Process (defining address space)
1518 * LPBYTE BaseAddress [in] Base address of view to be unmapped
1520 * Output: EAX: NtStatus
1523 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1524 DWORD ProcessHandle = stack[0]; /* ignored */
1525 LPBYTE BaseAddress = (LPBYTE)W32S_APP2WINE(stack[1]);
1527 TRACE("NtUnmapViewOfSection(%lx, %lx)\n",
1528 ProcessHandle, (DWORD)BaseAddress);
1530 UnmapViewOfFile(BaseAddress);
1532 context->Eax = STATUS_SUCCESS;
1534 break;
1537 case 0x0013: /* NtFlushVirtualMemory */
1539 * Input: EDX: Flat address of arguments on stack
1541 * DWORD ProcessHandle [in] Process (defining address space)
1542 * LPBYTE *BaseAddress [in?] Base address of range to be flushed
1543 * DWORD *ViewSize [in?] Number of bytes to be flushed
1544 * DWORD *unknown [???] (?? unknown ??)
1546 * Output: EAX: NtStatus
1549 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1550 DWORD ProcessHandle = stack[0]; /* ignored */
1551 DWORD *BaseAddress = (DWORD *)W32S_APP2WINE(stack[1]);
1552 DWORD *ViewSize = (DWORD *)W32S_APP2WINE(stack[2]);
1553 DWORD *unknown = (DWORD *)W32S_APP2WINE(stack[3]);
1555 LPBYTE address = (LPBYTE)(BaseAddress? W32S_APP2WINE(*BaseAddress) : 0);
1556 DWORD size = ViewSize? *ViewSize : 0;
1558 TRACE("NtFlushVirtualMemory(%lx, %lx, %lx, %lx)\n",
1559 ProcessHandle, (DWORD)BaseAddress, (DWORD)ViewSize,
1560 (DWORD)unknown);
1561 TRACE("NtFlushVirtualMemory: base=%lx, size=%lx\n",
1562 (DWORD)address, size);
1564 FlushViewOfFile(address, size);
1566 context->Eax = STATUS_SUCCESS;
1568 break;
1571 case 0x0014: /* Get/Set Debug Registers */
1573 * Input: ECX: 0 if Get, 1 if Set
1575 * EDX: Get: Flat address of buffer to receive values of
1576 * debug registers DR0 .. DR7
1577 * Set: Flat address of buffer containing values of
1578 * debug registers DR0 .. DR7 to be set
1579 * Output: None
1582 FIXME("[0014] ECX=%lx EDX=%lx\n",
1583 context->Ecx, context->Edx);
1585 /* FIXME */
1586 break;
1589 case 0x0015: /* Set Coprocessor Emulation Flag */
1591 * Input: EDX: 0 to deactivate, 1 to activate coprocessor emulation
1593 * Output: None
1596 TRACE("[0015] EDX=%lx\n", context->Edx);
1598 /* We don't care, as we always have a coprocessor anyway */
1599 break;
1602 case 0x0016: /* Init Win32S VxD PSP */
1604 * If called to query required PSP size:
1606 * Input: EBX: 0
1607 * Output: EDX: Required size of Win32s VxD PSP
1609 * If called to initialize allocated PSP:
1611 * Input: EBX: LoWord: Selector of Win32s VxD PSP
1612 * HiWord: Paragraph of Win32s VxD PSP (DOSMEM)
1613 * Output: None
1616 if (context->Ebx == 0)
1617 context->Edx = 0x80;
1618 else
1620 PDB16 *psp = MapSL( MAKESEGPTR( BX_reg(context), 0 ));
1621 psp->nbFiles = 32;
1622 psp->fileHandlesPtr = MAKELONG(HIWORD(context->Ebx), 0x5c);
1623 memset((LPBYTE)psp + 0x5c, '\xFF', 32);
1625 break;
1628 case 0x0017: /* Set Break Point */
1630 * Input: EBX: Offset of Break Point
1631 * CX: Selector of Break Point
1633 * Output: None
1636 FIXME("[0017] EBX=%lx CX=%x\n",
1637 context->Ebx, CX_reg(context));
1639 /* FIXME */
1640 break;
1643 case 0x0018: /* VirtualLock */
1645 * Input: ECX: Current Process
1647 * EDX: Flat address of arguments on stack
1649 * DWORD *retv [out] TRUE if success, FALSE if failure
1650 * LPVOID base [in] Flat address of range to lock
1651 * DWORD size [in] Size of range
1653 * Output: EAX: NtStatus
1656 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1657 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1658 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1659 DWORD size = stack[2];
1660 DWORD result;
1662 TRACE("VirtualLock(%lx, %lx, %lx)\n",
1663 (DWORD)retv, (DWORD)base, size);
1665 result = VirtualLock(base, size);
1667 if (result)
1668 *retv = TRUE,
1669 context->Eax = STATUS_SUCCESS;
1670 else
1671 *retv = FALSE,
1672 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1674 break;
1677 case 0x0019: /* VirtualUnlock */
1679 * Input: ECX: Current Process
1681 * EDX: Flat address of arguments on stack
1683 * DWORD *retv [out] TRUE if success, FALSE if failure
1684 * LPVOID base [in] Flat address of range to unlock
1685 * DWORD size [in] Size of range
1687 * Output: EAX: NtStatus
1690 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1691 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1692 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1693 DWORD size = stack[2];
1694 DWORD result;
1696 TRACE("VirtualUnlock(%lx, %lx, %lx)\n",
1697 (DWORD)retv, (DWORD)base, size);
1699 result = VirtualUnlock(base, size);
1701 if (result)
1702 *retv = TRUE,
1703 context->Eax = STATUS_SUCCESS;
1704 else
1705 *retv = FALSE,
1706 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1708 break;
1711 case 0x001A: /* KGetSystemInfo */
1713 * Input: None
1715 * Output: ECX: Start of sparse memory arena
1716 * EDX: End of sparse memory arena
1719 TRACE("KGetSystemInfo()\n");
1722 * Note: Win32s reserves 0GB - 2GB for Win 3.1 and uses 2GB - 4GB as
1723 * sparse memory arena. We do it the other way around, since
1724 * we have to reserve 3GB - 4GB for Linux, and thus use
1725 * 0GB - 3GB as sparse memory arena.
1727 * FIXME: What about other OSes ?
1730 context->Ecx = W32S_WINE2APP(0x00000000);
1731 context->Edx = W32S_WINE2APP(0xbfffffff);
1732 break;
1735 case 0x001B: /* KGlobalMemStat */
1737 * Input: ESI: Flat address of buffer to receive memory info
1739 * Output: None
1742 struct Win32sMemoryInfo
1744 DWORD DIPhys_Count; /* Total physical pages */
1745 DWORD DIFree_Count; /* Free physical pages */
1746 DWORD DILin_Total_Count; /* Total virtual pages (private arena) */
1747 DWORD DILin_Total_Free; /* Free virtual pages (private arena) */
1749 DWORD SparseTotal; /* Total size of sparse arena (bytes ?) */
1750 DWORD SparseFree; /* Free size of sparse arena (bytes ?) */
1753 struct Win32sMemoryInfo *info =
1754 (struct Win32sMemoryInfo *)W32S_APP2WINE(context->Esi);
1756 FIXME("KGlobalMemStat(%lx)\n", (DWORD)info);
1758 /* FIXME */
1760 break;
1763 case 0x001C: /* Enable/Disable Exceptions */
1765 * Input: ECX: 0 to disable, 1 to enable exception handling
1767 * Output: None
1770 TRACE("[001c] ECX=%lx\n", context->Ecx);
1772 /* FIXME */
1773 break;
1776 case 0x001D: /* VirtualAlloc called from 16-bit code */
1778 * Input: EDX: Segmented address of arguments on stack
1780 * LPVOID base [in] Flat address of region to reserve/commit
1781 * DWORD size [in] Size of region
1782 * DWORD type [in] Type of allocation
1783 * DWORD prot [in] Type of access protection
1785 * Output: EAX: NtStatus
1786 * EDX: Flat base address of allocated region
1789 DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) ));
1790 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]);
1791 DWORD size = stack[1];
1792 DWORD type = stack[2];
1793 DWORD prot = stack[3];
1794 DWORD result;
1796 TRACE("VirtualAlloc16(%lx, %lx, %lx, %lx)\n",
1797 (DWORD)base, size, type, prot);
1799 if (type & 0x80000000)
1801 WARN("VirtualAlloc16: strange type %lx\n", type);
1802 type &= 0x7fffffff;
1805 result = (DWORD)VirtualAlloc(base, size, type, prot);
1807 if (W32S_WINE2APP(result))
1808 context->Edx = W32S_WINE2APP(result),
1809 context->Eax = STATUS_SUCCESS;
1810 else
1811 context->Edx = 0,
1812 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1813 TRACE("VirtualAlloc16: returning base %lx\n", context->Edx);
1815 break;
1818 case 0x001E: /* VirtualFree called from 16-bit code */
1820 * Input: EDX: Segmented address of arguments on stack
1822 * LPVOID base [in] Flat address of region
1823 * DWORD size [in] Size of region
1824 * DWORD type [in] Type of operation
1826 * Output: EAX: NtStatus
1827 * EDX: TRUE if success, FALSE if failure
1830 DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) ));
1831 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]);
1832 DWORD size = stack[1];
1833 DWORD type = stack[2];
1834 DWORD result;
1836 TRACE("VirtualFree16(%lx, %lx, %lx)\n",
1837 (DWORD)base, size, type);
1839 result = VirtualFree(base, size, type);
1841 if (result)
1842 context->Edx = TRUE,
1843 context->Eax = STATUS_SUCCESS;
1844 else
1845 context->Edx = FALSE,
1846 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1848 break;
1851 case 0x001F: /* FWorkingSetSize */
1853 * Input: EDX: 0 if Get, 1 if Set
1855 * ECX: Get: Buffer to receive Working Set Size
1856 * Set: Buffer containing Working Set Size
1858 * Output: NtStatus
1861 DWORD *ptr = (DWORD *)W32S_APP2WINE(context->Ecx);
1862 BOOL set = context->Edx;
1864 TRACE("FWorkingSetSize(%lx, %lx)\n", (DWORD)ptr, (DWORD)set);
1866 if (set)
1867 /* We do it differently ... */;
1868 else
1869 *ptr = 0x100;
1871 context->Eax = STATUS_SUCCESS;
1873 break;
1875 default:
1876 VXD_BARF( context, "W32S" );