Fixed header dependencies to be fully compatible with the Windows
[wine/multimedia.git] / dlls / winedos / vxd.c
blob6fa723b149bf566bf2eec5d72c7bc79186331138
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 <stdarg.h>
27 #include <stdio.h>
28 #include <sys/types.h>
29 #ifdef HAVE_UNISTD_H
30 # include <unistd.h>
31 #endif
33 #define NONAMELESSUNION
34 #define NONAMELESSSTRUCT
35 #include "windef.h"
36 #include "winbase.h"
37 #include "winreg.h"
38 #include "winternl.h"
39 #include "wingdi.h"
40 #include "winuser.h"
41 #include "ntstatus.h"
42 #include "wine/winbase16.h"
43 #include "wine/winuser16.h"
44 #include "msdos.h"
45 #include "miscemu.h"
46 #include "selectors.h"
47 #include "task.h"
48 #include "file.h"
49 #include "wine/debug.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(vxd);
53 #define W32S_APP2WINE(addr) ((addr)? (DWORD)(addr) + W32S_offset : 0)
54 #define W32S_WINE2APP(addr) ((addr)? (DWORD)(addr) - W32S_offset : 0)
56 #define VXD_BARF(context,name) \
57 DPRINTF( "vxd %s: unknown/not implemented parameters:\n" \
58 "vxd %s: AX %04x, BX %04x, CX %04x, DX %04x, " \
59 "SI %04x, DI %04x, DS %04x, ES %04x\n", \
60 (name), (name), AX_reg(context), BX_reg(context), \
61 CX_reg(context), DX_reg(context), SI_reg(context), \
62 DI_reg(context), (WORD)context->SegDs, (WORD)context->SegEs )
64 UINT W32S_offset = 0;
66 static WORD VXD_WinVersion(void)
68 WORD version = LOWORD(GetVersion16());
69 return (version >> 8) | (version << 8);
72 /***********************************************************************
73 * VXD_VMM (WPROCS.401)
75 void WINAPI VXD_VMM ( CONTEXT86 *context )
77 unsigned service = AX_reg(context);
79 TRACE("[%04x] VMM\n", (UINT16)service);
81 switch(service)
83 case 0x0000: /* version */
84 SET_AX( context, VXD_WinVersion() );
85 RESET_CFLAG(context);
86 break;
88 case 0x026d: /* Get_Debug_Flag '/m' */
89 case 0x026e: /* Get_Debug_Flag '/n' */
90 SET_AL( context, 0 );
91 RESET_CFLAG(context);
92 break;
94 default:
95 VXD_BARF( context, "VMM" );
99 /***********************************************************************
100 * VXD_PageFile (WPROCS.433)
102 void WINAPI VXD_PageFile( CONTEXT86 *context )
104 unsigned service = AX_reg(context);
106 /* taken from Ralf Brown's Interrupt List */
108 TRACE("[%04x] PageFile\n", (UINT16)service );
110 switch(service)
112 case 0x00: /* get version, is this windows version? */
113 TRACE("returning version\n");
114 SET_AX( context, VXD_WinVersion() );
115 RESET_CFLAG(context);
116 break;
118 case 0x01: /* get swap file info */
119 TRACE("VxD PageFile: returning swap file info\n");
120 SET_AX( context, 0x00 ); /* paging disabled */
121 context->Ecx = 0; /* maximum size of paging file */
122 /* FIXME: do I touch DS:SI or DS:DI? */
123 RESET_CFLAG(context);
124 break;
126 case 0x02: /* delete permanent swap on exit */
127 TRACE("VxD PageFile: supposed to delete swap\n");
128 RESET_CFLAG(context);
129 break;
131 case 0x03: /* current temporary swap file size */
132 TRACE("VxD PageFile: what is current temp. swap size\n");
133 RESET_CFLAG(context);
134 break;
136 case 0x04: /* read or write?? INTERRUP.D */
137 case 0x05: /* cancel?? INTERRUP.D */
138 case 0x06: /* test I/O valid INTERRUP.D */
139 default:
140 VXD_BARF( context, "pagefile" );
141 break;
145 /***********************************************************************
146 * VXD_Reboot (WPROCS.409)
148 void WINAPI VXD_Reboot ( CONTEXT86 *context )
150 unsigned service = AX_reg(context);
152 TRACE("[%04x] Reboot\n", (UINT16)service);
154 switch(service)
156 case 0x0000: /* version */
157 SET_AX( context, VXD_WinVersion() );
158 RESET_CFLAG(context);
159 break;
161 default:
162 VXD_BARF( context, "REBOOT" );
166 /***********************************************************************
167 * VXD_VDD (WPROCS.410)
169 void WINAPI VXD_VDD ( CONTEXT86 *context )
171 unsigned service = AX_reg(context);
173 TRACE("[%04x] VDD\n", (UINT16)service);
175 switch(service)
177 case 0x0000: /* version */
178 SET_AX( context, VXD_WinVersion() );
179 RESET_CFLAG(context);
180 break;
182 default:
183 VXD_BARF( context, "VDD" );
187 /***********************************************************************
188 * VXD_VMD (WPROCS.412)
190 void WINAPI VXD_VMD ( CONTEXT86 *context )
192 unsigned service = AX_reg(context);
194 TRACE("[%04x] VMD\n", (UINT16)service);
196 switch(service)
198 case 0x0000: /* version */
199 SET_AX( context, VXD_WinVersion() );
200 RESET_CFLAG(context);
201 break;
203 default:
204 VXD_BARF( context, "VMD" );
208 /***********************************************************************
209 * VXD_VXDLoader (WPROCS.439)
211 void WINAPI VXD_VXDLoader( CONTEXT86 *context )
213 unsigned service = AX_reg(context);
215 TRACE("[%04x] VXDLoader\n", (UINT16)service);
217 switch (service)
219 case 0x0000: /* get version */
220 TRACE("returning version\n");
221 SET_AX( context, 0x0000 );
222 SET_DX( context, VXD_WinVersion() );
223 RESET_CFLAG(context);
224 break;
226 case 0x0001: /* load device */
227 FIXME("load device %04lx:%04x (%s)\n",
228 context->SegDs, DX_reg(context),
229 debugstr_a(MapSL(MAKESEGPTR(context->SegDs, DX_reg(context)))));
230 SET_AX( context, 0x0000 );
231 context->SegEs = 0x0000;
232 SET_DI( context, 0x0000 );
233 RESET_CFLAG(context);
234 break;
236 case 0x0002: /* unload device */
237 FIXME("unload device (%08lx)\n", context->Ebx);
238 SET_AX( context, 0x0000 );
239 RESET_CFLAG(context);
240 break;
242 default:
243 VXD_BARF( context, "VXDLDR" );
244 SET_AX( context, 0x000B ); /* invalid function number */
245 SET_CFLAG(context);
246 break;
250 /***********************************************************************
251 * VXD_Shell (WPROCS.423)
253 void WINAPI VXD_Shell( CONTEXT86 *context )
255 unsigned service = DX_reg(context);
257 TRACE("[%04x] Shell\n", (UINT16)service);
259 switch (service) /* Ralf Brown says EDX, but I use DX instead */
261 case 0x0000:
262 TRACE("returning version\n");
263 SET_AX( context, VXD_WinVersion() );
264 context->Ebx = 1; /* system VM Handle */
265 break;
267 case 0x0001:
268 case 0x0002:
269 case 0x0003:
270 /* SHELL_SYSMODAL_Message
271 ebx virtual maschine handle
272 eax message box flags
273 ecx address of message
274 edi address of caption
275 return response in eax
277 case 0x0004:
278 /* SHELL_Message
279 ebx virtual maschine handle
280 eax message box flags
281 ecx address of message
282 edi address of caption
283 esi address callback
284 edx reference data for callback
285 return response in eax
287 case 0x0005:
288 VXD_BARF( context, "shell" );
289 break;
291 case 0x0006: /* SHELL_Get_VM_State */
292 TRACE("VxD Shell: returning VM state\n");
293 /* Actually we don't, not yet. We have to return a structure
294 * and I am not to sure how to set it up and return it yet,
295 * so for now let's do nothing. I can (hopefully) get this
296 * by the next release
298 /* RESET_CFLAG(context); */
299 break;
301 case 0x0007:
302 case 0x0008:
303 case 0x0009:
304 case 0x000A:
305 case 0x000B:
306 case 0x000C:
307 case 0x000D:
308 case 0x000E:
309 case 0x000F:
310 case 0x0010:
311 case 0x0011:
312 case 0x0012:
313 case 0x0013:
314 case 0x0014:
315 case 0x0015:
316 case 0x0016:
317 VXD_BARF( context, "SHELL" );
318 break;
320 /* the new Win95 shell API */
321 case 0x0100: /* get version */
322 SET_AX( context, VXD_WinVersion() );
323 break;
325 case 0x0104: /* retrieve Hook_Properties list */
326 case 0x0105: /* call Hook_Properties callbacks */
327 VXD_BARF( context, "SHELL" );
328 break;
330 case 0x0106: /* install timeout callback */
331 TRACE("VxD Shell: ignoring shell callback (%ld sec.)\n", context->Ebx);
332 SET_CFLAG(context);
333 break;
335 case 0x0107: /* get version of any VxD */
336 default:
337 VXD_BARF( context, "SHELL" );
338 break;
343 /***********************************************************************
344 * VXD_Comm (WPROCS.414)
346 void WINAPI VXD_Comm( CONTEXT86 *context )
348 unsigned service = AX_reg(context);
350 TRACE("[%04x] Comm\n", (UINT16)service);
352 switch (service)
354 case 0x0000: /* get version */
355 TRACE("returning version\n");
356 SET_AX( context, VXD_WinVersion() );
357 RESET_CFLAG(context);
358 break;
360 case 0x0001: /* set port global */
361 case 0x0002: /* get focus */
362 case 0x0003: /* virtualise port */
363 default:
364 VXD_BARF( context, "comm" );
368 /***********************************************************************
369 * VXD_Timer (WPROCS.405)
371 void WINAPI VXD_Timer( CONTEXT86 *context )
373 unsigned service = AX_reg(context);
375 TRACE("[%04x] Virtual Timer\n", (UINT16)service);
377 switch(service)
379 case 0x0000: /* version */
380 SET_AX( context, VXD_WinVersion() );
381 RESET_CFLAG(context);
382 break;
384 case 0x0100: /* clock tick time, in 840nsecs */
385 context->Eax = GetTickCount();
387 context->Edx = context->Eax >> 22;
388 context->Eax <<= 10; /* not very precise */
389 break;
391 case 0x0101: /* current Windows time, msecs */
392 case 0x0102: /* current VM time, msecs */
393 context->Eax = GetTickCount();
394 break;
396 default:
397 VXD_BARF( context, "VTD" );
402 /***********************************************************************
403 * timer_thread
405 static DWORD CALLBACK timer_thread( void *arg )
407 DWORD *system_time = arg;
409 for (;;)
411 *system_time = GetTickCount();
412 Sleep( 55 );
417 /***********************************************************************
418 * VXD_TimerAPI (WPROCS.1490)
420 void WINAPI VXD_TimerAPI ( CONTEXT86 *context )
422 static WORD System_Time_Selector;
424 unsigned service = AX_reg(context);
426 TRACE("[%04x] TimerAPI\n", (UINT16)service);
428 switch(service)
430 case 0x0000: /* version */
431 SET_AX( context, VXD_WinVersion() );
432 RESET_CFLAG(context);
433 break;
435 case 0x0009: /* get system time selector */
436 if ( !System_Time_Selector )
438 HANDLE16 handle = GlobalAlloc16( GMEM_FIXED, sizeof(DWORD) );
439 System_Time_Selector = handle | 7;
440 CloseHandle( CreateThread( NULL, 0, timer_thread, GlobalLock16(handle), 0, NULL ) );
442 SET_AX( context, System_Time_Selector );
443 RESET_CFLAG(context);
444 break;
446 default:
447 VXD_BARF( context, "VTDAPI" );
451 /***********************************************************************
452 * VXD_ConfigMG (WPROCS.451)
454 void WINAPI VXD_ConfigMG ( CONTEXT86 *context )
456 unsigned service = AX_reg(context);
458 TRACE("[%04x] ConfigMG\n", (UINT16)service);
460 switch(service)
462 case 0x0000: /* version */
463 SET_AX( context, VXD_WinVersion() );
464 RESET_CFLAG(context);
465 break;
467 default:
468 VXD_BARF( context, "CONFIGMG" );
472 /***********************************************************************
473 * VXD_Enable (WPROCS.455)
475 void WINAPI VXD_Enable ( CONTEXT86 *context )
477 unsigned service = AX_reg(context);
479 TRACE("[%04x] Enable\n", (UINT16)service);
481 switch(service)
483 case 0x0000: /* version */
484 SET_AX( context, VXD_WinVersion() );
485 RESET_CFLAG(context);
486 break;
488 default:
489 VXD_BARF( context, "ENABLE" );
493 /***********************************************************************
494 * VXD_APM (WPROCS.438)
496 void WINAPI VXD_APM ( CONTEXT86 *context )
498 unsigned service = AX_reg(context);
500 TRACE("[%04x] APM\n", (UINT16)service);
502 switch(service)
504 case 0x0000: /* version */
505 SET_AX( context, VXD_WinVersion() );
506 RESET_CFLAG(context);
507 break;
509 default:
510 VXD_BARF( context, "APM" );
514 /***********************************************************************
515 * VXD_Win32s (WPROCS.445)
517 * This is an implementation of the services of the Win32s VxD.
518 * Since official documentation of these does not seem to be available,
519 * certain arguments of some of the services remain unclear.
521 * FIXME: The following services are currently unimplemented:
522 * Exception handling (0x01, 0x1C)
523 * Debugger support (0x0C, 0x14, 0x17)
524 * Low-level memory access (0x02, 0x03, 0x0A, 0x0B)
525 * Memory Statistics (0x1B)
528 * We have a specific problem running Win32s on Linux (and probably also
529 * the other x86 unixes), since Win32s tries to allocate its main 'flat
530 * code/data segment' selectors with a base of 0xffff0000 (and limit 4GB).
531 * The rationale for this seems to be that they want one the one hand to
532 * be able to leave the Win 3.1 memory (starting with the main DOS memory)
533 * at linear address 0, but want at other hand to have offset 0 of the
534 * flat data/code segment point to an unmapped page (to catch NULL pointer
535 * accesses). Hence they allocate the flat segments with a base of 0xffff0000
536 * so that the Win 3.1 memory area at linear address zero shows up in the
537 * flat segments at offset 0x10000 (since linear addresses wrap around at
538 * 4GB). To compensate for that discrepancy between flat segment offsets
539 * and plain linear addresses, all flat pointers passed between the 32-bit
540 * and the 16-bit parts of Win32s are shifted by 0x10000 in the appropriate
541 * direction by the glue code (mainly) in W32SKRNL and WIN32S16.
543 * The problem for us is now that Linux does not allow a LDT selector with
544 * base 0xffff0000 to be created, since it would 'see' a part of the kernel
545 * address space. To address this problem we introduce *another* offset:
546 * We add 0x10000 to every linear address we get as an argument from Win32s.
547 * This means especially that the flat code/data selectors get actually
548 * allocated with base 0x0, so that flat offsets and (real) linear addresses
549 * do again agree! In fact, every call e.g. of a Win32s VxD service now
550 * has all pointer arguments (which are offsets in the flat data segement)
551 * first reduced by 0x10000 by the W32SKRNL glue code, and then again
552 * increased by 0x10000 by *our* code.
554 * Note that to keep everything consistent, this offset has to be applied by
555 * every Wine function that operates on 'linear addresses' passed to it by
556 * Win32s. Fortunately, since Win32s does not directly call any Wine 32-bit
557 * API routines, this affects only two locations: this VxD and the DPMI
558 * handler. (NOTE: Should any Win32s application pass a linear address to
559 * any routine apart from those, e.g. some other VxD handler, that code
560 * would have to take the offset into account as well!)
562 * The offset is set the first time any application calls the GetVersion()
563 * service of the Win32s VxD. (Note that the offset is never reset.)
567 void WINAPI VXD_Win32s( CONTEXT86 *context )
569 switch (AX_reg(context))
571 case 0x0000: /* Get Version */
573 * Input: None
575 * Output: EAX: LoWord: Win32s Version (1.30)
576 * HiWord: VxD Version (200)
578 * EBX: Build (172)
580 * ECX: ??? (1)
582 * EDX: Debugging Flags
584 * EDI: Error Flag
585 * 0 if OK,
586 * 1 if VMCPD VxD not found
589 TRACE("GetVersion()\n");
591 context->Eax = VXD_WinVersion() | (200 << 16);
592 context->Ebx = 0;
593 context->Ecx = 0;
594 context->Edx = 0;
595 context->Edi = 0;
598 * If this is the first time we are called for this process,
599 * hack the memory image of WIN32S16 so that it doesn't try
600 * to access the GDT directly ...
602 * The first code segment of WIN32S16 (version 1.30) contains
603 * an unexported function somewhere between the exported functions
604 * SetFS and StackLinearToSegmented that tries to find a selector
605 * in the LDT that maps to the memory image of the LDT itself.
606 * If it succeeds, it stores this selector into a global variable
607 * which will be used to speed up execution by using this selector
608 * to modify the LDT directly instead of using the DPMI calls.
610 * To perform this search of the LDT, this function uses the
611 * sgdt and sldt instructions to find the linear address of
612 * the (GDT and then) LDT. While those instructions themselves
613 * execute without problem, the linear address that sgdt returns
614 * points (at least under Linux) to the kernel address space, so
615 * that any subsequent access leads to a segfault.
617 * Fortunately, WIN32S16 still contains as a fallback option the
618 * mechanism of using DPMI calls to modify LDT selectors instead
619 * of direct writes to the LDT. Thus we can circumvent the problem
620 * by simply replacing the first byte of the offending function
621 * with an 'retf' instruction. This means that the global variable
622 * supposed to contain the LDT alias selector will remain zero,
623 * and hence WIN32S16 will fall back to using DPMI calls.
625 * The heuristic we employ to _find_ that function is as follows:
626 * We search between the addresses of the exported symbols SetFS
627 * and StackLinearToSegmented for the byte sequence '0F 01 04'
628 * (this is the opcode of 'sgdt [si]'). We then search backwards
629 * from this address for the last occurrence of 'CB' (retf) that marks
630 * the end of the preceeding function. The following byte (which
631 * should now be the first byte of the function we are looking for)
632 * will be replaced by 'CB' (retf).
634 * This heuristic works for the retail as well as the debug version
635 * of Win32s version 1.30. For versions earlier than that this
636 * hack should not be necessary at all, since the whole mechanism
637 * ('PERF130') was introduced only in 1.30 to improve the overall
638 * performance of Win32s.
641 if (!W32S_offset)
643 HMODULE16 hModule = GetModuleHandle16("win32s16");
644 SEGPTR func1 = (SEGPTR)GetProcAddress16(hModule, "SetFS");
645 SEGPTR func2 = (SEGPTR)GetProcAddress16(hModule, "StackLinearToSegmented");
647 if ( hModule && func1 && func2
648 && SELECTOROF(func1) == SELECTOROF(func2))
650 BYTE *start = MapSL(func1);
651 BYTE *end = MapSL(func2);
652 BYTE *p, *retv = NULL;
653 int found = 0;
655 for (p = start; p < end; p++)
656 if (*p == 0xCB) found = 0, retv = p;
657 else if (*p == 0x0F) found = 1;
658 else if (*p == 0x01 && found == 1) found = 2;
659 else if (*p == 0x04 && found == 2) { found = 3; break; }
660 else found = 0;
662 if (found == 3 && retv)
664 TRACE("PERF130 hack: "
665 "Replacing byte %02X at offset %04X:%04X\n",
666 *(retv+1), SELECTOROF(func1),
667 OFFSETOF(func1) + retv+1-start);
669 *(retv+1) = (BYTE)0xCB;
675 * Mark process as Win32s, so that subsequent DPMI calls
676 * will perform the W32S_APP2WINE/W32S_WINE2APP address shift.
678 W32S_offset = 0x10000;
679 break;
682 case 0x0001: /* Install Exception Handling */
684 * Input: EBX: Flat address of W32SKRNL Exception Data
686 * ECX: LoWord: Flat Code Selector
687 * HiWord: Flat Data Selector
689 * EDX: Flat address of W32SKRNL Exception Handler
690 * (this is equal to W32S_BackTo32 + 0x40)
692 * ESI: SEGPTR KERNEL.HASGPHANDLER
694 * EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10)
696 * Output: EAX: 0 if OK
699 TRACE("[0001] EBX=%lx ECX=%lx EDX=%lx ESI=%lx EDI=%lx\n",
700 context->Ebx, context->Ecx, context->Edx,
701 context->Esi, context->Edi);
703 /* FIXME */
705 context->Eax = 0;
706 break;
709 case 0x0002: /* Set Page Access Flags */
711 * Input: EBX: New access flags
712 * Bit 2: User Page if set, Supervisor Page if clear
713 * Bit 1: Read-Write if set, Read-Only if clear
715 * ECX: Size of memory area to change
717 * EDX: Flat start address of memory area
719 * Output: EAX: Size of area changed
722 TRACE("[0002] EBX=%lx ECX=%lx EDX=%lx\n",
723 context->Ebx, context->Ecx, context->Edx);
725 /* FIXME */
727 context->Eax = context->Ecx;
728 break;
731 case 0x0003: /* Get Page Access Flags */
733 * Input: EDX: Flat address of page to query
735 * Output: EAX: Page access flags
736 * Bit 2: User Page if set, Supervisor Page if clear
737 * Bit 1: Read-Write if set, Read-Only if clear
740 TRACE("[0003] EDX=%lx\n", context->Edx);
742 /* FIXME */
744 context->Eax = 6;
745 break;
748 case 0x0004: /* Map Module */
750 * Input: ECX: IMTE (offset in Module Table) of new module
752 * EDX: Flat address of Win32s Module Table
754 * Output: EAX: 0 if OK
757 if (!context->Edx || CX_reg(context) == 0xFFFF)
759 TRACE("MapModule: Initialization call\n");
760 context->Eax = 0;
762 else
765 * Structure of a Win32s Module Table Entry:
767 struct Win32sModule
769 DWORD flags;
770 DWORD flatBaseAddr;
771 LPCSTR moduleName;
772 LPCSTR pathName;
773 LPCSTR unknown;
774 LPBYTE baseAddr;
775 DWORD hModule;
776 DWORD relocDelta;
780 * Note: This function should set up a demand-paged memory image
781 * of the given module. Since mmap does not allow file offsets
782 * not aligned at 1024 bytes, we simply load the image fully
783 * into memory.
786 struct Win32sModule *moduleTable =
787 (struct Win32sModule *)W32S_APP2WINE(context->Edx);
788 struct Win32sModule *module = moduleTable + context->Ecx;
790 IMAGE_NT_HEADERS *nt_header = RtlImageNtHeader( (HMODULE)module->baseAddr );
791 IMAGE_SECTION_HEADER *pe_seg = (IMAGE_SECTION_HEADER*)((char *)&nt_header->OptionalHeader +
792 nt_header->FileHeader.SizeOfOptionalHeader);
795 HFILE image = _lopen(module->pathName, OF_READ);
796 BOOL error = (image == HFILE_ERROR);
797 UINT i;
799 TRACE("MapModule: Loading %s\n", module->pathName);
801 for (i = 0;
802 !error && i < nt_header->FileHeader.NumberOfSections;
803 i++, pe_seg++)
804 if(!(pe_seg->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA))
806 DWORD off = pe_seg->PointerToRawData;
807 DWORD len = pe_seg->SizeOfRawData;
808 LPBYTE addr = module->baseAddr + pe_seg->VirtualAddress;
810 TRACE("MapModule: "
811 "Section %d at %08lx from %08lx len %08lx\n",
812 i, (DWORD)addr, off, len);
814 if ( _llseek(image, off, SEEK_SET) != off
815 || _lread(image, addr, len) != len)
816 error = TRUE;
819 _lclose(image);
821 if (error)
822 ERR("MapModule: Unable to load %s\n", module->pathName);
824 else if (module->relocDelta != 0)
826 IMAGE_DATA_DIRECTORY *dir = nt_header->OptionalHeader.DataDirectory
827 + IMAGE_DIRECTORY_ENTRY_BASERELOC;
828 IMAGE_BASE_RELOCATION *r = (IMAGE_BASE_RELOCATION *)
829 (dir->Size? module->baseAddr + dir->VirtualAddress : 0);
831 TRACE("MapModule: Reloc delta %08lx\n", module->relocDelta);
833 while (r && r->VirtualAddress)
835 LPBYTE page = module->baseAddr + r->VirtualAddress;
836 WORD *TypeOffset = (WORD *)(r + 1);
837 int count = (r->SizeOfBlock - sizeof(*r)) / sizeof(*TypeOffset);
839 TRACE("MapModule: %d relocations for page %08lx\n",
840 count, (DWORD)page);
842 for(i = 0; i < count; i++)
844 int offset = TypeOffset[i] & 0xFFF;
845 int type = TypeOffset[i] >> 12;
846 switch(type)
848 case IMAGE_REL_BASED_ABSOLUTE:
849 break;
850 case IMAGE_REL_BASED_HIGH:
851 *(WORD *)(page+offset) += HIWORD(module->relocDelta);
852 break;
853 case IMAGE_REL_BASED_LOW:
854 *(WORD *)(page+offset) += LOWORD(module->relocDelta);
855 break;
856 case IMAGE_REL_BASED_HIGHLOW:
857 *(DWORD*)(page+offset) += module->relocDelta;
858 break;
859 default:
860 WARN("MapModule: Unsupported fixup type\n");
861 break;
865 r = (IMAGE_BASE_RELOCATION *)((LPBYTE)r + r->SizeOfBlock);
869 context->Eax = 0;
870 RESET_CFLAG(context);
872 break;
875 case 0x0005: /* UnMap Module */
877 * Input: EDX: Flat address of module image
879 * Output: EAX: 1 if OK
882 TRACE("UnMapModule: %lx\n", (DWORD)W32S_APP2WINE(context->Edx));
884 /* As we didn't map anything, there's nothing to unmap ... */
886 context->Eax = 1;
887 break;
890 case 0x0006: /* VirtualAlloc */
892 * Input: ECX: Current Process
894 * EDX: Flat address of arguments on stack
896 * DWORD *retv [out] Flat base address of allocated region
897 * LPVOID base [in] Flat address of region to reserve/commit
898 * DWORD size [in] Size of region
899 * DWORD type [in] Type of allocation
900 * DWORD prot [in] Type of access protection
902 * Output: EAX: NtStatus
905 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
906 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
907 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
908 DWORD size = stack[2];
909 DWORD type = stack[3];
910 DWORD prot = stack[4];
911 DWORD result;
913 TRACE("VirtualAlloc(%lx, %lx, %lx, %lx, %lx)\n",
914 (DWORD)retv, (DWORD)base, size, type, prot);
916 if (type & 0x80000000)
918 WARN("VirtualAlloc: strange type %lx\n", type);
919 type &= 0x7fffffff;
922 if (!base && (type & MEM_COMMIT) && prot == PAGE_READONLY)
924 WARN("VirtualAlloc: NLS hack, allowing write access!\n");
925 prot = PAGE_READWRITE;
928 result = (DWORD)VirtualAlloc(base, size, type, prot);
930 if (W32S_WINE2APP(result))
931 *retv = W32S_WINE2APP(result),
932 context->Eax = STATUS_SUCCESS;
933 else
934 *retv = 0,
935 context->Eax = STATUS_NO_MEMORY; /* FIXME */
937 break;
940 case 0x0007: /* VirtualFree */
942 * Input: ECX: Current Process
944 * EDX: Flat address of arguments on stack
946 * DWORD *retv [out] TRUE if success, FALSE if failure
947 * LPVOID base [in] Flat address of region
948 * DWORD size [in] Size of region
949 * DWORD type [in] Type of operation
951 * Output: EAX: NtStatus
954 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
955 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
956 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
957 DWORD size = stack[2];
958 DWORD type = stack[3];
959 DWORD result;
961 TRACE("VirtualFree(%lx, %lx, %lx, %lx)\n",
962 (DWORD)retv, (DWORD)base, size, type);
964 result = VirtualFree(base, size, type);
966 if (result)
967 *retv = TRUE,
968 context->Eax = STATUS_SUCCESS;
969 else
970 *retv = FALSE,
971 context->Eax = STATUS_NO_MEMORY; /* FIXME */
973 break;
976 case 0x0008: /* VirtualProtect */
978 * Input: ECX: Current Process
980 * EDX: Flat address of arguments on stack
982 * DWORD *retv [out] TRUE if success, FALSE if failure
983 * LPVOID base [in] Flat address of region
984 * DWORD size [in] Size of region
985 * DWORD new_prot [in] Desired access protection
986 * DWORD *old_prot [out] Previous access protection
988 * Output: EAX: NtStatus
991 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
992 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
993 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
994 DWORD size = stack[2];
995 DWORD new_prot = stack[3];
996 DWORD *old_prot = (DWORD *)W32S_APP2WINE(stack[4]);
997 DWORD result;
999 TRACE("VirtualProtect(%lx, %lx, %lx, %lx, %lx)\n",
1000 (DWORD)retv, (DWORD)base, size, new_prot, (DWORD)old_prot);
1002 result = VirtualProtect(base, size, new_prot, old_prot);
1004 if (result)
1005 *retv = TRUE,
1006 context->Eax = STATUS_SUCCESS;
1007 else
1008 *retv = FALSE,
1009 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1011 break;
1014 case 0x0009: /* VirtualQuery */
1016 * Input: ECX: Current Process
1018 * EDX: Flat address of arguments on stack
1020 * DWORD *retv [out] Nr. bytes returned
1021 * LPVOID base [in] Flat address of region
1022 * LPMEMORY_BASIC_INFORMATION info [out] Info buffer
1023 * DWORD len [in] Size of buffer
1025 * Output: EAX: NtStatus
1028 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1029 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1030 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1031 PMEMORY_BASIC_INFORMATION info =
1032 (PMEMORY_BASIC_INFORMATION)W32S_APP2WINE(stack[2]);
1033 DWORD len = stack[3];
1034 DWORD result;
1036 TRACE("VirtualQuery(%lx, %lx, %lx, %lx)\n",
1037 (DWORD)retv, (DWORD)base, (DWORD)info, len);
1039 result = VirtualQuery(base, info, len);
1041 *retv = result;
1042 context->Eax = STATUS_SUCCESS;
1044 break;
1047 case 0x000A: /* SetVirtMemProcess */
1049 * Input: ECX: Process Handle
1051 * EDX: Flat address of region
1053 * Output: EAX: NtStatus
1056 TRACE("[000a] ECX=%lx EDX=%lx\n",
1057 context->Ecx, context->Edx);
1059 /* FIXME */
1061 context->Eax = STATUS_SUCCESS;
1062 break;
1065 case 0x000B: /* ??? some kind of cleanup */
1067 * Input: ECX: Process Handle
1069 * Output: EAX: NtStatus
1072 TRACE("[000b] ECX=%lx\n", context->Ecx);
1074 /* FIXME */
1076 context->Eax = STATUS_SUCCESS;
1077 break;
1080 case 0x000C: /* Set Debug Flags */
1082 * Input: EDX: Debug Flags
1084 * Output: EDX: Previous Debug Flags
1087 FIXME("[000c] EDX=%lx\n", context->Edx);
1089 /* FIXME */
1091 context->Edx = 0;
1092 break;
1095 case 0x000D: /* NtCreateSection */
1097 * Input: EDX: Flat address of arguments on stack
1099 * HANDLE32 *retv [out] Handle of Section created
1100 * DWORD flags1 [in] (?? unknown ??)
1101 * DWORD atom [in] Name of Section to create
1102 * LARGE_INTEGER *size [in] Size of Section
1103 * DWORD protect [in] Access protection
1104 * DWORD flags2 [in] (?? unknown ??)
1105 * HFILE32 hFile [in] Handle of file to map
1106 * DWORD psp [in] (Win32s: PSP that hFile belongs to)
1108 * Output: EAX: NtStatus
1111 DWORD *stack = (DWORD *) W32S_APP2WINE(context->Edx);
1112 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]);
1113 DWORD flags1 = stack[1];
1114 DWORD atom = stack[2];
1115 LARGE_INTEGER *size = (LARGE_INTEGER *)W32S_APP2WINE(stack[3]);
1116 DWORD protect = stack[4];
1117 DWORD flags2 = stack[5];
1118 HANDLE hFile = DosFileHandleToWin32Handle(stack[6]);
1119 DWORD psp = stack[7];
1121 HANDLE result = INVALID_HANDLE_VALUE;
1122 char name[128];
1124 TRACE("NtCreateSection(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1125 (DWORD)retv, flags1, atom, (DWORD)size, protect, flags2,
1126 (DWORD)hFile, psp);
1128 if (!atom || GlobalGetAtomNameA(atom, name, sizeof(name)))
1130 TRACE("NtCreateSection: name=%s\n", atom? name : NULL);
1132 result = CreateFileMappingA(hFile, NULL, protect,
1133 size? size->s.HighPart : 0,
1134 size? size->s.LowPart : 0,
1135 atom? name : NULL);
1138 if (result == INVALID_HANDLE_VALUE)
1139 WARN("NtCreateSection: failed!\n");
1140 else
1141 TRACE("NtCreateSection: returned %lx\n", (DWORD)result);
1143 if (result != INVALID_HANDLE_VALUE)
1144 *retv = result,
1145 context->Eax = STATUS_SUCCESS;
1146 else
1147 *retv = result,
1148 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1150 break;
1153 case 0x000E: /* NtOpenSection */
1155 * Input: EDX: Flat address of arguments on stack
1157 * HANDLE32 *retv [out] Handle of Section opened
1158 * DWORD protect [in] Access protection
1159 * DWORD atom [in] Name of Section to create
1161 * Output: EAX: NtStatus
1164 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1165 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]);
1166 DWORD protect = stack[1];
1167 DWORD atom = stack[2];
1169 HANDLE result = INVALID_HANDLE_VALUE;
1170 char name[128];
1172 TRACE("NtOpenSection(%lx, %lx, %lx)\n",
1173 (DWORD)retv, protect, atom);
1175 if (atom && GlobalGetAtomNameA(atom, name, sizeof(name)))
1177 TRACE("NtOpenSection: name=%s\n", name);
1179 result = OpenFileMappingA(protect, FALSE, name);
1182 if (result == INVALID_HANDLE_VALUE)
1183 WARN("NtOpenSection: failed!\n");
1184 else
1185 TRACE("NtOpenSection: returned %lx\n", (DWORD)result);
1187 if (result != INVALID_HANDLE_VALUE)
1188 *retv = result,
1189 context->Eax = STATUS_SUCCESS;
1190 else
1191 *retv = result,
1192 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1194 break;
1197 case 0x000F: /* NtCloseSection */
1199 * Input: EDX: Flat address of arguments on stack
1201 * HANDLE32 handle [in] Handle of Section to close
1202 * DWORD *id [out] Unique ID (?? unclear ??)
1204 * Output: EAX: NtStatus
1207 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1208 HANDLE handle = (HANDLE)stack[0];
1209 DWORD *id = (DWORD *)W32S_APP2WINE(stack[1]);
1211 TRACE("NtCloseSection(%lx, %lx)\n", (DWORD)handle, (DWORD)id);
1213 CloseHandle(handle);
1214 if (id) *id = 0; /* FIXME */
1216 context->Eax = STATUS_SUCCESS;
1218 break;
1221 case 0x0010: /* NtDupSection */
1223 * Input: EDX: Flat address of arguments on stack
1225 * HANDLE32 handle [in] Handle of Section to duplicate
1227 * Output: EAX: NtStatus
1230 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1231 HANDLE handle = (HANDLE)stack[0];
1232 HANDLE new_handle;
1234 TRACE("NtDupSection(%lx)\n", (DWORD)handle);
1236 DuplicateHandle( GetCurrentProcess(), handle,
1237 GetCurrentProcess(), &new_handle,
1238 0, FALSE, DUPLICATE_SAME_ACCESS );
1239 context->Eax = STATUS_SUCCESS;
1241 break;
1244 case 0x0011: /* NtMapViewOfSection */
1246 * Input: EDX: Flat address of arguments on stack
1248 * HANDLE32 SectionHandle [in] Section to be mapped
1249 * DWORD ProcessHandle [in] Process to be mapped into
1250 * DWORD * BaseAddress [in/out] Address to be mapped at
1251 * DWORD ZeroBits [in] (?? unclear ??)
1252 * DWORD CommitSize [in] (?? unclear ??)
1253 * LARGE_INTEGER *SectionOffset [in] Offset within section
1254 * DWORD * ViewSize [in] Size of view
1255 * DWORD InheritDisposition [in] (?? unclear ??)
1256 * DWORD AllocationType [in] (?? unclear ??)
1257 * DWORD Protect [in] Access protection
1259 * Output: EAX: NtStatus
1262 DWORD * stack = (DWORD *)W32S_APP2WINE(context->Edx);
1263 HANDLE SectionHandle = (HANDLE)stack[0];
1264 DWORD ProcessHandle = stack[1]; /* ignored */
1265 DWORD * BaseAddress = (DWORD *)W32S_APP2WINE(stack[2]);
1266 DWORD ZeroBits = stack[3];
1267 DWORD CommitSize = stack[4];
1268 LARGE_INTEGER *SectionOffset = (LARGE_INTEGER *)W32S_APP2WINE(stack[5]);
1269 DWORD * ViewSize = (DWORD *)W32S_APP2WINE(stack[6]);
1270 DWORD InheritDisposition = stack[7];
1271 DWORD AllocationType = stack[8];
1272 DWORD Protect = stack[9];
1274 LPBYTE address = (LPBYTE)(BaseAddress?
1275 W32S_APP2WINE(*BaseAddress) : 0);
1276 DWORD access = 0, result;
1278 switch (Protect & ~(PAGE_GUARD|PAGE_NOCACHE))
1280 case PAGE_READONLY: access = FILE_MAP_READ; break;
1281 case PAGE_READWRITE: access = FILE_MAP_WRITE; break;
1282 case PAGE_WRITECOPY: access = FILE_MAP_COPY; break;
1284 case PAGE_EXECUTE_READ: access = FILE_MAP_READ; break;
1285 case PAGE_EXECUTE_READWRITE: access = FILE_MAP_WRITE; break;
1286 case PAGE_EXECUTE_WRITECOPY: access = FILE_MAP_COPY; break;
1289 TRACE("NtMapViewOfSection"
1290 "(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1291 (DWORD)SectionHandle, ProcessHandle, (DWORD)BaseAddress,
1292 ZeroBits, CommitSize, (DWORD)SectionOffset, (DWORD)ViewSize,
1293 InheritDisposition, AllocationType, Protect);
1294 TRACE("NtMapViewOfSection: "
1295 "base=%lx, offset=%lx, size=%lx, access=%lx\n",
1296 (DWORD)address, SectionOffset? SectionOffset->s.LowPart : 0,
1297 ViewSize? *ViewSize : 0, access);
1299 result = (DWORD)MapViewOfFileEx(SectionHandle, access,
1300 SectionOffset? SectionOffset->s.HighPart : 0,
1301 SectionOffset? SectionOffset->s.LowPart : 0,
1302 ViewSize? *ViewSize : 0, address);
1304 TRACE("NtMapViewOfSection: result=%lx\n", result);
1306 if (W32S_WINE2APP(result))
1308 if (BaseAddress) *BaseAddress = W32S_WINE2APP(result);
1309 context->Eax = STATUS_SUCCESS;
1311 else
1312 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1314 break;
1317 case 0x0012: /* NtUnmapViewOfSection */
1319 * Input: EDX: Flat address of arguments on stack
1321 * DWORD ProcessHandle [in] Process (defining address space)
1322 * LPBYTE BaseAddress [in] Base address of view to be unmapped
1324 * Output: EAX: NtStatus
1327 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1328 DWORD ProcessHandle = stack[0]; /* ignored */
1329 LPBYTE BaseAddress = (LPBYTE)W32S_APP2WINE(stack[1]);
1331 TRACE("NtUnmapViewOfSection(%lx, %lx)\n",
1332 ProcessHandle, (DWORD)BaseAddress);
1334 UnmapViewOfFile(BaseAddress);
1336 context->Eax = STATUS_SUCCESS;
1338 break;
1341 case 0x0013: /* NtFlushVirtualMemory */
1343 * Input: EDX: Flat address of arguments on stack
1345 * DWORD ProcessHandle [in] Process (defining address space)
1346 * LPBYTE *BaseAddress [in?] Base address of range to be flushed
1347 * DWORD *ViewSize [in?] Number of bytes to be flushed
1348 * DWORD *unknown [???] (?? unknown ??)
1350 * Output: EAX: NtStatus
1353 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1354 DWORD ProcessHandle = stack[0]; /* ignored */
1355 DWORD *BaseAddress = (DWORD *)W32S_APP2WINE(stack[1]);
1356 DWORD *ViewSize = (DWORD *)W32S_APP2WINE(stack[2]);
1357 DWORD *unknown = (DWORD *)W32S_APP2WINE(stack[3]);
1359 LPBYTE address = (LPBYTE)(BaseAddress? W32S_APP2WINE(*BaseAddress) : 0);
1360 DWORD size = ViewSize? *ViewSize : 0;
1362 TRACE("NtFlushVirtualMemory(%lx, %lx, %lx, %lx)\n",
1363 ProcessHandle, (DWORD)BaseAddress, (DWORD)ViewSize,
1364 (DWORD)unknown);
1365 TRACE("NtFlushVirtualMemory: base=%lx, size=%lx\n",
1366 (DWORD)address, size);
1368 FlushViewOfFile(address, size);
1370 context->Eax = STATUS_SUCCESS;
1372 break;
1375 case 0x0014: /* Get/Set Debug Registers */
1377 * Input: ECX: 0 if Get, 1 if Set
1379 * EDX: Get: Flat address of buffer to receive values of
1380 * debug registers DR0 .. DR7
1381 * Set: Flat address of buffer containing values of
1382 * debug registers DR0 .. DR7 to be set
1383 * Output: None
1386 FIXME("[0014] ECX=%lx EDX=%lx\n",
1387 context->Ecx, context->Edx);
1389 /* FIXME */
1390 break;
1393 case 0x0015: /* Set Coprocessor Emulation Flag */
1395 * Input: EDX: 0 to deactivate, 1 to activate coprocessor emulation
1397 * Output: None
1400 TRACE("[0015] EDX=%lx\n", context->Edx);
1402 /* We don't care, as we always have a coprocessor anyway */
1403 break;
1406 case 0x0016: /* Init Win32S VxD PSP */
1408 * If called to query required PSP size:
1410 * Input: EBX: 0
1411 * Output: EDX: Required size of Win32s VxD PSP
1413 * If called to initialize allocated PSP:
1415 * Input: EBX: LoWord: Selector of Win32s VxD PSP
1416 * HiWord: Paragraph of Win32s VxD PSP (DOSMEM)
1417 * Output: None
1420 if (context->Ebx == 0)
1421 context->Edx = 0x80;
1422 else
1424 PDB16 *psp = MapSL( MAKESEGPTR( BX_reg(context), 0 ));
1425 psp->nbFiles = 32;
1426 psp->fileHandlesPtr = MAKELONG(HIWORD(context->Ebx), 0x5c);
1427 memset((LPBYTE)psp + 0x5c, '\xFF', 32);
1429 break;
1432 case 0x0017: /* Set Break Point */
1434 * Input: EBX: Offset of Break Point
1435 * CX: Selector of Break Point
1437 * Output: None
1440 FIXME("[0017] EBX=%lx CX=%x\n",
1441 context->Ebx, CX_reg(context));
1443 /* FIXME */
1444 break;
1447 case 0x0018: /* VirtualLock */
1449 * Input: ECX: Current Process
1451 * EDX: Flat address of arguments on stack
1453 * DWORD *retv [out] TRUE if success, FALSE if failure
1454 * LPVOID base [in] Flat address of range to lock
1455 * DWORD size [in] Size of range
1457 * Output: EAX: NtStatus
1460 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1461 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1462 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1463 DWORD size = stack[2];
1464 DWORD result;
1466 TRACE("VirtualLock(%lx, %lx, %lx)\n",
1467 (DWORD)retv, (DWORD)base, size);
1469 result = VirtualLock(base, size);
1471 if (result)
1472 *retv = TRUE,
1473 context->Eax = STATUS_SUCCESS;
1474 else
1475 *retv = FALSE,
1476 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1478 break;
1481 case 0x0019: /* VirtualUnlock */
1483 * Input: ECX: Current Process
1485 * EDX: Flat address of arguments on stack
1487 * DWORD *retv [out] TRUE if success, FALSE if failure
1488 * LPVOID base [in] Flat address of range to unlock
1489 * DWORD size [in] Size of range
1491 * Output: EAX: NtStatus
1494 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx);
1495 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]);
1496 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]);
1497 DWORD size = stack[2];
1498 DWORD result;
1500 TRACE("VirtualUnlock(%lx, %lx, %lx)\n",
1501 (DWORD)retv, (DWORD)base, size);
1503 result = VirtualUnlock(base, size);
1505 if (result)
1506 *retv = TRUE,
1507 context->Eax = STATUS_SUCCESS;
1508 else
1509 *retv = FALSE,
1510 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1512 break;
1515 case 0x001A: /* KGetSystemInfo */
1517 * Input: None
1519 * Output: ECX: Start of sparse memory arena
1520 * EDX: End of sparse memory arena
1523 TRACE("KGetSystemInfo()\n");
1526 * Note: Win32s reserves 0GB - 2GB for Win 3.1 and uses 2GB - 4GB as
1527 * sparse memory arena. We do it the other way around, since
1528 * we have to reserve 3GB - 4GB for Linux, and thus use
1529 * 0GB - 3GB as sparse memory arena.
1531 * FIXME: What about other OSes ?
1534 context->Ecx = W32S_WINE2APP(0x00000000);
1535 context->Edx = W32S_WINE2APP(0xbfffffff);
1536 break;
1539 case 0x001B: /* KGlobalMemStat */
1541 * Input: ESI: Flat address of buffer to receive memory info
1543 * Output: None
1546 struct Win32sMemoryInfo
1548 DWORD DIPhys_Count; /* Total physical pages */
1549 DWORD DIFree_Count; /* Free physical pages */
1550 DWORD DILin_Total_Count; /* Total virtual pages (private arena) */
1551 DWORD DILin_Total_Free; /* Free virtual pages (private arena) */
1553 DWORD SparseTotal; /* Total size of sparse arena (bytes ?) */
1554 DWORD SparseFree; /* Free size of sparse arena (bytes ?) */
1557 struct Win32sMemoryInfo *info =
1558 (struct Win32sMemoryInfo *)W32S_APP2WINE(context->Esi);
1560 FIXME("KGlobalMemStat(%lx)\n", (DWORD)info);
1562 /* FIXME */
1564 break;
1567 case 0x001C: /* Enable/Disable Exceptions */
1569 * Input: ECX: 0 to disable, 1 to enable exception handling
1571 * Output: None
1574 TRACE("[001c] ECX=%lx\n", context->Ecx);
1576 /* FIXME */
1577 break;
1580 case 0x001D: /* VirtualAlloc called from 16-bit code */
1582 * Input: EDX: Segmented address of arguments on stack
1584 * LPVOID base [in] Flat address of region to reserve/commit
1585 * DWORD size [in] Size of region
1586 * DWORD type [in] Type of allocation
1587 * DWORD prot [in] Type of access protection
1589 * Output: EAX: NtStatus
1590 * EDX: Flat base address of allocated region
1593 DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) ));
1594 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]);
1595 DWORD size = stack[1];
1596 DWORD type = stack[2];
1597 DWORD prot = stack[3];
1598 DWORD result;
1600 TRACE("VirtualAlloc16(%lx, %lx, %lx, %lx)\n",
1601 (DWORD)base, size, type, prot);
1603 if (type & 0x80000000)
1605 WARN("VirtualAlloc16: strange type %lx\n", type);
1606 type &= 0x7fffffff;
1609 result = (DWORD)VirtualAlloc(base, size, type, prot);
1611 if (W32S_WINE2APP(result))
1612 context->Edx = W32S_WINE2APP(result),
1613 context->Eax = STATUS_SUCCESS;
1614 else
1615 context->Edx = 0,
1616 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1617 TRACE("VirtualAlloc16: returning base %lx\n", context->Edx);
1619 break;
1622 case 0x001E: /* VirtualFree called from 16-bit code */
1624 * Input: EDX: Segmented address of arguments on stack
1626 * LPVOID base [in] Flat address of region
1627 * DWORD size [in] Size of region
1628 * DWORD type [in] Type of operation
1630 * Output: EAX: NtStatus
1631 * EDX: TRUE if success, FALSE if failure
1634 DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) ));
1635 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]);
1636 DWORD size = stack[1];
1637 DWORD type = stack[2];
1638 DWORD result;
1640 TRACE("VirtualFree16(%lx, %lx, %lx)\n",
1641 (DWORD)base, size, type);
1643 result = VirtualFree(base, size, type);
1645 if (result)
1646 context->Edx = TRUE,
1647 context->Eax = STATUS_SUCCESS;
1648 else
1649 context->Edx = FALSE,
1650 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1652 break;
1655 case 0x001F: /* FWorkingSetSize */
1657 * Input: EDX: 0 if Get, 1 if Set
1659 * ECX: Get: Buffer to receive Working Set Size
1660 * Set: Buffer containing Working Set Size
1662 * Output: NtStatus
1665 DWORD *ptr = (DWORD *)W32S_APP2WINE(context->Ecx);
1666 BOOL set = context->Edx;
1668 TRACE("FWorkingSetSize(%lx, %lx)\n", (DWORD)ptr, (DWORD)set);
1670 if (set)
1671 /* We do it differently ... */;
1672 else
1673 *ptr = 0x100;
1675 context->Eax = STATUS_SUCCESS;
1677 break;
1680 default:
1681 VXD_BARF( context, "W32S" );