- overwrite (rather than append) the output file if we have no separator
[wine/multimedia.git] / msdos / vxd.c
blobac9f97f861848168f5f6bd1fe38e6071f153ba08
1 /*
2 * VxD emulation
4 * Copyright 1995 Anand Kumria
5 */
7 #include <fcntl.h>
8 #include <memory.h>
9 #include <sys/types.h>
10 #include <unistd.h>
11 #include "winbase.h"
12 #include "windef.h"
13 #include "wingdi.h"
14 #include "winuser.h"
15 #include "wine/winbase16.h"
16 #include "wine/winuser16.h"
17 #include "msdos.h"
18 #include "miscemu.h"
19 #include "selectors.h"
20 #include "task.h"
21 #include "process.h"
22 #include "file.h"
23 #include "debugtools.h"
25 DEFAULT_DEBUG_CHANNEL(vxd);
28 #define VXD_BARF(context,name) \
29 DPRINTF( "vxd %s: unknown/not implemented parameters:\n" \
30 "vxd %s: AX %04x, BX %04x, CX %04x, DX %04x, " \
31 "SI %04x, DI %04x, DS %04x, ES %04x\n", \
32 (name), (name), AX_reg(context), BX_reg(context), \
33 CX_reg(context), DX_reg(context), SI_reg(context), \
34 DI_reg(context), (WORD)context->SegDs, (WORD)context->SegEs )
37 static WORD VXD_WinVersion(void)
39 WORD version = LOWORD(GetVersion16());
40 return (version >> 8) | (version << 8);
43 /***********************************************************************
44 * VXD_VMM
46 void WINAPI VXD_VMM ( CONTEXT86 *context )
48 unsigned service = AX_reg(context);
50 TRACE("[%04x] VMM\n", (UINT16)service);
52 switch(service)
54 case 0x0000: /* version */
55 AX_reg(context) = VXD_WinVersion();
56 RESET_CFLAG(context);
57 break;
59 case 0x026d: /* Get_Debug_Flag '/m' */
60 case 0x026e: /* Get_Debug_Flag '/n' */
61 AL_reg(context) = 0;
62 RESET_CFLAG(context);
63 break;
65 default:
66 VXD_BARF( context, "VMM" );
70 /***********************************************************************
71 * VXD_PageFile
73 void WINAPI VXD_PageFile( CONTEXT86 *context )
75 unsigned service = AX_reg(context);
77 /* taken from Ralf Brown's Interrupt List */
79 TRACE("[%04x] PageFile\n", (UINT16)service );
81 switch(service)
83 case 0x00: /* get version, is this windows version? */
84 TRACE("returning version\n");
85 AX_reg(context) = VXD_WinVersion();
86 RESET_CFLAG(context);
87 break;
89 case 0x01: /* get swap file info */
90 TRACE("VxD PageFile: returning swap file info\n");
91 AX_reg(context) = 0x00; /* paging disabled */
92 context->Ecx = 0; /* maximum size of paging file */
93 /* FIXME: do I touch DS:SI or DS:DI? */
94 RESET_CFLAG(context);
95 break;
97 case 0x02: /* delete permanent swap on exit */
98 TRACE("VxD PageFile: supposed to delete swap\n");
99 RESET_CFLAG(context);
100 break;
102 case 0x03: /* current temporary swap file size */
103 TRACE("VxD PageFile: what is current temp. swap size\n");
104 RESET_CFLAG(context);
105 break;
107 case 0x04: /* read or write?? INTERRUP.D */
108 case 0x05: /* cancel?? INTERRUP.D */
109 case 0x06: /* test I/O valid INTERRUP.D */
110 default:
111 VXD_BARF( context, "pagefile" );
112 break;
116 /***********************************************************************
117 * VXD_Reboot
119 void WINAPI VXD_Reboot ( CONTEXT86 *context )
121 unsigned service = AX_reg(context);
123 TRACE("[%04x] Reboot\n", (UINT16)service);
125 switch(service)
127 case 0x0000: /* version */
128 AX_reg(context) = VXD_WinVersion();
129 RESET_CFLAG(context);
130 break;
132 default:
133 VXD_BARF( context, "REBOOT" );
137 /***********************************************************************
138 * VXD_VDD
140 void WINAPI VXD_VDD ( CONTEXT86 *context )
142 unsigned service = AX_reg(context);
144 TRACE("[%04x] VDD\n", (UINT16)service);
146 switch(service)
148 case 0x0000: /* version */
149 AX_reg(context) = VXD_WinVersion();
150 RESET_CFLAG(context);
151 break;
153 default:
154 VXD_BARF( context, "VDD" );
158 /***********************************************************************
159 * VXD_VMD
161 void WINAPI VXD_VMD ( CONTEXT86 *context )
163 unsigned service = AX_reg(context);
165 TRACE("[%04x] VMD\n", (UINT16)service);
167 switch(service)
169 case 0x0000: /* version */
170 AX_reg(context) = VXD_WinVersion();
171 RESET_CFLAG(context);
172 break;
174 default:
175 VXD_BARF( context, "VMD" );
179 /***********************************************************************
180 * VXD_VXDLoader
182 void WINAPI VXD_VXDLoader( CONTEXT86 *context )
184 unsigned service = AX_reg(context);
186 TRACE("[%04x] VXDLoader\n", (UINT16)service);
188 switch (service)
190 case 0x0000: /* get version */
191 TRACE("returning version\n");
192 AX_reg(context) = 0x0000;
193 DX_reg(context) = VXD_WinVersion();
194 RESET_CFLAG(context);
195 break;
197 case 0x0001: /* load device */
198 FIXME("load device %04lx:%04x (%s)\n",
199 context->SegDs, DX_reg(context),
200 debugstr_a(PTR_SEG_OFF_TO_LIN(context->SegDs, DX_reg(context))));
201 AX_reg(context) = 0x0000;
202 context->SegEs = 0x0000;
203 DI_reg(context) = 0x0000;
204 RESET_CFLAG(context);
205 break;
207 case 0x0002: /* unload device */
208 FIXME("unload device (%08lx)\n", context->Ebx);
209 AX_reg(context) = 0x0000;
210 RESET_CFLAG(context);
211 break;
213 default:
214 VXD_BARF( context, "VXDLDR" );
215 AX_reg(context) = 0x000B; /* invalid function number */
216 SET_CFLAG(context);
217 break;
221 /***********************************************************************
222 * VXD_Shell
224 void WINAPI VXD_Shell( CONTEXT86 *context )
226 unsigned service = DX_reg(context);
228 TRACE("[%04x] Shell\n", (UINT16)service);
230 switch (service) /* Ralf Brown says EDX, but I use DX instead */
232 case 0x0000:
233 TRACE("returning version\n");
234 AX_reg(context) = VXD_WinVersion();
235 context->Ebx = 1; /* system VM Handle */
236 break;
238 case 0x0001:
239 case 0x0002:
240 case 0x0003:
241 /* SHELL_SYSMODAL_Message
242 ebx virtual maschine handle
243 eax message box flags
244 ecx address of message
245 edi address of caption
246 return response in eax
248 case 0x0004:
249 /* SHELL_Message
250 ebx virtual maschine handle
251 eax message box flags
252 ecx address of message
253 edi address of caption
254 esi address callback
255 edx reference data for callback
256 return response in eax
258 case 0x0005:
259 VXD_BARF( context, "shell" );
260 break;
262 case 0x0006: /* SHELL_Get_VM_State */
263 TRACE("VxD Shell: returning VM state\n");
264 /* Actually we don't, not yet. We have to return a structure
265 * and I am not to sure how to set it up and return it yet,
266 * so for now let's do nothing. I can (hopefully) get this
267 * by the next release
269 /* RESET_CFLAG(context); */
270 break;
272 case 0x0007:
273 case 0x0008:
274 case 0x0009:
275 case 0x000A:
276 case 0x000B:
277 case 0x000C:
278 case 0x000D:
279 case 0x000E:
280 case 0x000F:
281 case 0x0010:
282 case 0x0011:
283 case 0x0012:
284 case 0x0013:
285 case 0x0014:
286 case 0x0015:
287 case 0x0016:
288 VXD_BARF( context, "SHELL" );
289 break;
291 /* the new Win95 shell API */
292 case 0x0100: /* get version */
293 AX_reg(context) = VXD_WinVersion();
294 break;
296 case 0x0104: /* retrieve Hook_Properties list */
297 case 0x0105: /* call Hook_Properties callbacks */
298 VXD_BARF( context, "SHELL" );
299 break;
301 case 0x0106: /* install timeout callback */
302 TRACE("VxD Shell: ignoring shell callback (%ld sec.)\n", context->Ebx);
303 SET_CFLAG(context);
304 break;
306 case 0x0107: /* get version of any VxD */
307 default:
308 VXD_BARF( context, "SHELL" );
309 break;
314 /***********************************************************************
315 * VXD_Comm
317 void WINAPI VXD_Comm( CONTEXT86 *context )
319 unsigned service = AX_reg(context);
321 TRACE("[%04x] Comm\n", (UINT16)service);
323 switch (service)
325 case 0x0000: /* get version */
326 TRACE("returning version\n");
327 AX_reg(context) = VXD_WinVersion();
328 RESET_CFLAG(context);
329 break;
331 case 0x0001: /* set port global */
332 case 0x0002: /* get focus */
333 case 0x0003: /* virtualise port */
334 default:
335 VXD_BARF( context, "comm" );
339 /***********************************************************************
340 * VXD_Timer
342 void WINAPI VXD_Timer( CONTEXT86 *context )
344 unsigned service = AX_reg(context);
346 TRACE("[%04x] Virtual Timer\n", (UINT16)service);
348 switch(service)
350 case 0x0000: /* version */
351 AX_reg(context) = VXD_WinVersion();
352 RESET_CFLAG(context);
353 break;
355 case 0x0100: /* clock tick time, in 840nsecs */
356 context->Eax = GetTickCount();
358 context->Edx = context->Eax >> 22;
359 context->Eax <<= 10; /* not very precise */
360 break;
362 case 0x0101: /* current Windows time, msecs */
363 case 0x0102: /* current VM time, msecs */
364 context->Eax = GetTickCount();
365 break;
367 default:
368 VXD_BARF( context, "VTD" );
372 /***********************************************************************
373 * VXD_TimerAPI
375 static DWORD System_Time = 0;
376 static WORD System_Time_Selector = 0;
377 static void System_Time_Tick( WORD timer ) { System_Time += 55; }
378 void WINAPI VXD_TimerAPI ( CONTEXT86 *context )
380 unsigned service = AX_reg(context);
382 TRACE("[%04x] TimerAPI\n", (UINT16)service);
384 switch(service)
386 case 0x0000: /* version */
387 AX_reg(context) = VXD_WinVersion();
388 RESET_CFLAG(context);
389 break;
391 case 0x0009: /* get system time selector */
392 if ( !System_Time_Selector )
394 System_Time_Selector = SELECTOR_AllocBlock( &System_Time, sizeof(DWORD), WINE_LDT_FLAGS_DATA );
395 CreateSystemTimer( 55, System_Time_Tick );
398 AX_reg(context) = System_Time_Selector;
399 RESET_CFLAG(context);
400 break;
402 default:
403 VXD_BARF( context, "VTDAPI" );
407 /***********************************************************************
408 * VXD_ConfigMG
410 void WINAPI VXD_ConfigMG ( CONTEXT86 *context )
412 unsigned service = AX_reg(context);
414 TRACE("[%04x] ConfigMG\n", (UINT16)service);
416 switch(service)
418 case 0x0000: /* version */
419 AX_reg(context) = VXD_WinVersion();
420 RESET_CFLAG(context);
421 break;
423 default:
424 VXD_BARF( context, "CONFIGMG" );
428 /***********************************************************************
429 * VXD_Enable
431 void WINAPI VXD_Enable ( CONTEXT86 *context )
433 unsigned service = AX_reg(context);
435 TRACE("[%04x] Enable\n", (UINT16)service);
437 switch(service)
439 case 0x0000: /* version */
440 AX_reg(context) = VXD_WinVersion();
441 RESET_CFLAG(context);
442 break;
444 default:
445 VXD_BARF( context, "ENABLE" );
449 /***********************************************************************
450 * VXD_APM
452 void WINAPI VXD_APM ( CONTEXT86 *context )
454 unsigned service = AX_reg(context);
456 TRACE("[%04x] APM\n", (UINT16)service);
458 switch(service)
460 case 0x0000: /* version */
461 AX_reg(context) = VXD_WinVersion();
462 RESET_CFLAG(context);
463 break;
465 default:
466 VXD_BARF( context, "APM" );
470 /***********************************************************************
471 * VXD_Win32s
473 * This is an implementation of the services of the Win32s VxD.
474 * Since official documentation of these does not seem to be available,
475 * certain arguments of some of the services remain unclear.
477 * FIXME: The following services are currently unimplemented:
478 * Exception handling (0x01, 0x1C)
479 * Debugger support (0x0C, 0x14, 0x17)
480 * Low-level memory access (0x02, 0x03, 0x0A, 0x0B)
481 * Memory Statistics (0x1B)
484 * We have a specific problem running Win32s on Linux (and probably also
485 * the other x86 unixes), since Win32s tries to allocate its main 'flat
486 * code/data segment' selectors with a base of 0xffff0000 (and limit 4GB).
487 * The rationale for this seems to be that they want one the one hand to
488 * be able to leave the Win 3.1 memory (starting with the main DOS memory)
489 * at linear address 0, but want at other hand to have offset 0 of the
490 * flat data/code segment point to an unmapped page (to catch NULL pointer
491 * accesses). Hence they allocate the flat segments with a base of 0xffff0000
492 * so that the Win 3.1 memory area at linear address zero shows up in the
493 * flat segments at offset 0x10000 (since linear addresses wrap around at
494 * 4GB). To compensate for that discrepancy between flat segment offsets
495 * and plain linear addresses, all flat pointers passed between the 32-bit
496 * and the 16-bit parts of Win32s are shifted by 0x10000 in the appropriate
497 * direction by the glue code (mainly) in W32SKRNL and WIN32S16.
499 * The problem for us is now that Linux does not allow a LDT selector with
500 * base 0xffff0000 to be created, since it would 'see' a part of the kernel
501 * address space. To address this problem we introduce *another* offset:
502 * We add 0x10000 to every linear address we get as an argument from Win32s.
503 * This means especially that the flat code/data selectors get actually
504 * allocated with base 0x0, so that flat offsets and (real) linear addresses
505 * do again agree! In fact, every call e.g. of a Win32s VxD service now
506 * has all pointer arguments (which are offsets in the flat data segement)
507 * first reduced by 0x10000 by the W32SKRNL glue code, and then again
508 * increased by 0x10000 by *our* code.
510 * Note that to keep everything consistent, this offset has to be applied by
511 * every Wine function that operates on 'linear addresses' passed to it by
512 * Win32s. Fortunately, since Win32s does not directly call any Wine 32-bit
513 * API routines, this affects only two locations: this VxD and the DPMI
514 * handler. (NOTE: Should any Win32s application pass a linear address to
515 * any routine apart from those, e.g. some other VxD handler, that code
516 * would have to take the offset into account as well!)
518 * The application of the offset is triggered by marking the current process
519 * as a Win32s process by setting the PDB32_WIN32S_PROC flag in the process
520 * database. This is done the first time any application calls the GetVersion()
521 * service of the Win32s VxD. (Note that the flag is never removed.)
525 void WINAPI VXD_Win32s( CONTEXT86 *context )
527 switch (AX_reg(context))
529 case 0x0000: /* Get Version */
531 * Input: None
533 * Output: EAX: LoWord: Win32s Version (1.30)
534 * HiWord: VxD Version (200)
536 * EBX: Build (172)
538 * ECX: ??? (1)
540 * EDX: Debugging Flags
542 * EDI: Error Flag
543 * 0 if OK,
544 * 1 if VMCPD VxD not found
547 TRACE("GetVersion()\n");
549 context->Eax = VXD_WinVersion() | (200 << 16);
550 context->Ebx = 0;
551 context->Ecx = 0;
552 context->Edx = 0;
553 context->Edi = 0;
556 * If this is the first time we are called for this process,
557 * hack the memory image of WIN32S16 so that it doesn't try
558 * to access the GDT directly ...
560 * The first code segment of WIN32S16 (version 1.30) contains
561 * an unexported function somewhere between the exported functions
562 * SetFS and StackLinearToSegmented that tries to find a selector
563 * in the LDT that maps to the memory image of the LDT itself.
564 * If it succeeds, it stores this selector into a global variable
565 * which will be used to speed up execution by using this selector
566 * to modify the LDT directly instead of using the DPMI calls.
568 * To perform this search of the LDT, this function uses the
569 * sgdt and sldt instructions to find the linear address of
570 * the (GDT and then) LDT. While those instructions themselves
571 * execute without problem, the linear address that sgdt returns
572 * points (at least under Linux) to the kernel address space, so
573 * that any subsequent access leads to a segfault.
575 * Fortunately, WIN32S16 still contains as a fallback option the
576 * mechanism of using DPMI calls to modify LDT selectors instead
577 * of direct writes to the LDT. Thus we can circumvent the problem
578 * by simply replacing the first byte of the offending function
579 * with an 'retf' instruction. This means that the global variable
580 * supposed to contain the LDT alias selector will remain zero,
581 * and hence WIN32S16 will fall back to using DPMI calls.
583 * The heuristic we employ to _find_ that function is as follows:
584 * We search between the addresses of the exported symbols SetFS
585 * and StackLinearToSegmented for the byte sequence '0F 01 04'
586 * (this is the opcode of 'sgdt [si]'). We then search backwards
587 * from this address for the last occurrance of 'CB' (retf) that marks
588 * the end of the preceeding function. The following byte (which
589 * should now be the first byte of the function we are looking for)
590 * will be replaced by 'CB' (retf).
592 * This heuristic works for the retail as well as the debug version
593 * of Win32s version 1.30. For versions earlier than that this
594 * hack should not be necessary at all, since the whole mechanism
595 * ('PERF130') was introduced only in 1.30 to improve the overall
596 * performance of Win32s.
599 if (!(PROCESS_Current()->flags & PDB32_WIN32S_PROC))
601 HMODULE16 hModule = GetModuleHandle16("win32s16");
602 SEGPTR func1 = (SEGPTR)GetProcAddress16(hModule, "SetFS");
603 SEGPTR func2 = (SEGPTR)GetProcAddress16(hModule, "StackLinearToSegmented");
605 if ( hModule && func1 && func2
606 && SELECTOROF(func1) == SELECTOROF(func2))
608 BYTE *start = PTR_SEG_TO_LIN(func1);
609 BYTE *end = PTR_SEG_TO_LIN(func2);
610 BYTE *p, *retv = NULL;
611 int found = 0;
613 for (p = start; p < end; p++)
614 if (*p == 0xCB) found = 0, retv = p;
615 else if (*p == 0x0F) found = 1;
616 else if (*p == 0x01 && found == 1) found = 2;
617 else if (*p == 0x04 && found == 2) { found = 3; break; }
618 else found = 0;
620 if (found == 3 && retv)
622 TRACE("PERF130 hack: "
623 "Replacing byte %02X at offset %04X:%04X\n",
624 *(retv+1), SELECTOROF(func1),
625 OFFSETOF(func1) + retv+1-start);
627 *(retv+1) = (BYTE)0xCB;
633 * Mark process as Win32s, so that subsequent DPMI calls
634 * will perform the W32S_APP2WINE/W32S_WINE2APP address shift.
637 PROCESS_Current()->flags |= PDB32_WIN32S_PROC;
638 break;
641 case 0x0001: /* Install Exception Handling */
643 * Input: EBX: Flat address of W32SKRNL Exception Data
645 * ECX: LoWord: Flat Code Selector
646 * HiWord: Flat Data Selector
648 * EDX: Flat address of W32SKRNL Exception Handler
649 * (this is equal to W32S_BackTo32 + 0x40)
651 * ESI: SEGPTR KERNEL.HASGPHANDLER
653 * EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10)
655 * Output: EAX: 0 if OK
658 TRACE("[0001] EBX=%lx ECX=%lx EDX=%lx ESI=%lx EDI=%lx\n",
659 context->Ebx, context->Ecx, context->Edx,
660 context->Esi, context->Edi);
662 /* FIXME */
664 context->Eax = 0;
665 break;
668 case 0x0002: /* Set Page Access Flags */
670 * Input: EBX: New access flags
671 * Bit 2: User Page if set, Supervisor Page if clear
672 * Bit 1: Read-Write if set, Read-Only if clear
674 * ECX: Size of memory area to change
676 * EDX: Flat start address of memory area
678 * Output: EAX: Size of area changed
681 TRACE("[0002] EBX=%lx ECX=%lx EDX=%lx\n",
682 context->Ebx, context->Ecx, context->Edx);
684 /* FIXME */
686 context->Eax = context->Ecx;
687 break;
690 case 0x0003: /* Get Page Access Flags */
692 * Input: EDX: Flat address of page to query
694 * Output: EAX: Page access flags
695 * Bit 2: User Page if set, Supervisor Page if clear
696 * Bit 1: Read-Write if set, Read-Only if clear
699 TRACE("[0003] EDX=%lx\n", context->Edx);
701 /* FIXME */
703 context->Eax = 6;
704 break;
707 case 0x0004: /* Map Module */
709 * Input: ECX: IMTE (offset in Module Table) of new module
711 * EDX: Flat address of Win32s Module Table
713 * Output: EAX: 0 if OK
716 if (!context->Edx || CX_reg(context) == 0xFFFF)
718 TRACE("MapModule: Initialization call\n");
719 context->Eax = 0;
721 else
724 * Structure of a Win32s Module Table Entry:
726 struct Win32sModule
728 DWORD flags;
729 DWORD flatBaseAddr;
730 LPCSTR moduleName;
731 LPCSTR pathName;
732 LPCSTR unknown;
733 LPBYTE baseAddr;
734 DWORD hModule;
735 DWORD relocDelta;
739 * Note: This function should set up a demand-paged memory image
740 * of the given module. Since mmap does not allow file offsets
741 * not aligned at 1024 bytes, we simply load the image fully
742 * into memory.
745 struct Win32sModule *moduleTable =
746 (struct Win32sModule *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
747 struct Win32sModule *module = moduleTable + context->Ecx;
749 IMAGE_NT_HEADERS *nt_header = PE_HEADER(module->baseAddr);
750 IMAGE_SECTION_HEADER *pe_seg = PE_SECTIONS(module->baseAddr);
752 HFILE image = _lopen(module->pathName, OF_READ);
753 BOOL error = (image == HFILE_ERROR);
754 UINT i;
756 TRACE("MapModule: Loading %s\n", module->pathName);
758 for (i = 0;
759 !error && i < nt_header->FileHeader.NumberOfSections;
760 i++, pe_seg++)
761 if(!(pe_seg->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA))
763 DWORD off = pe_seg->PointerToRawData;
764 DWORD len = pe_seg->SizeOfRawData;
765 LPBYTE addr = module->baseAddr + pe_seg->VirtualAddress;
767 TRACE("MapModule: "
768 "Section %d at %08lx from %08lx len %08lx\n",
769 i, (DWORD)addr, off, len);
771 if ( _llseek(image, off, SEEK_SET) != off
772 || _lread(image, addr, len) != len)
773 error = TRUE;
776 _lclose(image);
778 if (error)
779 ERR("MapModule: Unable to load %s\n", module->pathName);
781 else if (module->relocDelta != 0)
783 IMAGE_DATA_DIRECTORY *dir = nt_header->OptionalHeader.DataDirectory
784 + IMAGE_DIRECTORY_ENTRY_BASERELOC;
785 IMAGE_BASE_RELOCATION *r = (IMAGE_BASE_RELOCATION *)
786 (dir->Size? module->baseAddr + dir->VirtualAddress : 0);
788 TRACE("MapModule: Reloc delta %08lx\n", module->relocDelta);
790 while (r && r->VirtualAddress)
792 LPBYTE page = module->baseAddr + r->VirtualAddress;
793 int count = (r->SizeOfBlock - 8) / 2;
795 TRACE("MapModule: %d relocations for page %08lx\n",
796 count, (DWORD)page);
798 for(i = 0; i < count; i++)
800 int offset = r->TypeOffset[i] & 0xFFF;
801 int type = r->TypeOffset[i] >> 12;
802 switch(type)
804 case IMAGE_REL_BASED_ABSOLUTE:
805 break;
806 case IMAGE_REL_BASED_HIGH:
807 *(WORD *)(page+offset) += HIWORD(module->relocDelta);
808 break;
809 case IMAGE_REL_BASED_LOW:
810 *(WORD *)(page+offset) += LOWORD(module->relocDelta);
811 break;
812 case IMAGE_REL_BASED_HIGHLOW:
813 *(DWORD*)(page+offset) += module->relocDelta;
814 break;
815 default:
816 WARN("MapModule: Unsupported fixup type\n");
817 break;
821 r = (IMAGE_BASE_RELOCATION *)((LPBYTE)r + r->SizeOfBlock);
825 context->Eax = 0;
826 RESET_CFLAG(context);
828 break;
831 case 0x0005: /* UnMap Module */
833 * Input: EDX: Flat address of module image
835 * Output: EAX: 1 if OK
838 TRACE("UnMapModule: %lx\n", (DWORD)W32S_APP2WINE(context->Edx, W32S_OFFSET));
840 /* As we didn't map anything, there's nothing to unmap ... */
842 context->Eax = 1;
843 break;
846 case 0x0006: /* VirtualAlloc */
848 * Input: ECX: Current Process
850 * EDX: Flat address of arguments on stack
852 * DWORD *retv [out] Flat base address of allocated region
853 * LPVOID base [in] Flat address of region to reserve/commit
854 * DWORD size [in] Size of region
855 * DWORD type [in] Type of allocation
856 * DWORD prot [in] Type of access protection
858 * Output: EAX: NtStatus
861 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
862 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
863 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
864 DWORD size = stack[2];
865 DWORD type = stack[3];
866 DWORD prot = stack[4];
867 DWORD result;
869 TRACE("VirtualAlloc(%lx, %lx, %lx, %lx, %lx)\n",
870 (DWORD)retv, (DWORD)base, size, type, prot);
872 if (type & 0x80000000)
874 WARN("VirtualAlloc: strange type %lx\n", type);
875 type &= 0x7fffffff;
878 if (!base && (type & MEM_COMMIT) && prot == PAGE_READONLY)
880 WARN("VirtualAlloc: NLS hack, allowing write access!\n");
881 prot = PAGE_READWRITE;
884 result = (DWORD)VirtualAlloc(base, size, type, prot);
886 if (W32S_WINE2APP(result, W32S_OFFSET))
887 *retv = W32S_WINE2APP(result, W32S_OFFSET),
888 context->Eax = STATUS_SUCCESS;
889 else
890 *retv = 0,
891 context->Eax = STATUS_NO_MEMORY; /* FIXME */
893 break;
896 case 0x0007: /* VirtualFree */
898 * Input: ECX: Current Process
900 * EDX: Flat address of arguments on stack
902 * DWORD *retv [out] TRUE if success, FALSE if failure
903 * LPVOID base [in] Flat address of region
904 * DWORD size [in] Size of region
905 * DWORD type [in] Type of operation
907 * Output: EAX: NtStatus
910 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
911 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
912 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
913 DWORD size = stack[2];
914 DWORD type = stack[3];
915 DWORD result;
917 TRACE("VirtualFree(%lx, %lx, %lx, %lx)\n",
918 (DWORD)retv, (DWORD)base, size, type);
920 result = VirtualFree(base, size, type);
922 if (result)
923 *retv = TRUE,
924 context->Eax = STATUS_SUCCESS;
925 else
926 *retv = FALSE,
927 context->Eax = STATUS_NO_MEMORY; /* FIXME */
929 break;
932 case 0x0008: /* VirtualProtect */
934 * Input: ECX: Current Process
936 * EDX: Flat address of arguments on stack
938 * DWORD *retv [out] TRUE if success, FALSE if failure
939 * LPVOID base [in] Flat address of region
940 * DWORD size [in] Size of region
941 * DWORD new_prot [in] Desired access protection
942 * DWORD *old_prot [out] Previous access protection
944 * Output: EAX: NtStatus
947 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
948 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
949 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
950 DWORD size = stack[2];
951 DWORD new_prot = stack[3];
952 DWORD *old_prot = (DWORD *)W32S_APP2WINE(stack[4], W32S_OFFSET);
953 DWORD result;
955 TRACE("VirtualProtect(%lx, %lx, %lx, %lx, %lx)\n",
956 (DWORD)retv, (DWORD)base, size, new_prot, (DWORD)old_prot);
958 result = VirtualProtect(base, size, new_prot, old_prot);
960 if (result)
961 *retv = TRUE,
962 context->Eax = STATUS_SUCCESS;
963 else
964 *retv = FALSE,
965 context->Eax = STATUS_NO_MEMORY; /* FIXME */
967 break;
970 case 0x0009: /* VirtualQuery */
972 * Input: ECX: Current Process
974 * EDX: Flat address of arguments on stack
976 * DWORD *retv [out] Nr. bytes returned
977 * LPVOID base [in] Flat address of region
978 * LPMEMORY_BASIC_INFORMATION info [out] Info buffer
979 * DWORD len [in] Size of buffer
981 * Output: EAX: NtStatus
984 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
985 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
986 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
987 LPMEMORY_BASIC_INFORMATION info =
988 (LPMEMORY_BASIC_INFORMATION)W32S_APP2WINE(stack[2], W32S_OFFSET);
989 DWORD len = stack[3];
990 DWORD result;
992 TRACE("VirtualQuery(%lx, %lx, %lx, %lx)\n",
993 (DWORD)retv, (DWORD)base, (DWORD)info, len);
995 result = VirtualQuery(base, info, len);
997 *retv = result;
998 context->Eax = STATUS_SUCCESS;
1000 break;
1003 case 0x000A: /* SetVirtMemProcess */
1005 * Input: ECX: Process Handle
1007 * EDX: Flat address of region
1009 * Output: EAX: NtStatus
1012 TRACE("[000a] ECX=%lx EDX=%lx\n",
1013 context->Ecx, context->Edx);
1015 /* FIXME */
1017 context->Eax = STATUS_SUCCESS;
1018 break;
1021 case 0x000B: /* ??? some kind of cleanup */
1023 * Input: ECX: Process Handle
1025 * Output: EAX: NtStatus
1028 TRACE("[000b] ECX=%lx\n", context->Ecx);
1030 /* FIXME */
1032 context->Eax = STATUS_SUCCESS;
1033 break;
1036 case 0x000C: /* Set Debug Flags */
1038 * Input: EDX: Debug Flags
1040 * Output: EDX: Previous Debug Flags
1043 FIXME("[000c] EDX=%lx\n", context->Edx);
1045 /* FIXME */
1047 context->Edx = 0;
1048 break;
1051 case 0x000D: /* NtCreateSection */
1053 * Input: EDX: Flat address of arguments on stack
1055 * HANDLE32 *retv [out] Handle of Section created
1056 * DWORD flags1 [in] (?? unknown ??)
1057 * DWORD atom [in] Name of Section to create
1058 * LARGE_INTEGER *size [in] Size of Section
1059 * DWORD protect [in] Access protection
1060 * DWORD flags2 [in] (?? unknown ??)
1061 * HFILE32 hFile [in] Handle of file to map
1062 * DWORD psp [in] (Win32s: PSP that hFile belongs to)
1064 * Output: EAX: NtStatus
1067 DWORD *stack = (DWORD *) W32S_APP2WINE(context->Edx, W32S_OFFSET);
1068 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1069 DWORD flags1 = stack[1];
1070 DWORD atom = stack[2];
1071 LARGE_INTEGER *size = (LARGE_INTEGER *)W32S_APP2WINE(stack[3], W32S_OFFSET);
1072 DWORD protect = stack[4];
1073 DWORD flags2 = stack[5];
1074 HANDLE hFile = DosFileHandleToWin32Handle(stack[6]);
1075 DWORD psp = stack[7];
1077 HANDLE result = INVALID_HANDLE_VALUE;
1078 char name[128];
1080 TRACE("NtCreateSection(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1081 (DWORD)retv, flags1, atom, (DWORD)size, protect, flags2,
1082 (DWORD)hFile, psp);
1084 if (!atom || GlobalGetAtomNameA(atom, name, sizeof(name)))
1086 TRACE("NtCreateSection: name=%s\n", atom? name : NULL);
1088 result = CreateFileMappingA(hFile, NULL, protect,
1089 size? size->s.HighPart : 0,
1090 size? size->s.LowPart : 0,
1091 atom? name : NULL);
1094 if (result == INVALID_HANDLE_VALUE)
1095 WARN("NtCreateSection: failed!\n");
1096 else
1097 TRACE("NtCreateSection: returned %lx\n", (DWORD)result);
1099 if (result != INVALID_HANDLE_VALUE)
1100 *retv = result,
1101 context->Eax = STATUS_SUCCESS;
1102 else
1103 *retv = result,
1104 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1106 break;
1109 case 0x000E: /* NtOpenSection */
1111 * Input: EDX: Flat address of arguments on stack
1113 * HANDLE32 *retv [out] Handle of Section opened
1114 * DWORD protect [in] Access protection
1115 * DWORD atom [in] Name of Section to create
1117 * Output: EAX: NtStatus
1120 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
1121 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1122 DWORD protect = stack[1];
1123 DWORD atom = stack[2];
1125 HANDLE result = INVALID_HANDLE_VALUE;
1126 char name[128];
1128 TRACE("NtOpenSection(%lx, %lx, %lx)\n",
1129 (DWORD)retv, protect, atom);
1131 if (atom && GlobalGetAtomNameA(atom, name, sizeof(name)))
1133 TRACE("NtOpenSection: name=%s\n", name);
1135 result = OpenFileMappingA(protect, FALSE, name);
1138 if (result == INVALID_HANDLE_VALUE)
1139 WARN("NtOpenSection: failed!\n");
1140 else
1141 TRACE("NtOpenSection: 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 0x000F: /* NtCloseSection */
1155 * Input: EDX: Flat address of arguments on stack
1157 * HANDLE32 handle [in] Handle of Section to close
1158 * DWORD *id [out] Unique ID (?? unclear ??)
1160 * Output: EAX: NtStatus
1163 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
1164 HANDLE handle = stack[0];
1165 DWORD *id = (DWORD *)W32S_APP2WINE(stack[1], W32S_OFFSET);
1167 TRACE("NtCloseSection(%lx, %lx)\n", (DWORD)handle, (DWORD)id);
1169 CloseHandle(handle);
1170 if (id) *id = 0; /* FIXME */
1172 context->Eax = STATUS_SUCCESS;
1174 break;
1177 case 0x0010: /* NtDupSection */
1179 * Input: EDX: Flat address of arguments on stack
1181 * HANDLE32 handle [in] Handle of Section to duplicate
1183 * Output: EAX: NtStatus
1186 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
1187 HANDLE handle = stack[0];
1188 HANDLE new_handle;
1190 TRACE("NtDupSection(%lx)\n", (DWORD)handle);
1192 DuplicateHandle( GetCurrentProcess(), handle,
1193 GetCurrentProcess(), &new_handle,
1194 0, FALSE, DUPLICATE_SAME_ACCESS );
1195 context->Eax = STATUS_SUCCESS;
1197 break;
1200 case 0x0011: /* NtMapViewOfSection */
1202 * Input: EDX: Flat address of arguments on stack
1204 * HANDLE32 SectionHandle [in] Section to be mapped
1205 * DWORD ProcessHandle [in] Process to be mapped into
1206 * DWORD * BaseAddress [in/out] Address to be mapped at
1207 * DWORD ZeroBits [in] (?? unclear ??)
1208 * DWORD CommitSize [in] (?? unclear ??)
1209 * LARGE_INTEGER *SectionOffset [in] Offset within section
1210 * DWORD * ViewSize [in] Size of view
1211 * DWORD InheritDisposition [in] (?? unclear ??)
1212 * DWORD AllocationType [in] (?? unclear ??)
1213 * DWORD Protect [in] Access protection
1215 * Output: EAX: NtStatus
1218 DWORD * stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
1219 HANDLE SectionHandle = stack[0];
1220 DWORD ProcessHandle = stack[1]; /* ignored */
1221 DWORD * BaseAddress = (DWORD *)W32S_APP2WINE(stack[2], W32S_OFFSET);
1222 DWORD ZeroBits = stack[3];
1223 DWORD CommitSize = stack[4];
1224 LARGE_INTEGER *SectionOffset = (LARGE_INTEGER *)W32S_APP2WINE(stack[5], W32S_OFFSET);
1225 DWORD * ViewSize = (DWORD *)W32S_APP2WINE(stack[6], W32S_OFFSET);
1226 DWORD InheritDisposition = stack[7];
1227 DWORD AllocationType = stack[8];
1228 DWORD Protect = stack[9];
1230 LPBYTE address = (LPBYTE)(BaseAddress?
1231 W32S_APP2WINE(*BaseAddress, W32S_OFFSET) : 0);
1232 DWORD access = 0, result;
1234 switch (Protect & ~(PAGE_GUARD|PAGE_NOCACHE))
1236 case PAGE_READONLY: access = FILE_MAP_READ; break;
1237 case PAGE_READWRITE: access = FILE_MAP_WRITE; break;
1238 case PAGE_WRITECOPY: access = FILE_MAP_COPY; break;
1240 case PAGE_EXECUTE_READ: access = FILE_MAP_READ; break;
1241 case PAGE_EXECUTE_READWRITE: access = FILE_MAP_WRITE; break;
1242 case PAGE_EXECUTE_WRITECOPY: access = FILE_MAP_COPY; break;
1245 TRACE("NtMapViewOfSection"
1246 "(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1247 (DWORD)SectionHandle, ProcessHandle, (DWORD)BaseAddress,
1248 ZeroBits, CommitSize, (DWORD)SectionOffset, (DWORD)ViewSize,
1249 InheritDisposition, AllocationType, Protect);
1250 TRACE("NtMapViewOfSection: "
1251 "base=%lx, offset=%lx, size=%lx, access=%lx\n",
1252 (DWORD)address, SectionOffset? SectionOffset->s.LowPart : 0,
1253 ViewSize? *ViewSize : 0, access);
1255 result = (DWORD)MapViewOfFileEx(SectionHandle, access,
1256 SectionOffset? SectionOffset->s.HighPart : 0,
1257 SectionOffset? SectionOffset->s.LowPart : 0,
1258 ViewSize? *ViewSize : 0, address);
1260 TRACE("NtMapViewOfSection: result=%lx\n", result);
1262 if (W32S_WINE2APP(result, W32S_OFFSET))
1264 if (BaseAddress) *BaseAddress = W32S_WINE2APP(result, W32S_OFFSET);
1265 context->Eax = STATUS_SUCCESS;
1267 else
1268 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1270 break;
1273 case 0x0012: /* NtUnmapViewOfSection */
1275 * Input: EDX: Flat address of arguments on stack
1277 * DWORD ProcessHandle [in] Process (defining address space)
1278 * LPBYTE BaseAddress [in] Base address of view to be unmapped
1280 * Output: EAX: NtStatus
1283 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
1284 DWORD ProcessHandle = stack[0]; /* ignored */
1285 LPBYTE BaseAddress = (LPBYTE)W32S_APP2WINE(stack[1], W32S_OFFSET);
1287 TRACE("NtUnmapViewOfSection(%lx, %lx)\n",
1288 ProcessHandle, (DWORD)BaseAddress);
1290 UnmapViewOfFile(BaseAddress);
1292 context->Eax = STATUS_SUCCESS;
1294 break;
1297 case 0x0013: /* NtFlushVirtualMemory */
1299 * Input: EDX: Flat address of arguments on stack
1301 * DWORD ProcessHandle [in] Process (defining address space)
1302 * LPBYTE *BaseAddress [in?] Base address of range to be flushed
1303 * DWORD *ViewSize [in?] Number of bytes to be flushed
1304 * DWORD *unknown [???] (?? unknown ??)
1306 * Output: EAX: NtStatus
1309 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
1310 DWORD ProcessHandle = stack[0]; /* ignored */
1311 DWORD *BaseAddress = (DWORD *)W32S_APP2WINE(stack[1], W32S_OFFSET);
1312 DWORD *ViewSize = (DWORD *)W32S_APP2WINE(stack[2], W32S_OFFSET);
1313 DWORD *unknown = (DWORD *)W32S_APP2WINE(stack[3], W32S_OFFSET);
1315 LPBYTE address = (LPBYTE)(BaseAddress? W32S_APP2WINE(*BaseAddress, W32S_OFFSET) : 0);
1316 DWORD size = ViewSize? *ViewSize : 0;
1318 TRACE("NtFlushVirtualMemory(%lx, %lx, %lx, %lx)\n",
1319 ProcessHandle, (DWORD)BaseAddress, (DWORD)ViewSize,
1320 (DWORD)unknown);
1321 TRACE("NtFlushVirtualMemory: base=%lx, size=%lx\n",
1322 (DWORD)address, size);
1324 FlushViewOfFile(address, size);
1326 context->Eax = STATUS_SUCCESS;
1328 break;
1331 case 0x0014: /* Get/Set Debug Registers */
1333 * Input: ECX: 0 if Get, 1 if Set
1335 * EDX: Get: Flat address of buffer to receive values of
1336 * debug registers DR0 .. DR7
1337 * Set: Flat address of buffer containing values of
1338 * debug registers DR0 .. DR7 to be set
1339 * Output: None
1342 FIXME("[0014] ECX=%lx EDX=%lx\n",
1343 context->Ecx, context->Edx);
1345 /* FIXME */
1346 break;
1349 case 0x0015: /* Set Coprocessor Emulation Flag */
1351 * Input: EDX: 0 to deactivate, 1 to activate coprocessor emulation
1353 * Output: None
1356 TRACE("[0015] EDX=%lx\n", context->Edx);
1358 /* We don't care, as we always have a coprocessor anyway */
1359 break;
1362 case 0x0016: /* Init Win32S VxD PSP */
1364 * If called to query required PSP size:
1366 * Input: EBX: 0
1367 * Output: EDX: Required size of Win32s VxD PSP
1369 * If called to initialize allocated PSP:
1371 * Input: EBX: LoWord: Selector of Win32s VxD PSP
1372 * HiWord: Paragraph of Win32s VxD PSP (DOSMEM)
1373 * Output: None
1376 if (context->Ebx == 0)
1377 context->Edx = 0x80;
1378 else
1380 PDB16 *psp = PTR_SEG_OFF_TO_LIN(BX_reg(context), 0);
1381 psp->nbFiles = 32;
1382 psp->fileHandlesPtr = MAKELONG(HIWORD(context->Ebx), 0x5c);
1383 memset((LPBYTE)psp + 0x5c, '\xFF', 32);
1385 break;
1388 case 0x0017: /* Set Break Point */
1390 * Input: EBX: Offset of Break Point
1391 * CX: Selector of Break Point
1393 * Output: None
1396 FIXME("[0017] EBX=%lx CX=%x\n",
1397 context->Ebx, CX_reg(context));
1399 /* FIXME */
1400 break;
1403 case 0x0018: /* VirtualLock */
1405 * Input: ECX: Current Process
1407 * EDX: Flat address of arguments on stack
1409 * DWORD *retv [out] TRUE if success, FALSE if failure
1410 * LPVOID base [in] Flat address of range to lock
1411 * DWORD size [in] Size of range
1413 * Output: EAX: NtStatus
1416 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
1417 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1418 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
1419 DWORD size = stack[2];
1420 DWORD result;
1422 TRACE("VirtualLock(%lx, %lx, %lx)\n",
1423 (DWORD)retv, (DWORD)base, size);
1425 result = VirtualLock(base, size);
1427 if (result)
1428 *retv = TRUE,
1429 context->Eax = STATUS_SUCCESS;
1430 else
1431 *retv = FALSE,
1432 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1434 break;
1437 case 0x0019: /* VirtualUnlock */
1439 * Input: ECX: Current Process
1441 * EDX: Flat address of arguments on stack
1443 * DWORD *retv [out] TRUE if success, FALSE if failure
1444 * LPVOID base [in] Flat address of range to unlock
1445 * DWORD size [in] Size of range
1447 * Output: EAX: NtStatus
1450 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
1451 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1452 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
1453 DWORD size = stack[2];
1454 DWORD result;
1456 TRACE("VirtualUnlock(%lx, %lx, %lx)\n",
1457 (DWORD)retv, (DWORD)base, size);
1459 result = VirtualUnlock(base, size);
1461 if (result)
1462 *retv = TRUE,
1463 context->Eax = STATUS_SUCCESS;
1464 else
1465 *retv = FALSE,
1466 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1468 break;
1471 case 0x001A: /* KGetSystemInfo */
1473 * Input: None
1475 * Output: ECX: Start of sparse memory arena
1476 * EDX: End of sparse memory arena
1479 TRACE("KGetSystemInfo()\n");
1482 * Note: Win32s reserves 0GB - 2GB for Win 3.1 and uses 2GB - 4GB as
1483 * sparse memory arena. We do it the other way around, since
1484 * we have to reserve 3GB - 4GB for Linux, and thus use
1485 * 0GB - 3GB as sparse memory arena.
1487 * FIXME: What about other OSes ?
1490 context->Ecx = W32S_WINE2APP(0x00000000, W32S_OFFSET);
1491 context->Edx = W32S_WINE2APP(0xbfffffff, W32S_OFFSET);
1492 break;
1495 case 0x001B: /* KGlobalMemStat */
1497 * Input: ESI: Flat address of buffer to receive memory info
1499 * Output: None
1502 struct Win32sMemoryInfo
1504 DWORD DIPhys_Count; /* Total physical pages */
1505 DWORD DIFree_Count; /* Free physical pages */
1506 DWORD DILin_Total_Count; /* Total virtual pages (private arena) */
1507 DWORD DILin_Total_Free; /* Free virtual pages (private arena) */
1509 DWORD SparseTotal; /* Total size of sparse arena (bytes ?) */
1510 DWORD SparseFree; /* Free size of sparse arena (bytes ?) */
1513 struct Win32sMemoryInfo *info =
1514 (struct Win32sMemoryInfo *)W32S_APP2WINE(context->Esi, W32S_OFFSET);
1516 FIXME("KGlobalMemStat(%lx)\n", (DWORD)info);
1518 /* FIXME */
1520 break;
1523 case 0x001C: /* Enable/Disable Exceptions */
1525 * Input: ECX: 0 to disable, 1 to enable exception handling
1527 * Output: None
1530 TRACE("[001c] ECX=%lx\n", context->Ecx);
1532 /* FIXME */
1533 break;
1536 case 0x001D: /* VirtualAlloc called from 16-bit code */
1538 * Input: EDX: Segmented address of arguments on stack
1540 * LPVOID base [in] Flat address of region to reserve/commit
1541 * DWORD size [in] Size of region
1542 * DWORD type [in] Type of allocation
1543 * DWORD prot [in] Type of access protection
1545 * Output: EAX: NtStatus
1546 * EDX: Flat base address of allocated region
1549 DWORD *stack = PTR_SEG_OFF_TO_LIN(LOWORD(context->Edx),
1550 HIWORD(context->Edx));
1551 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0], W32S_OFFSET);
1552 DWORD size = stack[1];
1553 DWORD type = stack[2];
1554 DWORD prot = stack[3];
1555 DWORD result;
1557 TRACE("VirtualAlloc16(%lx, %lx, %lx, %lx)\n",
1558 (DWORD)base, size, type, prot);
1560 if (type & 0x80000000)
1562 WARN("VirtualAlloc16: strange type %lx\n", type);
1563 type &= 0x7fffffff;
1566 result = (DWORD)VirtualAlloc(base, size, type, prot);
1568 if (W32S_WINE2APP(result, W32S_OFFSET))
1569 context->Edx = W32S_WINE2APP(result, W32S_OFFSET),
1570 context->Eax = STATUS_SUCCESS;
1571 else
1572 context->Edx = 0,
1573 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1574 TRACE("VirtualAlloc16: returning base %lx\n", context->Edx);
1576 break;
1579 case 0x001E: /* VirtualFree called from 16-bit code */
1581 * Input: EDX: Segmented address of arguments on stack
1583 * LPVOID base [in] Flat address of region
1584 * DWORD size [in] Size of region
1585 * DWORD type [in] Type of operation
1587 * Output: EAX: NtStatus
1588 * EDX: TRUE if success, FALSE if failure
1591 DWORD *stack = PTR_SEG_OFF_TO_LIN(LOWORD(context->Edx),
1592 HIWORD(context->Edx));
1593 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0], W32S_OFFSET);
1594 DWORD size = stack[1];
1595 DWORD type = stack[2];
1596 DWORD result;
1598 TRACE("VirtualFree16(%lx, %lx, %lx)\n",
1599 (DWORD)base, size, type);
1601 result = VirtualFree(base, size, type);
1603 if (result)
1604 context->Edx = TRUE,
1605 context->Eax = STATUS_SUCCESS;
1606 else
1607 context->Edx = FALSE,
1608 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1610 break;
1613 case 0x001F: /* FWorkingSetSize */
1615 * Input: EDX: 0 if Get, 1 if Set
1617 * ECX: Get: Buffer to receive Working Set Size
1618 * Set: Buffer containing Working Set Size
1620 * Output: NtStatus
1623 DWORD *ptr = (DWORD *)W32S_APP2WINE(context->Ecx, W32S_OFFSET);
1624 BOOL set = context->Edx;
1626 TRACE("FWorkingSetSize(%lx, %lx)\n", (DWORD)ptr, (DWORD)set);
1628 if (set)
1629 /* We do it differently ... */;
1630 else
1631 *ptr = 0x100;
1633 context->Eax = STATUS_SUCCESS;
1635 break;
1638 default:
1639 VXD_BARF( context, "W32S" );