4 * Copyright 1995 Anand Kumria
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "wine/port.h"
27 #include <sys/types.h>
36 #include "wine/winbase16.h"
37 #include "wine/winuser16.h"
41 #include "selectors.h"
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(vxd);
48 #define W32S_APP2WINE(addr) ((addr)? (DWORD)(addr) + W32S_offset : 0)
49 #define W32S_WINE2APP(addr) ((addr)? (DWORD)(addr) - W32S_offset : 0)
51 #define VXD_BARF(context,name) \
52 DPRINTF( "vxd %s: unknown/not implemented parameters:\n" \
53 "vxd %s: AX %04x, BX %04x, CX %04x, DX %04x, " \
54 "SI %04x, DI %04x, DS %04x, ES %04x\n", \
55 (name), (name), AX_reg(context), BX_reg(context), \
56 CX_reg(context), DX_reg(context), SI_reg(context), \
57 DI_reg(context), (WORD)context->SegDs, (WORD)context->SegEs )
61 static WORD VXD_WinVersion(void)
63 WORD version = LOWORD(GetVersion16());
64 return (version >> 8) | (version << 8);
67 /***********************************************************************
68 * VXD_VMM (WPROCS.401)
70 void WINAPI VXD_VMM ( CONTEXT86 *context )
72 unsigned service = AX_reg(context);
74 TRACE("[%04x] VMM\n", (UINT16)service);
78 case 0x0000: /* version */
79 SET_AX( context, VXD_WinVersion() );
83 case 0x026d: /* Get_Debug_Flag '/m' */
84 case 0x026e: /* Get_Debug_Flag '/n' */
90 VXD_BARF( context, "VMM" );
94 /***********************************************************************
95 * VXD_PageFile (WPROCS.433)
97 void WINAPI VXD_PageFile( CONTEXT86 *context )
99 unsigned service = AX_reg(context);
101 /* taken from Ralf Brown's Interrupt List */
103 TRACE("[%04x] PageFile\n", (UINT16)service );
107 case 0x00: /* get version, is this windows version? */
108 TRACE("returning version\n");
109 SET_AX( context, VXD_WinVersion() );
110 RESET_CFLAG(context);
113 case 0x01: /* get swap file info */
114 TRACE("VxD PageFile: returning swap file info\n");
115 SET_AX( context, 0x00 ); /* paging disabled */
116 context->Ecx = 0; /* maximum size of paging file */
117 /* FIXME: do I touch DS:SI or DS:DI? */
118 RESET_CFLAG(context);
121 case 0x02: /* delete permanent swap on exit */
122 TRACE("VxD PageFile: supposed to delete swap\n");
123 RESET_CFLAG(context);
126 case 0x03: /* current temporary swap file size */
127 TRACE("VxD PageFile: what is current temp. swap size\n");
128 RESET_CFLAG(context);
131 case 0x04: /* read or write?? INTERRUP.D */
132 case 0x05: /* cancel?? INTERRUP.D */
133 case 0x06: /* test I/O valid INTERRUP.D */
135 VXD_BARF( context, "pagefile" );
140 /***********************************************************************
141 * VXD_Reboot (WPROCS.409)
143 void WINAPI VXD_Reboot ( CONTEXT86 *context )
145 unsigned service = AX_reg(context);
147 TRACE("[%04x] Reboot\n", (UINT16)service);
151 case 0x0000: /* version */
152 SET_AX( context, VXD_WinVersion() );
153 RESET_CFLAG(context);
157 VXD_BARF( context, "REBOOT" );
161 /***********************************************************************
162 * VXD_VDD (WPROCS.410)
164 void WINAPI VXD_VDD ( CONTEXT86 *context )
166 unsigned service = AX_reg(context);
168 TRACE("[%04x] VDD\n", (UINT16)service);
172 case 0x0000: /* version */
173 SET_AX( context, VXD_WinVersion() );
174 RESET_CFLAG(context);
178 VXD_BARF( context, "VDD" );
182 /***********************************************************************
183 * VXD_VMD (WPROCS.412)
185 void WINAPI VXD_VMD ( CONTEXT86 *context )
187 unsigned service = AX_reg(context);
189 TRACE("[%04x] VMD\n", (UINT16)service);
193 case 0x0000: /* version */
194 SET_AX( context, VXD_WinVersion() );
195 RESET_CFLAG(context);
199 VXD_BARF( context, "VMD" );
203 /***********************************************************************
204 * VXD_VXDLoader (WPROCS.439)
206 void WINAPI VXD_VXDLoader( CONTEXT86 *context )
208 unsigned service = AX_reg(context);
210 TRACE("[%04x] VXDLoader\n", (UINT16)service);
214 case 0x0000: /* get version */
215 TRACE("returning version\n");
216 SET_AX( context, 0x0000 );
217 SET_DX( context, VXD_WinVersion() );
218 RESET_CFLAG(context);
221 case 0x0001: /* load device */
222 FIXME("load device %04lx:%04x (%s)\n",
223 context->SegDs, DX_reg(context),
224 debugstr_a(MapSL(MAKESEGPTR(context->SegDs, DX_reg(context)))));
225 SET_AX( context, 0x0000 );
226 context->SegEs = 0x0000;
227 SET_DI( context, 0x0000 );
228 RESET_CFLAG(context);
231 case 0x0002: /* unload device */
232 FIXME("unload device (%08lx)\n", context->Ebx);
233 SET_AX( context, 0x0000 );
234 RESET_CFLAG(context);
238 VXD_BARF( context, "VXDLDR" );
239 SET_AX( context, 0x000B ); /* invalid function number */
245 /***********************************************************************
246 * VXD_Shell (WPROCS.423)
248 void WINAPI VXD_Shell( CONTEXT86 *context )
250 unsigned service = DX_reg(context);
252 TRACE("[%04x] Shell\n", (UINT16)service);
254 switch (service) /* Ralf Brown says EDX, but I use DX instead */
257 TRACE("returning version\n");
258 SET_AX( context, VXD_WinVersion() );
259 context->Ebx = 1; /* system VM Handle */
265 /* SHELL_SYSMODAL_Message
266 ebx virtual maschine handle
267 eax message box flags
268 ecx address of message
269 edi address of caption
270 return response in eax
274 ebx virtual maschine handle
275 eax message box flags
276 ecx address of message
277 edi address of caption
279 edx reference data for callback
280 return response in eax
283 VXD_BARF( context, "shell" );
286 case 0x0006: /* SHELL_Get_VM_State */
287 TRACE("VxD Shell: returning VM state\n");
288 /* Actually we don't, not yet. We have to return a structure
289 * and I am not to sure how to set it up and return it yet,
290 * so for now let's do nothing. I can (hopefully) get this
291 * by the next release
293 /* RESET_CFLAG(context); */
312 VXD_BARF( context, "SHELL" );
315 /* the new Win95 shell API */
316 case 0x0100: /* get version */
317 SET_AX( context, VXD_WinVersion() );
320 case 0x0104: /* retrieve Hook_Properties list */
321 case 0x0105: /* call Hook_Properties callbacks */
322 VXD_BARF( context, "SHELL" );
325 case 0x0106: /* install timeout callback */
326 TRACE("VxD Shell: ignoring shell callback (%ld sec.)\n", context->Ebx);
330 case 0x0107: /* get version of any VxD */
332 VXD_BARF( context, "SHELL" );
338 /***********************************************************************
339 * VXD_Comm (WPROCS.414)
341 void WINAPI VXD_Comm( CONTEXT86 *context )
343 unsigned service = AX_reg(context);
345 TRACE("[%04x] Comm\n", (UINT16)service);
349 case 0x0000: /* get version */
350 TRACE("returning version\n");
351 SET_AX( context, VXD_WinVersion() );
352 RESET_CFLAG(context);
355 case 0x0001: /* set port global */
356 case 0x0002: /* get focus */
357 case 0x0003: /* virtualise port */
359 VXD_BARF( context, "comm" );
363 /***********************************************************************
364 * VXD_Timer (WPROCS.405)
366 void WINAPI VXD_Timer( CONTEXT86 *context )
368 unsigned service = AX_reg(context);
370 TRACE("[%04x] Virtual Timer\n", (UINT16)service);
374 case 0x0000: /* version */
375 SET_AX( context, VXD_WinVersion() );
376 RESET_CFLAG(context);
379 case 0x0100: /* clock tick time, in 840nsecs */
380 context->Eax = GetTickCount();
382 context->Edx = context->Eax >> 22;
383 context->Eax <<= 10; /* not very precise */
386 case 0x0101: /* current Windows time, msecs */
387 case 0x0102: /* current VM time, msecs */
388 context->Eax = GetTickCount();
392 VXD_BARF( context, "VTD" );
396 /***********************************************************************
397 * VXD_TimerAPI (WPROCS.1490)
399 static DWORD System_Time = 0;
400 static WORD System_Time_Selector = 0;
401 static void System_Time_Tick( WORD timer ) { System_Time += 55; }
402 void WINAPI VXD_TimerAPI ( CONTEXT86 *context )
404 unsigned service = AX_reg(context);
406 TRACE("[%04x] TimerAPI\n", (UINT16)service);
410 case 0x0000: /* version */
411 SET_AX( context, VXD_WinVersion() );
412 RESET_CFLAG(context);
415 case 0x0009: /* get system time selector */
416 if ( !System_Time_Selector )
418 System_Time_Selector = SELECTOR_AllocBlock( &System_Time, sizeof(DWORD), WINE_LDT_FLAGS_DATA );
419 CreateSystemTimer( 55, System_Time_Tick );
422 SET_AX( context, System_Time_Selector );
423 RESET_CFLAG(context);
427 VXD_BARF( context, "VTDAPI" );
431 /***********************************************************************
432 * VXD_ConfigMG (WPROCS.451)
434 void WINAPI VXD_ConfigMG ( CONTEXT86 *context )
436 unsigned service = AX_reg(context);
438 TRACE("[%04x] ConfigMG\n", (UINT16)service);
442 case 0x0000: /* version */
443 SET_AX( context, VXD_WinVersion() );
444 RESET_CFLAG(context);
448 VXD_BARF( context, "CONFIGMG" );
452 /***********************************************************************
453 * VXD_Enable (WPROCS.455)
455 void WINAPI VXD_Enable ( CONTEXT86 *context )
457 unsigned service = AX_reg(context);
459 TRACE("[%04x] Enable\n", (UINT16)service);
463 case 0x0000: /* version */
464 SET_AX( context, VXD_WinVersion() );
465 RESET_CFLAG(context);
469 VXD_BARF( context, "ENABLE" );
473 /***********************************************************************
474 * VXD_APM (WPROCS.438)
476 void WINAPI VXD_APM ( CONTEXT86 *context )
478 unsigned service = AX_reg(context);
480 TRACE("[%04x] APM\n", (UINT16)service);
484 case 0x0000: /* version */
485 SET_AX( context, VXD_WinVersion() );
486 RESET_CFLAG(context);
490 VXD_BARF( context, "APM" );
494 /***********************************************************************
495 * VXD_Win32s (WPROCS.445)
497 * This is an implementation of the services of the Win32s VxD.
498 * Since official documentation of these does not seem to be available,
499 * certain arguments of some of the services remain unclear.
501 * FIXME: The following services are currently unimplemented:
502 * Exception handling (0x01, 0x1C)
503 * Debugger support (0x0C, 0x14, 0x17)
504 * Low-level memory access (0x02, 0x03, 0x0A, 0x0B)
505 * Memory Statistics (0x1B)
508 * We have a specific problem running Win32s on Linux (and probably also
509 * the other x86 unixes), since Win32s tries to allocate its main 'flat
510 * code/data segment' selectors with a base of 0xffff0000 (and limit 4GB).
511 * The rationale for this seems to be that they want one the one hand to
512 * be able to leave the Win 3.1 memory (starting with the main DOS memory)
513 * at linear address 0, but want at other hand to have offset 0 of the
514 * flat data/code segment point to an unmapped page (to catch NULL pointer
515 * accesses). Hence they allocate the flat segments with a base of 0xffff0000
516 * so that the Win 3.1 memory area at linear address zero shows up in the
517 * flat segments at offset 0x10000 (since linear addresses wrap around at
518 * 4GB). To compensate for that discrepancy between flat segment offsets
519 * and plain linear addresses, all flat pointers passed between the 32-bit
520 * and the 16-bit parts of Win32s are shifted by 0x10000 in the appropriate
521 * direction by the glue code (mainly) in W32SKRNL and WIN32S16.
523 * The problem for us is now that Linux does not allow a LDT selector with
524 * base 0xffff0000 to be created, since it would 'see' a part of the kernel
525 * address space. To address this problem we introduce *another* offset:
526 * We add 0x10000 to every linear address we get as an argument from Win32s.
527 * This means especially that the flat code/data selectors get actually
528 * allocated with base 0x0, so that flat offsets and (real) linear addresses
529 * do again agree! In fact, every call e.g. of a Win32s VxD service now
530 * has all pointer arguments (which are offsets in the flat data segement)
531 * first reduced by 0x10000 by the W32SKRNL glue code, and then again
532 * increased by 0x10000 by *our* code.
534 * Note that to keep everything consistent, this offset has to be applied by
535 * every Wine function that operates on 'linear addresses' passed to it by
536 * Win32s. Fortunately, since Win32s does not directly call any Wine 32-bit
537 * API routines, this affects only two locations: this VxD and the DPMI
538 * handler. (NOTE: Should any Win32s application pass a linear address to
539 * any routine apart from those, e.g. some other VxD handler, that code
540 * would have to take the offset into account as well!)
542 * The offset is set the first time any application calls the GetVersion()
543 * service of the Win32s VxD. (Note that the offset is never reset.)
547 void WINAPI VXD_Win32s( CONTEXT86 *context )
549 switch (AX_reg(context))
551 case 0x0000: /* Get Version */
555 * Output: EAX: LoWord: Win32s Version (1.30)
556 * HiWord: VxD Version (200)
562 * EDX: Debugging Flags
566 * 1 if VMCPD VxD not found
569 TRACE("GetVersion()\n");
571 context->Eax = VXD_WinVersion() | (200 << 16);
578 * If this is the first time we are called for this process,
579 * hack the memory image of WIN32S16 so that it doesn't try
580 * to access the GDT directly ...
582 * The first code segment of WIN32S16 (version 1.30) contains
583 * an unexported function somewhere between the exported functions
584 * SetFS and StackLinearToSegmented that tries to find a selector
585 * in the LDT that maps to the memory image of the LDT itself.
586 * If it succeeds, it stores this selector into a global variable
587 * which will be used to speed up execution by using this selector
588 * to modify the LDT directly instead of using the DPMI calls.
590 * To perform this search of the LDT, this function uses the
591 * sgdt and sldt instructions to find the linear address of
592 * the (GDT and then) LDT. While those instructions themselves
593 * execute without problem, the linear address that sgdt returns
594 * points (at least under Linux) to the kernel address space, so
595 * that any subsequent access leads to a segfault.
597 * Fortunately, WIN32S16 still contains as a fallback option the
598 * mechanism of using DPMI calls to modify LDT selectors instead
599 * of direct writes to the LDT. Thus we can circumvent the problem
600 * by simply replacing the first byte of the offending function
601 * with an 'retf' instruction. This means that the global variable
602 * supposed to contain the LDT alias selector will remain zero,
603 * and hence WIN32S16 will fall back to using DPMI calls.
605 * The heuristic we employ to _find_ that function is as follows:
606 * We search between the addresses of the exported symbols SetFS
607 * and StackLinearToSegmented for the byte sequence '0F 01 04'
608 * (this is the opcode of 'sgdt [si]'). We then search backwards
609 * from this address for the last occurrence of 'CB' (retf) that marks
610 * the end of the preceeding function. The following byte (which
611 * should now be the first byte of the function we are looking for)
612 * will be replaced by 'CB' (retf).
614 * This heuristic works for the retail as well as the debug version
615 * of Win32s version 1.30. For versions earlier than that this
616 * hack should not be necessary at all, since the whole mechanism
617 * ('PERF130') was introduced only in 1.30 to improve the overall
618 * performance of Win32s.
623 HMODULE16 hModule = GetModuleHandle16("win32s16");
624 SEGPTR func1 = (SEGPTR)GetProcAddress16(hModule, "SetFS");
625 SEGPTR func2 = (SEGPTR)GetProcAddress16(hModule, "StackLinearToSegmented");
627 if ( hModule && func1 && func2
628 && SELECTOROF(func1) == SELECTOROF(func2))
630 BYTE *start = MapSL(func1);
631 BYTE *end = MapSL(func2);
632 BYTE *p, *retv = NULL;
635 for (p = start; p < end; p++)
636 if (*p == 0xCB) found = 0, retv = p;
637 else if (*p == 0x0F) found = 1;
638 else if (*p == 0x01 && found == 1) found = 2;
639 else if (*p == 0x04 && found == 2) { found = 3; break; }
642 if (found == 3 && retv)
644 TRACE("PERF130 hack: "
645 "Replacing byte %02X at offset %04X:%04X\n",
646 *(retv+1), SELECTOROF(func1),
647 OFFSETOF(func1) + retv+1-start);
649 *(retv+1) = (BYTE)0xCB;
655 * Mark process as Win32s, so that subsequent DPMI calls
656 * will perform the W32S_APP2WINE/W32S_WINE2APP address shift.
658 W32S_offset = 0x10000;
662 case 0x0001: /* Install Exception Handling */
664 * Input: EBX: Flat address of W32SKRNL Exception Data
666 * ECX: LoWord: Flat Code Selector
667 * HiWord: Flat Data Selector
669 * EDX: Flat address of W32SKRNL Exception Handler
670 * (this is equal to W32S_BackTo32 + 0x40)
672 * ESI: SEGPTR KERNEL.HASGPHANDLER
674 * EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10)
676 * Output: EAX: 0 if OK
679 TRACE("[0001] EBX=%lx ECX=%lx EDX=%lx ESI=%lx EDI=%lx\n",
680 context->Ebx, context->Ecx, context->Edx,
681 context->Esi, context->Edi);
689 case 0x0002: /* Set Page Access Flags */
691 * Input: EBX: New access flags
692 * Bit 2: User Page if set, Supervisor Page if clear
693 * Bit 1: Read-Write if set, Read-Only if clear
695 * ECX: Size of memory area to change
697 * EDX: Flat start address of memory area
699 * Output: EAX: Size of area changed
702 TRACE("[0002] EBX=%lx ECX=%lx EDX=%lx\n",
703 context->Ebx, context->Ecx, context->Edx);
707 context->Eax = context->Ecx;
711 case 0x0003: /* Get Page Access Flags */
713 * Input: EDX: Flat address of page to query
715 * Output: EAX: Page access flags
716 * Bit 2: User Page if set, Supervisor Page if clear
717 * Bit 1: Read-Write if set, Read-Only if clear
720 TRACE("[0003] EDX=%lx\n", context->Edx);
728 case 0x0004: /* Map Module */
730 * Input: ECX: IMTE (offset in Module Table) of new module
732 * EDX: Flat address of Win32s Module Table
734 * Output: EAX: 0 if OK
737 if (!context->Edx || CX_reg(context) == 0xFFFF)
739 TRACE("MapModule: Initialization call\n");
745 * Structure of a Win32s Module Table Entry:
760 * Note: This function should set up a demand-paged memory image
761 * of the given module. Since mmap does not allow file offsets
762 * not aligned at 1024 bytes, we simply load the image fully
766 struct Win32sModule *moduleTable =
767 (struct Win32sModule *)W32S_APP2WINE(context->Edx);
768 struct Win32sModule *module = moduleTable + context->Ecx;
770 IMAGE_NT_HEADERS *nt_header = RtlImageNtHeader( (HMODULE)module->baseAddr );
771 IMAGE_SECTION_HEADER *pe_seg = (IMAGE_SECTION_HEADER*)((char *)&nt_header->OptionalHeader +
772 nt_header->FileHeader.SizeOfOptionalHeader);
775 HFILE image = _lopen(module->pathName, OF_READ);
776 BOOL error = (image == HFILE_ERROR);
779 TRACE("MapModule: Loading %s\n", module->pathName);
782 !error && i < nt_header->FileHeader.NumberOfSections;
784 if(!(pe_seg->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA))
786 DWORD off = pe_seg->PointerToRawData;
787 DWORD len = pe_seg->SizeOfRawData;
788 LPBYTE addr = module->baseAddr + pe_seg->VirtualAddress;
791 "Section %d at %08lx from %08lx len %08lx\n",
792 i, (DWORD)addr, off, len);
794 if ( _llseek(image, off, SEEK_SET) != off
795 || _lread(image, addr, len) != len)
802 ERR("MapModule: Unable to load %s\n", module->pathName);
804 else if (module->relocDelta != 0)
806 IMAGE_DATA_DIRECTORY *dir = nt_header->OptionalHeader.DataDirectory
807 + IMAGE_DIRECTORY_ENTRY_BASERELOC;
808 IMAGE_BASE_RELOCATION *r = (IMAGE_BASE_RELOCATION *)
809 (dir->Size? module->baseAddr + dir->VirtualAddress : 0);
811 TRACE("MapModule: Reloc delta %08lx\n", module->relocDelta);
813 while (r && r->VirtualAddress)
815 LPBYTE page = module->baseAddr + r->VirtualAddress;
816 WORD *TypeOffset = (WORD *)(r + 1);
817 int count = (r->SizeOfBlock - sizeof(*r)) / sizeof(*TypeOffset);
819 TRACE("MapModule: %d relocations for page %08lx\n",
822 for(i = 0; i < count; i++)
824 int offset = TypeOffset[i] & 0xFFF;
825 int type = TypeOffset[i] >> 12;
828 case IMAGE_REL_BASED_ABSOLUTE:
830 case IMAGE_REL_BASED_HIGH:
831 *(WORD *)(page+offset) += HIWORD(module->relocDelta);
833 case IMAGE_REL_BASED_LOW:
834 *(WORD *)(page+offset) += LOWORD(module->relocDelta);
836 case IMAGE_REL_BASED_HIGHLOW:
837 *(DWORD*)(page+offset) += module->relocDelta;
840 WARN("MapModule: Unsupported fixup type\n");
845 r = (IMAGE_BASE_RELOCATION *)((LPBYTE)r + r->SizeOfBlock);
850 RESET_CFLAG(context);
855 case 0x0005: /* UnMap Module */
857 * Input: EDX: Flat address of module image
859 * Output: EAX: 1 if OK
862 TRACE("UnMapModule: %lx\n", (DWORD)W32S_APP2WINE(context->Edx));
864 /* As we didn't map anything, there's nothing to unmap ... */
870 case 0x0006: /* VirtualAlloc */
872 * Input: ECX: Current Process
874 * EDX: Flat address of arguments on stack
876 * DWORD *retv [out] Flat base address of allocated region
877 * LPVOID base [in] Flat address of region to reserve/commit
878 * DWORD size [in] Size of region
879 * DWORD type [in] Type of allocation
880 * DWORD prot [in] Type of access protection
882 * Output: EAX: NtStatus
885 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
886 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
887 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
888 DWORD size = stack[2];
889 DWORD type = stack[3];
890 DWORD prot = stack[4];
893 TRACE("VirtualAlloc(%lx, %lx, %lx, %lx, %lx)\n",
894 (DWORD)retv, (DWORD)base, size, type, prot);
896 if (type & 0x80000000)
898 WARN("VirtualAlloc: strange type %lx\n", type);
902 if (!base && (type & MEM_COMMIT) && prot == PAGE_READONLY)
904 WARN("VirtualAlloc: NLS hack, allowing write access!\n");
905 prot = PAGE_READWRITE;
908 result = (DWORD)VirtualAlloc(base, size, type, prot);
910 if (W32S_WINE2APP(result))
911 *retv = W32S_WINE2APP(result),
912 context->Eax = STATUS_SUCCESS;
915 context->Eax = STATUS_NO_MEMORY; /* FIXME */
920 case 0x0007: /* VirtualFree */
922 * Input: ECX: Current Process
924 * EDX: Flat address of arguments on stack
926 * DWORD *retv [out] TRUE if success, FALSE if failure
927 * LPVOID base [in] Flat address of region
928 * DWORD size [in] Size of region
929 * DWORD type [in] Type of operation
931 * Output: EAX: NtStatus
934 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
935 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
936 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
937 DWORD size = stack[2];
938 DWORD type = stack[3];
941 TRACE("VirtualFree(%lx, %lx, %lx, %lx)\n",
942 (DWORD)retv, (DWORD)base, size, type);
944 result = VirtualFree(base, size, type);
948 context->Eax = STATUS_SUCCESS;
951 context->Eax = STATUS_NO_MEMORY; /* FIXME */
956 case 0x0008: /* VirtualProtect */
958 * Input: ECX: Current Process
960 * EDX: Flat address of arguments on stack
962 * DWORD *retv [out] TRUE if success, FALSE if failure
963 * LPVOID base [in] Flat address of region
964 * DWORD size [in] Size of region
965 * DWORD new_prot [in] Desired access protection
966 * DWORD *old_prot [out] Previous access protection
968 * Output: EAX: NtStatus
971 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
972 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
973 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
974 DWORD size = stack[2];
975 DWORD new_prot = stack[3];
976 DWORD *old_prot = (DWORD *)W32S_APP2WINE(stack[4]);
979 TRACE("VirtualProtect(%lx, %lx, %lx, %lx, %lx)\n",
980 (DWORD)retv, (DWORD)base, size, new_prot, (DWORD)old_prot);
982 result = VirtualProtect(base, size, new_prot, old_prot);
986 context->Eax = STATUS_SUCCESS;
989 context->Eax = STATUS_NO_MEMORY; /* FIXME */
994 case 0x0009: /* VirtualQuery */
996 * Input: ECX: Current Process
998 * EDX: Flat address of arguments on stack
1000 * DWORD *retv [out] Nr. bytes returned
1001 * LPVOID base [in] Flat address of region
1002 * LPMEMORY_BASIC_INFORMATION info [out] Info buffer
1003 * DWORD len [in] Size of buffer
1005 * Output: EAX: NtStatus
1008 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1009 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1010 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1011 PMEMORY_BASIC_INFORMATION info =
1012 (PMEMORY_BASIC_INFORMATION)W32S_APP2WINE(stack[2]);
1013 DWORD len = stack[3];
1016 TRACE("VirtualQuery(%lx, %lx, %lx, %lx)\n",
1017 (DWORD)retv, (DWORD)base, (DWORD)info, len);
1019 result = VirtualQuery(base, info, len);
1022 context->Eax = STATUS_SUCCESS;
1027 case 0x000A: /* SetVirtMemProcess */
1029 * Input: ECX: Process Handle
1031 * EDX: Flat address of region
1033 * Output: EAX: NtStatus
1036 TRACE("[000a] ECX=%lx EDX=%lx\n",
1037 context->Ecx, context->Edx);
1041 context->Eax = STATUS_SUCCESS;
1045 case 0x000B: /* ??? some kind of cleanup */
1047 * Input: ECX: Process Handle
1049 * Output: EAX: NtStatus
1052 TRACE("[000b] ECX=%lx\n", context->Ecx);
1056 context->Eax = STATUS_SUCCESS;
1060 case 0x000C: /* Set Debug Flags */
1062 * Input: EDX: Debug Flags
1064 * Output: EDX: Previous Debug Flags
1067 FIXME("[000c] EDX=%lx\n", context->Edx);
1075 case 0x000D: /* NtCreateSection */
1077 * Input: EDX: Flat address of arguments on stack
1079 * HANDLE32 *retv [out] Handle of Section created
1080 * DWORD flags1 [in] (?? unknown ??)
1081 * DWORD atom [in] Name of Section to create
1082 * LARGE_INTEGER *size [in] Size of Section
1083 * DWORD protect [in] Access protection
1084 * DWORD flags2 [in] (?? unknown ??)
1085 * HFILE32 hFile [in] Handle of file to map
1086 * DWORD psp [in] (Win32s: PSP that hFile belongs to)
1088 * Output: EAX: NtStatus
1091 DWORD *stack = (DWORD *) W32S_APP2WINE(context->Edx);
1092 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]);
1093 DWORD flags1 = stack[1];
1094 DWORD atom = stack[2];
1095 LARGE_INTEGER *size = (LARGE_INTEGER *)W32S_APP2WINE(stack[3]);
1096 DWORD protect = stack[4];
1097 DWORD flags2 = stack[5];
1098 HANDLE hFile = DosFileHandleToWin32Handle(stack[6]);
1099 DWORD psp = stack[7];
1101 HANDLE result = INVALID_HANDLE_VALUE;
1104 TRACE("NtCreateSection(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1105 (DWORD)retv, flags1, atom, (DWORD)size, protect, flags2,
1108 if (!atom || GlobalGetAtomNameA(atom, name, sizeof(name)))
1110 TRACE("NtCreateSection: name=%s\n", atom? name : NULL);
1112 result = CreateFileMappingA(hFile, NULL, protect,
1113 size? size->s.HighPart : 0,
1114 size? size->s.LowPart : 0,
1118 if (result == INVALID_HANDLE_VALUE)
1119 WARN("NtCreateSection: failed!\n");
1121 TRACE("NtCreateSection: returned %lx\n", (DWORD)result);
1123 if (result != INVALID_HANDLE_VALUE)
1125 context->Eax = STATUS_SUCCESS;
1128 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1133 case 0x000E: /* NtOpenSection */
1135 * Input: EDX: Flat address of arguments on stack
1137 * HANDLE32 *retv [out] Handle of Section opened
1138 * DWORD protect [in] Access protection
1139 * DWORD atom [in] Name of Section to create
1141 * Output: EAX: NtStatus
1144 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1145 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]);
1146 DWORD protect = stack[1];
1147 DWORD atom = stack[2];
1149 HANDLE result = INVALID_HANDLE_VALUE;
1152 TRACE("NtOpenSection(%lx, %lx, %lx)\n",
1153 (DWORD)retv, protect, atom);
1155 if (atom && GlobalGetAtomNameA(atom, name, sizeof(name)))
1157 TRACE("NtOpenSection: name=%s\n", name);
1159 result = OpenFileMappingA(protect, FALSE, name);
1162 if (result == INVALID_HANDLE_VALUE)
1163 WARN("NtOpenSection: failed!\n");
1165 TRACE("NtOpenSection: returned %lx\n", (DWORD)result);
1167 if (result != INVALID_HANDLE_VALUE)
1169 context->Eax = STATUS_SUCCESS;
1172 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1177 case 0x000F: /* NtCloseSection */
1179 * Input: EDX: Flat address of arguments on stack
1181 * HANDLE32 handle [in] Handle of Section to close
1182 * DWORD *id [out] Unique ID (?? unclear ??)
1184 * Output: EAX: NtStatus
1187 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1188 HANDLE handle = (HANDLE)stack[0];
1189 DWORD *id = (DWORD *)W32S_APP2WINE(stack[1]);
1191 TRACE("NtCloseSection(%lx, %lx)\n", (DWORD)handle, (DWORD)id);
1193 CloseHandle(handle);
1194 if (id) *id = 0; /* FIXME */
1196 context->Eax = STATUS_SUCCESS;
1201 case 0x0010: /* NtDupSection */
1203 * Input: EDX: Flat address of arguments on stack
1205 * HANDLE32 handle [in] Handle of Section to duplicate
1207 * Output: EAX: NtStatus
1210 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1211 HANDLE handle = (HANDLE)stack[0];
1214 TRACE("NtDupSection(%lx)\n", (DWORD)handle);
1216 DuplicateHandle( GetCurrentProcess(), handle,
1217 GetCurrentProcess(), &new_handle,
1218 0, FALSE, DUPLICATE_SAME_ACCESS );
1219 context->Eax = STATUS_SUCCESS;
1224 case 0x0011: /* NtMapViewOfSection */
1226 * Input: EDX: Flat address of arguments on stack
1228 * HANDLE32 SectionHandle [in] Section to be mapped
1229 * DWORD ProcessHandle [in] Process to be mapped into
1230 * DWORD * BaseAddress [in/out] Address to be mapped at
1231 * DWORD ZeroBits [in] (?? unclear ??)
1232 * DWORD CommitSize [in] (?? unclear ??)
1233 * LARGE_INTEGER *SectionOffset [in] Offset within section
1234 * DWORD * ViewSize [in] Size of view
1235 * DWORD InheritDisposition [in] (?? unclear ??)
1236 * DWORD AllocationType [in] (?? unclear ??)
1237 * DWORD Protect [in] Access protection
1239 * Output: EAX: NtStatus
1242 DWORD * stack = (DWORD *)W32S_APP2WINE(context->Edx);
1243 HANDLE SectionHandle = (HANDLE)stack[0];
1244 DWORD ProcessHandle = stack[1]; /* ignored */
1245 DWORD * BaseAddress = (DWORD *)W32S_APP2WINE(stack[2]);
1246 DWORD ZeroBits = stack[3];
1247 DWORD CommitSize = stack[4];
1248 LARGE_INTEGER *SectionOffset = (LARGE_INTEGER *)W32S_APP2WINE(stack[5]);
1249 DWORD * ViewSize = (DWORD *)W32S_APP2WINE(stack[6]);
1250 DWORD InheritDisposition = stack[7];
1251 DWORD AllocationType = stack[8];
1252 DWORD Protect = stack[9];
1254 LPBYTE address = (LPBYTE)(BaseAddress?
1255 W32S_APP2WINE(*BaseAddress) : 0);
1256 DWORD access = 0, result;
1258 switch (Protect & ~(PAGE_GUARD|PAGE_NOCACHE))
1260 case PAGE_READONLY: access = FILE_MAP_READ; break;
1261 case PAGE_READWRITE: access = FILE_MAP_WRITE; break;
1262 case PAGE_WRITECOPY: access = FILE_MAP_COPY; break;
1264 case PAGE_EXECUTE_READ: access = FILE_MAP_READ; break;
1265 case PAGE_EXECUTE_READWRITE: access = FILE_MAP_WRITE; break;
1266 case PAGE_EXECUTE_WRITECOPY: access = FILE_MAP_COPY; break;
1269 TRACE("NtMapViewOfSection"
1270 "(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1271 (DWORD)SectionHandle, ProcessHandle, (DWORD)BaseAddress,
1272 ZeroBits, CommitSize, (DWORD)SectionOffset, (DWORD)ViewSize,
1273 InheritDisposition, AllocationType, Protect);
1274 TRACE("NtMapViewOfSection: "
1275 "base=%lx, offset=%lx, size=%lx, access=%lx\n",
1276 (DWORD)address, SectionOffset? SectionOffset->s.LowPart : 0,
1277 ViewSize? *ViewSize : 0, access);
1279 result = (DWORD)MapViewOfFileEx(SectionHandle, access,
1280 SectionOffset? SectionOffset->s.HighPart : 0,
1281 SectionOffset? SectionOffset->s.LowPart : 0,
1282 ViewSize? *ViewSize : 0, address);
1284 TRACE("NtMapViewOfSection: result=%lx\n", result);
1286 if (W32S_WINE2APP(result))
1288 if (BaseAddress) *BaseAddress = W32S_WINE2APP(result);
1289 context->Eax = STATUS_SUCCESS;
1292 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1297 case 0x0012: /* NtUnmapViewOfSection */
1299 * Input: EDX: Flat address of arguments on stack
1301 * DWORD ProcessHandle [in] Process (defining address space)
1302 * LPBYTE BaseAddress [in] Base address of view to be unmapped
1304 * Output: EAX: NtStatus
1307 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1308 DWORD ProcessHandle = stack[0]; /* ignored */
1309 LPBYTE BaseAddress = (LPBYTE)W32S_APP2WINE(stack[1]);
1311 TRACE("NtUnmapViewOfSection(%lx, %lx)\n",
1312 ProcessHandle, (DWORD)BaseAddress);
1314 UnmapViewOfFile(BaseAddress);
1316 context->Eax = STATUS_SUCCESS;
1321 case 0x0013: /* NtFlushVirtualMemory */
1323 * Input: EDX: Flat address of arguments on stack
1325 * DWORD ProcessHandle [in] Process (defining address space)
1326 * LPBYTE *BaseAddress [in?] Base address of range to be flushed
1327 * DWORD *ViewSize [in?] Number of bytes to be flushed
1328 * DWORD *unknown [???] (?? unknown ??)
1330 * Output: EAX: NtStatus
1333 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1334 DWORD ProcessHandle = stack[0]; /* ignored */
1335 DWORD *BaseAddress = (DWORD *)W32S_APP2WINE(stack[1]);
1336 DWORD *ViewSize = (DWORD *)W32S_APP2WINE(stack[2]);
1337 DWORD *unknown = (DWORD *)W32S_APP2WINE(stack[3]);
1339 LPBYTE address = (LPBYTE)(BaseAddress? W32S_APP2WINE(*BaseAddress) : 0);
1340 DWORD size = ViewSize? *ViewSize : 0;
1342 TRACE("NtFlushVirtualMemory(%lx, %lx, %lx, %lx)\n",
1343 ProcessHandle, (DWORD)BaseAddress, (DWORD)ViewSize,
1345 TRACE("NtFlushVirtualMemory: base=%lx, size=%lx\n",
1346 (DWORD)address, size);
1348 FlushViewOfFile(address, size);
1350 context->Eax = STATUS_SUCCESS;
1355 case 0x0014: /* Get/Set Debug Registers */
1357 * Input: ECX: 0 if Get, 1 if Set
1359 * EDX: Get: Flat address of buffer to receive values of
1360 * debug registers DR0 .. DR7
1361 * Set: Flat address of buffer containing values of
1362 * debug registers DR0 .. DR7 to be set
1366 FIXME("[0014] ECX=%lx EDX=%lx\n",
1367 context->Ecx, context->Edx);
1373 case 0x0015: /* Set Coprocessor Emulation Flag */
1375 * Input: EDX: 0 to deactivate, 1 to activate coprocessor emulation
1380 TRACE("[0015] EDX=%lx\n", context->Edx);
1382 /* We don't care, as we always have a coprocessor anyway */
1386 case 0x0016: /* Init Win32S VxD PSP */
1388 * If called to query required PSP size:
1391 * Output: EDX: Required size of Win32s VxD PSP
1393 * If called to initialize allocated PSP:
1395 * Input: EBX: LoWord: Selector of Win32s VxD PSP
1396 * HiWord: Paragraph of Win32s VxD PSP (DOSMEM)
1400 if (context->Ebx == 0)
1401 context->Edx = 0x80;
1404 PDB16 *psp = MapSL( MAKESEGPTR( BX_reg(context), 0 ));
1406 psp->fileHandlesPtr = MAKELONG(HIWORD(context->Ebx), 0x5c);
1407 memset((LPBYTE)psp + 0x5c, '\xFF', 32);
1412 case 0x0017: /* Set Break Point */
1414 * Input: EBX: Offset of Break Point
1415 * CX: Selector of Break Point
1420 FIXME("[0017] EBX=%lx CX=%x\n",
1421 context->Ebx, CX_reg(context));
1427 case 0x0018: /* VirtualLock */
1429 * Input: ECX: Current Process
1431 * EDX: Flat address of arguments on stack
1433 * DWORD *retv [out] TRUE if success, FALSE if failure
1434 * LPVOID base [in] Flat address of range to lock
1435 * DWORD size [in] Size of range
1437 * Output: EAX: NtStatus
1440 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1441 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1442 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1443 DWORD size = stack[2];
1446 TRACE("VirtualLock(%lx, %lx, %lx)\n",
1447 (DWORD)retv, (DWORD)base, size);
1449 result = VirtualLock(base, size);
1453 context->Eax = STATUS_SUCCESS;
1456 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1461 case 0x0019: /* VirtualUnlock */
1463 * Input: ECX: Current Process
1465 * EDX: Flat address of arguments on stack
1467 * DWORD *retv [out] TRUE if success, FALSE if failure
1468 * LPVOID base [in] Flat address of range to unlock
1469 * DWORD size [in] Size of range
1471 * Output: EAX: NtStatus
1474 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1475 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1476 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1477 DWORD size = stack[2];
1480 TRACE("VirtualUnlock(%lx, %lx, %lx)\n",
1481 (DWORD)retv, (DWORD)base, size);
1483 result = VirtualUnlock(base, size);
1487 context->Eax = STATUS_SUCCESS;
1490 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1495 case 0x001A: /* KGetSystemInfo */
1499 * Output: ECX: Start of sparse memory arena
1500 * EDX: End of sparse memory arena
1503 TRACE("KGetSystemInfo()\n");
1506 * Note: Win32s reserves 0GB - 2GB for Win 3.1 and uses 2GB - 4GB as
1507 * sparse memory arena. We do it the other way around, since
1508 * we have to reserve 3GB - 4GB for Linux, and thus use
1509 * 0GB - 3GB as sparse memory arena.
1511 * FIXME: What about other OSes ?
1514 context->Ecx = W32S_WINE2APP(0x00000000);
1515 context->Edx = W32S_WINE2APP(0xbfffffff);
1519 case 0x001B: /* KGlobalMemStat */
1521 * Input: ESI: Flat address of buffer to receive memory info
1526 struct Win32sMemoryInfo
1528 DWORD DIPhys_Count; /* Total physical pages */
1529 DWORD DIFree_Count; /* Free physical pages */
1530 DWORD DILin_Total_Count; /* Total virtual pages (private arena) */
1531 DWORD DILin_Total_Free; /* Free virtual pages (private arena) */
1533 DWORD SparseTotal; /* Total size of sparse arena (bytes ?) */
1534 DWORD SparseFree; /* Free size of sparse arena (bytes ?) */
1537 struct Win32sMemoryInfo *info =
1538 (struct Win32sMemoryInfo *)W32S_APP2WINE(context->Esi);
1540 FIXME("KGlobalMemStat(%lx)\n", (DWORD)info);
1547 case 0x001C: /* Enable/Disable Exceptions */
1549 * Input: ECX: 0 to disable, 1 to enable exception handling
1554 TRACE("[001c] ECX=%lx\n", context->Ecx);
1560 case 0x001D: /* VirtualAlloc called from 16-bit code */
1562 * Input: EDX: Segmented address of arguments on stack
1564 * LPVOID base [in] Flat address of region to reserve/commit
1565 * DWORD size [in] Size of region
1566 * DWORD type [in] Type of allocation
1567 * DWORD prot [in] Type of access protection
1569 * Output: EAX: NtStatus
1570 * EDX: Flat base address of allocated region
1573 DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) ));
1574 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]);
1575 DWORD size = stack[1];
1576 DWORD type = stack[2];
1577 DWORD prot = stack[3];
1580 TRACE("VirtualAlloc16(%lx, %lx, %lx, %lx)\n",
1581 (DWORD)base, size, type, prot);
1583 if (type & 0x80000000)
1585 WARN("VirtualAlloc16: strange type %lx\n", type);
1589 result = (DWORD)VirtualAlloc(base, size, type, prot);
1591 if (W32S_WINE2APP(result))
1592 context->Edx = W32S_WINE2APP(result),
1593 context->Eax = STATUS_SUCCESS;
1596 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1597 TRACE("VirtualAlloc16: returning base %lx\n", context->Edx);
1602 case 0x001E: /* VirtualFree called from 16-bit code */
1604 * Input: EDX: Segmented address of arguments on stack
1606 * LPVOID base [in] Flat address of region
1607 * DWORD size [in] Size of region
1608 * DWORD type [in] Type of operation
1610 * Output: EAX: NtStatus
1611 * EDX: TRUE if success, FALSE if failure
1614 DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) ));
1615 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]);
1616 DWORD size = stack[1];
1617 DWORD type = stack[2];
1620 TRACE("VirtualFree16(%lx, %lx, %lx)\n",
1621 (DWORD)base, size, type);
1623 result = VirtualFree(base, size, type);
1626 context->Edx = TRUE,
1627 context->Eax = STATUS_SUCCESS;
1629 context->Edx = FALSE,
1630 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1635 case 0x001F: /* FWorkingSetSize */
1637 * Input: EDX: 0 if Get, 1 if Set
1639 * ECX: Get: Buffer to receive Working Set Size
1640 * Set: Buffer containing Working Set Size
1645 DWORD *ptr = (DWORD *)W32S_APP2WINE(context->Ecx);
1646 BOOL set = context->Edx;
1648 TRACE("FWorkingSetSize(%lx, %lx)\n", (DWORD)ptr, (DWORD)set);
1651 /* We do it differently ... */;
1655 context->Eax = STATUS_SUCCESS;
1661 VXD_BARF( context, "W32S" );