From e7715126eb8ab561c592af0c160ca199c6d7f61a Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Tue, 29 Dec 2009 12:32:36 +0100 Subject: [PATCH] winedos: Move 16-bit VxD support back into kernel. --- .gitignore | 1 - dlls/Makefile.in | 5 +- dlls/krnl386.exe16/kernel16_private.h | 39 + dlls/krnl386.exe16/krnl386.exe16.spec | 20 +- dlls/krnl386.exe16/vxd.c | 1636 ++++++++++++++++++++++++ dlls/winedos/Makefile.in | 3 - dlls/winedos/int2f.c | 7 +- dlls/winedos/vxd.c | 1682 ------------------------- 8 files changed, 1698 insertions(+), 1695 deletions(-) delete mode 100644 dlls/winedos/vxd.c diff --git a/.gitignore b/.gitignore index 6a63858845d..180ae51895d 100644 --- a/.gitignore +++ b/.gitignore @@ -118,7 +118,6 @@ dlls/sti/sti_wia.h dlls/sti/sti_wia_p.c dlls/urlmon/urlmon_urlmon.h dlls/urlmon/urlmon_urlmon_p.c -dlls/wprocs.dll16 include/activaut.h include/activdbg.h include/activscp.h diff --git a/dlls/Makefile.in b/dlls/Makefile.in index 13b3cbf680e..53bf1b3e6e8 100644 --- a/dlls/Makefile.in +++ b/dlls/Makefile.in @@ -18,7 +18,7 @@ DOCSUBDIRS = $(DLLSUBDIRS) # 16-bit dlls WIN16_FILES = \ - wprocs.dll16 + @MAKE_RULES@ @@ -28,9 +28,6 @@ all: $(BUILDSUBDIRS) @WIN16_FILES@ # Placeholders for 16-bit libraries -wprocs.dll16: - echo "winedos.dll" >$@ - # Import libraries STATIC_IMPLIBEXT = $(IMPLIBEXT:def=def.a) diff --git a/dlls/krnl386.exe16/kernel16_private.h b/dlls/krnl386.exe16/kernel16_private.h index 4c739a57926..14c558c9e77 100644 --- a/dlls/krnl386.exe16/kernel16_private.h +++ b/dlls/krnl386.exe16/kernel16_private.h @@ -298,4 +298,43 @@ static inline struct kernel_thread_data *kernel_get_thread_data(void) "call " __ASM_NAME("__wine_call_from_32_regs") "\n\t" \ "ret $(4*" #args ")" ) /* fake ret to make copy protections happy */ +#define AX_reg(context) ((WORD)(context)->Eax) +#define BX_reg(context) ((WORD)(context)->Ebx) +#define CX_reg(context) ((WORD)(context)->Ecx) +#define DX_reg(context) ((WORD)(context)->Edx) +#define SI_reg(context) ((WORD)(context)->Esi) +#define DI_reg(context) ((WORD)(context)->Edi) + +#define AL_reg(context) ((BYTE)(context)->Eax) +#define AH_reg(context) ((BYTE)((context)->Eax >> 8)) +#define BL_reg(context) ((BYTE)(context)->Ebx) +#define BH_reg(context) ((BYTE)((context)->Ebx >> 8)) +#define CL_reg(context) ((BYTE)(context)->Ecx) +#define CH_reg(context) ((BYTE)((context)->Ecx >> 8)) +#define DL_reg(context) ((BYTE)(context)->Edx) +#define DH_reg(context) ((BYTE)((context)->Edx >> 8)) + +#define SET_CFLAG(context) ((context)->EFlags |= 0x0001) +#define RESET_CFLAG(context) ((context)->EFlags &= ~0x0001) +#define SET_ZFLAG(context) ((context)->EFlags |= 0x0040) +#define RESET_ZFLAG(context) ((context)->EFlags &= ~0x0040) +#define ISV86(context) ((context)->EFlags & 0x00020000) + +#define SET_AX(context,val) ((void)((context)->Eax = ((context)->Eax & ~0xffff) | (WORD)(val))) +#define SET_BX(context,val) ((void)((context)->Ebx = ((context)->Ebx & ~0xffff) | (WORD)(val))) +#define SET_CX(context,val) ((void)((context)->Ecx = ((context)->Ecx & ~0xffff) | (WORD)(val))) +#define SET_DX(context,val) ((void)((context)->Edx = ((context)->Edx & ~0xffff) | (WORD)(val))) +#define SET_SI(context,val) ((void)((context)->Esi = ((context)->Esi & ~0xffff) | (WORD)(val))) +#define SET_DI(context,val) ((void)((context)->Edi = ((context)->Edi & ~0xffff) | (WORD)(val))) + +#define SET_AL(context,val) ((void)((context)->Eax = ((context)->Eax & ~0xff) | (BYTE)(val))) +#define SET_BL(context,val) ((void)((context)->Ebx = ((context)->Ebx & ~0xff) | (BYTE)(val))) +#define SET_CL(context,val) ((void)((context)->Ecx = ((context)->Ecx & ~0xff) | (BYTE)(val))) +#define SET_DL(context,val) ((void)((context)->Edx = ((context)->Edx & ~0xff) | (BYTE)(val))) + +#define SET_AH(context,val) ((void)((context)->Eax = ((context)->Eax & ~0xff00) | (((BYTE)(val)) << 8))) +#define SET_BH(context,val) ((void)((context)->Ebx = ((context)->Ebx & ~0xff00) | (((BYTE)(val)) << 8))) +#define SET_CH(context,val) ((void)((context)->Ecx = ((context)->Ecx & ~0xff00) | (((BYTE)(val)) << 8))) +#define SET_DH(context,val) ((void)((context)->Edx = ((context)->Edx & ~0xff00) | (((BYTE)(val)) << 8))) + #endif /* __WINE_KERNEL16_PRIVATE_H */ diff --git a/dlls/krnl386.exe16/krnl386.exe16.spec b/dlls/krnl386.exe16/krnl386.exe16.spec index 8e08ff59bf3..7999a4592ea 100644 --- a/dlls/krnl386.exe16/krnl386.exe16.spec +++ b/dlls/krnl386.exe16/krnl386.exe16.spec @@ -523,11 +523,29 @@ 703 stub CallProc32WFix 704 pascal -register SSConfirmSmallStack() SSConfirmSmallStack - # Win95 krnl386.exe also exports ordinals 802-864, # however, those seem to be only callback stubs that are # never called directly by other modules ... +################################################################ +# VxD entry points +# + 901 pascal -register __wine_vxd_vmm() __wine_vxd_vmm + 905 pascal -register __wine_vxd_timer() __wine_vxd_timer + 909 pascal -register __wine_vxd_reboot() __wine_vxd_reboot + 910 pascal -register __wine_vxd_vdd() __wine_vxd_vdd + 912 pascal -register __wine_vxd_vmd() __wine_vxd_vmd + 914 pascal -register __wine_vxd_comm() __wine_vxd_comm +#915 pascal -register __wine_vxd_printer() __wine_vxd_printer + 923 pascal -register __wine_vxd_shell() __wine_vxd_shell + 933 pascal -register __wine_vxd_pagefile() __wine_vxd_pagefile + 938 pascal -register __wine_vxd_apm() __wine_vxd_apm + 939 pascal -register __wine_vxd_vxdloader() __wine_vxd_vxdloader + 945 pascal -register __wine_vxd_win32s() __wine_vxd_win32s + 951 pascal -register __wine_vxd_configmg() __wine_vxd_configmg + 955 pascal -register __wine_vxd_enable() __wine_vxd_enable +1990 pascal -register __wine_vxd_timerapi() __wine_vxd_timerapi + ################################################################ # 32-bit version of the various 16-bit functions exported by kernel32 # diff --git a/dlls/krnl386.exe16/vxd.c b/dlls/krnl386.exe16/vxd.c index a4208051064..ddaaab2b832 100644 --- a/dlls/krnl386.exe16/vxd.c +++ b/dlls/krnl386.exe16/vxd.c @@ -34,6 +34,10 @@ #include #include +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#include "ntstatus.h" +#define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" #include "winerror.h" @@ -78,6 +82,17 @@ static struct vxdcall_service vxd_services[] = #define NB_VXD_SERVICES (sizeof(vxd_services)/sizeof(vxd_services[0])) +#define W32S_APP2WINE(addr) ((addr)? (DWORD)(addr) + W32S_offset : 0) +#define W32S_WINE2APP(addr) ((addr)? (DWORD)(addr) - W32S_offset : 0) + +#define VXD_BARF(context,name) \ + TRACE( "vxd %s: unknown/not implemented parameters:\n" \ + "vxd %s: AX %04x, BX %04x, CX %04x, DX %04x, " \ + "SI %04x, DI %04x, DS %04x, ES %04x\n", \ + (name), (name), AX_reg(context), BX_reg(context), \ + CX_reg(context), DX_reg(context), SI_reg(context), \ + DI_reg(context), (WORD)context->SegDs, (WORD)context->SegEs ) + static CRITICAL_SECTION vxd_section; static CRITICAL_SECTION_DEBUG critsect_debug = { @@ -87,6 +102,13 @@ static CRITICAL_SECTION_DEBUG critsect_debug = }; static CRITICAL_SECTION vxd_section = { &critsect_debug, -1, 0, 0, 0, 0 }; +static UINT W32S_offset; + +static WORD VXD_WinVersion(void) +{ + WORD version = LOWORD(GetVersion16()); + return (version >> 8) | (version << 8); +} /* create a file handle to represent a VxD, by opening a dummy file in the wineserver directory */ static HANDLE open_vxd_handle( LPCWSTR name ) @@ -293,3 +315,1617 @@ void WINAPI __regs_VxDCall( DWORD service, CONTEXT86 *context ) #ifdef DEFINE_REGS_ENTRYPOINT DEFINE_REGS_ENTRYPOINT( VxDCall, 1 ) #endif + + +/*********************************************************************** + * __wine_vxd_vmm (WPROCS.401) + */ +void WINAPI __wine_vxd_vmm ( CONTEXT86 *context ) +{ + unsigned service = AX_reg(context); + + TRACE("[%04x] VMM\n", (UINT16)service); + + switch(service) + { + case 0x0000: /* version */ + SET_AX( context, VXD_WinVersion() ); + RESET_CFLAG(context); + break; + + case 0x026d: /* Get_Debug_Flag '/m' */ + case 0x026e: /* Get_Debug_Flag '/n' */ + SET_AL( context, 0 ); + RESET_CFLAG(context); + break; + + default: + VXD_BARF( context, "VMM" ); + } +} + +/*********************************************************************** + * __wine_vxd_pagefile (WPROCS.433) + */ +void WINAPI __wine_vxd_pagefile( CONTEXT86 *context ) +{ + unsigned service = AX_reg(context); + + /* taken from Ralf Brown's Interrupt List */ + + TRACE("[%04x] PageFile\n", (UINT16)service ); + + switch(service) + { + case 0x00: /* get version, is this windows version? */ + TRACE("returning version\n"); + SET_AX( context, VXD_WinVersion() ); + RESET_CFLAG(context); + break; + + case 0x01: /* get swap file info */ + TRACE("VxD PageFile: returning swap file info\n"); + SET_AX( context, 0x00 ); /* paging disabled */ + context->Ecx = 0; /* maximum size of paging file */ + /* FIXME: do I touch DS:SI or DS:DI? */ + RESET_CFLAG(context); + break; + + case 0x02: /* delete permanent swap on exit */ + TRACE("VxD PageFile: supposed to delete swap\n"); + RESET_CFLAG(context); + break; + + case 0x03: /* current temporary swap file size */ + TRACE("VxD PageFile: what is current temp. swap size\n"); + RESET_CFLAG(context); + break; + + case 0x04: /* read or write?? INTERRUP.D */ + case 0x05: /* cancel?? INTERRUP.D */ + case 0x06: /* test I/O valid INTERRUP.D */ + default: + VXD_BARF( context, "pagefile" ); + break; + } +} + +/*********************************************************************** + * __wine_vxd_reboot (WPROCS.409) + */ +void WINAPI __wine_vxd_reboot( CONTEXT86 *context ) +{ + unsigned service = AX_reg(context); + + TRACE("[%04x] Reboot\n", (UINT16)service); + + switch(service) + { + case 0x0000: /* version */ + SET_AX( context, VXD_WinVersion() ); + RESET_CFLAG(context); + break; + + default: + VXD_BARF( context, "REBOOT" ); + } +} + +/*********************************************************************** + * __wine_vxd_vdd (WPROCS.410) + */ +void WINAPI __wine_vxd_vdd( CONTEXT86 *context ) +{ + unsigned service = AX_reg(context); + + TRACE("[%04x] VDD\n", (UINT16)service); + + switch(service) + { + case 0x0000: /* version */ + SET_AX( context, VXD_WinVersion() ); + RESET_CFLAG(context); + break; + + default: + VXD_BARF( context, "VDD" ); + } +} + +/*********************************************************************** + * __wine_vxd_vmd (WPROCS.412) + */ +void WINAPI __wine_vxd_vmd( CONTEXT86 *context ) +{ + unsigned service = AX_reg(context); + + TRACE("[%04x] VMD\n", (UINT16)service); + + switch(service) + { + case 0x0000: /* version */ + SET_AX( context, VXD_WinVersion() ); + RESET_CFLAG(context); + break; + + default: + VXD_BARF( context, "VMD" ); + } +} + +/*********************************************************************** + * __wine_vxd_vxdloader (WPROCS.439) + */ +void WINAPI __wine_vxd_vxdloader( CONTEXT86 *context ) +{ + unsigned service = AX_reg(context); + + TRACE("[%04x] VXDLoader\n", (UINT16)service); + + switch (service) + { + case 0x0000: /* get version */ + TRACE("returning version\n"); + SET_AX( context, 0x0000 ); + SET_DX( context, VXD_WinVersion() ); + RESET_CFLAG(context); + break; + + case 0x0001: /* load device */ + FIXME("load device %04x:%04x (%s)\n", + context->SegDs, DX_reg(context), + debugstr_a(MapSL(MAKESEGPTR(context->SegDs, DX_reg(context))))); + SET_AX( context, 0x0000 ); + context->SegEs = 0x0000; + SET_DI( context, 0x0000 ); + RESET_CFLAG(context); + break; + + case 0x0002: /* unload device */ + FIXME("unload device (%08x)\n", context->Ebx); + SET_AX( context, 0x0000 ); + RESET_CFLAG(context); + break; + + default: + VXD_BARF( context, "VXDLDR" ); + SET_AX( context, 0x000B ); /* invalid function number */ + SET_CFLAG(context); + break; + } +} + +/*********************************************************************** + * __wine_vxd_shell (WPROCS.423) + */ +void WINAPI __wine_vxd_shell( CONTEXT86 *context ) +{ + unsigned service = DX_reg(context); + + TRACE("[%04x] Shell\n", (UINT16)service); + + switch (service) /* Ralf Brown says EDX, but I use DX instead */ + { + case 0x0000: + TRACE("returning version\n"); + SET_AX( context, VXD_WinVersion() ); + context->Ebx = 1; /* system VM Handle */ + break; + + case 0x0001: + case 0x0002: + case 0x0003: + /* SHELL_SYSMODAL_Message + ebx virtual machine handle + eax message box flags + ecx address of message + edi address of caption + return response in eax + */ + case 0x0004: + /* SHELL_Message + ebx virtual machine handle + eax message box flags + ecx address of message + edi address of caption + esi address callback + edx reference data for callback + return response in eax + */ + case 0x0005: + VXD_BARF( context, "shell" ); + break; + + case 0x0006: /* SHELL_Get_VM_State */ + TRACE("VxD Shell: returning VM state\n"); + /* Actually we don't, not yet. We have to return a structure + * and I am not to sure how to set it up and return it yet, + * so for now let's do nothing. I can (hopefully) get this + * by the next release + */ + /* RESET_CFLAG(context); */ + break; + + case 0x0007: + case 0x0008: + case 0x0009: + case 0x000A: + case 0x000B: + case 0x000C: + case 0x000D: + case 0x000E: + case 0x000F: + case 0x0010: + case 0x0011: + case 0x0012: + case 0x0013: + case 0x0014: + case 0x0015: + case 0x0016: + VXD_BARF( context, "SHELL" ); + break; + + /* the new Win95 shell API */ + case 0x0100: /* get version */ + SET_AX( context, VXD_WinVersion() ); + break; + + case 0x0104: /* retrieve Hook_Properties list */ + case 0x0105: /* call Hook_Properties callbacks */ + VXD_BARF( context, "SHELL" ); + break; + + case 0x0106: /* install timeout callback */ + TRACE("VxD Shell: ignoring shell callback (%d sec.)\n", context->Ebx); + SET_CFLAG(context); + break; + + case 0x0107: /* get version of any VxD */ + default: + VXD_BARF( context, "SHELL" ); + break; + } +} + + +/*********************************************************************** + * __wine_vxd_comm (WPROCS.414) + */ +void WINAPI __wine_vxd_comm( CONTEXT86 *context ) +{ + unsigned service = AX_reg(context); + + TRACE("[%04x] Comm\n", (UINT16)service); + + switch (service) + { + case 0x0000: /* get version */ + TRACE("returning version\n"); + SET_AX( context, VXD_WinVersion() ); + RESET_CFLAG(context); + break; + + case 0x0001: /* set port global */ + case 0x0002: /* get focus */ + case 0x0003: /* virtualise port */ + default: + VXD_BARF( context, "comm" ); + } +} + +/*********************************************************************** + * __wine_vxd_timer (WPROCS.405) + */ +void WINAPI __wine_vxd_timer( CONTEXT86 *context ) +{ + unsigned service = AX_reg(context); + + TRACE("[%04x] Virtual Timer\n", (UINT16)service); + + switch(service) + { + case 0x0000: /* version */ + SET_AX( context, VXD_WinVersion() ); + RESET_CFLAG(context); + break; + + case 0x0100: /* clock tick time, in 840nsecs */ + context->Eax = GetTickCount(); + + context->Edx = context->Eax >> 22; + context->Eax <<= 10; /* not very precise */ + break; + + case 0x0101: /* current Windows time, msecs */ + case 0x0102: /* current VM time, msecs */ + context->Eax = GetTickCount(); + break; + + default: + VXD_BARF( context, "VTD" ); + } +} + + +/*********************************************************************** + * timer_thread + */ +static DWORD CALLBACK timer_thread( void *arg ) +{ + DWORD *system_time = arg; + + for (;;) + { + *system_time = GetTickCount(); + Sleep( 55 ); + } + + return 0; +} + + +/*********************************************************************** + * __wine_vxd_timerapi (WPROCS.1490) + */ +void WINAPI __wine_vxd_timerapi( CONTEXT86 *context ) +{ + static WORD System_Time_Selector; + + unsigned service = AX_reg(context); + + TRACE("[%04x] TimerAPI\n", (UINT16)service); + + switch(service) + { + case 0x0000: /* version */ + SET_AX( context, VXD_WinVersion() ); + RESET_CFLAG(context); + break; + + case 0x0009: /* get system time selector */ + if ( !System_Time_Selector ) + { + HANDLE16 handle = GlobalAlloc16( GMEM_FIXED, sizeof(DWORD) ); + System_Time_Selector = handle | 7; + CloseHandle( CreateThread( NULL, 0, timer_thread, GlobalLock16(handle), 0, NULL ) ); + } + SET_AX( context, System_Time_Selector ); + RESET_CFLAG(context); + break; + + default: + VXD_BARF( context, "VTDAPI" ); + } +} + +/*********************************************************************** + * __wine_vxd_configmg (WPROCS.451) + */ +void WINAPI __wine_vxd_configmg( CONTEXT86 *context ) +{ + unsigned service = AX_reg(context); + + TRACE("[%04x] ConfigMG\n", (UINT16)service); + + switch(service) + { + case 0x0000: /* version */ + SET_AX( context, VXD_WinVersion() ); + RESET_CFLAG(context); + break; + + default: + VXD_BARF( context, "CONFIGMG" ); + } +} + +/*********************************************************************** + * __wine_vxd_enable (WPROCS.455) + */ +void WINAPI __wine_vxd_enable( CONTEXT86 *context ) +{ + unsigned service = AX_reg(context); + + TRACE("[%04x] Enable\n", (UINT16)service); + + switch(service) + { + case 0x0000: /* version */ + SET_AX( context, VXD_WinVersion() ); + RESET_CFLAG(context); + break; + + default: + VXD_BARF( context, "ENABLE" ); + } +} + +/*********************************************************************** + * __wine_vxd_apm (WPROCS.438) + */ +void WINAPI __wine_vxd_apm( CONTEXT86 *context ) +{ + unsigned service = AX_reg(context); + + TRACE("[%04x] APM\n", (UINT16)service); + + switch(service) + { + case 0x0000: /* version */ + SET_AX( context, VXD_WinVersion() ); + RESET_CFLAG(context); + break; + + default: + VXD_BARF( context, "APM" ); + } +} + +/*********************************************************************** + * __wine_vxd_win32s (WPROCS.445) + * + * This is an implementation of the services of the Win32s VxD. + * Since official documentation of these does not seem to be available, + * certain arguments of some of the services remain unclear. + * + * FIXME: The following services are currently unimplemented: + * Exception handling (0x01, 0x1C) + * Debugger support (0x0C, 0x14, 0x17) + * Low-level memory access (0x02, 0x03, 0x0A, 0x0B) + * Memory Statistics (0x1B) + * + * + * We have a specific problem running Win32s on Linux (and probably also + * the other x86 unixes), since Win32s tries to allocate its main 'flat + * code/data segment' selectors with a base of 0xffff0000 (and limit 4GB). + * The rationale for this seems to be that they want one the one hand to + * be able to leave the Win 3.1 memory (starting with the main DOS memory) + * at linear address 0, but want at other hand to have offset 0 of the + * flat data/code segment point to an unmapped page (to catch NULL pointer + * accesses). Hence they allocate the flat segments with a base of 0xffff0000 + * so that the Win 3.1 memory area at linear address zero shows up in the + * flat segments at offset 0x10000 (since linear addresses wrap around at + * 4GB). To compensate for that discrepancy between flat segment offsets + * and plain linear addresses, all flat pointers passed between the 32-bit + * and the 16-bit parts of Win32s are shifted by 0x10000 in the appropriate + * direction by the glue code (mainly) in W32SKRNL and WIN32S16. + * + * The problem for us is now that Linux does not allow a LDT selector with + * base 0xffff0000 to be created, since it would 'see' a part of the kernel + * address space. To address this problem we introduce *another* offset: + * We add 0x10000 to every linear address we get as an argument from Win32s. + * This means especially that the flat code/data selectors get actually + * allocated with base 0x0, so that flat offsets and (real) linear addresses + * do again agree! In fact, every call e.g. of a Win32s VxD service now + * has all pointer arguments (which are offsets in the flat data segment) + * first reduced by 0x10000 by the W32SKRNL glue code, and then again + * increased by 0x10000 by *our* code. + * + * Note that to keep everything consistent, this offset has to be applied by + * every Wine function that operates on 'linear addresses' passed to it by + * Win32s. Fortunately, since Win32s does not directly call any Wine 32-bit + * API routines, this affects only two locations: this VxD and the DPMI + * handler. (NOTE: Should any Win32s application pass a linear address to + * any routine apart from those, e.g. some other VxD handler, that code + * would have to take the offset into account as well!) + * + * The offset is set the first time any application calls the GetVersion() + * service of the Win32s VxD. (Note that the offset is never reset.) + * + */ +void WINAPI __wine_vxd_win32s( CONTEXT86 *context ) +{ + switch (AX_reg(context)) + { + case 0x0000: /* Get Version */ + /* + * Input: None + * + * Output: EAX: LoWord: Win32s Version (1.30) + * HiWord: VxD Version (200) + * + * EBX: Build (172) + * + * ECX: ??? (1) + * + * EDX: Debugging Flags + * + * EDI: Error Flag + * 0 if OK, + * 1 if VMCPD VxD not found + */ + + TRACE("GetVersion()\n"); + + context->Eax = VXD_WinVersion() | (200 << 16); + context->Ebx = 0; + context->Ecx = 0; + context->Edx = 0; + context->Edi = 0; + + /* + * If this is the first time we are called for this process, + * hack the memory image of WIN32S16 so that it doesn't try + * to access the GDT directly ... + * + * The first code segment of WIN32S16 (version 1.30) contains + * an unexported function somewhere between the exported functions + * SetFS and StackLinearToSegmented that tries to find a selector + * in the LDT that maps to the memory image of the LDT itself. + * If it succeeds, it stores this selector into a global variable + * which will be used to speed up execution by using this selector + * to modify the LDT directly instead of using the DPMI calls. + * + * To perform this search of the LDT, this function uses the + * sgdt and sldt instructions to find the linear address of + * the (GDT and then) LDT. While those instructions themselves + * execute without problem, the linear address that sgdt returns + * points (at least under Linux) to the kernel address space, so + * that any subsequent access leads to a segfault. + * + * Fortunately, WIN32S16 still contains as a fallback option the + * mechanism of using DPMI calls to modify LDT selectors instead + * of direct writes to the LDT. Thus we can circumvent the problem + * by simply replacing the first byte of the offending function + * with an 'retf' instruction. This means that the global variable + * supposed to contain the LDT alias selector will remain zero, + * and hence WIN32S16 will fall back to using DPMI calls. + * + * The heuristic we employ to _find_ that function is as follows: + * We search between the addresses of the exported symbols SetFS + * and StackLinearToSegmented for the byte sequence '0F 01 04' + * (this is the opcode of 'sgdt [si]'). We then search backwards + * from this address for the last occurrence of 'CB' (retf) that marks + * the end of the preceding function. The following byte (which + * should now be the first byte of the function we are looking for) + * will be replaced by 'CB' (retf). + * + * This heuristic works for the retail as well as the debug version + * of Win32s version 1.30. For versions earlier than that this + * hack should not be necessary at all, since the whole mechanism + * ('PERF130') was introduced only in 1.30 to improve the overall + * performance of Win32s. + */ + + if (!W32S_offset) + { + HMODULE16 hModule = GetModuleHandle16("win32s16"); + SEGPTR func1 = (SEGPTR)GetProcAddress16(hModule, "SetFS"); + SEGPTR func2 = (SEGPTR)GetProcAddress16(hModule, "StackLinearToSegmented"); + + if ( hModule && func1 && func2 + && SELECTOROF(func1) == SELECTOROF(func2)) + { + BYTE *start = MapSL(func1); + BYTE *end = MapSL(func2); + BYTE *p, *retv = NULL; + int found = 0; + + for (p = start; p < end; p++) + if (*p == 0xCB) found = 0, retv = p; + else if (*p == 0x0F) found = 1; + else if (*p == 0x01 && found == 1) found = 2; + else if (*p == 0x04 && found == 2) { found = 3; break; } + else found = 0; + + if (found == 3 && retv) + { + TRACE("PERF130 hack: " + "Replacing byte %02X at offset %04X:%04X\n", + *(retv+1), SELECTOROF(func1), + OFFSETOF(func1) + retv+1-start); + + *(retv+1) = (BYTE)0xCB; + } + } + } + + /* + * Mark process as Win32s, so that subsequent DPMI calls + * will perform the W32S_APP2WINE/W32S_WINE2APP address shift. + */ + W32S_offset = 0x10000; + break; + + + case 0x0001: /* Install Exception Handling */ + /* + * Input: EBX: Flat address of W32SKRNL Exception Data + * + * ECX: LoWord: Flat Code Selector + * HiWord: Flat Data Selector + * + * EDX: Flat address of W32SKRNL Exception Handler + * (this is equal to W32S_BackTo32 + 0x40) + * + * ESI: SEGPTR KERNEL.HASGPHANDLER + * + * EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10) + * + * Output: EAX: 0 if OK + */ + + TRACE("[0001] EBX=%x ECX=%x EDX=%x ESI=%x EDI=%x\n", + context->Ebx, context->Ecx, context->Edx, + context->Esi, context->Edi); + + /* FIXME */ + + context->Eax = 0; + break; + + + case 0x0002: /* Set Page Access Flags */ + /* + * Input: EBX: New access flags + * Bit 2: User Page if set, Supervisor Page if clear + * Bit 1: Read-Write if set, Read-Only if clear + * + * ECX: Size of memory area to change + * + * EDX: Flat start address of memory area + * + * Output: EAX: Size of area changed + */ + + TRACE("[0002] EBX=%x ECX=%x EDX=%x\n", + context->Ebx, context->Ecx, context->Edx); + + /* FIXME */ + + context->Eax = context->Ecx; + break; + + + case 0x0003: /* Get Page Access Flags */ + /* + * Input: EDX: Flat address of page to query + * + * Output: EAX: Page access flags + * Bit 2: User Page if set, Supervisor Page if clear + * Bit 1: Read-Write if set, Read-Only if clear + */ + + TRACE("[0003] EDX=%x\n", context->Edx); + + /* FIXME */ + + context->Eax = 6; + break; + + + case 0x0004: /* Map Module */ + /* + * Input: ECX: IMTE (offset in Module Table) of new module + * + * EDX: Flat address of Win32s Module Table + * + * Output: EAX: 0 if OK + */ + + if (!context->Edx || CX_reg(context) == 0xFFFF) + { + TRACE("MapModule: Initialization call\n"); + context->Eax = 0; + } + else + { + /* + * Structure of a Win32s Module Table Entry: + */ + struct Win32sModule + { + DWORD flags; + DWORD flatBaseAddr; + LPCSTR moduleName; + LPCSTR pathName; + LPCSTR unknown; + LPBYTE baseAddr; + DWORD hModule; + DWORD relocDelta; + }; + + /* + * Note: This function should set up a demand-paged memory image + * of the given module. Since mmap does not allow file offsets + * not aligned at 1024 bytes, we simply load the image fully + * into memory. + */ + + struct Win32sModule *moduleTable = + (struct Win32sModule *)W32S_APP2WINE(context->Edx); + struct Win32sModule *module = moduleTable + context->Ecx; + + IMAGE_NT_HEADERS *nt_header = RtlImageNtHeader( (HMODULE)module->baseAddr ); + IMAGE_SECTION_HEADER *pe_seg = (IMAGE_SECTION_HEADER*)((char *)&nt_header->OptionalHeader + + nt_header->FileHeader.SizeOfOptionalHeader); + + + HFILE image = _lopen(module->pathName, OF_READ); + BOOL error = (image == HFILE_ERROR); + UINT i; + + TRACE("MapModule: Loading %s\n", module->pathName); + + for (i = 0; + !error && i < nt_header->FileHeader.NumberOfSections; + i++, pe_seg++) + if(!(pe_seg->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)) + { + DWORD off = pe_seg->PointerToRawData; + DWORD len = pe_seg->SizeOfRawData; + LPBYTE addr = module->baseAddr + pe_seg->VirtualAddress; + + TRACE("MapModule: " + "Section %d at %08x from %08x len %08x\n", + i, (DWORD)addr, off, len); + + if ( _llseek(image, off, SEEK_SET) != off + || _lread(image, addr, len) != len) + error = TRUE; + } + + _lclose(image); + + if (error) + ERR("MapModule: Unable to load %s\n", module->pathName); + + else if (module->relocDelta != 0) + { + IMAGE_DATA_DIRECTORY *dir = nt_header->OptionalHeader.DataDirectory + + IMAGE_DIRECTORY_ENTRY_BASERELOC; + IMAGE_BASE_RELOCATION *r = (IMAGE_BASE_RELOCATION *) + (dir->Size? module->baseAddr + dir->VirtualAddress : 0); + + TRACE("MapModule: Reloc delta %08x\n", module->relocDelta); + + while (r && r->VirtualAddress) + { + LPBYTE page = module->baseAddr + r->VirtualAddress; + WORD *TypeOffset = (WORD *)(r + 1); + unsigned int count = (r->SizeOfBlock - sizeof(*r)) / sizeof(*TypeOffset); + + TRACE("MapModule: %d relocations for page %08x\n", + count, (DWORD)page); + + for(i = 0; i < count; i++) + { + int offset = TypeOffset[i] & 0xFFF; + int type = TypeOffset[i] >> 12; + switch(type) + { + case IMAGE_REL_BASED_ABSOLUTE: + break; + case IMAGE_REL_BASED_HIGH: + *(WORD *)(page+offset) += HIWORD(module->relocDelta); + break; + case IMAGE_REL_BASED_LOW: + *(WORD *)(page+offset) += LOWORD(module->relocDelta); + break; + case IMAGE_REL_BASED_HIGHLOW: + *(DWORD*)(page+offset) += module->relocDelta; + break; + default: + WARN("MapModule: Unsupported fixup type\n"); + break; + } + } + + r = (IMAGE_BASE_RELOCATION *)((LPBYTE)r + r->SizeOfBlock); + } + } + + context->Eax = 0; + RESET_CFLAG(context); + } + break; + + + case 0x0005: /* UnMap Module */ + /* + * Input: EDX: Flat address of module image + * + * Output: EAX: 1 if OK + */ + + TRACE("UnMapModule: %x\n", W32S_APP2WINE(context->Edx)); + + /* As we didn't map anything, there's nothing to unmap ... */ + + context->Eax = 1; + break; + + + case 0x0006: /* VirtualAlloc */ + /* + * Input: ECX: Current Process + * + * EDX: Flat address of arguments on stack + * + * DWORD *retv [out] Flat base address of allocated region + * LPVOID base [in] Flat address of region to reserve/commit + * DWORD size [in] Size of region + * DWORD type [in] Type of allocation + * DWORD prot [in] Type of access protection + * + * Output: EAX: NtStatus + */ + { + DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx); + DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]); + LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]); + DWORD size = stack[2]; + DWORD type = stack[3]; + DWORD prot = stack[4]; + DWORD result; + + TRACE("VirtualAlloc(%x, %x, %x, %x, %x)\n", + (DWORD)retv, (DWORD)base, size, type, prot); + + if (type & 0x80000000) + { + WARN("VirtualAlloc: strange type %x\n", type); + type &= 0x7fffffff; + } + + if (!base && (type & MEM_COMMIT) && prot == PAGE_READONLY) + { + WARN("VirtualAlloc: NLS hack, allowing write access!\n"); + prot = PAGE_READWRITE; + } + + result = (DWORD)VirtualAlloc(base, size, type, prot); + + if (W32S_WINE2APP(result)) + *retv = W32S_WINE2APP(result), + context->Eax = STATUS_SUCCESS; + else + *retv = 0, + context->Eax = STATUS_NO_MEMORY; /* FIXME */ + } + break; + + + case 0x0007: /* VirtualFree */ + /* + * Input: ECX: Current Process + * + * EDX: Flat address of arguments on stack + * + * DWORD *retv [out] TRUE if success, FALSE if failure + * LPVOID base [in] Flat address of region + * DWORD size [in] Size of region + * DWORD type [in] Type of operation + * + * Output: EAX: NtStatus + */ + { + DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx); + DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]); + LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]); + DWORD size = stack[2]; + DWORD type = stack[3]; + DWORD result; + + TRACE("VirtualFree(%x, %x, %x, %x)\n", + (DWORD)retv, (DWORD)base, size, type); + + result = VirtualFree(base, size, type); + + if (result) + *retv = TRUE, + context->Eax = STATUS_SUCCESS; + else + *retv = FALSE, + context->Eax = STATUS_NO_MEMORY; /* FIXME */ + } + break; + + + case 0x0008: /* VirtualProtect */ + /* + * Input: ECX: Current Process + * + * EDX: Flat address of arguments on stack + * + * DWORD *retv [out] TRUE if success, FALSE if failure + * LPVOID base [in] Flat address of region + * DWORD size [in] Size of region + * DWORD new_prot [in] Desired access protection + * DWORD *old_prot [out] Previous access protection + * + * Output: EAX: NtStatus + */ + { + DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx); + DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]); + LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]); + DWORD size = stack[2]; + DWORD new_prot = stack[3]; + DWORD *old_prot = (DWORD *)W32S_APP2WINE(stack[4]); + DWORD result; + + TRACE("VirtualProtect(%x, %x, %x, %x, %x)\n", + (DWORD)retv, (DWORD)base, size, new_prot, (DWORD)old_prot); + + result = VirtualProtect(base, size, new_prot, old_prot); + + if (result) + *retv = TRUE, + context->Eax = STATUS_SUCCESS; + else + *retv = FALSE, + context->Eax = STATUS_NO_MEMORY; /* FIXME */ + } + break; + + + case 0x0009: /* VirtualQuery */ + /* + * Input: ECX: Current Process + * + * EDX: Flat address of arguments on stack + * + * DWORD *retv [out] Nr. bytes returned + * LPVOID base [in] Flat address of region + * LPMEMORY_BASIC_INFORMATION info [out] Info buffer + * DWORD len [in] Size of buffer + * + * Output: EAX: NtStatus + */ + { + DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx); + DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]); + LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]); + PMEMORY_BASIC_INFORMATION info = + (PMEMORY_BASIC_INFORMATION)W32S_APP2WINE(stack[2]); + DWORD len = stack[3]; + DWORD result; + + TRACE("VirtualQuery(%x, %x, %x, %x)\n", + (DWORD)retv, (DWORD)base, (DWORD)info, len); + + result = VirtualQuery(base, info, len); + + *retv = result; + context->Eax = STATUS_SUCCESS; + } + break; + + + case 0x000A: /* SetVirtMemProcess */ + /* + * Input: ECX: Process Handle + * + * EDX: Flat address of region + * + * Output: EAX: NtStatus + */ + + TRACE("[000a] ECX=%x EDX=%x\n", + context->Ecx, context->Edx); + + /* FIXME */ + + context->Eax = STATUS_SUCCESS; + break; + + + case 0x000B: /* ??? some kind of cleanup */ + /* + * Input: ECX: Process Handle + * + * Output: EAX: NtStatus + */ + + TRACE("[000b] ECX=%x\n", context->Ecx); + + /* FIXME */ + + context->Eax = STATUS_SUCCESS; + break; + + + case 0x000C: /* Set Debug Flags */ + /* + * Input: EDX: Debug Flags + * + * Output: EDX: Previous Debug Flags + */ + + FIXME("[000c] EDX=%x\n", context->Edx); + + /* FIXME */ + + context->Edx = 0; + break; + + + case 0x000D: /* NtCreateSection */ + /* + * Input: EDX: Flat address of arguments on stack + * + * HANDLE32 *retv [out] Handle of Section created + * DWORD flags1 [in] (?? unknown ??) + * DWORD atom [in] Name of Section to create + * LARGE_INTEGER *size [in] Size of Section + * DWORD protect [in] Access protection + * DWORD flags2 [in] (?? unknown ??) + * HFILE32 hFile [in] Handle of file to map + * DWORD psp [in] (Win32s: PSP that hFile belongs to) + * + * Output: EAX: NtStatus + */ + { + DWORD *stack = (DWORD *) W32S_APP2WINE(context->Edx); + HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]); + DWORD flags1 = stack[1]; + DWORD atom = stack[2]; + LARGE_INTEGER *size = (LARGE_INTEGER *)W32S_APP2WINE(stack[3]); + DWORD protect = stack[4]; + DWORD flags2 = stack[5]; + HANDLE hFile = DosFileHandleToWin32Handle(stack[6]); + DWORD psp = stack[7]; + + HANDLE result = INVALID_HANDLE_VALUE; + char name[128]; + + TRACE("NtCreateSection(%x, %x, %x, %x, %x, %x, %x, %x)\n", + (DWORD)retv, flags1, atom, (DWORD)size, protect, flags2, + (DWORD)hFile, psp); + + if (!atom || GlobalGetAtomNameA(atom, name, sizeof(name))) + { + TRACE("NtCreateSection: name=%s\n", atom? name : NULL); + + result = CreateFileMappingA(hFile, NULL, protect, + size? size->u.HighPart : 0, + size? size->u.LowPart : 0, + atom? name : NULL); + } + + if (result == INVALID_HANDLE_VALUE) + WARN("NtCreateSection: failed!\n"); + else + TRACE("NtCreateSection: returned %x\n", (DWORD)result); + + if (result != INVALID_HANDLE_VALUE) + *retv = result, + context->Eax = STATUS_SUCCESS; + else + *retv = result, + context->Eax = STATUS_NO_MEMORY; /* FIXME */ + } + break; + + + case 0x000E: /* NtOpenSection */ + /* + * Input: EDX: Flat address of arguments on stack + * + * HANDLE32 *retv [out] Handle of Section opened + * DWORD protect [in] Access protection + * DWORD atom [in] Name of Section to create + * + * Output: EAX: NtStatus + */ + { + DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx); + HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]); + DWORD protect = stack[1]; + DWORD atom = stack[2]; + + HANDLE result = INVALID_HANDLE_VALUE; + char name[128]; + + TRACE("NtOpenSection(%x, %x, %x)\n", + (DWORD)retv, protect, atom); + + if (atom && GlobalGetAtomNameA(atom, name, sizeof(name))) + { + TRACE("NtOpenSection: name=%s\n", name); + + result = OpenFileMappingA(protect, FALSE, name); + } + + if (result == INVALID_HANDLE_VALUE) + WARN("NtOpenSection: failed!\n"); + else + TRACE("NtOpenSection: returned %x\n", (DWORD)result); + + if (result != INVALID_HANDLE_VALUE) + *retv = result, + context->Eax = STATUS_SUCCESS; + else + *retv = result, + context->Eax = STATUS_NO_MEMORY; /* FIXME */ + } + break; + + + case 0x000F: /* NtCloseSection */ + /* + * Input: EDX: Flat address of arguments on stack + * + * HANDLE32 handle [in] Handle of Section to close + * DWORD *id [out] Unique ID (?? unclear ??) + * + * Output: EAX: NtStatus + */ + { + DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx); + HANDLE handle = (HANDLE)stack[0]; + DWORD *id = (DWORD *)W32S_APP2WINE(stack[1]); + + TRACE("NtCloseSection(%x, %x)\n", (DWORD)handle, (DWORD)id); + + CloseHandle(handle); + if (id) *id = 0; /* FIXME */ + + context->Eax = STATUS_SUCCESS; + } + break; + + + case 0x0010: /* NtDupSection */ + /* + * Input: EDX: Flat address of arguments on stack + * + * HANDLE32 handle [in] Handle of Section to duplicate + * + * Output: EAX: NtStatus + */ + { + DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx); + HANDLE handle = (HANDLE)stack[0]; + HANDLE new_handle; + + TRACE("NtDupSection(%x)\n", (DWORD)handle); + + DuplicateHandle( GetCurrentProcess(), handle, + GetCurrentProcess(), &new_handle, + 0, FALSE, DUPLICATE_SAME_ACCESS ); + context->Eax = STATUS_SUCCESS; + } + break; + + + case 0x0011: /* NtMapViewOfSection */ + /* + * Input: EDX: Flat address of arguments on stack + * + * HANDLE32 SectionHandle [in] Section to be mapped + * DWORD ProcessHandle [in] Process to be mapped into + * DWORD * BaseAddress [in/out] Address to be mapped at + * DWORD ZeroBits [in] (?? unclear ??) + * DWORD CommitSize [in] (?? unclear ??) + * LARGE_INTEGER *SectionOffset [in] Offset within section + * DWORD * ViewSize [in] Size of view + * DWORD InheritDisposition [in] (?? unclear ??) + * DWORD AllocationType [in] (?? unclear ??) + * DWORD Protect [in] Access protection + * + * Output: EAX: NtStatus + */ + { + DWORD * stack = (DWORD *)W32S_APP2WINE(context->Edx); + HANDLE SectionHandle = (HANDLE)stack[0]; + DWORD ProcessHandle = stack[1]; /* ignored */ + DWORD * BaseAddress = (DWORD *)W32S_APP2WINE(stack[2]); + DWORD ZeroBits = stack[3]; + DWORD CommitSize = stack[4]; + LARGE_INTEGER *SectionOffset = (LARGE_INTEGER *)W32S_APP2WINE(stack[5]); + DWORD * ViewSize = (DWORD *)W32S_APP2WINE(stack[6]); + DWORD InheritDisposition = stack[7]; + DWORD AllocationType = stack[8]; + DWORD Protect = stack[9]; + + LPBYTE address = (LPBYTE)(BaseAddress? + W32S_APP2WINE(*BaseAddress) : 0); + DWORD access = 0, result; + + switch (Protect & ~(PAGE_GUARD|PAGE_NOCACHE)) + { + case PAGE_READONLY: access = FILE_MAP_READ; break; + case PAGE_READWRITE: access = FILE_MAP_WRITE; break; + case PAGE_WRITECOPY: access = FILE_MAP_COPY; break; + + case PAGE_EXECUTE_READ: access = FILE_MAP_READ; break; + case PAGE_EXECUTE_READWRITE: access = FILE_MAP_WRITE; break; + case PAGE_EXECUTE_WRITECOPY: access = FILE_MAP_COPY; break; + } + + TRACE("NtMapViewOfSection" + "(%x, %x, %x, %x, %x, %x, %x, %x, %x, %x)\n", + (DWORD)SectionHandle, ProcessHandle, (DWORD)BaseAddress, + ZeroBits, CommitSize, (DWORD)SectionOffset, (DWORD)ViewSize, + InheritDisposition, AllocationType, Protect); + TRACE("NtMapViewOfSection: " + "base=%x, offset=%x, size=%x, access=%x\n", + (DWORD)address, SectionOffset? SectionOffset->u.LowPart : 0, + ViewSize? *ViewSize : 0, access); + + result = (DWORD)MapViewOfFileEx(SectionHandle, access, + SectionOffset? SectionOffset->u.HighPart : 0, + SectionOffset? SectionOffset->u.LowPart : 0, + ViewSize? *ViewSize : 0, address); + + TRACE("NtMapViewOfSection: result=%x\n", result); + + if (W32S_WINE2APP(result)) + { + if (BaseAddress) *BaseAddress = W32S_WINE2APP(result); + context->Eax = STATUS_SUCCESS; + } + else + context->Eax = STATUS_NO_MEMORY; /* FIXME */ + } + break; + + + case 0x0012: /* NtUnmapViewOfSection */ + /* + * Input: EDX: Flat address of arguments on stack + * + * DWORD ProcessHandle [in] Process (defining address space) + * LPBYTE BaseAddress [in] Base address of view to be unmapped + * + * Output: EAX: NtStatus + */ + { + DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx); + DWORD ProcessHandle = stack[0]; /* ignored */ + LPBYTE BaseAddress = (LPBYTE)W32S_APP2WINE(stack[1]); + + TRACE("NtUnmapViewOfSection(%x, %x)\n", + ProcessHandle, (DWORD)BaseAddress); + + UnmapViewOfFile(BaseAddress); + + context->Eax = STATUS_SUCCESS; + } + break; + + + case 0x0013: /* NtFlushVirtualMemory */ + /* + * Input: EDX: Flat address of arguments on stack + * + * DWORD ProcessHandle [in] Process (defining address space) + * LPBYTE *BaseAddress [in?] Base address of range to be flushed + * DWORD *ViewSize [in?] Number of bytes to be flushed + * DWORD *unknown [???] (?? unknown ??) + * + * Output: EAX: NtStatus + */ + { + DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx); + DWORD ProcessHandle = stack[0]; /* ignored */ + DWORD *BaseAddress = (DWORD *)W32S_APP2WINE(stack[1]); + DWORD *ViewSize = (DWORD *)W32S_APP2WINE(stack[2]); + DWORD *unknown = (DWORD *)W32S_APP2WINE(stack[3]); + + LPBYTE address = (LPBYTE)(BaseAddress? W32S_APP2WINE(*BaseAddress) : 0); + DWORD size = ViewSize? *ViewSize : 0; + + TRACE("NtFlushVirtualMemory(%x, %x, %x, %x)\n", + ProcessHandle, (DWORD)BaseAddress, (DWORD)ViewSize, + (DWORD)unknown); + TRACE("NtFlushVirtualMemory: base=%x, size=%x\n", + (DWORD)address, size); + + FlushViewOfFile(address, size); + + context->Eax = STATUS_SUCCESS; + } + break; + + + case 0x0014: /* Get/Set Debug Registers */ + /* + * Input: ECX: 0 if Get, 1 if Set + * + * EDX: Get: Flat address of buffer to receive values of + * debug registers DR0 .. DR7 + * Set: Flat address of buffer containing values of + * debug registers DR0 .. DR7 to be set + * Output: None + */ + + FIXME("[0014] ECX=%x EDX=%x\n", + context->Ecx, context->Edx); + + /* FIXME */ + break; + + + case 0x0015: /* Set Coprocessor Emulation Flag */ + /* + * Input: EDX: 0 to deactivate, 1 to activate coprocessor emulation + * + * Output: None + */ + + TRACE("[0015] EDX=%x\n", context->Edx); + + /* We don't care, as we always have a coprocessor anyway */ + break; + + + case 0x0016: /* Init Win32S VxD PSP */ + /* + * If called to query required PSP size: + * + * Input: EBX: 0 + * Output: EDX: Required size of Win32s VxD PSP + * + * If called to initialize allocated PSP: + * + * Input: EBX: LoWord: Selector of Win32s VxD PSP + * HiWord: Paragraph of Win32s VxD PSP (DOSMEM) + * Output: None + */ + + if (context->Ebx == 0) + context->Edx = 0x80; + else + { + PDB16 *psp = MapSL( MAKESEGPTR( BX_reg(context), 0 )); + psp->nbFiles = 32; + psp->fileHandlesPtr = MAKELONG(HIWORD(context->Ebx), 0x5c); + memset((LPBYTE)psp + 0x5c, '\xFF', 32); + } + break; + + + case 0x0017: /* Set Break Point */ + /* + * Input: EBX: Offset of Break Point + * CX: Selector of Break Point + * + * Output: None + */ + + FIXME("[0017] EBX=%x CX=%x\n", + context->Ebx, CX_reg(context)); + + /* FIXME */ + break; + + + case 0x0018: /* VirtualLock */ + /* + * Input: ECX: Current Process + * + * EDX: Flat address of arguments on stack + * + * DWORD *retv [out] TRUE if success, FALSE if failure + * LPVOID base [in] Flat address of range to lock + * DWORD size [in] Size of range + * + * Output: EAX: NtStatus + */ + { + DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx); + DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]); + LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]); + DWORD size = stack[2]; + DWORD result; + + TRACE("VirtualLock(%x, %x, %x)\n", + (DWORD)retv, (DWORD)base, size); + + result = VirtualLock(base, size); + + if (result) + *retv = TRUE, + context->Eax = STATUS_SUCCESS; + else + *retv = FALSE, + context->Eax = STATUS_NO_MEMORY; /* FIXME */ + } + break; + + + case 0x0019: /* VirtualUnlock */ + /* + * Input: ECX: Current Process + * + * EDX: Flat address of arguments on stack + * + * DWORD *retv [out] TRUE if success, FALSE if failure + * LPVOID base [in] Flat address of range to unlock + * DWORD size [in] Size of range + * + * Output: EAX: NtStatus + */ + { + DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx); + DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]); + LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]); + DWORD size = stack[2]; + DWORD result; + + TRACE("VirtualUnlock(%x, %x, %x)\n", + (DWORD)retv, (DWORD)base, size); + + result = VirtualUnlock(base, size); + + if (result) + *retv = TRUE, + context->Eax = STATUS_SUCCESS; + else + *retv = FALSE, + context->Eax = STATUS_NO_MEMORY; /* FIXME */ + } + break; + + + case 0x001A: /* KGetSystemInfo */ + /* + * Input: None + * + * Output: ECX: Start of sparse memory arena + * EDX: End of sparse memory arena + */ + + TRACE("KGetSystemInfo()\n"); + + /* + * Note: Win32s reserves 0GB - 2GB for Win 3.1 and uses 2GB - 4GB as + * sparse memory arena. We do it the other way around, since + * we have to reserve 3GB - 4GB for Linux, and thus use + * 0GB - 3GB as sparse memory arena. + * + * FIXME: What about other OSes ? + */ + + context->Ecx = W32S_WINE2APP(0x00000000); + context->Edx = W32S_WINE2APP(0xbfffffff); + break; + + + case 0x001B: /* KGlobalMemStat */ + /* + * Input: ESI: Flat address of buffer to receive memory info + * + * Output: None + */ + { + struct Win32sMemoryInfo + { + DWORD DIPhys_Count; /* Total physical pages */ + DWORD DIFree_Count; /* Free physical pages */ + DWORD DILin_Total_Count; /* Total virtual pages (private arena) */ + DWORD DILin_Total_Free; /* Free virtual pages (private arena) */ + + DWORD SparseTotal; /* Total size of sparse arena (bytes ?) */ + DWORD SparseFree; /* Free size of sparse arena (bytes ?) */ + }; + + struct Win32sMemoryInfo *info = + (struct Win32sMemoryInfo *)W32S_APP2WINE(context->Esi); + + FIXME("KGlobalMemStat(%x)\n", (DWORD)info); + + /* FIXME */ + } + break; + + + case 0x001C: /* Enable/Disable Exceptions */ + /* + * Input: ECX: 0 to disable, 1 to enable exception handling + * + * Output: None + */ + + TRACE("[001c] ECX=%x\n", context->Ecx); + + /* FIXME */ + break; + + + case 0x001D: /* VirtualAlloc called from 16-bit code */ + /* + * Input: EDX: Segmented address of arguments on stack + * + * LPVOID base [in] Flat address of region to reserve/commit + * DWORD size [in] Size of region + * DWORD type [in] Type of allocation + * DWORD prot [in] Type of access protection + * + * Output: EAX: NtStatus + * EDX: Flat base address of allocated region + */ + { + DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) )); + LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]); + DWORD size = stack[1]; + DWORD type = stack[2]; + DWORD prot = stack[3]; + DWORD result; + + TRACE("VirtualAlloc16(%x, %x, %x, %x)\n", + (DWORD)base, size, type, prot); + + if (type & 0x80000000) + { + WARN("VirtualAlloc16: strange type %x\n", type); + type &= 0x7fffffff; + } + + result = (DWORD)VirtualAlloc(base, size, type, prot); + + if (W32S_WINE2APP(result)) + context->Edx = W32S_WINE2APP(result), + context->Eax = STATUS_SUCCESS; + else + context->Edx = 0, + context->Eax = STATUS_NO_MEMORY; /* FIXME */ + TRACE("VirtualAlloc16: returning base %x\n", context->Edx); + } + break; + + + case 0x001E: /* VirtualFree called from 16-bit code */ + /* + * Input: EDX: Segmented address of arguments on stack + * + * LPVOID base [in] Flat address of region + * DWORD size [in] Size of region + * DWORD type [in] Type of operation + * + * Output: EAX: NtStatus + * EDX: TRUE if success, FALSE if failure + */ + { + DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) )); + LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]); + DWORD size = stack[1]; + DWORD type = stack[2]; + DWORD result; + + TRACE("VirtualFree16(%x, %x, %x)\n", + (DWORD)base, size, type); + + result = VirtualFree(base, size, type); + + if (result) + context->Edx = TRUE, + context->Eax = STATUS_SUCCESS; + else + context->Edx = FALSE, + context->Eax = STATUS_NO_MEMORY; /* FIXME */ + } + break; + + + case 0x001F: /* FWorkingSetSize */ + /* + * Input: EDX: 0 if Get, 1 if Set + * + * ECX: Get: Buffer to receive Working Set Size + * Set: Buffer containing Working Set Size + * + * Output: NtStatus + */ + { + DWORD *ptr = (DWORD *)W32S_APP2WINE(context->Ecx); + BOOL set = context->Edx; + + TRACE("FWorkingSetSize(%x, %x)\n", (DWORD)ptr, (DWORD)set); + + if (set) + /* We do it differently ... */; + else + *ptr = 0x100; + + context->Eax = STATUS_SUCCESS; + } + break; + + default: + VXD_BARF( context, "W32S" ); + } +} diff --git a/dlls/winedos/Makefile.in b/dlls/winedos/Makefile.in index ede4c7cbd10..58a50c984f5 100644 --- a/dlls/winedos/Makefile.in +++ b/dlls/winedos/Makefile.in @@ -5,8 +5,6 @@ VPATH = @srcdir@ MODULE = winedos.dll IMPORTS = user32 kernel32 ntdll -SPEC_SRCS16 = wprocs.spec - C_SRCS = \ devices.c \ dma.c \ @@ -36,7 +34,6 @@ C_SRCS = \ soundblaster.c \ timer.c \ vga.c \ - vxd.c \ xms.c @MAKE_DLL_RULES@ diff --git a/dlls/winedos/int2f.c b/dlls/winedos/int2f.c index d5353ab7337..13b86ee6cc9 100644 --- a/dlls/winedos/int2f.c +++ b/dlls/winedos/int2f.c @@ -39,8 +39,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(int); -/* base WPROCS.DLL ordinal number for VxDs */ -#define VXD_BASE 400 +/* base KERNEL ordinal number for VxDs */ +#define VXD_BASE 900 typedef struct { @@ -432,8 +432,7 @@ static void do_int2f_16( CONTEXT86 *context ) case 0x84: /* Get device API entry point */ { - HMODULE16 mod = GetModuleHandle16("wprocs"); - if (mod < 32) mod = LoadLibrary16( "wprocs" ); + HMODULE16 mod = GetModuleHandle16("kernel"); addr = (DWORD)GetProcAddress16( mod, (LPCSTR)(VXD_BASE + BX_reg(context)) ); if (!addr) /* not supported */ ERR("Accessing unknown VxD %04x - Expect a failure now.\n", BX_reg(context) ); diff --git a/dlls/winedos/vxd.c b/dlls/winedos/vxd.c deleted file mode 100644 index a719c30e108..00000000000 --- a/dlls/winedos/vxd.c +++ /dev/null @@ -1,1682 +0,0 @@ -/* - * VxD emulation - * - * Copyright 1995 Anand Kumria - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "config.h" -#include "wine/port.h" - -#include -#include -#include -#include -#include -#ifdef HAVE_UNISTD_H -# include -#endif - -#define NONAMELESSUNION -#define NONAMELESSSTRUCT -#include "ntstatus.h" -#define WIN32_NO_STATUS -#include "windef.h" -#include "winbase.h" -#include "winreg.h" -#include "winternl.h" -#include "wingdi.h" -#include "winuser.h" -#include "wine/winbase16.h" -#include "dosexe.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(vxd); - -#define W32S_APP2WINE(addr) ((addr)? (DWORD)(addr) + W32S_offset : 0) -#define W32S_WINE2APP(addr) ((addr)? (DWORD)(addr) - W32S_offset : 0) - -#define VXD_BARF(context,name) \ - TRACE( "vxd %s: unknown/not implemented parameters:\n" \ - "vxd %s: AX %04x, BX %04x, CX %04x, DX %04x, " \ - "SI %04x, DI %04x, DS %04x, ES %04x\n", \ - (name), (name), AX_reg(context), BX_reg(context), \ - CX_reg(context), DX_reg(context), SI_reg(context), \ - DI_reg(context), (WORD)context->SegDs, (WORD)context->SegEs ) - -static UINT W32S_offset; - -static WORD VXD_WinVersion(void) -{ - WORD version = LOWORD(GetVersion16()); - return (version >> 8) | (version << 8); -} - -/*********************************************************************** - * VXD_VMM (WPROCS.401) - */ -void WINAPI VXD_VMM ( CONTEXT86 *context ) -{ - unsigned service = AX_reg(context); - - TRACE("[%04x] VMM\n", (UINT16)service); - - switch(service) - { - case 0x0000: /* version */ - SET_AX( context, VXD_WinVersion() ); - RESET_CFLAG(context); - break; - - case 0x026d: /* Get_Debug_Flag '/m' */ - case 0x026e: /* Get_Debug_Flag '/n' */ - SET_AL( context, 0 ); - RESET_CFLAG(context); - break; - - default: - VXD_BARF( context, "VMM" ); - } -} - -/*********************************************************************** - * VXD_PageFile (WPROCS.433) - */ -void WINAPI VXD_PageFile( CONTEXT86 *context ) -{ - unsigned service = AX_reg(context); - - /* taken from Ralf Brown's Interrupt List */ - - TRACE("[%04x] PageFile\n", (UINT16)service ); - - switch(service) - { - case 0x00: /* get version, is this windows version? */ - TRACE("returning version\n"); - SET_AX( context, VXD_WinVersion() ); - RESET_CFLAG(context); - break; - - case 0x01: /* get swap file info */ - TRACE("VxD PageFile: returning swap file info\n"); - SET_AX( context, 0x00 ); /* paging disabled */ - context->Ecx = 0; /* maximum size of paging file */ - /* FIXME: do I touch DS:SI or DS:DI? */ - RESET_CFLAG(context); - break; - - case 0x02: /* delete permanent swap on exit */ - TRACE("VxD PageFile: supposed to delete swap\n"); - RESET_CFLAG(context); - break; - - case 0x03: /* current temporary swap file size */ - TRACE("VxD PageFile: what is current temp. swap size\n"); - RESET_CFLAG(context); - break; - - case 0x04: /* read or write?? INTERRUP.D */ - case 0x05: /* cancel?? INTERRUP.D */ - case 0x06: /* test I/O valid INTERRUP.D */ - default: - VXD_BARF( context, "pagefile" ); - break; - } -} - -/*********************************************************************** - * VXD_Reboot (WPROCS.409) - */ -void WINAPI VXD_Reboot ( CONTEXT86 *context ) -{ - unsigned service = AX_reg(context); - - TRACE("[%04x] Reboot\n", (UINT16)service); - - switch(service) - { - case 0x0000: /* version */ - SET_AX( context, VXD_WinVersion() ); - RESET_CFLAG(context); - break; - - default: - VXD_BARF( context, "REBOOT" ); - } -} - -/*********************************************************************** - * VXD_VDD (WPROCS.410) - */ -void WINAPI VXD_VDD ( CONTEXT86 *context ) -{ - unsigned service = AX_reg(context); - - TRACE("[%04x] VDD\n", (UINT16)service); - - switch(service) - { - case 0x0000: /* version */ - SET_AX( context, VXD_WinVersion() ); - RESET_CFLAG(context); - break; - - default: - VXD_BARF( context, "VDD" ); - } -} - -/*********************************************************************** - * VXD_VMD (WPROCS.412) - */ -void WINAPI VXD_VMD ( CONTEXT86 *context ) -{ - unsigned service = AX_reg(context); - - TRACE("[%04x] VMD\n", (UINT16)service); - - switch(service) - { - case 0x0000: /* version */ - SET_AX( context, VXD_WinVersion() ); - RESET_CFLAG(context); - break; - - default: - VXD_BARF( context, "VMD" ); - } -} - -/*********************************************************************** - * VXD_VXDLoader (WPROCS.439) - */ -void WINAPI VXD_VXDLoader( CONTEXT86 *context ) -{ - unsigned service = AX_reg(context); - - TRACE("[%04x] VXDLoader\n", (UINT16)service); - - switch (service) - { - case 0x0000: /* get version */ - TRACE("returning version\n"); - SET_AX( context, 0x0000 ); - SET_DX( context, VXD_WinVersion() ); - RESET_CFLAG(context); - break; - - case 0x0001: /* load device */ - FIXME("load device %04x:%04x (%s)\n", - context->SegDs, DX_reg(context), - debugstr_a(MapSL(MAKESEGPTR(context->SegDs, DX_reg(context))))); - SET_AX( context, 0x0000 ); - context->SegEs = 0x0000; - SET_DI( context, 0x0000 ); - RESET_CFLAG(context); - break; - - case 0x0002: /* unload device */ - FIXME("unload device (%08x)\n", context->Ebx); - SET_AX( context, 0x0000 ); - RESET_CFLAG(context); - break; - - default: - VXD_BARF( context, "VXDLDR" ); - SET_AX( context, 0x000B ); /* invalid function number */ - SET_CFLAG(context); - break; - } -} - -/*********************************************************************** - * VXD_Shell (WPROCS.423) - */ -void WINAPI VXD_Shell( CONTEXT86 *context ) -{ - unsigned service = DX_reg(context); - - TRACE("[%04x] Shell\n", (UINT16)service); - - switch (service) /* Ralf Brown says EDX, but I use DX instead */ - { - case 0x0000: - TRACE("returning version\n"); - SET_AX( context, VXD_WinVersion() ); - context->Ebx = 1; /* system VM Handle */ - break; - - case 0x0001: - case 0x0002: - case 0x0003: - /* SHELL_SYSMODAL_Message - ebx virtual machine handle - eax message box flags - ecx address of message - edi address of caption - return response in eax - */ - case 0x0004: - /* SHELL_Message - ebx virtual machine handle - eax message box flags - ecx address of message - edi address of caption - esi address callback - edx reference data for callback - return response in eax - */ - case 0x0005: - VXD_BARF( context, "shell" ); - break; - - case 0x0006: /* SHELL_Get_VM_State */ - TRACE("VxD Shell: returning VM state\n"); - /* Actually we don't, not yet. We have to return a structure - * and I am not to sure how to set it up and return it yet, - * so for now let's do nothing. I can (hopefully) get this - * by the next release - */ - /* RESET_CFLAG(context); */ - break; - - case 0x0007: - case 0x0008: - case 0x0009: - case 0x000A: - case 0x000B: - case 0x000C: - case 0x000D: - case 0x000E: - case 0x000F: - case 0x0010: - case 0x0011: - case 0x0012: - case 0x0013: - case 0x0014: - case 0x0015: - case 0x0016: - VXD_BARF( context, "SHELL" ); - break; - - /* the new Win95 shell API */ - case 0x0100: /* get version */ - SET_AX( context, VXD_WinVersion() ); - break; - - case 0x0104: /* retrieve Hook_Properties list */ - case 0x0105: /* call Hook_Properties callbacks */ - VXD_BARF( context, "SHELL" ); - break; - - case 0x0106: /* install timeout callback */ - TRACE("VxD Shell: ignoring shell callback (%d sec.)\n", context->Ebx); - SET_CFLAG(context); - break; - - case 0x0107: /* get version of any VxD */ - default: - VXD_BARF( context, "SHELL" ); - break; - } -} - - -/*********************************************************************** - * VXD_Comm (WPROCS.414) - */ -void WINAPI VXD_Comm( CONTEXT86 *context ) -{ - unsigned service = AX_reg(context); - - TRACE("[%04x] Comm\n", (UINT16)service); - - switch (service) - { - case 0x0000: /* get version */ - TRACE("returning version\n"); - SET_AX( context, VXD_WinVersion() ); - RESET_CFLAG(context); - break; - - case 0x0001: /* set port global */ - case 0x0002: /* get focus */ - case 0x0003: /* virtualise port */ - default: - VXD_BARF( context, "comm" ); - } -} - -/*********************************************************************** - * VXD_Timer (WPROCS.405) - */ -void WINAPI VXD_Timer( CONTEXT86 *context ) -{ - unsigned service = AX_reg(context); - - TRACE("[%04x] Virtual Timer\n", (UINT16)service); - - switch(service) - { - case 0x0000: /* version */ - SET_AX( context, VXD_WinVersion() ); - RESET_CFLAG(context); - break; - - case 0x0100: /* clock tick time, in 840nsecs */ - context->Eax = GetTickCount(); - - context->Edx = context->Eax >> 22; - context->Eax <<= 10; /* not very precise */ - break; - - case 0x0101: /* current Windows time, msecs */ - case 0x0102: /* current VM time, msecs */ - context->Eax = GetTickCount(); - break; - - default: - VXD_BARF( context, "VTD" ); - } -} - - -/*********************************************************************** - * timer_thread - */ -static DWORD CALLBACK timer_thread( void *arg ) -{ - DWORD *system_time = arg; - - for (;;) - { - *system_time = GetTickCount(); - Sleep( 55 ); - } - - return 0; -} - - -/*********************************************************************** - * VXD_TimerAPI (WPROCS.1490) - */ -void WINAPI VXD_TimerAPI ( CONTEXT86 *context ) -{ - static WORD System_Time_Selector; - - unsigned service = AX_reg(context); - - TRACE("[%04x] TimerAPI\n", (UINT16)service); - - switch(service) - { - case 0x0000: /* version */ - SET_AX( context, VXD_WinVersion() ); - RESET_CFLAG(context); - break; - - case 0x0009: /* get system time selector */ - if ( !System_Time_Selector ) - { - HANDLE16 handle = GlobalAlloc16( GMEM_FIXED, sizeof(DWORD) ); - System_Time_Selector = handle | 7; - CloseHandle( CreateThread( NULL, 0, timer_thread, GlobalLock16(handle), 0, NULL ) ); - } - SET_AX( context, System_Time_Selector ); - RESET_CFLAG(context); - break; - - default: - VXD_BARF( context, "VTDAPI" ); - } -} - -/*********************************************************************** - * VXD_ConfigMG (WPROCS.451) - */ -void WINAPI VXD_ConfigMG ( CONTEXT86 *context ) -{ - unsigned service = AX_reg(context); - - TRACE("[%04x] ConfigMG\n", (UINT16)service); - - switch(service) - { - case 0x0000: /* version */ - SET_AX( context, VXD_WinVersion() ); - RESET_CFLAG(context); - break; - - default: - VXD_BARF( context, "CONFIGMG" ); - } -} - -/*********************************************************************** - * VXD_Enable (WPROCS.455) - */ -void WINAPI VXD_Enable ( CONTEXT86 *context ) -{ - unsigned service = AX_reg(context); - - TRACE("[%04x] Enable\n", (UINT16)service); - - switch(service) - { - case 0x0000: /* version */ - SET_AX( context, VXD_WinVersion() ); - RESET_CFLAG(context); - break; - - default: - VXD_BARF( context, "ENABLE" ); - } -} - -/*********************************************************************** - * VXD_APM (WPROCS.438) - */ -void WINAPI VXD_APM ( CONTEXT86 *context ) -{ - unsigned service = AX_reg(context); - - TRACE("[%04x] APM\n", (UINT16)service); - - switch(service) - { - case 0x0000: /* version */ - SET_AX( context, VXD_WinVersion() ); - RESET_CFLAG(context); - break; - - default: - VXD_BARF( context, "APM" ); - } -} - -/*********************************************************************** - * VXD_Win32s (WPROCS.445) - * - * This is an implementation of the services of the Win32s VxD. - * Since official documentation of these does not seem to be available, - * certain arguments of some of the services remain unclear. - * - * FIXME: The following services are currently unimplemented: - * Exception handling (0x01, 0x1C) - * Debugger support (0x0C, 0x14, 0x17) - * Low-level memory access (0x02, 0x03, 0x0A, 0x0B) - * Memory Statistics (0x1B) - * - * - * We have a specific problem running Win32s on Linux (and probably also - * the other x86 unixes), since Win32s tries to allocate its main 'flat - * code/data segment' selectors with a base of 0xffff0000 (and limit 4GB). - * The rationale for this seems to be that they want one the one hand to - * be able to leave the Win 3.1 memory (starting with the main DOS memory) - * at linear address 0, but want at other hand to have offset 0 of the - * flat data/code segment point to an unmapped page (to catch NULL pointer - * accesses). Hence they allocate the flat segments with a base of 0xffff0000 - * so that the Win 3.1 memory area at linear address zero shows up in the - * flat segments at offset 0x10000 (since linear addresses wrap around at - * 4GB). To compensate for that discrepancy between flat segment offsets - * and plain linear addresses, all flat pointers passed between the 32-bit - * and the 16-bit parts of Win32s are shifted by 0x10000 in the appropriate - * direction by the glue code (mainly) in W32SKRNL and WIN32S16. - * - * The problem for us is now that Linux does not allow a LDT selector with - * base 0xffff0000 to be created, since it would 'see' a part of the kernel - * address space. To address this problem we introduce *another* offset: - * We add 0x10000 to every linear address we get as an argument from Win32s. - * This means especially that the flat code/data selectors get actually - * allocated with base 0x0, so that flat offsets and (real) linear addresses - * do again agree! In fact, every call e.g. of a Win32s VxD service now - * has all pointer arguments (which are offsets in the flat data segment) - * first reduced by 0x10000 by the W32SKRNL glue code, and then again - * increased by 0x10000 by *our* code. - * - * Note that to keep everything consistent, this offset has to be applied by - * every Wine function that operates on 'linear addresses' passed to it by - * Win32s. Fortunately, since Win32s does not directly call any Wine 32-bit - * API routines, this affects only two locations: this VxD and the DPMI - * handler. (NOTE: Should any Win32s application pass a linear address to - * any routine apart from those, e.g. some other VxD handler, that code - * would have to take the offset into account as well!) - * - * The offset is set the first time any application calls the GetVersion() - * service of the Win32s VxD. (Note that the offset is never reset.) - * - */ - -void WINAPI VXD_Win32s( CONTEXT86 *context ) -{ - switch (AX_reg(context)) - { - case 0x0000: /* Get Version */ - /* - * Input: None - * - * Output: EAX: LoWord: Win32s Version (1.30) - * HiWord: VxD Version (200) - * - * EBX: Build (172) - * - * ECX: ??? (1) - * - * EDX: Debugging Flags - * - * EDI: Error Flag - * 0 if OK, - * 1 if VMCPD VxD not found - */ - - TRACE("GetVersion()\n"); - - context->Eax = VXD_WinVersion() | (200 << 16); - context->Ebx = 0; - context->Ecx = 0; - context->Edx = 0; - context->Edi = 0; - - /* - * If this is the first time we are called for this process, - * hack the memory image of WIN32S16 so that it doesn't try - * to access the GDT directly ... - * - * The first code segment of WIN32S16 (version 1.30) contains - * an unexported function somewhere between the exported functions - * SetFS and StackLinearToSegmented that tries to find a selector - * in the LDT that maps to the memory image of the LDT itself. - * If it succeeds, it stores this selector into a global variable - * which will be used to speed up execution by using this selector - * to modify the LDT directly instead of using the DPMI calls. - * - * To perform this search of the LDT, this function uses the - * sgdt and sldt instructions to find the linear address of - * the (GDT and then) LDT. While those instructions themselves - * execute without problem, the linear address that sgdt returns - * points (at least under Linux) to the kernel address space, so - * that any subsequent access leads to a segfault. - * - * Fortunately, WIN32S16 still contains as a fallback option the - * mechanism of using DPMI calls to modify LDT selectors instead - * of direct writes to the LDT. Thus we can circumvent the problem - * by simply replacing the first byte of the offending function - * with an 'retf' instruction. This means that the global variable - * supposed to contain the LDT alias selector will remain zero, - * and hence WIN32S16 will fall back to using DPMI calls. - * - * The heuristic we employ to _find_ that function is as follows: - * We search between the addresses of the exported symbols SetFS - * and StackLinearToSegmented for the byte sequence '0F 01 04' - * (this is the opcode of 'sgdt [si]'). We then search backwards - * from this address for the last occurrence of 'CB' (retf) that marks - * the end of the preceding function. The following byte (which - * should now be the first byte of the function we are looking for) - * will be replaced by 'CB' (retf). - * - * This heuristic works for the retail as well as the debug version - * of Win32s version 1.30. For versions earlier than that this - * hack should not be necessary at all, since the whole mechanism - * ('PERF130') was introduced only in 1.30 to improve the overall - * performance of Win32s. - */ - - if (!W32S_offset) - { - HMODULE16 hModule = GetModuleHandle16("win32s16"); - SEGPTR func1 = (SEGPTR)GetProcAddress16(hModule, "SetFS"); - SEGPTR func2 = (SEGPTR)GetProcAddress16(hModule, "StackLinearToSegmented"); - - if ( hModule && func1 && func2 - && SELECTOROF(func1) == SELECTOROF(func2)) - { - BYTE *start = MapSL(func1); - BYTE *end = MapSL(func2); - BYTE *p, *retv = NULL; - int found = 0; - - for (p = start; p < end; p++) - if (*p == 0xCB) found = 0, retv = p; - else if (*p == 0x0F) found = 1; - else if (*p == 0x01 && found == 1) found = 2; - else if (*p == 0x04 && found == 2) { found = 3; break; } - else found = 0; - - if (found == 3 && retv) - { - TRACE("PERF130 hack: " - "Replacing byte %02X at offset %04X:%04X\n", - *(retv+1), SELECTOROF(func1), - OFFSETOF(func1) + retv+1-start); - - *(retv+1) = (BYTE)0xCB; - } - } - } - - /* - * Mark process as Win32s, so that subsequent DPMI calls - * will perform the W32S_APP2WINE/W32S_WINE2APP address shift. - */ - W32S_offset = 0x10000; - break; - - - case 0x0001: /* Install Exception Handling */ - /* - * Input: EBX: Flat address of W32SKRNL Exception Data - * - * ECX: LoWord: Flat Code Selector - * HiWord: Flat Data Selector - * - * EDX: Flat address of W32SKRNL Exception Handler - * (this is equal to W32S_BackTo32 + 0x40) - * - * ESI: SEGPTR KERNEL.HASGPHANDLER - * - * EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10) - * - * Output: EAX: 0 if OK - */ - - TRACE("[0001] EBX=%x ECX=%x EDX=%x ESI=%x EDI=%x\n", - context->Ebx, context->Ecx, context->Edx, - context->Esi, context->Edi); - - /* FIXME */ - - context->Eax = 0; - break; - - - case 0x0002: /* Set Page Access Flags */ - /* - * Input: EBX: New access flags - * Bit 2: User Page if set, Supervisor Page if clear - * Bit 1: Read-Write if set, Read-Only if clear - * - * ECX: Size of memory area to change - * - * EDX: Flat start address of memory area - * - * Output: EAX: Size of area changed - */ - - TRACE("[0002] EBX=%x ECX=%x EDX=%x\n", - context->Ebx, context->Ecx, context->Edx); - - /* FIXME */ - - context->Eax = context->Ecx; - break; - - - case 0x0003: /* Get Page Access Flags */ - /* - * Input: EDX: Flat address of page to query - * - * Output: EAX: Page access flags - * Bit 2: User Page if set, Supervisor Page if clear - * Bit 1: Read-Write if set, Read-Only if clear - */ - - TRACE("[0003] EDX=%x\n", context->Edx); - - /* FIXME */ - - context->Eax = 6; - break; - - - case 0x0004: /* Map Module */ - /* - * Input: ECX: IMTE (offset in Module Table) of new module - * - * EDX: Flat address of Win32s Module Table - * - * Output: EAX: 0 if OK - */ - - if (!context->Edx || CX_reg(context) == 0xFFFF) - { - TRACE("MapModule: Initialization call\n"); - context->Eax = 0; - } - else - { - /* - * Structure of a Win32s Module Table Entry: - */ - struct Win32sModule - { - DWORD flags; - DWORD flatBaseAddr; - LPCSTR moduleName; - LPCSTR pathName; - LPCSTR unknown; - LPBYTE baseAddr; - DWORD hModule; - DWORD relocDelta; - }; - - /* - * Note: This function should set up a demand-paged memory image - * of the given module. Since mmap does not allow file offsets - * not aligned at 1024 bytes, we simply load the image fully - * into memory. - */ - - struct Win32sModule *moduleTable = - (struct Win32sModule *)W32S_APP2WINE(context->Edx); - struct Win32sModule *module = moduleTable + context->Ecx; - - IMAGE_NT_HEADERS *nt_header = RtlImageNtHeader( (HMODULE)module->baseAddr ); - IMAGE_SECTION_HEADER *pe_seg = (IMAGE_SECTION_HEADER*)((char *)&nt_header->OptionalHeader + - nt_header->FileHeader.SizeOfOptionalHeader); - - - HFILE image = _lopen(module->pathName, OF_READ); - BOOL error = (image == HFILE_ERROR); - UINT i; - - TRACE("MapModule: Loading %s\n", module->pathName); - - for (i = 0; - !error && i < nt_header->FileHeader.NumberOfSections; - i++, pe_seg++) - if(!(pe_seg->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)) - { - DWORD off = pe_seg->PointerToRawData; - DWORD len = pe_seg->SizeOfRawData; - LPBYTE addr = module->baseAddr + pe_seg->VirtualAddress; - - TRACE("MapModule: " - "Section %d at %08x from %08x len %08x\n", - i, (DWORD)addr, off, len); - - if ( _llseek(image, off, SEEK_SET) != off - || _lread(image, addr, len) != len) - error = TRUE; - } - - _lclose(image); - - if (error) - ERR("MapModule: Unable to load %s\n", module->pathName); - - else if (module->relocDelta != 0) - { - IMAGE_DATA_DIRECTORY *dir = nt_header->OptionalHeader.DataDirectory - + IMAGE_DIRECTORY_ENTRY_BASERELOC; - IMAGE_BASE_RELOCATION *r = (IMAGE_BASE_RELOCATION *) - (dir->Size? module->baseAddr + dir->VirtualAddress : 0); - - TRACE("MapModule: Reloc delta %08x\n", module->relocDelta); - - while (r && r->VirtualAddress) - { - LPBYTE page = module->baseAddr + r->VirtualAddress; - WORD *TypeOffset = (WORD *)(r + 1); - unsigned int count = (r->SizeOfBlock - sizeof(*r)) / sizeof(*TypeOffset); - - TRACE("MapModule: %d relocations for page %08x\n", - count, (DWORD)page); - - for(i = 0; i < count; i++) - { - int offset = TypeOffset[i] & 0xFFF; - int type = TypeOffset[i] >> 12; - switch(type) - { - case IMAGE_REL_BASED_ABSOLUTE: - break; - case IMAGE_REL_BASED_HIGH: - *(WORD *)(page+offset) += HIWORD(module->relocDelta); - break; - case IMAGE_REL_BASED_LOW: - *(WORD *)(page+offset) += LOWORD(module->relocDelta); - break; - case IMAGE_REL_BASED_HIGHLOW: - *(DWORD*)(page+offset) += module->relocDelta; - break; - default: - WARN("MapModule: Unsupported fixup type\n"); - break; - } - } - - r = (IMAGE_BASE_RELOCATION *)((LPBYTE)r + r->SizeOfBlock); - } - } - - context->Eax = 0; - RESET_CFLAG(context); - } - break; - - - case 0x0005: /* UnMap Module */ - /* - * Input: EDX: Flat address of module image - * - * Output: EAX: 1 if OK - */ - - TRACE("UnMapModule: %x\n", W32S_APP2WINE(context->Edx)); - - /* As we didn't map anything, there's nothing to unmap ... */ - - context->Eax = 1; - break; - - - case 0x0006: /* VirtualAlloc */ - /* - * Input: ECX: Current Process - * - * EDX: Flat address of arguments on stack - * - * DWORD *retv [out] Flat base address of allocated region - * LPVOID base [in] Flat address of region to reserve/commit - * DWORD size [in] Size of region - * DWORD type [in] Type of allocation - * DWORD prot [in] Type of access protection - * - * Output: EAX: NtStatus - */ - { - DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx); - DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]); - LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]); - DWORD size = stack[2]; - DWORD type = stack[3]; - DWORD prot = stack[4]; - DWORD result; - - TRACE("VirtualAlloc(%x, %x, %x, %x, %x)\n", - (DWORD)retv, (DWORD)base, size, type, prot); - - if (type & 0x80000000) - { - WARN("VirtualAlloc: strange type %x\n", type); - type &= 0x7fffffff; - } - - if (!base && (type & MEM_COMMIT) && prot == PAGE_READONLY) - { - WARN("VirtualAlloc: NLS hack, allowing write access!\n"); - prot = PAGE_READWRITE; - } - - result = (DWORD)VirtualAlloc(base, size, type, prot); - - if (W32S_WINE2APP(result)) - *retv = W32S_WINE2APP(result), - context->Eax = STATUS_SUCCESS; - else - *retv = 0, - context->Eax = STATUS_NO_MEMORY; /* FIXME */ - } - break; - - - case 0x0007: /* VirtualFree */ - /* - * Input: ECX: Current Process - * - * EDX: Flat address of arguments on stack - * - * DWORD *retv [out] TRUE if success, FALSE if failure - * LPVOID base [in] Flat address of region - * DWORD size [in] Size of region - * DWORD type [in] Type of operation - * - * Output: EAX: NtStatus - */ - { - DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx); - DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]); - LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]); - DWORD size = stack[2]; - DWORD type = stack[3]; - DWORD result; - - TRACE("VirtualFree(%x, %x, %x, %x)\n", - (DWORD)retv, (DWORD)base, size, type); - - result = VirtualFree(base, size, type); - - if (result) - *retv = TRUE, - context->Eax = STATUS_SUCCESS; - else - *retv = FALSE, - context->Eax = STATUS_NO_MEMORY; /* FIXME */ - } - break; - - - case 0x0008: /* VirtualProtect */ - /* - * Input: ECX: Current Process - * - * EDX: Flat address of arguments on stack - * - * DWORD *retv [out] TRUE if success, FALSE if failure - * LPVOID base [in] Flat address of region - * DWORD size [in] Size of region - * DWORD new_prot [in] Desired access protection - * DWORD *old_prot [out] Previous access protection - * - * Output: EAX: NtStatus - */ - { - DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx); - DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]); - LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]); - DWORD size = stack[2]; - DWORD new_prot = stack[3]; - DWORD *old_prot = (DWORD *)W32S_APP2WINE(stack[4]); - DWORD result; - - TRACE("VirtualProtect(%x, %x, %x, %x, %x)\n", - (DWORD)retv, (DWORD)base, size, new_prot, (DWORD)old_prot); - - result = VirtualProtect(base, size, new_prot, old_prot); - - if (result) - *retv = TRUE, - context->Eax = STATUS_SUCCESS; - else - *retv = FALSE, - context->Eax = STATUS_NO_MEMORY; /* FIXME */ - } - break; - - - case 0x0009: /* VirtualQuery */ - /* - * Input: ECX: Current Process - * - * EDX: Flat address of arguments on stack - * - * DWORD *retv [out] Nr. bytes returned - * LPVOID base [in] Flat address of region - * LPMEMORY_BASIC_INFORMATION info [out] Info buffer - * DWORD len [in] Size of buffer - * - * Output: EAX: NtStatus - */ - { - DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx); - DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]); - LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]); - PMEMORY_BASIC_INFORMATION info = - (PMEMORY_BASIC_INFORMATION)W32S_APP2WINE(stack[2]); - DWORD len = stack[3]; - DWORD result; - - TRACE("VirtualQuery(%x, %x, %x, %x)\n", - (DWORD)retv, (DWORD)base, (DWORD)info, len); - - result = VirtualQuery(base, info, len); - - *retv = result; - context->Eax = STATUS_SUCCESS; - } - break; - - - case 0x000A: /* SetVirtMemProcess */ - /* - * Input: ECX: Process Handle - * - * EDX: Flat address of region - * - * Output: EAX: NtStatus - */ - - TRACE("[000a] ECX=%x EDX=%x\n", - context->Ecx, context->Edx); - - /* FIXME */ - - context->Eax = STATUS_SUCCESS; - break; - - - case 0x000B: /* ??? some kind of cleanup */ - /* - * Input: ECX: Process Handle - * - * Output: EAX: NtStatus - */ - - TRACE("[000b] ECX=%x\n", context->Ecx); - - /* FIXME */ - - context->Eax = STATUS_SUCCESS; - break; - - - case 0x000C: /* Set Debug Flags */ - /* - * Input: EDX: Debug Flags - * - * Output: EDX: Previous Debug Flags - */ - - FIXME("[000c] EDX=%x\n", context->Edx); - - /* FIXME */ - - context->Edx = 0; - break; - - - case 0x000D: /* NtCreateSection */ - /* - * Input: EDX: Flat address of arguments on stack - * - * HANDLE32 *retv [out] Handle of Section created - * DWORD flags1 [in] (?? unknown ??) - * DWORD atom [in] Name of Section to create - * LARGE_INTEGER *size [in] Size of Section - * DWORD protect [in] Access protection - * DWORD flags2 [in] (?? unknown ??) - * HFILE32 hFile [in] Handle of file to map - * DWORD psp [in] (Win32s: PSP that hFile belongs to) - * - * Output: EAX: NtStatus - */ - { - DWORD *stack = (DWORD *) W32S_APP2WINE(context->Edx); - HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]); - DWORD flags1 = stack[1]; - DWORD atom = stack[2]; - LARGE_INTEGER *size = (LARGE_INTEGER *)W32S_APP2WINE(stack[3]); - DWORD protect = stack[4]; - DWORD flags2 = stack[5]; - HANDLE hFile = DosFileHandleToWin32Handle(stack[6]); - DWORD psp = stack[7]; - - HANDLE result = INVALID_HANDLE_VALUE; - char name[128]; - - TRACE("NtCreateSection(%x, %x, %x, %x, %x, %x, %x, %x)\n", - (DWORD)retv, flags1, atom, (DWORD)size, protect, flags2, - (DWORD)hFile, psp); - - if (!atom || GlobalGetAtomNameA(atom, name, sizeof(name))) - { - TRACE("NtCreateSection: name=%s\n", atom? name : NULL); - - result = CreateFileMappingA(hFile, NULL, protect, - size? size->u.HighPart : 0, - size? size->u.LowPart : 0, - atom? name : NULL); - } - - if (result == INVALID_HANDLE_VALUE) - WARN("NtCreateSection: failed!\n"); - else - TRACE("NtCreateSection: returned %x\n", (DWORD)result); - - if (result != INVALID_HANDLE_VALUE) - *retv = result, - context->Eax = STATUS_SUCCESS; - else - *retv = result, - context->Eax = STATUS_NO_MEMORY; /* FIXME */ - } - break; - - - case 0x000E: /* NtOpenSection */ - /* - * Input: EDX: Flat address of arguments on stack - * - * HANDLE32 *retv [out] Handle of Section opened - * DWORD protect [in] Access protection - * DWORD atom [in] Name of Section to create - * - * Output: EAX: NtStatus - */ - { - DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx); - HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]); - DWORD protect = stack[1]; - DWORD atom = stack[2]; - - HANDLE result = INVALID_HANDLE_VALUE; - char name[128]; - - TRACE("NtOpenSection(%x, %x, %x)\n", - (DWORD)retv, protect, atom); - - if (atom && GlobalGetAtomNameA(atom, name, sizeof(name))) - { - TRACE("NtOpenSection: name=%s\n", name); - - result = OpenFileMappingA(protect, FALSE, name); - } - - if (result == INVALID_HANDLE_VALUE) - WARN("NtOpenSection: failed!\n"); - else - TRACE("NtOpenSection: returned %x\n", (DWORD)result); - - if (result != INVALID_HANDLE_VALUE) - *retv = result, - context->Eax = STATUS_SUCCESS; - else - *retv = result, - context->Eax = STATUS_NO_MEMORY; /* FIXME */ - } - break; - - - case 0x000F: /* NtCloseSection */ - /* - * Input: EDX: Flat address of arguments on stack - * - * HANDLE32 handle [in] Handle of Section to close - * DWORD *id [out] Unique ID (?? unclear ??) - * - * Output: EAX: NtStatus - */ - { - DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx); - HANDLE handle = (HANDLE)stack[0]; - DWORD *id = (DWORD *)W32S_APP2WINE(stack[1]); - - TRACE("NtCloseSection(%x, %x)\n", (DWORD)handle, (DWORD)id); - - CloseHandle(handle); - if (id) *id = 0; /* FIXME */ - - context->Eax = STATUS_SUCCESS; - } - break; - - - case 0x0010: /* NtDupSection */ - /* - * Input: EDX: Flat address of arguments on stack - * - * HANDLE32 handle [in] Handle of Section to duplicate - * - * Output: EAX: NtStatus - */ - { - DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx); - HANDLE handle = (HANDLE)stack[0]; - HANDLE new_handle; - - TRACE("NtDupSection(%x)\n", (DWORD)handle); - - DuplicateHandle( GetCurrentProcess(), handle, - GetCurrentProcess(), &new_handle, - 0, FALSE, DUPLICATE_SAME_ACCESS ); - context->Eax = STATUS_SUCCESS; - } - break; - - - case 0x0011: /* NtMapViewOfSection */ - /* - * Input: EDX: Flat address of arguments on stack - * - * HANDLE32 SectionHandle [in] Section to be mapped - * DWORD ProcessHandle [in] Process to be mapped into - * DWORD * BaseAddress [in/out] Address to be mapped at - * DWORD ZeroBits [in] (?? unclear ??) - * DWORD CommitSize [in] (?? unclear ??) - * LARGE_INTEGER *SectionOffset [in] Offset within section - * DWORD * ViewSize [in] Size of view - * DWORD InheritDisposition [in] (?? unclear ??) - * DWORD AllocationType [in] (?? unclear ??) - * DWORD Protect [in] Access protection - * - * Output: EAX: NtStatus - */ - { - DWORD * stack = (DWORD *)W32S_APP2WINE(context->Edx); - HANDLE SectionHandle = (HANDLE)stack[0]; - DWORD ProcessHandle = stack[1]; /* ignored */ - DWORD * BaseAddress = (DWORD *)W32S_APP2WINE(stack[2]); - DWORD ZeroBits = stack[3]; - DWORD CommitSize = stack[4]; - LARGE_INTEGER *SectionOffset = (LARGE_INTEGER *)W32S_APP2WINE(stack[5]); - DWORD * ViewSize = (DWORD *)W32S_APP2WINE(stack[6]); - DWORD InheritDisposition = stack[7]; - DWORD AllocationType = stack[8]; - DWORD Protect = stack[9]; - - LPBYTE address = (LPBYTE)(BaseAddress? - W32S_APP2WINE(*BaseAddress) : 0); - DWORD access = 0, result; - - switch (Protect & ~(PAGE_GUARD|PAGE_NOCACHE)) - { - case PAGE_READONLY: access = FILE_MAP_READ; break; - case PAGE_READWRITE: access = FILE_MAP_WRITE; break; - case PAGE_WRITECOPY: access = FILE_MAP_COPY; break; - - case PAGE_EXECUTE_READ: access = FILE_MAP_READ; break; - case PAGE_EXECUTE_READWRITE: access = FILE_MAP_WRITE; break; - case PAGE_EXECUTE_WRITECOPY: access = FILE_MAP_COPY; break; - } - - TRACE("NtMapViewOfSection" - "(%x, %x, %x, %x, %x, %x, %x, %x, %x, %x)\n", - (DWORD)SectionHandle, ProcessHandle, (DWORD)BaseAddress, - ZeroBits, CommitSize, (DWORD)SectionOffset, (DWORD)ViewSize, - InheritDisposition, AllocationType, Protect); - TRACE("NtMapViewOfSection: " - "base=%x, offset=%x, size=%x, access=%x\n", - (DWORD)address, SectionOffset? SectionOffset->u.LowPart : 0, - ViewSize? *ViewSize : 0, access); - - result = (DWORD)MapViewOfFileEx(SectionHandle, access, - SectionOffset? SectionOffset->u.HighPart : 0, - SectionOffset? SectionOffset->u.LowPart : 0, - ViewSize? *ViewSize : 0, address); - - TRACE("NtMapViewOfSection: result=%x\n", result); - - if (W32S_WINE2APP(result)) - { - if (BaseAddress) *BaseAddress = W32S_WINE2APP(result); - context->Eax = STATUS_SUCCESS; - } - else - context->Eax = STATUS_NO_MEMORY; /* FIXME */ - } - break; - - - case 0x0012: /* NtUnmapViewOfSection */ - /* - * Input: EDX: Flat address of arguments on stack - * - * DWORD ProcessHandle [in] Process (defining address space) - * LPBYTE BaseAddress [in] Base address of view to be unmapped - * - * Output: EAX: NtStatus - */ - { - DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx); - DWORD ProcessHandle = stack[0]; /* ignored */ - LPBYTE BaseAddress = (LPBYTE)W32S_APP2WINE(stack[1]); - - TRACE("NtUnmapViewOfSection(%x, %x)\n", - ProcessHandle, (DWORD)BaseAddress); - - UnmapViewOfFile(BaseAddress); - - context->Eax = STATUS_SUCCESS; - } - break; - - - case 0x0013: /* NtFlushVirtualMemory */ - /* - * Input: EDX: Flat address of arguments on stack - * - * DWORD ProcessHandle [in] Process (defining address space) - * LPBYTE *BaseAddress [in?] Base address of range to be flushed - * DWORD *ViewSize [in?] Number of bytes to be flushed - * DWORD *unknown [???] (?? unknown ??) - * - * Output: EAX: NtStatus - */ - { - DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx); - DWORD ProcessHandle = stack[0]; /* ignored */ - DWORD *BaseAddress = (DWORD *)W32S_APP2WINE(stack[1]); - DWORD *ViewSize = (DWORD *)W32S_APP2WINE(stack[2]); - DWORD *unknown = (DWORD *)W32S_APP2WINE(stack[3]); - - LPBYTE address = (LPBYTE)(BaseAddress? W32S_APP2WINE(*BaseAddress) : 0); - DWORD size = ViewSize? *ViewSize : 0; - - TRACE("NtFlushVirtualMemory(%x, %x, %x, %x)\n", - ProcessHandle, (DWORD)BaseAddress, (DWORD)ViewSize, - (DWORD)unknown); - TRACE("NtFlushVirtualMemory: base=%x, size=%x\n", - (DWORD)address, size); - - FlushViewOfFile(address, size); - - context->Eax = STATUS_SUCCESS; - } - break; - - - case 0x0014: /* Get/Set Debug Registers */ - /* - * Input: ECX: 0 if Get, 1 if Set - * - * EDX: Get: Flat address of buffer to receive values of - * debug registers DR0 .. DR7 - * Set: Flat address of buffer containing values of - * debug registers DR0 .. DR7 to be set - * Output: None - */ - - FIXME("[0014] ECX=%x EDX=%x\n", - context->Ecx, context->Edx); - - /* FIXME */ - break; - - - case 0x0015: /* Set Coprocessor Emulation Flag */ - /* - * Input: EDX: 0 to deactivate, 1 to activate coprocessor emulation - * - * Output: None - */ - - TRACE("[0015] EDX=%x\n", context->Edx); - - /* We don't care, as we always have a coprocessor anyway */ - break; - - - case 0x0016: /* Init Win32S VxD PSP */ - /* - * If called to query required PSP size: - * - * Input: EBX: 0 - * Output: EDX: Required size of Win32s VxD PSP - * - * If called to initialize allocated PSP: - * - * Input: EBX: LoWord: Selector of Win32s VxD PSP - * HiWord: Paragraph of Win32s VxD PSP (DOSMEM) - * Output: None - */ - - if (context->Ebx == 0) - context->Edx = 0x80; - else - { - PDB16 *psp = MapSL( MAKESEGPTR( BX_reg(context), 0 )); - psp->nbFiles = 32; - psp->fileHandlesPtr = MAKELONG(HIWORD(context->Ebx), 0x5c); - memset((LPBYTE)psp + 0x5c, '\xFF', 32); - } - break; - - - case 0x0017: /* Set Break Point */ - /* - * Input: EBX: Offset of Break Point - * CX: Selector of Break Point - * - * Output: None - */ - - FIXME("[0017] EBX=%x CX=%x\n", - context->Ebx, CX_reg(context)); - - /* FIXME */ - break; - - - case 0x0018: /* VirtualLock */ - /* - * Input: ECX: Current Process - * - * EDX: Flat address of arguments on stack - * - * DWORD *retv [out] TRUE if success, FALSE if failure - * LPVOID base [in] Flat address of range to lock - * DWORD size [in] Size of range - * - * Output: EAX: NtStatus - */ - { - DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx); - DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]); - LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]); - DWORD size = stack[2]; - DWORD result; - - TRACE("VirtualLock(%x, %x, %x)\n", - (DWORD)retv, (DWORD)base, size); - - result = VirtualLock(base, size); - - if (result) - *retv = TRUE, - context->Eax = STATUS_SUCCESS; - else - *retv = FALSE, - context->Eax = STATUS_NO_MEMORY; /* FIXME */ - } - break; - - - case 0x0019: /* VirtualUnlock */ - /* - * Input: ECX: Current Process - * - * EDX: Flat address of arguments on stack - * - * DWORD *retv [out] TRUE if success, FALSE if failure - * LPVOID base [in] Flat address of range to unlock - * DWORD size [in] Size of range - * - * Output: EAX: NtStatus - */ - { - DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx); - DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]); - LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]); - DWORD size = stack[2]; - DWORD result; - - TRACE("VirtualUnlock(%x, %x, %x)\n", - (DWORD)retv, (DWORD)base, size); - - result = VirtualUnlock(base, size); - - if (result) - *retv = TRUE, - context->Eax = STATUS_SUCCESS; - else - *retv = FALSE, - context->Eax = STATUS_NO_MEMORY; /* FIXME */ - } - break; - - - case 0x001A: /* KGetSystemInfo */ - /* - * Input: None - * - * Output: ECX: Start of sparse memory arena - * EDX: End of sparse memory arena - */ - - TRACE("KGetSystemInfo()\n"); - - /* - * Note: Win32s reserves 0GB - 2GB for Win 3.1 and uses 2GB - 4GB as - * sparse memory arena. We do it the other way around, since - * we have to reserve 3GB - 4GB for Linux, and thus use - * 0GB - 3GB as sparse memory arena. - * - * FIXME: What about other OSes ? - */ - - context->Ecx = W32S_WINE2APP(0x00000000); - context->Edx = W32S_WINE2APP(0xbfffffff); - break; - - - case 0x001B: /* KGlobalMemStat */ - /* - * Input: ESI: Flat address of buffer to receive memory info - * - * Output: None - */ - { - struct Win32sMemoryInfo - { - DWORD DIPhys_Count; /* Total physical pages */ - DWORD DIFree_Count; /* Free physical pages */ - DWORD DILin_Total_Count; /* Total virtual pages (private arena) */ - DWORD DILin_Total_Free; /* Free virtual pages (private arena) */ - - DWORD SparseTotal; /* Total size of sparse arena (bytes ?) */ - DWORD SparseFree; /* Free size of sparse arena (bytes ?) */ - }; - - struct Win32sMemoryInfo *info = - (struct Win32sMemoryInfo *)W32S_APP2WINE(context->Esi); - - FIXME("KGlobalMemStat(%x)\n", (DWORD)info); - - /* FIXME */ - } - break; - - - case 0x001C: /* Enable/Disable Exceptions */ - /* - * Input: ECX: 0 to disable, 1 to enable exception handling - * - * Output: None - */ - - TRACE("[001c] ECX=%x\n", context->Ecx); - - /* FIXME */ - break; - - - case 0x001D: /* VirtualAlloc called from 16-bit code */ - /* - * Input: EDX: Segmented address of arguments on stack - * - * LPVOID base [in] Flat address of region to reserve/commit - * DWORD size [in] Size of region - * DWORD type [in] Type of allocation - * DWORD prot [in] Type of access protection - * - * Output: EAX: NtStatus - * EDX: Flat base address of allocated region - */ - { - DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) )); - LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]); - DWORD size = stack[1]; - DWORD type = stack[2]; - DWORD prot = stack[3]; - DWORD result; - - TRACE("VirtualAlloc16(%x, %x, %x, %x)\n", - (DWORD)base, size, type, prot); - - if (type & 0x80000000) - { - WARN("VirtualAlloc16: strange type %x\n", type); - type &= 0x7fffffff; - } - - result = (DWORD)VirtualAlloc(base, size, type, prot); - - if (W32S_WINE2APP(result)) - context->Edx = W32S_WINE2APP(result), - context->Eax = STATUS_SUCCESS; - else - context->Edx = 0, - context->Eax = STATUS_NO_MEMORY; /* FIXME */ - TRACE("VirtualAlloc16: returning base %x\n", context->Edx); - } - break; - - - case 0x001E: /* VirtualFree called from 16-bit code */ - /* - * Input: EDX: Segmented address of arguments on stack - * - * LPVOID base [in] Flat address of region - * DWORD size [in] Size of region - * DWORD type [in] Type of operation - * - * Output: EAX: NtStatus - * EDX: TRUE if success, FALSE if failure - */ - { - DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) )); - LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]); - DWORD size = stack[1]; - DWORD type = stack[2]; - DWORD result; - - TRACE("VirtualFree16(%x, %x, %x)\n", - (DWORD)base, size, type); - - result = VirtualFree(base, size, type); - - if (result) - context->Edx = TRUE, - context->Eax = STATUS_SUCCESS; - else - context->Edx = FALSE, - context->Eax = STATUS_NO_MEMORY; /* FIXME */ - } - break; - - - case 0x001F: /* FWorkingSetSize */ - /* - * Input: EDX: 0 if Get, 1 if Set - * - * ECX: Get: Buffer to receive Working Set Size - * Set: Buffer containing Working Set Size - * - * Output: NtStatus - */ - { - DWORD *ptr = (DWORD *)W32S_APP2WINE(context->Ecx); - BOOL set = context->Edx; - - TRACE("FWorkingSetSize(%x, %x)\n", (DWORD)ptr, (DWORD)set); - - if (set) - /* We do it differently ... */; - else - *ptr = 0x100; - - context->Eax = STATUS_SUCCESS; - } - break; - - - default: - VXD_BARF( context, "W32S" ); - } - -}