Add DotProduct3 support if supported by opengl.
[wine/dcerpc.git] / msdos / vxd.c
bloba1581fa79c3e26ee99ff59c73f5fe973f0d4116d
1 /*
2 * VxD emulation
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include <fcntl.h>
25 #include <memory.h>
26 #include <stdio.h>
27 #include <sys/types.h>
28 #ifdef HAVE_UNISTD_H
29 # include <unistd.h>
30 #endif
32 #define NONAMELESSUNION
33 #define NONAMELESSSTRUCT
34 #include "winbase.h"
35 #include "windef.h"
36 #include "winternl.h"
37 #include "wingdi.h"
38 #include "winuser.h"
39 #include "wine/winbase16.h"
40 #include "wine/winuser16.h"
41 #include "msdos.h"
42 #include "miscemu.h"
43 #include "selectors.h"
44 #include "task.h"
45 #include "file.h"
46 #include "wine/debug.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(vxd);
50 #define W32S_APP2WINE(addr) ((addr)? (DWORD)(addr) + W32S_offset : 0)
51 #define W32S_WINE2APP(addr) ((addr)? (DWORD)(addr) - W32S_offset : 0)
53 #define VXD_BARF(context,name) \
54 DPRINTF( "vxd %s: unknown/not implemented parameters:\n" \
55 "vxd %s: AX %04x, BX %04x, CX %04x, DX %04x, " \
56 "SI %04x, DI %04x, DS %04x, ES %04x\n", \
57 (name), (name), AX_reg(context), BX_reg(context), \
58 CX_reg(context), DX_reg(context), SI_reg(context), \
59 DI_reg(context), (WORD)context->SegDs, (WORD)context->SegEs )
61 UINT W32S_offset = 0;
63 static WORD VXD_WinVersion(void)
65 WORD version = LOWORD(GetVersion16());
66 return (version >> 8) | (version << 8);
69 /***********************************************************************
70 * VXD_VMM (WPROCS.401)
72 void WINAPI VXD_VMM ( CONTEXT86 *context )
74 unsigned service = AX_reg(context);
76 TRACE("[%04x] VMM\n", (UINT16)service);
78 switch(service)
80 case 0x0000: /* version */
81 SET_AX( context, VXD_WinVersion() );
82 RESET_CFLAG(context);
83 break;
85 case 0x026d: /* Get_Debug_Flag '/m' */
86 case 0x026e: /* Get_Debug_Flag '/n' */
87 SET_AL( context, 0 );
88 RESET_CFLAG(context);
89 break;
91 default:
92 VXD_BARF( context, "VMM" );
96 /***********************************************************************
97 * VXD_PageFile (WPROCS.433)
99 void WINAPI VXD_PageFile( CONTEXT86 *context )
101 unsigned service = AX_reg(context);
103 /* taken from Ralf Brown's Interrupt List */
105 TRACE("[%04x] PageFile\n", (UINT16)service );
107 switch(service)
109 case 0x00: /* get version, is this windows version? */
110 TRACE("returning version\n");
111 SET_AX( context, VXD_WinVersion() );
112 RESET_CFLAG(context);
113 break;
115 case 0x01: /* get swap file info */
116 TRACE("VxD PageFile: returning swap file info\n");
117 SET_AX( context, 0x00 ); /* paging disabled */
118 context->Ecx = 0; /* maximum size of paging file */
119 /* FIXME: do I touch DS:SI or DS:DI? */
120 RESET_CFLAG(context);
121 break;
123 case 0x02: /* delete permanent swap on exit */
124 TRACE("VxD PageFile: supposed to delete swap\n");
125 RESET_CFLAG(context);
126 break;
128 case 0x03: /* current temporary swap file size */
129 TRACE("VxD PageFile: what is current temp. swap size\n");
130 RESET_CFLAG(context);
131 break;
133 case 0x04: /* read or write?? INTERRUP.D */
134 case 0x05: /* cancel?? INTERRUP.D */
135 case 0x06: /* test I/O valid INTERRUP.D */
136 default:
137 VXD_BARF( context, "pagefile" );
138 break;
142 /***********************************************************************
143 * VXD_Reboot (WPROCS.409)
145 void WINAPI VXD_Reboot ( CONTEXT86 *context )
147 unsigned service = AX_reg(context);
149 TRACE("[%04x] Reboot\n", (UINT16)service);
151 switch(service)
153 case 0x0000: /* version */
154 SET_AX( context, VXD_WinVersion() );
155 RESET_CFLAG(context);
156 break;
158 default:
159 VXD_BARF( context, "REBOOT" );
163 /***********************************************************************
164 * VXD_VDD (WPROCS.410)
166 void WINAPI VXD_VDD ( CONTEXT86 *context )
168 unsigned service = AX_reg(context);
170 TRACE("[%04x] VDD\n", (UINT16)service);
172 switch(service)
174 case 0x0000: /* version */
175 SET_AX( context, VXD_WinVersion() );
176 RESET_CFLAG(context);
177 break;
179 default:
180 VXD_BARF( context, "VDD" );
184 /***********************************************************************
185 * VXD_VMD (WPROCS.412)
187 void WINAPI VXD_VMD ( CONTEXT86 *context )
189 unsigned service = AX_reg(context);
191 TRACE("[%04x] VMD\n", (UINT16)service);
193 switch(service)
195 case 0x0000: /* version */
196 SET_AX( context, VXD_WinVersion() );
197 RESET_CFLAG(context);
198 break;
200 default:
201 VXD_BARF( context, "VMD" );
205 /***********************************************************************
206 * VXD_VXDLoader (WPROCS.439)
208 void WINAPI VXD_VXDLoader( CONTEXT86 *context )
210 unsigned service = AX_reg(context);
212 TRACE("[%04x] VXDLoader\n", (UINT16)service);
214 switch (service)
216 case 0x0000: /* get version */
217 TRACE("returning version\n");
218 SET_AX( context, 0x0000 );
219 SET_DX( context, VXD_WinVersion() );
220 RESET_CFLAG(context);
221 break;
223 case 0x0001: /* load device */
224 FIXME("load device %04lx:%04x (%s)\n",
225 context->SegDs, DX_reg(context),
226 debugstr_a(MapSL(MAKESEGPTR(context->SegDs, DX_reg(context)))));
227 SET_AX( context, 0x0000 );
228 context->SegEs = 0x0000;
229 SET_DI( context, 0x0000 );
230 RESET_CFLAG(context);
231 break;
233 case 0x0002: /* unload device */
234 FIXME("unload device (%08lx)\n", context->Ebx);
235 SET_AX( context, 0x0000 );
236 RESET_CFLAG(context);
237 break;
239 default:
240 VXD_BARF( context, "VXDLDR" );
241 SET_AX( context, 0x000B ); /* invalid function number */
242 SET_CFLAG(context);
243 break;
247 /***********************************************************************
248 * VXD_Shell (WPROCS.423)
250 void WINAPI VXD_Shell( CONTEXT86 *context )
252 unsigned service = DX_reg(context);
254 TRACE("[%04x] Shell\n", (UINT16)service);
256 switch (service) /* Ralf Brown says EDX, but I use DX instead */
258 case 0x0000:
259 TRACE("returning version\n");
260 SET_AX( context, VXD_WinVersion() );
261 context->Ebx = 1; /* system VM Handle */
262 break;
264 case 0x0001:
265 case 0x0002:
266 case 0x0003:
267 /* SHELL_SYSMODAL_Message
268 ebx virtual maschine handle
269 eax message box flags
270 ecx address of message
271 edi address of caption
272 return response in eax
274 case 0x0004:
275 /* SHELL_Message
276 ebx virtual maschine handle
277 eax message box flags
278 ecx address of message
279 edi address of caption
280 esi address callback
281 edx reference data for callback
282 return response in eax
284 case 0x0005:
285 VXD_BARF( context, "shell" );
286 break;
288 case 0x0006: /* SHELL_Get_VM_State */
289 TRACE("VxD Shell: returning VM state\n");
290 /* Actually we don't, not yet. We have to return a structure
291 * and I am not to sure how to set it up and return it yet,
292 * so for now let's do nothing. I can (hopefully) get this
293 * by the next release
295 /* RESET_CFLAG(context); */
296 break;
298 case 0x0007:
299 case 0x0008:
300 case 0x0009:
301 case 0x000A:
302 case 0x000B:
303 case 0x000C:
304 case 0x000D:
305 case 0x000E:
306 case 0x000F:
307 case 0x0010:
308 case 0x0011:
309 case 0x0012:
310 case 0x0013:
311 case 0x0014:
312 case 0x0015:
313 case 0x0016:
314 VXD_BARF( context, "SHELL" );
315 break;
317 /* the new Win95 shell API */
318 case 0x0100: /* get version */
319 SET_AX( context, VXD_WinVersion() );
320 break;
322 case 0x0104: /* retrieve Hook_Properties list */
323 case 0x0105: /* call Hook_Properties callbacks */
324 VXD_BARF( context, "SHELL" );
325 break;
327 case 0x0106: /* install timeout callback */
328 TRACE("VxD Shell: ignoring shell callback (%ld sec.)\n", context->Ebx);
329 SET_CFLAG(context);
330 break;
332 case 0x0107: /* get version of any VxD */
333 default:
334 VXD_BARF( context, "SHELL" );
335 break;
340 /***********************************************************************
341 * VXD_Comm (WPROCS.414)
343 void WINAPI VXD_Comm( CONTEXT86 *context )
345 unsigned service = AX_reg(context);
347 TRACE("[%04x] Comm\n", (UINT16)service);
349 switch (service)
351 case 0x0000: /* get version */
352 TRACE("returning version\n");
353 SET_AX( context, VXD_WinVersion() );
354 RESET_CFLAG(context);
355 break;
357 case 0x0001: /* set port global */
358 case 0x0002: /* get focus */
359 case 0x0003: /* virtualise port */
360 default:
361 VXD_BARF( context, "comm" );
365 /***********************************************************************
366 * VXD_Timer (WPROCS.405)
368 void WINAPI VXD_Timer( CONTEXT86 *context )
370 unsigned service = AX_reg(context);
372 TRACE("[%04x] Virtual Timer\n", (UINT16)service);
374 switch(service)
376 case 0x0000: /* version */
377 SET_AX( context, VXD_WinVersion() );
378 RESET_CFLAG(context);
379 break;
381 case 0x0100: /* clock tick time, in 840nsecs */
382 context->Eax = GetTickCount();
384 context->Edx = context->Eax >> 22;
385 context->Eax <<= 10; /* not very precise */
386 break;
388 case 0x0101: /* current Windows time, msecs */
389 case 0x0102: /* current VM time, msecs */
390 context->Eax = GetTickCount();
391 break;
393 default:
394 VXD_BARF( context, "VTD" );
398 /***********************************************************************
399 * VXD_TimerAPI (WPROCS.1490)
401 static DWORD System_Time = 0;
402 static WORD System_Time_Selector = 0;
403 static void System_Time_Tick( WORD timer ) { System_Time += 55; }
404 void WINAPI VXD_TimerAPI ( CONTEXT86 *context )
406 unsigned service = AX_reg(context);
408 TRACE("[%04x] TimerAPI\n", (UINT16)service);
410 switch(service)
412 case 0x0000: /* version */
413 SET_AX( context, VXD_WinVersion() );
414 RESET_CFLAG(context);
415 break;
417 case 0x0009: /* get system time selector */
418 if ( !System_Time_Selector )
420 System_Time_Selector = SELECTOR_AllocBlock( &System_Time, sizeof(DWORD), WINE_LDT_FLAGS_DATA );
421 CreateSystemTimer( 55, System_Time_Tick );
424 SET_AX( context, System_Time_Selector );
425 RESET_CFLAG(context);
426 break;
428 default:
429 VXD_BARF( context, "VTDAPI" );
433 /***********************************************************************
434 * VXD_ConfigMG (WPROCS.451)
436 void WINAPI VXD_ConfigMG ( CONTEXT86 *context )
438 unsigned service = AX_reg(context);
440 TRACE("[%04x] ConfigMG\n", (UINT16)service);
442 switch(service)
444 case 0x0000: /* version */
445 SET_AX( context, VXD_WinVersion() );
446 RESET_CFLAG(context);
447 break;
449 default:
450 VXD_BARF( context, "CONFIGMG" );
454 /***********************************************************************
455 * VXD_Enable (WPROCS.455)
457 void WINAPI VXD_Enable ( CONTEXT86 *context )
459 unsigned service = AX_reg(context);
461 TRACE("[%04x] Enable\n", (UINT16)service);
463 switch(service)
465 case 0x0000: /* version */
466 SET_AX( context, VXD_WinVersion() );
467 RESET_CFLAG(context);
468 break;
470 default:
471 VXD_BARF( context, "ENABLE" );
475 /***********************************************************************
476 * VXD_APM (WPROCS.438)
478 void WINAPI VXD_APM ( CONTEXT86 *context )
480 unsigned service = AX_reg(context);
482 TRACE("[%04x] APM\n", (UINT16)service);
484 switch(service)
486 case 0x0000: /* version */
487 SET_AX( context, VXD_WinVersion() );
488 RESET_CFLAG(context);
489 break;
491 default:
492 VXD_BARF( context, "APM" );
496 /***********************************************************************
497 * VXD_Win32s (WPROCS.445)
499 * This is an implementation of the services of the Win32s VxD.
500 * Since official documentation of these does not seem to be available,
501 * certain arguments of some of the services remain unclear.
503 * FIXME: The following services are currently unimplemented:
504 * Exception handling (0x01, 0x1C)
505 * Debugger support (0x0C, 0x14, 0x17)
506 * Low-level memory access (0x02, 0x03, 0x0A, 0x0B)
507 * Memory Statistics (0x1B)
510 * We have a specific problem running Win32s on Linux (and probably also
511 * the other x86 unixes), since Win32s tries to allocate its main 'flat
512 * code/data segment' selectors with a base of 0xffff0000 (and limit 4GB).
513 * The rationale for this seems to be that they want one the one hand to
514 * be able to leave the Win 3.1 memory (starting with the main DOS memory)
515 * at linear address 0, but want at other hand to have offset 0 of the
516 * flat data/code segment point to an unmapped page (to catch NULL pointer
517 * accesses). Hence they allocate the flat segments with a base of 0xffff0000
518 * so that the Win 3.1 memory area at linear address zero shows up in the
519 * flat segments at offset 0x10000 (since linear addresses wrap around at
520 * 4GB). To compensate for that discrepancy between flat segment offsets
521 * and plain linear addresses, all flat pointers passed between the 32-bit
522 * and the 16-bit parts of Win32s are shifted by 0x10000 in the appropriate
523 * direction by the glue code (mainly) in W32SKRNL and WIN32S16.
525 * The problem for us is now that Linux does not allow a LDT selector with
526 * base 0xffff0000 to be created, since it would 'see' a part of the kernel
527 * address space. To address this problem we introduce *another* offset:
528 * We add 0x10000 to every linear address we get as an argument from Win32s.
529 * This means especially that the flat code/data selectors get actually
530 * allocated with base 0x0, so that flat offsets and (real) linear addresses
531 * do again agree! In fact, every call e.g. of a Win32s VxD service now
532 * has all pointer arguments (which are offsets in the flat data segement)
533 * first reduced by 0x10000 by the W32SKRNL glue code, and then again
534 * increased by 0x10000 by *our* code.
536 * Note that to keep everything consistent, this offset has to be applied by
537 * every Wine function that operates on 'linear addresses' passed to it by
538 * Win32s. Fortunately, since Win32s does not directly call any Wine 32-bit
539 * API routines, this affects only two locations: this VxD and the DPMI
540 * handler. (NOTE: Should any Win32s application pass a linear address to
541 * any routine apart from those, e.g. some other VxD handler, that code
542 * would have to take the offset into account as well!)
544 * The offset is set the first time any application calls the GetVersion()
545 * service of the Win32s VxD. (Note that the offset is never reset.)
549 void WINAPI VXD_Win32s( CONTEXT86 *context )
551 switch (AX_reg(context))
553 case 0x0000: /* Get Version */
555 * Input: None
557 * Output: EAX: LoWord: Win32s Version (1.30)
558 * HiWord: VxD Version (200)
560 * EBX: Build (172)
562 * ECX: ??? (1)
564 * EDX: Debugging Flags
566 * EDI: Error Flag
567 * 0 if OK,
568 * 1 if VMCPD VxD not found
571 TRACE("GetVersion()\n");
573 context->Eax = VXD_WinVersion() | (200 << 16);
574 context->Ebx = 0;
575 context->Ecx = 0;
576 context->Edx = 0;
577 context->Edi = 0;
580 * If this is the first time we are called for this process,
581 * hack the memory image of WIN32S16 so that it doesn't try
582 * to access the GDT directly ...
584 * The first code segment of WIN32S16 (version 1.30) contains
585 * an unexported function somewhere between the exported functions
586 * SetFS and StackLinearToSegmented that tries to find a selector
587 * in the LDT that maps to the memory image of the LDT itself.
588 * If it succeeds, it stores this selector into a global variable
589 * which will be used to speed up execution by using this selector
590 * to modify the LDT directly instead of using the DPMI calls.
592 * To perform this search of the LDT, this function uses the
593 * sgdt and sldt instructions to find the linear address of
594 * the (GDT and then) LDT. While those instructions themselves
595 * execute without problem, the linear address that sgdt returns
596 * points (at least under Linux) to the kernel address space, so
597 * that any subsequent access leads to a segfault.
599 * Fortunately, WIN32S16 still contains as a fallback option the
600 * mechanism of using DPMI calls to modify LDT selectors instead
601 * of direct writes to the LDT. Thus we can circumvent the problem
602 * by simply replacing the first byte of the offending function
603 * with an 'retf' instruction. This means that the global variable
604 * supposed to contain the LDT alias selector will remain zero,
605 * and hence WIN32S16 will fall back to using DPMI calls.
607 * The heuristic we employ to _find_ that function is as follows:
608 * We search between the addresses of the exported symbols SetFS
609 * and StackLinearToSegmented for the byte sequence '0F 01 04'
610 * (this is the opcode of 'sgdt [si]'). We then search backwards
611 * from this address for the last occurrence of 'CB' (retf) that marks
612 * the end of the preceeding function. The following byte (which
613 * should now be the first byte of the function we are looking for)
614 * will be replaced by 'CB' (retf).
616 * This heuristic works for the retail as well as the debug version
617 * of Win32s version 1.30. For versions earlier than that this
618 * hack should not be necessary at all, since the whole mechanism
619 * ('PERF130') was introduced only in 1.30 to improve the overall
620 * performance of Win32s.
623 if (!W32S_offset)
625 HMODULE16 hModule = GetModuleHandle16("win32s16");
626 SEGPTR func1 = (SEGPTR)GetProcAddress16(hModule, "SetFS");
627 SEGPTR func2 = (SEGPTR)GetProcAddress16(hModule, "StackLinearToSegmented");
629 if ( hModule && func1 && func2
630 && SELECTOROF(func1) == SELECTOROF(func2))
632 BYTE *start = MapSL(func1);
633 BYTE *end = MapSL(func2);
634 BYTE *p, *retv = NULL;
635 int found = 0;
637 for (p = start; p < end; p++)
638 if (*p == 0xCB) found = 0, retv = p;
639 else if (*p == 0x0F) found = 1;
640 else if (*p == 0x01 && found == 1) found = 2;
641 else if (*p == 0x04 && found == 2) { found = 3; break; }
642 else found = 0;
644 if (found == 3 && retv)
646 TRACE("PERF130 hack: "
647 "Replacing byte %02X at offset %04X:%04X\n",
648 *(retv+1), SELECTOROF(func1),
649 OFFSETOF(func1) + retv+1-start);
651 *(retv+1) = (BYTE)0xCB;
657 * Mark process as Win32s, so that subsequent DPMI calls
658 * will perform the W32S_APP2WINE/W32S_WINE2APP address shift.
660 W32S_offset = 0x10000;
661 break;
664 case 0x0001: /* Install Exception Handling */
666 * Input: EBX: Flat address of W32SKRNL Exception Data
668 * ECX: LoWord: Flat Code Selector
669 * HiWord: Flat Data Selector
671 * EDX: Flat address of W32SKRNL Exception Handler
672 * (this is equal to W32S_BackTo32 + 0x40)
674 * ESI: SEGPTR KERNEL.HASGPHANDLER
676 * EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10)
678 * Output: EAX: 0 if OK
681 TRACE("[0001] EBX=%lx ECX=%lx EDX=%lx ESI=%lx EDI=%lx\n",
682 context->Ebx, context->Ecx, context->Edx,
683 context->Esi, context->Edi);
685 /* FIXME */
687 context->Eax = 0;
688 break;
691 case 0x0002: /* Set Page Access Flags */
693 * Input: EBX: New access flags
694 * Bit 2: User Page if set, Supervisor Page if clear
695 * Bit 1: Read-Write if set, Read-Only if clear
697 * ECX: Size of memory area to change
699 * EDX: Flat start address of memory area
701 * Output: EAX: Size of area changed
704 TRACE("[0002] EBX=%lx ECX=%lx EDX=%lx\n",
705 context->Ebx, context->Ecx, context->Edx);
707 /* FIXME */
709 context->Eax = context->Ecx;
710 break;
713 case 0x0003: /* Get Page Access Flags */
715 * Input: EDX: Flat address of page to query
717 * Output: EAX: Page access flags
718 * Bit 2: User Page if set, Supervisor Page if clear
719 * Bit 1: Read-Write if set, Read-Only if clear
722 TRACE("[0003] EDX=%lx\n", context->Edx);
724 /* FIXME */
726 context->Eax = 6;
727 break;
730 case 0x0004: /* Map Module */
732 * Input: ECX: IMTE (offset in Module Table) of new module
734 * EDX: Flat address of Win32s Module Table
736 * Output: EAX: 0 if OK
739 if (!context->Edx || CX_reg(context) == 0xFFFF)
741 TRACE("MapModule: Initialization call\n");
742 context->Eax = 0;
744 else
747 * Structure of a Win32s Module Table Entry:
749 struct Win32sModule
751 DWORD flags;
752 DWORD flatBaseAddr;
753 LPCSTR moduleName;
754 LPCSTR pathName;
755 LPCSTR unknown;
756 LPBYTE baseAddr;
757 DWORD hModule;
758 DWORD relocDelta;
762 * Note: This function should set up a demand-paged memory image
763 * of the given module. Since mmap does not allow file offsets
764 * not aligned at 1024 bytes, we simply load the image fully
765 * into memory.
768 struct Win32sModule *moduleTable =
769 (struct Win32sModule *)W32S_APP2WINE(context->Edx);
770 struct Win32sModule *module = moduleTable + context->Ecx;
772 IMAGE_NT_HEADERS *nt_header = RtlImageNtHeader( (HMODULE)module->baseAddr );
773 IMAGE_SECTION_HEADER *pe_seg = (IMAGE_SECTION_HEADER*)((char *)&nt_header->OptionalHeader +
774 nt_header->FileHeader.SizeOfOptionalHeader);
777 HFILE image = _lopen(module->pathName, OF_READ);
778 BOOL error = (image == HFILE_ERROR);
779 UINT i;
781 TRACE("MapModule: Loading %s\n", module->pathName);
783 for (i = 0;
784 !error && i < nt_header->FileHeader.NumberOfSections;
785 i++, pe_seg++)
786 if(!(pe_seg->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA))
788 DWORD off = pe_seg->PointerToRawData;
789 DWORD len = pe_seg->SizeOfRawData;
790 LPBYTE addr = module->baseAddr + pe_seg->VirtualAddress;
792 TRACE("MapModule: "
793 "Section %d at %08lx from %08lx len %08lx\n",
794 i, (DWORD)addr, off, len);
796 if ( _llseek(image, off, SEEK_SET) != off
797 || _lread(image, addr, len) != len)
798 error = TRUE;
801 _lclose(image);
803 if (error)
804 ERR("MapModule: Unable to load %s\n", module->pathName);
806 else if (module->relocDelta != 0)
808 IMAGE_DATA_DIRECTORY *dir = nt_header->OptionalHeader.DataDirectory
809 + IMAGE_DIRECTORY_ENTRY_BASERELOC;
810 IMAGE_BASE_RELOCATION *r = (IMAGE_BASE_RELOCATION *)
811 (dir->Size? module->baseAddr + dir->VirtualAddress : 0);
813 TRACE("MapModule: Reloc delta %08lx\n", module->relocDelta);
815 while (r && r->VirtualAddress)
817 LPBYTE page = module->baseAddr + r->VirtualAddress;
818 WORD *TypeOffset = (WORD *)(r + 1);
819 int count = (r->SizeOfBlock - sizeof(*r)) / sizeof(*TypeOffset);
821 TRACE("MapModule: %d relocations for page %08lx\n",
822 count, (DWORD)page);
824 for(i = 0; i < count; i++)
826 int offset = TypeOffset[i] & 0xFFF;
827 int type = TypeOffset[i] >> 12;
828 switch(type)
830 case IMAGE_REL_BASED_ABSOLUTE:
831 break;
832 case IMAGE_REL_BASED_HIGH:
833 *(WORD *)(page+offset) += HIWORD(module->relocDelta);
834 break;
835 case IMAGE_REL_BASED_LOW:
836 *(WORD *)(page+offset) += LOWORD(module->relocDelta);
837 break;
838 case IMAGE_REL_BASED_HIGHLOW:
839 *(DWORD*)(page+offset) += module->relocDelta;
840 break;
841 default:
842 WARN("MapModule: Unsupported fixup type\n");
843 break;
847 r = (IMAGE_BASE_RELOCATION *)((LPBYTE)r + r->SizeOfBlock);
851 context->Eax = 0;
852 RESET_CFLAG(context);
854 break;
857 case 0x0005: /* UnMap Module */
859 * Input: EDX: Flat address of module image
861 * Output: EAX: 1 if OK
864 TRACE("UnMapModule: %lx\n", (DWORD)W32S_APP2WINE(context->Edx));
866 /* As we didn't map anything, there's nothing to unmap ... */
868 context->Eax = 1;
869 break;
872 case 0x0006: /* VirtualAlloc */
874 * Input: ECX: Current Process
876 * EDX: Flat address of arguments on stack
878 * DWORD *retv [out] Flat base address of allocated region
879 * LPVOID base [in] Flat address of region to reserve/commit
880 * DWORD size [in] Size of region
881 * DWORD type [in] Type of allocation
882 * DWORD prot [in] Type of access protection
884 * Output: EAX: NtStatus
887 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
888 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
889 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
890 DWORD size = stack[2];
891 DWORD type = stack[3];
892 DWORD prot = stack[4];
893 DWORD result;
895 TRACE("VirtualAlloc(%lx, %lx, %lx, %lx, %lx)\n",
896 (DWORD)retv, (DWORD)base, size, type, prot);
898 if (type & 0x80000000)
900 WARN("VirtualAlloc: strange type %lx\n", type);
901 type &= 0x7fffffff;
904 if (!base && (type & MEM_COMMIT) && prot == PAGE_READONLY)
906 WARN("VirtualAlloc: NLS hack, allowing write access!\n");
907 prot = PAGE_READWRITE;
910 result = (DWORD)VirtualAlloc(base, size, type, prot);
912 if (W32S_WINE2APP(result))
913 *retv = W32S_WINE2APP(result),
914 context->Eax = STATUS_SUCCESS;
915 else
916 *retv = 0,
917 context->Eax = STATUS_NO_MEMORY; /* FIXME */
919 break;
922 case 0x0007: /* VirtualFree */
924 * Input: ECX: Current Process
926 * EDX: Flat address of arguments on stack
928 * DWORD *retv [out] TRUE if success, FALSE if failure
929 * LPVOID base [in] Flat address of region
930 * DWORD size [in] Size of region
931 * DWORD type [in] Type of operation
933 * Output: EAX: NtStatus
936 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
937 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
938 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
939 DWORD size = stack[2];
940 DWORD type = stack[3];
941 DWORD result;
943 TRACE("VirtualFree(%lx, %lx, %lx, %lx)\n",
944 (DWORD)retv, (DWORD)base, size, type);
946 result = VirtualFree(base, size, type);
948 if (result)
949 *retv = TRUE,
950 context->Eax = STATUS_SUCCESS;
951 else
952 *retv = FALSE,
953 context->Eax = STATUS_NO_MEMORY; /* FIXME */
955 break;
958 case 0x0008: /* VirtualProtect */
960 * Input: ECX: Current Process
962 * EDX: Flat address of arguments on stack
964 * DWORD *retv [out] TRUE if success, FALSE if failure
965 * LPVOID base [in] Flat address of region
966 * DWORD size [in] Size of region
967 * DWORD new_prot [in] Desired access protection
968 * DWORD *old_prot [out] Previous access protection
970 * Output: EAX: NtStatus
973 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
974 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
975 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
976 DWORD size = stack[2];
977 DWORD new_prot = stack[3];
978 DWORD *old_prot = (DWORD *)W32S_APP2WINE(stack[4]);
979 DWORD result;
981 TRACE("VirtualProtect(%lx, %lx, %lx, %lx, %lx)\n",
982 (DWORD)retv, (DWORD)base, size, new_prot, (DWORD)old_prot);
984 result = VirtualProtect(base, size, new_prot, old_prot);
986 if (result)
987 *retv = TRUE,
988 context->Eax = STATUS_SUCCESS;
989 else
990 *retv = FALSE,
991 context->Eax = STATUS_NO_MEMORY; /* FIXME */
993 break;
996 case 0x0009: /* VirtualQuery */
998 * Input: ECX: Current Process
1000 * EDX: Flat address of arguments on stack
1002 * DWORD *retv [out] Nr. bytes returned
1003 * LPVOID base [in] Flat address of region
1004 * LPMEMORY_BASIC_INFORMATION info [out] Info buffer
1005 * DWORD len [in] Size of buffer
1007 * Output: EAX: NtStatus
1010 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1011 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1012 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1013 PMEMORY_BASIC_INFORMATION info =
1014 (PMEMORY_BASIC_INFORMATION)W32S_APP2WINE(stack[2]);
1015 DWORD len = stack[3];
1016 DWORD result;
1018 TRACE("VirtualQuery(%lx, %lx, %lx, %lx)\n",
1019 (DWORD)retv, (DWORD)base, (DWORD)info, len);
1021 result = VirtualQuery(base, info, len);
1023 *retv = result;
1024 context->Eax = STATUS_SUCCESS;
1026 break;
1029 case 0x000A: /* SetVirtMemProcess */
1031 * Input: ECX: Process Handle
1033 * EDX: Flat address of region
1035 * Output: EAX: NtStatus
1038 TRACE("[000a] ECX=%lx EDX=%lx\n",
1039 context->Ecx, context->Edx);
1041 /* FIXME */
1043 context->Eax = STATUS_SUCCESS;
1044 break;
1047 case 0x000B: /* ??? some kind of cleanup */
1049 * Input: ECX: Process Handle
1051 * Output: EAX: NtStatus
1054 TRACE("[000b] ECX=%lx\n", context->Ecx);
1056 /* FIXME */
1058 context->Eax = STATUS_SUCCESS;
1059 break;
1062 case 0x000C: /* Set Debug Flags */
1064 * Input: EDX: Debug Flags
1066 * Output: EDX: Previous Debug Flags
1069 FIXME("[000c] EDX=%lx\n", context->Edx);
1071 /* FIXME */
1073 context->Edx = 0;
1074 break;
1077 case 0x000D: /* NtCreateSection */
1079 * Input: EDX: Flat address of arguments on stack
1081 * HANDLE32 *retv [out] Handle of Section created
1082 * DWORD flags1 [in] (?? unknown ??)
1083 * DWORD atom [in] Name of Section to create
1084 * LARGE_INTEGER *size [in] Size of Section
1085 * DWORD protect [in] Access protection
1086 * DWORD flags2 [in] (?? unknown ??)
1087 * HFILE32 hFile [in] Handle of file to map
1088 * DWORD psp [in] (Win32s: PSP that hFile belongs to)
1090 * Output: EAX: NtStatus
1093 DWORD *stack = (DWORD *) W32S_APP2WINE(context->Edx);
1094 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]);
1095 DWORD flags1 = stack[1];
1096 DWORD atom = stack[2];
1097 LARGE_INTEGER *size = (LARGE_INTEGER *)W32S_APP2WINE(stack[3]);
1098 DWORD protect = stack[4];
1099 DWORD flags2 = stack[5];
1100 HANDLE hFile = DosFileHandleToWin32Handle(stack[6]);
1101 DWORD psp = stack[7];
1103 HANDLE result = INVALID_HANDLE_VALUE;
1104 char name[128];
1106 TRACE("NtCreateSection(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1107 (DWORD)retv, flags1, atom, (DWORD)size, protect, flags2,
1108 (DWORD)hFile, psp);
1110 if (!atom || GlobalGetAtomNameA(atom, name, sizeof(name)))
1112 TRACE("NtCreateSection: name=%s\n", atom? name : NULL);
1114 result = CreateFileMappingA(hFile, NULL, protect,
1115 size? size->s.HighPart : 0,
1116 size? size->s.LowPart : 0,
1117 atom? name : NULL);
1120 if (result == INVALID_HANDLE_VALUE)
1121 WARN("NtCreateSection: failed!\n");
1122 else
1123 TRACE("NtCreateSection: returned %lx\n", (DWORD)result);
1125 if (result != INVALID_HANDLE_VALUE)
1126 *retv = result,
1127 context->Eax = STATUS_SUCCESS;
1128 else
1129 *retv = result,
1130 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1132 break;
1135 case 0x000E: /* NtOpenSection */
1137 * Input: EDX: Flat address of arguments on stack
1139 * HANDLE32 *retv [out] Handle of Section opened
1140 * DWORD protect [in] Access protection
1141 * DWORD atom [in] Name of Section to create
1143 * Output: EAX: NtStatus
1146 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1147 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]);
1148 DWORD protect = stack[1];
1149 DWORD atom = stack[2];
1151 HANDLE result = INVALID_HANDLE_VALUE;
1152 char name[128];
1154 TRACE("NtOpenSection(%lx, %lx, %lx)\n",
1155 (DWORD)retv, protect, atom);
1157 if (atom && GlobalGetAtomNameA(atom, name, sizeof(name)))
1159 TRACE("NtOpenSection: name=%s\n", name);
1161 result = OpenFileMappingA(protect, FALSE, name);
1164 if (result == INVALID_HANDLE_VALUE)
1165 WARN("NtOpenSection: failed!\n");
1166 else
1167 TRACE("NtOpenSection: returned %lx\n", (DWORD)result);
1169 if (result != INVALID_HANDLE_VALUE)
1170 *retv = result,
1171 context->Eax = STATUS_SUCCESS;
1172 else
1173 *retv = result,
1174 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1176 break;
1179 case 0x000F: /* NtCloseSection */
1181 * Input: EDX: Flat address of arguments on stack
1183 * HANDLE32 handle [in] Handle of Section to close
1184 * DWORD *id [out] Unique ID (?? unclear ??)
1186 * Output: EAX: NtStatus
1189 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1190 HANDLE handle = (HANDLE)stack[0];
1191 DWORD *id = (DWORD *)W32S_APP2WINE(stack[1]);
1193 TRACE("NtCloseSection(%lx, %lx)\n", (DWORD)handle, (DWORD)id);
1195 CloseHandle(handle);
1196 if (id) *id = 0; /* FIXME */
1198 context->Eax = STATUS_SUCCESS;
1200 break;
1203 case 0x0010: /* NtDupSection */
1205 * Input: EDX: Flat address of arguments on stack
1207 * HANDLE32 handle [in] Handle of Section to duplicate
1209 * Output: EAX: NtStatus
1212 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1213 HANDLE handle = (HANDLE)stack[0];
1214 HANDLE new_handle;
1216 TRACE("NtDupSection(%lx)\n", (DWORD)handle);
1218 DuplicateHandle( GetCurrentProcess(), handle,
1219 GetCurrentProcess(), &new_handle,
1220 0, FALSE, DUPLICATE_SAME_ACCESS );
1221 context->Eax = STATUS_SUCCESS;
1223 break;
1226 case 0x0011: /* NtMapViewOfSection */
1228 * Input: EDX: Flat address of arguments on stack
1230 * HANDLE32 SectionHandle [in] Section to be mapped
1231 * DWORD ProcessHandle [in] Process to be mapped into
1232 * DWORD * BaseAddress [in/out] Address to be mapped at
1233 * DWORD ZeroBits [in] (?? unclear ??)
1234 * DWORD CommitSize [in] (?? unclear ??)
1235 * LARGE_INTEGER *SectionOffset [in] Offset within section
1236 * DWORD * ViewSize [in] Size of view
1237 * DWORD InheritDisposition [in] (?? unclear ??)
1238 * DWORD AllocationType [in] (?? unclear ??)
1239 * DWORD Protect [in] Access protection
1241 * Output: EAX: NtStatus
1244 DWORD * stack = (DWORD *)W32S_APP2WINE(context->Edx);
1245 HANDLE SectionHandle = (HANDLE)stack[0];
1246 DWORD ProcessHandle = stack[1]; /* ignored */
1247 DWORD * BaseAddress = (DWORD *)W32S_APP2WINE(stack[2]);
1248 DWORD ZeroBits = stack[3];
1249 DWORD CommitSize = stack[4];
1250 LARGE_INTEGER *SectionOffset = (LARGE_INTEGER *)W32S_APP2WINE(stack[5]);
1251 DWORD * ViewSize = (DWORD *)W32S_APP2WINE(stack[6]);
1252 DWORD InheritDisposition = stack[7];
1253 DWORD AllocationType = stack[8];
1254 DWORD Protect = stack[9];
1256 LPBYTE address = (LPBYTE)(BaseAddress?
1257 W32S_APP2WINE(*BaseAddress) : 0);
1258 DWORD access = 0, result;
1260 switch (Protect & ~(PAGE_GUARD|PAGE_NOCACHE))
1262 case PAGE_READONLY: access = FILE_MAP_READ; break;
1263 case PAGE_READWRITE: access = FILE_MAP_WRITE; break;
1264 case PAGE_WRITECOPY: access = FILE_MAP_COPY; break;
1266 case PAGE_EXECUTE_READ: access = FILE_MAP_READ; break;
1267 case PAGE_EXECUTE_READWRITE: access = FILE_MAP_WRITE; break;
1268 case PAGE_EXECUTE_WRITECOPY: access = FILE_MAP_COPY; break;
1271 TRACE("NtMapViewOfSection"
1272 "(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1273 (DWORD)SectionHandle, ProcessHandle, (DWORD)BaseAddress,
1274 ZeroBits, CommitSize, (DWORD)SectionOffset, (DWORD)ViewSize,
1275 InheritDisposition, AllocationType, Protect);
1276 TRACE("NtMapViewOfSection: "
1277 "base=%lx, offset=%lx, size=%lx, access=%lx\n",
1278 (DWORD)address, SectionOffset? SectionOffset->s.LowPart : 0,
1279 ViewSize? *ViewSize : 0, access);
1281 result = (DWORD)MapViewOfFileEx(SectionHandle, access,
1282 SectionOffset? SectionOffset->s.HighPart : 0,
1283 SectionOffset? SectionOffset->s.LowPart : 0,
1284 ViewSize? *ViewSize : 0, address);
1286 TRACE("NtMapViewOfSection: result=%lx\n", result);
1288 if (W32S_WINE2APP(result))
1290 if (BaseAddress) *BaseAddress = W32S_WINE2APP(result);
1291 context->Eax = STATUS_SUCCESS;
1293 else
1294 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1296 break;
1299 case 0x0012: /* NtUnmapViewOfSection */
1301 * Input: EDX: Flat address of arguments on stack
1303 * DWORD ProcessHandle [in] Process (defining address space)
1304 * LPBYTE BaseAddress [in] Base address of view to be unmapped
1306 * Output: EAX: NtStatus
1309 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1310 DWORD ProcessHandle = stack[0]; /* ignored */
1311 LPBYTE BaseAddress = (LPBYTE)W32S_APP2WINE(stack[1]);
1313 TRACE("NtUnmapViewOfSection(%lx, %lx)\n",
1314 ProcessHandle, (DWORD)BaseAddress);
1316 UnmapViewOfFile(BaseAddress);
1318 context->Eax = STATUS_SUCCESS;
1320 break;
1323 case 0x0013: /* NtFlushVirtualMemory */
1325 * Input: EDX: Flat address of arguments on stack
1327 * DWORD ProcessHandle [in] Process (defining address space)
1328 * LPBYTE *BaseAddress [in?] Base address of range to be flushed
1329 * DWORD *ViewSize [in?] Number of bytes to be flushed
1330 * DWORD *unknown [???] (?? unknown ??)
1332 * Output: EAX: NtStatus
1335 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1336 DWORD ProcessHandle = stack[0]; /* ignored */
1337 DWORD *BaseAddress = (DWORD *)W32S_APP2WINE(stack[1]);
1338 DWORD *ViewSize = (DWORD *)W32S_APP2WINE(stack[2]);
1339 DWORD *unknown = (DWORD *)W32S_APP2WINE(stack[3]);
1341 LPBYTE address = (LPBYTE)(BaseAddress? W32S_APP2WINE(*BaseAddress) : 0);
1342 DWORD size = ViewSize? *ViewSize : 0;
1344 TRACE("NtFlushVirtualMemory(%lx, %lx, %lx, %lx)\n",
1345 ProcessHandle, (DWORD)BaseAddress, (DWORD)ViewSize,
1346 (DWORD)unknown);
1347 TRACE("NtFlushVirtualMemory: base=%lx, size=%lx\n",
1348 (DWORD)address, size);
1350 FlushViewOfFile(address, size);
1352 context->Eax = STATUS_SUCCESS;
1354 break;
1357 case 0x0014: /* Get/Set Debug Registers */
1359 * Input: ECX: 0 if Get, 1 if Set
1361 * EDX: Get: Flat address of buffer to receive values of
1362 * debug registers DR0 .. DR7
1363 * Set: Flat address of buffer containing values of
1364 * debug registers DR0 .. DR7 to be set
1365 * Output: None
1368 FIXME("[0014] ECX=%lx EDX=%lx\n",
1369 context->Ecx, context->Edx);
1371 /* FIXME */
1372 break;
1375 case 0x0015: /* Set Coprocessor Emulation Flag */
1377 * Input: EDX: 0 to deactivate, 1 to activate coprocessor emulation
1379 * Output: None
1382 TRACE("[0015] EDX=%lx\n", context->Edx);
1384 /* We don't care, as we always have a coprocessor anyway */
1385 break;
1388 case 0x0016: /* Init Win32S VxD PSP */
1390 * If called to query required PSP size:
1392 * Input: EBX: 0
1393 * Output: EDX: Required size of Win32s VxD PSP
1395 * If called to initialize allocated PSP:
1397 * Input: EBX: LoWord: Selector of Win32s VxD PSP
1398 * HiWord: Paragraph of Win32s VxD PSP (DOSMEM)
1399 * Output: None
1402 if (context->Ebx == 0)
1403 context->Edx = 0x80;
1404 else
1406 PDB16 *psp = MapSL( MAKESEGPTR( BX_reg(context), 0 ));
1407 psp->nbFiles = 32;
1408 psp->fileHandlesPtr = MAKELONG(HIWORD(context->Ebx), 0x5c);
1409 memset((LPBYTE)psp + 0x5c, '\xFF', 32);
1411 break;
1414 case 0x0017: /* Set Break Point */
1416 * Input: EBX: Offset of Break Point
1417 * CX: Selector of Break Point
1419 * Output: None
1422 FIXME("[0017] EBX=%lx CX=%x\n",
1423 context->Ebx, CX_reg(context));
1425 /* FIXME */
1426 break;
1429 case 0x0018: /* VirtualLock */
1431 * Input: ECX: Current Process
1433 * EDX: Flat address of arguments on stack
1435 * DWORD *retv [out] TRUE if success, FALSE if failure
1436 * LPVOID base [in] Flat address of range to lock
1437 * DWORD size [in] Size of range
1439 * Output: EAX: NtStatus
1442 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1443 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1444 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1445 DWORD size = stack[2];
1446 DWORD result;
1448 TRACE("VirtualLock(%lx, %lx, %lx)\n",
1449 (DWORD)retv, (DWORD)base, size);
1451 result = VirtualLock(base, size);
1453 if (result)
1454 *retv = TRUE,
1455 context->Eax = STATUS_SUCCESS;
1456 else
1457 *retv = FALSE,
1458 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1460 break;
1463 case 0x0019: /* VirtualUnlock */
1465 * Input: ECX: Current Process
1467 * EDX: Flat address of arguments on stack
1469 * DWORD *retv [out] TRUE if success, FALSE if failure
1470 * LPVOID base [in] Flat address of range to unlock
1471 * DWORD size [in] Size of range
1473 * Output: EAX: NtStatus
1476 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1477 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1478 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1479 DWORD size = stack[2];
1480 DWORD result;
1482 TRACE("VirtualUnlock(%lx, %lx, %lx)\n",
1483 (DWORD)retv, (DWORD)base, size);
1485 result = VirtualUnlock(base, size);
1487 if (result)
1488 *retv = TRUE,
1489 context->Eax = STATUS_SUCCESS;
1490 else
1491 *retv = FALSE,
1492 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1494 break;
1497 case 0x001A: /* KGetSystemInfo */
1499 * Input: None
1501 * Output: ECX: Start of sparse memory arena
1502 * EDX: End of sparse memory arena
1505 TRACE("KGetSystemInfo()\n");
1508 * Note: Win32s reserves 0GB - 2GB for Win 3.1 and uses 2GB - 4GB as
1509 * sparse memory arena. We do it the other way around, since
1510 * we have to reserve 3GB - 4GB for Linux, and thus use
1511 * 0GB - 3GB as sparse memory arena.
1513 * FIXME: What about other OSes ?
1516 context->Ecx = W32S_WINE2APP(0x00000000);
1517 context->Edx = W32S_WINE2APP(0xbfffffff);
1518 break;
1521 case 0x001B: /* KGlobalMemStat */
1523 * Input: ESI: Flat address of buffer to receive memory info
1525 * Output: None
1528 struct Win32sMemoryInfo
1530 DWORD DIPhys_Count; /* Total physical pages */
1531 DWORD DIFree_Count; /* Free physical pages */
1532 DWORD DILin_Total_Count; /* Total virtual pages (private arena) */
1533 DWORD DILin_Total_Free; /* Free virtual pages (private arena) */
1535 DWORD SparseTotal; /* Total size of sparse arena (bytes ?) */
1536 DWORD SparseFree; /* Free size of sparse arena (bytes ?) */
1539 struct Win32sMemoryInfo *info =
1540 (struct Win32sMemoryInfo *)W32S_APP2WINE(context->Esi);
1542 FIXME("KGlobalMemStat(%lx)\n", (DWORD)info);
1544 /* FIXME */
1546 break;
1549 case 0x001C: /* Enable/Disable Exceptions */
1551 * Input: ECX: 0 to disable, 1 to enable exception handling
1553 * Output: None
1556 TRACE("[001c] ECX=%lx\n", context->Ecx);
1558 /* FIXME */
1559 break;
1562 case 0x001D: /* VirtualAlloc called from 16-bit code */
1564 * Input: EDX: Segmented address of arguments on stack
1566 * LPVOID base [in] Flat address of region to reserve/commit
1567 * DWORD size [in] Size of region
1568 * DWORD type [in] Type of allocation
1569 * DWORD prot [in] Type of access protection
1571 * Output: EAX: NtStatus
1572 * EDX: Flat base address of allocated region
1575 DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) ));
1576 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]);
1577 DWORD size = stack[1];
1578 DWORD type = stack[2];
1579 DWORD prot = stack[3];
1580 DWORD result;
1582 TRACE("VirtualAlloc16(%lx, %lx, %lx, %lx)\n",
1583 (DWORD)base, size, type, prot);
1585 if (type & 0x80000000)
1587 WARN("VirtualAlloc16: strange type %lx\n", type);
1588 type &= 0x7fffffff;
1591 result = (DWORD)VirtualAlloc(base, size, type, prot);
1593 if (W32S_WINE2APP(result))
1594 context->Edx = W32S_WINE2APP(result),
1595 context->Eax = STATUS_SUCCESS;
1596 else
1597 context->Edx = 0,
1598 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1599 TRACE("VirtualAlloc16: returning base %lx\n", context->Edx);
1601 break;
1604 case 0x001E: /* VirtualFree called from 16-bit code */
1606 * Input: EDX: Segmented address of arguments on stack
1608 * LPVOID base [in] Flat address of region
1609 * DWORD size [in] Size of region
1610 * DWORD type [in] Type of operation
1612 * Output: EAX: NtStatus
1613 * EDX: TRUE if success, FALSE if failure
1616 DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) ));
1617 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]);
1618 DWORD size = stack[1];
1619 DWORD type = stack[2];
1620 DWORD result;
1622 TRACE("VirtualFree16(%lx, %lx, %lx)\n",
1623 (DWORD)base, size, type);
1625 result = VirtualFree(base, size, type);
1627 if (result)
1628 context->Edx = TRUE,
1629 context->Eax = STATUS_SUCCESS;
1630 else
1631 context->Edx = FALSE,
1632 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1634 break;
1637 case 0x001F: /* FWorkingSetSize */
1639 * Input: EDX: 0 if Get, 1 if Set
1641 * ECX: Get: Buffer to receive Working Set Size
1642 * Set: Buffer containing Working Set Size
1644 * Output: NtStatus
1647 DWORD *ptr = (DWORD *)W32S_APP2WINE(context->Ecx);
1648 BOOL set = context->Edx;
1650 TRACE("FWorkingSetSize(%lx, %lx)\n", (DWORD)ptr, (DWORD)set);
1652 if (set)
1653 /* We do it differently ... */;
1654 else
1655 *ptr = 0x100;
1657 context->Eax = STATUS_SUCCESS;
1659 break;
1662 default:
1663 VXD_BARF( context, "W32S" );