WARN() about missing /dev/sequencer, it's too confusing for newbies.
[wine.git] / msdos / vxd.c
blob09f8fa16f923fa42ccf1fe5b6762822094f7b10f
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 "neexe.h"
21 #include "task.h"
22 #include "process.h"
23 #include "file.h"
24 #include "debugtools.h"
26 DEFAULT_DEBUG_CHANNEL(vxd)
29 #define VXD_BARF(context,name) \
30 DPRINTF( "vxd %s: unknown/not implemented parameters:\n" \
31 "vxd %s: AX %04x, BX %04x, CX %04x, DX %04x, " \
32 "SI %04x, DI %04x, DS %04x, ES %04x\n", \
33 (name), (name), AX_reg(context), BX_reg(context), \
34 CX_reg(context), DX_reg(context), SI_reg(context), \
35 DI_reg(context), (WORD)context->SegDs, (WORD)context->SegEs )
38 static WORD VXD_WinVersion(void)
40 WORD version = LOWORD(GetVersion16());
41 return (version >> 8) | (version << 8);
44 /***********************************************************************
45 * VXD_VMM
47 void WINAPI VXD_VMM ( CONTEXT86 *context )
49 unsigned service = AX_reg(context);
51 TRACE("[%04x] VMM\n", (UINT16)service);
53 switch(service)
55 case 0x0000: /* version */
56 AX_reg(context) = VXD_WinVersion();
57 RESET_CFLAG(context);
58 break;
60 case 0x026d: /* Get_Debug_Flag '/m' */
61 case 0x026e: /* Get_Debug_Flag '/n' */
62 AL_reg(context) = 0;
63 RESET_CFLAG(context);
64 break;
66 default:
67 VXD_BARF( context, "VMM" );
71 /***********************************************************************
72 * VXD_PageFile
74 void WINAPI VXD_PageFile( CONTEXT86 *context )
76 unsigned service = AX_reg(context);
78 /* taken from Ralf Brown's Interrupt List */
80 TRACE("[%04x] PageFile\n", (UINT16)service );
82 switch(service)
84 case 0x00: /* get version, is this windows version? */
85 TRACE("returning version\n");
86 AX_reg(context) = VXD_WinVersion();
87 RESET_CFLAG(context);
88 break;
90 case 0x01: /* get swap file info */
91 TRACE("VxD PageFile: returning swap file info\n");
92 AX_reg(context) = 0x00; /* paging disabled */
93 context->Ecx = 0; /* maximum size of paging file */
94 /* FIXME: do I touch DS:SI or DS:DI? */
95 RESET_CFLAG(context);
96 break;
98 case 0x02: /* delete permanent swap on exit */
99 TRACE("VxD PageFile: supposed to delete swap\n");
100 RESET_CFLAG(context);
101 break;
103 case 0x03: /* current temporary swap file size */
104 TRACE("VxD PageFile: what is current temp. swap size\n");
105 RESET_CFLAG(context);
106 break;
108 case 0x04: /* read or write?? INTERRUP.D */
109 case 0x05: /* cancel?? INTERRUP.D */
110 case 0x06: /* test I/O valid INTERRUP.D */
111 default:
112 VXD_BARF( context, "pagefile" );
113 break;
117 /***********************************************************************
118 * VXD_Reboot
120 void WINAPI VXD_Reboot ( CONTEXT86 *context )
122 unsigned service = AX_reg(context);
124 TRACE("[%04x] Reboot\n", (UINT16)service);
126 switch(service)
128 case 0x0000: /* version */
129 AX_reg(context) = VXD_WinVersion();
130 RESET_CFLAG(context);
131 break;
133 default:
134 VXD_BARF( context, "REBOOT" );
138 /***********************************************************************
139 * VXD_VDD
141 void WINAPI VXD_VDD ( CONTEXT86 *context )
143 unsigned service = AX_reg(context);
145 TRACE("[%04x] VDD\n", (UINT16)service);
147 switch(service)
149 case 0x0000: /* version */
150 AX_reg(context) = VXD_WinVersion();
151 RESET_CFLAG(context);
152 break;
154 default:
155 VXD_BARF( context, "VDD" );
159 /***********************************************************************
160 * VXD_VMD
162 void WINAPI VXD_VMD ( CONTEXT86 *context )
164 unsigned service = AX_reg(context);
166 TRACE("[%04x] VMD\n", (UINT16)service);
168 switch(service)
170 case 0x0000: /* version */
171 AX_reg(context) = VXD_WinVersion();
172 RESET_CFLAG(context);
173 break;
175 default:
176 VXD_BARF( context, "VMD" );
180 /***********************************************************************
181 * VXD_VXDLoader
183 void WINAPI VXD_VXDLoader( CONTEXT86 *context )
185 unsigned service = AX_reg(context);
187 TRACE("[%04x] VXDLoader\n", (UINT16)service);
189 switch (service)
191 case 0x0000: /* get version */
192 TRACE("returning version\n");
193 AX_reg(context) = 0x0000;
194 DX_reg(context) = VXD_WinVersion();
195 RESET_CFLAG(context);
196 break;
198 case 0x0001: /* load device */
199 FIXME("load device %04lx:%04x (%s)\n",
200 context->SegDs, DX_reg(context),
201 debugstr_a(PTR_SEG_OFF_TO_LIN(context->SegDs, DX_reg(context))));
202 AX_reg(context) = 0x0000;
203 context->SegEs = 0x0000;
204 DI_reg(context) = 0x0000;
205 RESET_CFLAG(context);
206 break;
208 case 0x0002: /* unload device */
209 FIXME("unload device (%08lx)\n", context->Ebx);
210 AX_reg(context) = 0x0000;
211 RESET_CFLAG(context);
212 break;
214 default:
215 VXD_BARF( context, "VXDLDR" );
216 AX_reg(context) = 0x000B; /* invalid function number */
217 SET_CFLAG(context);
218 break;
222 /***********************************************************************
223 * VXD_Shell
225 void WINAPI VXD_Shell( CONTEXT86 *context )
227 unsigned service = DX_reg(context);
229 TRACE("[%04x] Shell\n", (UINT16)service);
231 switch (service) /* Ralf Brown says EDX, but I use DX instead */
233 case 0x0000:
234 TRACE("returning version\n");
235 AX_reg(context) = VXD_WinVersion();
236 context->Ebx = 1; /* system VM Handle */
237 break;
239 case 0x0001:
240 case 0x0002:
241 case 0x0003:
242 /* SHELL_SYSMODAL_Message
243 ebx virtual maschine handle
244 eax message box flags
245 ecx address of message
246 edi address of caption
247 return response in eax
249 case 0x0004:
250 /* SHELL_Message
251 ebx virtual maschine handle
252 eax message box flags
253 ecx address of message
254 edi address of caption
255 esi address callback
256 edx reference data for callback
257 return response in eax
259 case 0x0005:
260 VXD_BARF( context, "shell" );
261 break;
263 case 0x0006: /* SHELL_Get_VM_State */
264 TRACE("VxD Shell: returning VM state\n");
265 /* Actually we don't, not yet. We have to return a structure
266 * and I am not to sure how to set it up and return it yet,
267 * so for now let's do nothing. I can (hopefully) get this
268 * by the next release
270 /* RESET_CFLAG(context); */
271 break;
273 case 0x0007:
274 case 0x0008:
275 case 0x0009:
276 case 0x000A:
277 case 0x000B:
278 case 0x000C:
279 case 0x000D:
280 case 0x000E:
281 case 0x000F:
282 case 0x0010:
283 case 0x0011:
284 case 0x0012:
285 case 0x0013:
286 case 0x0014:
287 case 0x0015:
288 case 0x0016:
289 VXD_BARF( context, "SHELL" );
290 break;
292 /* the new Win95 shell API */
293 case 0x0100: /* get version */
294 AX_reg(context) = VXD_WinVersion();
295 break;
297 case 0x0104: /* retrieve Hook_Properties list */
298 case 0x0105: /* call Hook_Properties callbacks */
299 VXD_BARF( context, "SHELL" );
300 break;
302 case 0x0106: /* install timeout callback */
303 TRACE("VxD Shell: ignoring shell callback (%ld sec.)\n", context->Ebx);
304 SET_CFLAG(context);
305 break;
307 case 0x0107: /* get version of any VxD */
308 default:
309 VXD_BARF( context, "SHELL" );
310 break;
315 /***********************************************************************
316 * VXD_Comm
318 void WINAPI VXD_Comm( CONTEXT86 *context )
320 unsigned service = AX_reg(context);
322 TRACE("[%04x] Comm\n", (UINT16)service);
324 switch (service)
326 case 0x0000: /* get version */
327 TRACE("returning version\n");
328 AX_reg(context) = VXD_WinVersion();
329 RESET_CFLAG(context);
330 break;
332 case 0x0001: /* set port global */
333 case 0x0002: /* get focus */
334 case 0x0003: /* virtualise port */
335 default:
336 VXD_BARF( context, "comm" );
340 /***********************************************************************
341 * VXD_Timer
343 void WINAPI VXD_Timer( CONTEXT86 *context )
345 unsigned service = AX_reg(context);
347 TRACE("[%04x] Virtual Timer\n", (UINT16)service);
349 switch(service)
351 case 0x0000: /* version */
352 AX_reg(context) = VXD_WinVersion();
353 RESET_CFLAG(context);
354 break;
356 case 0x0100: /* clock tick time, in 840nsecs */
357 context->Eax = GetTickCount();
359 context->Edx = context->Eax >> 22;
360 context->Eax <<= 10; /* not very precise */
361 break;
363 case 0x0101: /* current Windows time, msecs */
364 case 0x0102: /* current VM time, msecs */
365 context->Eax = GetTickCount();
366 break;
368 default:
369 VXD_BARF( context, "VTD" );
373 /***********************************************************************
374 * VXD_TimerAPI
376 static DWORD System_Time = 0;
377 static WORD System_Time_Selector = 0;
378 static void System_Time_Tick( WORD timer ) { System_Time += 55; }
379 void WINAPI VXD_TimerAPI ( CONTEXT86 *context )
381 unsigned service = AX_reg(context);
383 TRACE("[%04x] TimerAPI\n", (UINT16)service);
385 switch(service)
387 case 0x0000: /* version */
388 AX_reg(context) = VXD_WinVersion();
389 RESET_CFLAG(context);
390 break;
392 case 0x0009: /* get system time selector */
393 if ( !System_Time_Selector )
395 System_Time_Selector = SELECTOR_AllocBlock( &System_Time, sizeof(DWORD), WINE_LDT_FLAGS_DATA );
396 CreateSystemTimer( 55, System_Time_Tick );
399 AX_reg(context) = System_Time_Selector;
400 RESET_CFLAG(context);
401 break;
403 default:
404 VXD_BARF( context, "VTDAPI" );
408 /***********************************************************************
409 * VXD_ConfigMG
411 void WINAPI VXD_ConfigMG ( CONTEXT86 *context )
413 unsigned service = AX_reg(context);
415 TRACE("[%04x] ConfigMG\n", (UINT16)service);
417 switch(service)
419 case 0x0000: /* version */
420 AX_reg(context) = VXD_WinVersion();
421 RESET_CFLAG(context);
422 break;
424 default:
425 VXD_BARF( context, "CONFIGMG" );
429 /***********************************************************************
430 * VXD_Enable
432 void WINAPI VXD_Enable ( CONTEXT86 *context )
434 unsigned service = AX_reg(context);
436 TRACE("[%04x] Enable\n", (UINT16)service);
438 switch(service)
440 case 0x0000: /* version */
441 AX_reg(context) = VXD_WinVersion();
442 RESET_CFLAG(context);
443 break;
445 default:
446 VXD_BARF( context, "ENABLE" );
450 /***********************************************************************
451 * VXD_APM
453 void WINAPI VXD_APM ( CONTEXT86 *context )
455 unsigned service = AX_reg(context);
457 TRACE("[%04x] APM\n", (UINT16)service);
459 switch(service)
461 case 0x0000: /* version */
462 AX_reg(context) = VXD_WinVersion();
463 RESET_CFLAG(context);
464 break;
466 default:
467 VXD_BARF( context, "APM" );
471 /***********************************************************************
472 * VXD_Win32s
474 * This is an implementation of the services of the Win32s VxD.
475 * Since official documentation of these does not seem to be available,
476 * certain arguments of some of the services remain unclear.
478 * FIXME: The following services are currently unimplemented:
479 * Exception handling (0x01, 0x1C)
480 * Debugger support (0x0C, 0x14, 0x17)
481 * Low-level memory access (0x02, 0x03, 0x0A, 0x0B)
482 * Memory Statistics (0x1B)
485 * We have a specific problem running Win32s on Linux (and probably also
486 * the other x86 unixes), since Win32s tries to allocate its main 'flat
487 * code/data segment' selectors with a base of 0xffff0000 (and limit 4GB).
488 * The rationale for this seems to be that they want one the one hand to
489 * be able to leave the Win 3.1 memory (starting with the main DOS memory)
490 * at linear address 0, but want at other hand to have offset 0 of the
491 * flat data/code segment point to an unmapped page (to catch NULL pointer
492 * accesses). Hence they allocate the flat segments with a base of 0xffff0000
493 * so that the Win 3.1 memory area at linear address zero shows up in the
494 * flat segments at offset 0x10000 (since linear addresses wrap around at
495 * 4GB). To compensate for that discrepancy between flat segment offsets
496 * and plain linear addresses, all flat pointers passed between the 32-bit
497 * and the 16-bit parts of Win32s are shifted by 0x10000 in the appropriate
498 * direction by the glue code (mainly) in W32SKRNL and WIN32S16.
500 * The problem for us is now that Linux does not allow a LDT selector with
501 * base 0xffff0000 to be created, since it would 'see' a part of the kernel
502 * address space. To address this problem we introduce *another* offset:
503 * We add 0x10000 to every linear address we get as an argument from Win32s.
504 * This means especially that the flat code/data selectors get actually
505 * allocated with base 0x0, so that flat offsets and (real) linear addresses
506 * do again agree! In fact, every call e.g. of a Win32s VxD service now
507 * has all pointer arguments (which are offsets in the flat data segement)
508 * first reduced by 0x10000 by the W32SKRNL glue code, and then again
509 * increased by 0x10000 by *our* code.
511 * Note that to keep everything consistent, this offset has to be applied by
512 * every Wine function that operates on 'linear addresses' passed to it by
513 * Win32s. Fortunately, since Win32s does not directly call any Wine 32-bit
514 * API routines, this affects only two locations: this VxD and the DPMI
515 * handler. (NOTE: Should any Win32s application pass a linear address to
516 * any routine apart from those, e.g. some other VxD handler, that code
517 * would have to take the offset into account as well!)
519 * The application of the offset is triggered by marking the current process
520 * as a Win32s process by setting the PDB32_WIN32S_PROC flag in the process
521 * database. This is done the first time any application calls the GetVersion()
522 * service of the Win32s VxD. (Note that the flag is never removed.)
526 void WINAPI VXD_Win32s( CONTEXT86 *context )
528 switch (AX_reg(context))
530 case 0x0000: /* Get Version */
532 * Input: None
534 * Output: EAX: LoWord: Win32s Version (1.30)
535 * HiWord: VxD Version (200)
537 * EBX: Build (172)
539 * ECX: ??? (1)
541 * EDX: Debugging Flags
543 * EDI: Error Flag
544 * 0 if OK,
545 * 1 if VMCPD VxD not found
548 TRACE("GetVersion()\n");
550 context->Eax = VXD_WinVersion() | (200 << 16);
551 context->Ebx = 0;
552 context->Ecx = 0;
553 context->Edx = 0;
554 context->Edi = 0;
557 * If this is the first time we are called for this process,
558 * hack the memory image of WIN32S16 so that it doesn't try
559 * to access the GDT directly ...
561 * The first code segment of WIN32S16 (version 1.30) contains
562 * an unexported function somewhere between the exported functions
563 * SetFS and StackLinearToSegmented that tries to find a selector
564 * in the LDT that maps to the memory image of the LDT itself.
565 * If it succeeds, it stores this selector into a global variable
566 * which will be used to speed up execution by using this selector
567 * to modify the LDT directly instead of using the DPMI calls.
569 * To perform this search of the LDT, this function uses the
570 * sgdt and sldt instructions to find the linear address of
571 * the (GDT and then) LDT. While those instructions themselves
572 * execute without problem, the linear address that sgdt returns
573 * points (at least under Linux) to the kernel address space, so
574 * that any subsequent access leads to a segfault.
576 * Fortunately, WIN32S16 still contains as a fallback option the
577 * mechanism of using DPMI calls to modify LDT selectors instead
578 * of direct writes to the LDT. Thus we can circumvent the problem
579 * by simply replacing the first byte of the offending function
580 * with an 'retf' instruction. This means that the global variable
581 * supposed to contain the LDT alias selector will remain zero,
582 * and hence WIN32S16 will fall back to using DPMI calls.
584 * The heuristic we employ to _find_ that function is as follows:
585 * We search between the addresses of the exported symbols SetFS
586 * and StackLinearToSegmented for the byte sequence '0F 01 04'
587 * (this is the opcode of 'sgdt [si]'). We then search backwards
588 * from this address for the last occurrance of 'CB' (retf) that marks
589 * the end of the preceeding function. The following byte (which
590 * should now be the first byte of the function we are looking for)
591 * will be replaced by 'CB' (retf).
593 * This heuristic works for the retail as well as the debug version
594 * of Win32s version 1.30. For versions earlier than that this
595 * hack should not be necessary at all, since the whole mechanism
596 * ('PERF130') was introduced only in 1.30 to improve the overall
597 * performance of Win32s.
600 if (!(PROCESS_Current()->flags & PDB32_WIN32S_PROC))
602 HMODULE16 hModule = GetModuleHandle16("win32s16");
603 SEGPTR func1 = (SEGPTR)GetProcAddress16(hModule, "SetFS");
604 SEGPTR func2 = (SEGPTR)GetProcAddress16(hModule, "StackLinearToSegmented");
606 if ( hModule && func1 && func2
607 && SELECTOROF(func1) == SELECTOROF(func2))
609 BYTE *start = PTR_SEG_TO_LIN(func1);
610 BYTE *end = PTR_SEG_TO_LIN(func2);
611 BYTE *p, *retv = NULL;
612 int found = 0;
614 for (p = start; p < end; p++)
615 if (*p == 0xCB) found = 0, retv = p;
616 else if (*p == 0x0F) found = 1;
617 else if (*p == 0x01 && found == 1) found = 2;
618 else if (*p == 0x04 && found == 2) { found = 3; break; }
619 else found = 0;
621 if (found == 3 && retv)
623 TRACE("PERF130 hack: "
624 "Replacing byte %02X at offset %04X:%04X\n",
625 *(retv+1), SELECTOROF(func1),
626 OFFSETOF(func1) + retv+1-start);
628 *(retv+1) = (BYTE)0xCB;
634 * Mark process as Win32s, so that subsequent DPMI calls
635 * will perform the W32S_APP2WINE/W32S_WINE2APP address shift.
638 PROCESS_Current()->flags |= PDB32_WIN32S_PROC;
639 break;
642 case 0x0001: /* Install Exception Handling */
644 * Input: EBX: Flat address of W32SKRNL Exception Data
646 * ECX: LoWord: Flat Code Selector
647 * HiWord: Flat Data Selector
649 * EDX: Flat address of W32SKRNL Exception Handler
650 * (this is equal to W32S_BackTo32 + 0x40)
652 * ESI: SEGPTR KERNEL.HASGPHANDLER
654 * EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10)
656 * Output: EAX: 0 if OK
659 TRACE("[0001] EBX=%lx ECX=%lx EDX=%lx ESI=%lx EDI=%lx\n",
660 context->Ebx, context->Ecx, context->Edx,
661 context->Esi, context->Edi);
663 /* FIXME */
665 context->Eax = 0;
666 break;
669 case 0x0002: /* Set Page Access Flags */
671 * Input: EBX: New access flags
672 * Bit 2: User Page if set, Supervisor Page if clear
673 * Bit 1: Read-Write if set, Read-Only if clear
675 * ECX: Size of memory area to change
677 * EDX: Flat start address of memory area
679 * Output: EAX: Size of area changed
682 TRACE("[0002] EBX=%lx ECX=%lx EDX=%lx\n",
683 context->Ebx, context->Ecx, context->Edx);
685 /* FIXME */
687 context->Eax = context->Ecx;
688 break;
691 case 0x0003: /* Get Page Access Flags */
693 * Input: EDX: Flat address of page to query
695 * Output: EAX: Page access flags
696 * Bit 2: User Page if set, Supervisor Page if clear
697 * Bit 1: Read-Write if set, Read-Only if clear
700 TRACE("[0003] EDX=%lx\n", context->Edx);
702 /* FIXME */
704 context->Eax = 6;
705 break;
708 case 0x0004: /* Map Module */
710 * Input: ECX: IMTE (offset in Module Table) of new module
712 * EDX: Flat address of Win32s Module Table
714 * Output: EAX: 0 if OK
717 if (!context->Edx || CX_reg(context) == 0xFFFF)
719 TRACE("MapModule: Initialization call\n");
720 context->Eax = 0;
722 else
725 * Structure of a Win32s Module Table Entry:
727 struct Win32sModule
729 DWORD flags;
730 DWORD flatBaseAddr;
731 LPCSTR moduleName;
732 LPCSTR pathName;
733 LPCSTR unknown;
734 LPBYTE baseAddr;
735 DWORD hModule;
736 DWORD relocDelta;
740 * Note: This function should set up a demand-paged memory image
741 * of the given module. Since mmap does not allow file offsets
742 * not aligned at 1024 bytes, we simply load the image fully
743 * into memory.
746 struct Win32sModule *moduleTable =
747 (struct Win32sModule *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
748 struct Win32sModule *module = moduleTable + context->Ecx;
750 IMAGE_NT_HEADERS *nt_header = PE_HEADER(module->baseAddr);
751 IMAGE_SECTION_HEADER *pe_seg = PE_SECTIONS(module->baseAddr);
753 HFILE image = _lopen(module->pathName, OF_READ);
754 BOOL error = (image == HFILE_ERROR);
755 UINT i;
757 TRACE("MapModule: Loading %s\n", module->pathName);
759 for (i = 0;
760 !error && i < nt_header->FileHeader.NumberOfSections;
761 i++, pe_seg++)
762 if(!(pe_seg->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA))
764 DWORD off = pe_seg->PointerToRawData;
765 DWORD len = pe_seg->SizeOfRawData;
766 LPBYTE addr = module->baseAddr + pe_seg->VirtualAddress;
768 TRACE("MapModule: "
769 "Section %d at %08lx from %08lx len %08lx\n",
770 i, (DWORD)addr, off, len);
772 if ( _llseek(image, off, SEEK_SET) != off
773 || _lread(image, addr, len) != len)
774 error = TRUE;
777 _lclose(image);
779 if (error)
780 ERR("MapModule: Unable to load %s\n", module->pathName);
782 else if (module->relocDelta != 0)
784 IMAGE_DATA_DIRECTORY *dir = nt_header->OptionalHeader.DataDirectory
785 + IMAGE_DIRECTORY_ENTRY_BASERELOC;
786 IMAGE_BASE_RELOCATION *r = (IMAGE_BASE_RELOCATION *)
787 (dir->Size? module->baseAddr + dir->VirtualAddress : 0);
789 TRACE("MapModule: Reloc delta %08lx\n", module->relocDelta);
791 while (r && r->VirtualAddress)
793 LPBYTE page = module->baseAddr + r->VirtualAddress;
794 int count = (r->SizeOfBlock - 8) / 2;
796 TRACE("MapModule: %d relocations for page %08lx\n",
797 count, (DWORD)page);
799 for(i = 0; i < count; i++)
801 int offset = r->TypeOffset[i] & 0xFFF;
802 int type = r->TypeOffset[i] >> 12;
803 switch(type)
805 case IMAGE_REL_BASED_ABSOLUTE:
806 break;
807 case IMAGE_REL_BASED_HIGH:
808 *(WORD *)(page+offset) += HIWORD(module->relocDelta);
809 break;
810 case IMAGE_REL_BASED_LOW:
811 *(WORD *)(page+offset) += LOWORD(module->relocDelta);
812 break;
813 case IMAGE_REL_BASED_HIGHLOW:
814 *(DWORD*)(page+offset) += module->relocDelta;
815 break;
816 default:
817 WARN("MapModule: Unsupported fixup type\n");
818 break;
822 r = (IMAGE_BASE_RELOCATION *)((LPBYTE)r + r->SizeOfBlock);
826 context->Eax = 0;
827 RESET_CFLAG(context);
829 break;
832 case 0x0005: /* UnMap Module */
834 * Input: EDX: Flat address of module image
836 * Output: EAX: 1 if OK
839 TRACE("UnMapModule: %lx\n", (DWORD)W32S_APP2WINE(context->Edx, W32S_OFFSET));
841 /* As we didn't map anything, there's nothing to unmap ... */
843 context->Eax = 1;
844 break;
847 case 0x0006: /* VirtualAlloc */
849 * Input: ECX: Current Process
851 * EDX: Flat address of arguments on stack
853 * DWORD *retv [out] Flat base address of allocated region
854 * LPVOID base [in] Flat address of region to reserve/commit
855 * DWORD size [in] Size of region
856 * DWORD type [in] Type of allocation
857 * DWORD prot [in] Type of access protection
859 * Output: EAX: NtStatus
862 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
863 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
864 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
865 DWORD size = stack[2];
866 DWORD type = stack[3];
867 DWORD prot = stack[4];
868 DWORD result;
870 TRACE("VirtualAlloc(%lx, %lx, %lx, %lx, %lx)\n",
871 (DWORD)retv, (DWORD)base, size, type, prot);
873 if (type & 0x80000000)
875 WARN("VirtualAlloc: strange type %lx\n", type);
876 type &= 0x7fffffff;
879 if (!base && (type & MEM_COMMIT) && prot == PAGE_READONLY)
881 WARN("VirtualAlloc: NLS hack, allowing write access!\n");
882 prot = PAGE_READWRITE;
885 result = (DWORD)VirtualAlloc(base, size, type, prot);
887 if (W32S_WINE2APP(result, W32S_OFFSET))
888 *retv = W32S_WINE2APP(result, W32S_OFFSET),
889 context->Eax = STATUS_SUCCESS;
890 else
891 *retv = 0,
892 context->Eax = STATUS_NO_MEMORY; /* FIXME */
894 break;
897 case 0x0007: /* VirtualFree */
899 * Input: ECX: Current Process
901 * EDX: Flat address of arguments on stack
903 * DWORD *retv [out] TRUE if success, FALSE if failure
904 * LPVOID base [in] Flat address of region
905 * DWORD size [in] Size of region
906 * DWORD type [in] Type of operation
908 * Output: EAX: NtStatus
911 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
912 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
913 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
914 DWORD size = stack[2];
915 DWORD type = stack[3];
916 DWORD result;
918 TRACE("VirtualFree(%lx, %lx, %lx, %lx)\n",
919 (DWORD)retv, (DWORD)base, size, type);
921 result = VirtualFree(base, size, type);
923 if (result)
924 *retv = TRUE,
925 context->Eax = STATUS_SUCCESS;
926 else
927 *retv = FALSE,
928 context->Eax = STATUS_NO_MEMORY; /* FIXME */
930 break;
933 case 0x0008: /* VirtualProtect */
935 * Input: ECX: Current Process
937 * EDX: Flat address of arguments on stack
939 * DWORD *retv [out] TRUE if success, FALSE if failure
940 * LPVOID base [in] Flat address of region
941 * DWORD size [in] Size of region
942 * DWORD new_prot [in] Desired access protection
943 * DWORD *old_prot [out] Previous access protection
945 * Output: EAX: NtStatus
948 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
949 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
950 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
951 DWORD size = stack[2];
952 DWORD new_prot = stack[3];
953 DWORD *old_prot = (DWORD *)W32S_APP2WINE(stack[4], W32S_OFFSET);
954 DWORD result;
956 TRACE("VirtualProtect(%lx, %lx, %lx, %lx, %lx)\n",
957 (DWORD)retv, (DWORD)base, size, new_prot, (DWORD)old_prot);
959 result = VirtualProtect(base, size, new_prot, old_prot);
961 if (result)
962 *retv = TRUE,
963 context->Eax = STATUS_SUCCESS;
964 else
965 *retv = FALSE,
966 context->Eax = STATUS_NO_MEMORY; /* FIXME */
968 break;
971 case 0x0009: /* VirtualQuery */
973 * Input: ECX: Current Process
975 * EDX: Flat address of arguments on stack
977 * DWORD *retv [out] Nr. bytes returned
978 * LPVOID base [in] Flat address of region
979 * LPMEMORY_BASIC_INFORMATION info [out] Info buffer
980 * DWORD len [in] Size of buffer
982 * Output: EAX: NtStatus
985 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
986 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
987 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
988 LPMEMORY_BASIC_INFORMATION info =
989 (LPMEMORY_BASIC_INFORMATION)W32S_APP2WINE(stack[2], W32S_OFFSET);
990 DWORD len = stack[3];
991 DWORD result;
993 TRACE("VirtualQuery(%lx, %lx, %lx, %lx)\n",
994 (DWORD)retv, (DWORD)base, (DWORD)info, len);
996 result = VirtualQuery(base, info, len);
998 *retv = result;
999 context->Eax = STATUS_SUCCESS;
1001 break;
1004 case 0x000A: /* SetVirtMemProcess */
1006 * Input: ECX: Process Handle
1008 * EDX: Flat address of region
1010 * Output: EAX: NtStatus
1013 TRACE("[000a] ECX=%lx EDX=%lx\n",
1014 context->Ecx, context->Edx);
1016 /* FIXME */
1018 context->Eax = STATUS_SUCCESS;
1019 break;
1022 case 0x000B: /* ??? some kind of cleanup */
1024 * Input: ECX: Process Handle
1026 * Output: EAX: NtStatus
1029 TRACE("[000b] ECX=%lx\n", context->Ecx);
1031 /* FIXME */
1033 context->Eax = STATUS_SUCCESS;
1034 break;
1037 case 0x000C: /* Set Debug Flags */
1039 * Input: EDX: Debug Flags
1041 * Output: EDX: Previous Debug Flags
1044 FIXME("[000c] EDX=%lx\n", context->Edx);
1046 /* FIXME */
1048 context->Edx = 0;
1049 break;
1052 case 0x000D: /* NtCreateSection */
1054 * Input: EDX: Flat address of arguments on stack
1056 * HANDLE32 *retv [out] Handle of Section created
1057 * DWORD flags1 [in] (?? unknown ??)
1058 * DWORD atom [in] Name of Section to create
1059 * LARGE_INTEGER *size [in] Size of Section
1060 * DWORD protect [in] Access protection
1061 * DWORD flags2 [in] (?? unknown ??)
1062 * HFILE32 hFile [in] Handle of file to map
1063 * DWORD psp [in] (Win32s: PSP that hFile belongs to)
1065 * Output: EAX: NtStatus
1068 DWORD *stack = (DWORD *) W32S_APP2WINE(context->Edx, W32S_OFFSET);
1069 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1070 DWORD flags1 = stack[1];
1071 DWORD atom = stack[2];
1072 LARGE_INTEGER *size = (LARGE_INTEGER *)W32S_APP2WINE(stack[3], W32S_OFFSET);
1073 DWORD protect = stack[4];
1074 DWORD flags2 = stack[5];
1075 HANDLE hFile = DosFileHandleToWin32Handle(stack[6]);
1076 DWORD psp = stack[7];
1078 HANDLE result = INVALID_HANDLE_VALUE;
1079 char name[128];
1081 TRACE("NtCreateSection(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1082 (DWORD)retv, flags1, atom, (DWORD)size, protect, flags2,
1083 (DWORD)hFile, psp);
1085 if (!atom || GlobalGetAtomNameA(atom, name, sizeof(name)))
1087 TRACE("NtCreateSection: name=%s\n", atom? name : NULL);
1089 result = CreateFileMappingA(hFile, NULL, protect,
1090 size? size->s.HighPart : 0,
1091 size? size->s.LowPart : 0,
1092 atom? name : NULL);
1095 if (result == INVALID_HANDLE_VALUE)
1096 WARN("NtCreateSection: failed!\n");
1097 else
1098 TRACE("NtCreateSection: returned %lx\n", (DWORD)result);
1100 if (result != INVALID_HANDLE_VALUE)
1101 *retv = result,
1102 context->Eax = STATUS_SUCCESS;
1103 else
1104 *retv = result,
1105 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1107 break;
1110 case 0x000E: /* NtOpenSection */
1112 * Input: EDX: Flat address of arguments on stack
1114 * HANDLE32 *retv [out] Handle of Section opened
1115 * DWORD protect [in] Access protection
1116 * DWORD atom [in] Name of Section to create
1118 * Output: EAX: NtStatus
1121 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
1122 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1123 DWORD protect = stack[1];
1124 DWORD atom = stack[2];
1126 HANDLE result = INVALID_HANDLE_VALUE;
1127 char name[128];
1129 TRACE("NtOpenSection(%lx, %lx, %lx)\n",
1130 (DWORD)retv, protect, atom);
1132 if (atom && GlobalGetAtomNameA(atom, name, sizeof(name)))
1134 TRACE("NtOpenSection: name=%s\n", name);
1136 result = OpenFileMappingA(protect, FALSE, name);
1139 if (result == INVALID_HANDLE_VALUE)
1140 WARN("NtOpenSection: failed!\n");
1141 else
1142 TRACE("NtOpenSection: returned %lx\n", (DWORD)result);
1144 if (result != INVALID_HANDLE_VALUE)
1145 *retv = result,
1146 context->Eax = STATUS_SUCCESS;
1147 else
1148 *retv = result,
1149 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1151 break;
1154 case 0x000F: /* NtCloseSection */
1156 * Input: EDX: Flat address of arguments on stack
1158 * HANDLE32 handle [in] Handle of Section to close
1159 * DWORD *id [out] Unique ID (?? unclear ??)
1161 * Output: EAX: NtStatus
1164 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
1165 HANDLE handle = stack[0];
1166 DWORD *id = (DWORD *)W32S_APP2WINE(stack[1], W32S_OFFSET);
1168 TRACE("NtCloseSection(%lx, %lx)\n", (DWORD)handle, (DWORD)id);
1170 CloseHandle(handle);
1171 if (id) *id = 0; /* FIXME */
1173 context->Eax = STATUS_SUCCESS;
1175 break;
1178 case 0x0010: /* NtDupSection */
1180 * Input: EDX: Flat address of arguments on stack
1182 * HANDLE32 handle [in] Handle of Section to duplicate
1184 * Output: EAX: NtStatus
1187 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
1188 HANDLE handle = stack[0];
1189 HANDLE new_handle;
1191 TRACE("NtDupSection(%lx)\n", (DWORD)handle);
1193 DuplicateHandle( GetCurrentProcess(), handle,
1194 GetCurrentProcess(), &new_handle,
1195 0, FALSE, DUPLICATE_SAME_ACCESS );
1196 context->Eax = STATUS_SUCCESS;
1198 break;
1201 case 0x0011: /* NtMapViewOfSection */
1203 * Input: EDX: Flat address of arguments on stack
1205 * HANDLE32 SectionHandle [in] Section to be mapped
1206 * DWORD ProcessHandle [in] Process to be mapped into
1207 * DWORD * BaseAddress [in/out] Address to be mapped at
1208 * DWORD ZeroBits [in] (?? unclear ??)
1209 * DWORD CommitSize [in] (?? unclear ??)
1210 * LARGE_INTEGER *SectionOffset [in] Offset within section
1211 * DWORD * ViewSize [in] Size of view
1212 * DWORD InheritDisposition [in] (?? unclear ??)
1213 * DWORD AllocationType [in] (?? unclear ??)
1214 * DWORD Protect [in] Access protection
1216 * Output: EAX: NtStatus
1219 DWORD * stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
1220 HANDLE SectionHandle = stack[0];
1221 DWORD ProcessHandle = stack[1]; /* ignored */
1222 DWORD * BaseAddress = (DWORD *)W32S_APP2WINE(stack[2], W32S_OFFSET);
1223 DWORD ZeroBits = stack[3];
1224 DWORD CommitSize = stack[4];
1225 LARGE_INTEGER *SectionOffset = (LARGE_INTEGER *)W32S_APP2WINE(stack[5], W32S_OFFSET);
1226 DWORD * ViewSize = (DWORD *)W32S_APP2WINE(stack[6], W32S_OFFSET);
1227 DWORD InheritDisposition = stack[7];
1228 DWORD AllocationType = stack[8];
1229 DWORD Protect = stack[9];
1231 LPBYTE address = (LPBYTE)(BaseAddress?
1232 W32S_APP2WINE(*BaseAddress, W32S_OFFSET) : 0);
1233 DWORD access = 0, result;
1235 switch (Protect & ~(PAGE_GUARD|PAGE_NOCACHE))
1237 case PAGE_READONLY: access = FILE_MAP_READ; break;
1238 case PAGE_READWRITE: access = FILE_MAP_WRITE; break;
1239 case PAGE_WRITECOPY: access = FILE_MAP_COPY; break;
1241 case PAGE_EXECUTE_READ: access = FILE_MAP_READ; break;
1242 case PAGE_EXECUTE_READWRITE: access = FILE_MAP_WRITE; break;
1243 case PAGE_EXECUTE_WRITECOPY: access = FILE_MAP_COPY; break;
1246 TRACE("NtMapViewOfSection"
1247 "(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1248 (DWORD)SectionHandle, ProcessHandle, (DWORD)BaseAddress,
1249 ZeroBits, CommitSize, (DWORD)SectionOffset, (DWORD)ViewSize,
1250 InheritDisposition, AllocationType, Protect);
1251 TRACE("NtMapViewOfSection: "
1252 "base=%lx, offset=%lx, size=%lx, access=%lx\n",
1253 (DWORD)address, SectionOffset? SectionOffset->s.LowPart : 0,
1254 ViewSize? *ViewSize : 0, access);
1256 result = (DWORD)MapViewOfFileEx(SectionHandle, access,
1257 SectionOffset? SectionOffset->s.HighPart : 0,
1258 SectionOffset? SectionOffset->s.LowPart : 0,
1259 ViewSize? *ViewSize : 0, address);
1261 TRACE("NtMapViewOfSection: result=%lx\n", result);
1263 if (W32S_WINE2APP(result, W32S_OFFSET))
1265 if (BaseAddress) *BaseAddress = W32S_WINE2APP(result, W32S_OFFSET);
1266 context->Eax = STATUS_SUCCESS;
1268 else
1269 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1271 break;
1274 case 0x0012: /* NtUnmapViewOfSection */
1276 * Input: EDX: Flat address of arguments on stack
1278 * DWORD ProcessHandle [in] Process (defining address space)
1279 * LPBYTE BaseAddress [in] Base address of view to be unmapped
1281 * Output: EAX: NtStatus
1284 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
1285 DWORD ProcessHandle = stack[0]; /* ignored */
1286 LPBYTE BaseAddress = (LPBYTE)W32S_APP2WINE(stack[1], W32S_OFFSET);
1288 TRACE("NtUnmapViewOfSection(%lx, %lx)\n",
1289 ProcessHandle, (DWORD)BaseAddress);
1291 UnmapViewOfFile(BaseAddress);
1293 context->Eax = STATUS_SUCCESS;
1295 break;
1298 case 0x0013: /* NtFlushVirtualMemory */
1300 * Input: EDX: Flat address of arguments on stack
1302 * DWORD ProcessHandle [in] Process (defining address space)
1303 * LPBYTE *BaseAddress [in?] Base address of range to be flushed
1304 * DWORD *ViewSize [in?] Number of bytes to be flushed
1305 * DWORD *unknown [???] (?? unknown ??)
1307 * Output: EAX: NtStatus
1310 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
1311 DWORD ProcessHandle = stack[0]; /* ignored */
1312 DWORD *BaseAddress = (DWORD *)W32S_APP2WINE(stack[1], W32S_OFFSET);
1313 DWORD *ViewSize = (DWORD *)W32S_APP2WINE(stack[2], W32S_OFFSET);
1314 DWORD *unknown = (DWORD *)W32S_APP2WINE(stack[3], W32S_OFFSET);
1316 LPBYTE address = (LPBYTE)(BaseAddress? W32S_APP2WINE(*BaseAddress, W32S_OFFSET) : 0);
1317 DWORD size = ViewSize? *ViewSize : 0;
1319 TRACE("NtFlushVirtualMemory(%lx, %lx, %lx, %lx)\n",
1320 ProcessHandle, (DWORD)BaseAddress, (DWORD)ViewSize,
1321 (DWORD)unknown);
1322 TRACE("NtFlushVirtualMemory: base=%lx, size=%lx\n",
1323 (DWORD)address, size);
1325 FlushViewOfFile(address, size);
1327 context->Eax = STATUS_SUCCESS;
1329 break;
1332 case 0x0014: /* Get/Set Debug Registers */
1334 * Input: ECX: 0 if Get, 1 if Set
1336 * EDX: Get: Flat address of buffer to receive values of
1337 * debug registers DR0 .. DR7
1338 * Set: Flat address of buffer containing values of
1339 * debug registers DR0 .. DR7 to be set
1340 * Output: None
1343 FIXME("[0014] ECX=%lx EDX=%lx\n",
1344 context->Ecx, context->Edx);
1346 /* FIXME */
1347 break;
1350 case 0x0015: /* Set Coprocessor Emulation Flag */
1352 * Input: EDX: 0 to deactivate, 1 to activate coprocessor emulation
1354 * Output: None
1357 TRACE("[0015] EDX=%lx\n", context->Edx);
1359 /* We don't care, as we always have a coprocessor anyway */
1360 break;
1363 case 0x0016: /* Init Win32S VxD PSP */
1365 * If called to query required PSP size:
1367 * Input: EBX: 0
1368 * Output: EDX: Required size of Win32s VxD PSP
1370 * If called to initialize allocated PSP:
1372 * Input: EBX: LoWord: Selector of Win32s VxD PSP
1373 * HiWord: Paragraph of Win32s VxD PSP (DOSMEM)
1374 * Output: None
1377 if (context->Ebx == 0)
1378 context->Edx = 0x80;
1379 else
1381 PDB16 *psp = PTR_SEG_OFF_TO_LIN(BX_reg(context), 0);
1382 psp->nbFiles = 32;
1383 psp->fileHandlesPtr = MAKELONG(HIWORD(context->Ebx), 0x5c);
1384 memset((LPBYTE)psp + 0x5c, '\xFF', 32);
1386 break;
1389 case 0x0017: /* Set Break Point */
1391 * Input: EBX: Offset of Break Point
1392 * CX: Selector of Break Point
1394 * Output: None
1397 FIXME("[0017] EBX=%lx CX=%x\n",
1398 context->Ebx, CX_reg(context));
1400 /* FIXME */
1401 break;
1404 case 0x0018: /* VirtualLock */
1406 * Input: ECX: Current Process
1408 * EDX: Flat address of arguments on stack
1410 * DWORD *retv [out] TRUE if success, FALSE if failure
1411 * LPVOID base [in] Flat address of range to lock
1412 * DWORD size [in] Size of range
1414 * Output: EAX: NtStatus
1417 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
1418 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1419 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
1420 DWORD size = stack[2];
1421 DWORD result;
1423 TRACE("VirtualLock(%lx, %lx, %lx)\n",
1424 (DWORD)retv, (DWORD)base, size);
1426 result = VirtualLock(base, size);
1428 if (result)
1429 *retv = TRUE,
1430 context->Eax = STATUS_SUCCESS;
1431 else
1432 *retv = FALSE,
1433 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1435 break;
1438 case 0x0019: /* VirtualUnlock */
1440 * Input: ECX: Current Process
1442 * EDX: Flat address of arguments on stack
1444 * DWORD *retv [out] TRUE if success, FALSE if failure
1445 * LPVOID base [in] Flat address of range to unlock
1446 * DWORD size [in] Size of range
1448 * Output: EAX: NtStatus
1451 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
1452 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1453 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
1454 DWORD size = stack[2];
1455 DWORD result;
1457 TRACE("VirtualUnlock(%lx, %lx, %lx)\n",
1458 (DWORD)retv, (DWORD)base, size);
1460 result = VirtualUnlock(base, size);
1462 if (result)
1463 *retv = TRUE,
1464 context->Eax = STATUS_SUCCESS;
1465 else
1466 *retv = FALSE,
1467 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1469 break;
1472 case 0x001A: /* KGetSystemInfo */
1474 * Input: None
1476 * Output: ECX: Start of sparse memory arena
1477 * EDX: End of sparse memory arena
1480 TRACE("KGetSystemInfo()\n");
1483 * Note: Win32s reserves 0GB - 2GB for Win 3.1 and uses 2GB - 4GB as
1484 * sparse memory arena. We do it the other way around, since
1485 * we have to reserve 3GB - 4GB for Linux, and thus use
1486 * 0GB - 3GB as sparse memory arena.
1488 * FIXME: What about other OSes ?
1491 context->Ecx = W32S_WINE2APP(0x00000000, W32S_OFFSET);
1492 context->Edx = W32S_WINE2APP(0xbfffffff, W32S_OFFSET);
1493 break;
1496 case 0x001B: /* KGlobalMemStat */
1498 * Input: ESI: Flat address of buffer to receive memory info
1500 * Output: None
1503 struct Win32sMemoryInfo
1505 DWORD DIPhys_Count; /* Total physical pages */
1506 DWORD DIFree_Count; /* Free physical pages */
1507 DWORD DILin_Total_Count; /* Total virtual pages (private arena) */
1508 DWORD DILin_Total_Free; /* Free virtual pages (private arena) */
1510 DWORD SparseTotal; /* Total size of sparse arena (bytes ?) */
1511 DWORD SparseFree; /* Free size of sparse arena (bytes ?) */
1514 struct Win32sMemoryInfo *info =
1515 (struct Win32sMemoryInfo *)W32S_APP2WINE(context->Esi, W32S_OFFSET);
1517 FIXME("KGlobalMemStat(%lx)\n", (DWORD)info);
1519 /* FIXME */
1521 break;
1524 case 0x001C: /* Enable/Disable Exceptions */
1526 * Input: ECX: 0 to disable, 1 to enable exception handling
1528 * Output: None
1531 TRACE("[001c] ECX=%lx\n", context->Ecx);
1533 /* FIXME */
1534 break;
1537 case 0x001D: /* VirtualAlloc called from 16-bit code */
1539 * Input: EDX: Segmented address of arguments on stack
1541 * LPVOID base [in] Flat address of region to reserve/commit
1542 * DWORD size [in] Size of region
1543 * DWORD type [in] Type of allocation
1544 * DWORD prot [in] Type of access protection
1546 * Output: EAX: NtStatus
1547 * EDX: Flat base address of allocated region
1550 DWORD *stack = PTR_SEG_OFF_TO_LIN(LOWORD(context->Edx),
1551 HIWORD(context->Edx));
1552 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0], W32S_OFFSET);
1553 DWORD size = stack[1];
1554 DWORD type = stack[2];
1555 DWORD prot = stack[3];
1556 DWORD result;
1558 TRACE("VirtualAlloc16(%lx, %lx, %lx, %lx)\n",
1559 (DWORD)base, size, type, prot);
1561 if (type & 0x80000000)
1563 WARN("VirtualAlloc16: strange type %lx\n", type);
1564 type &= 0x7fffffff;
1567 result = (DWORD)VirtualAlloc(base, size, type, prot);
1569 if (W32S_WINE2APP(result, W32S_OFFSET))
1570 context->Edx = W32S_WINE2APP(result, W32S_OFFSET),
1571 context->Eax = STATUS_SUCCESS;
1572 else
1573 context->Edx = 0,
1574 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1575 TRACE("VirtualAlloc16: returning base %lx\n", context->Edx);
1577 break;
1580 case 0x001E: /* VirtualFree called from 16-bit code */
1582 * Input: EDX: Segmented address of arguments on stack
1584 * LPVOID base [in] Flat address of region
1585 * DWORD size [in] Size of region
1586 * DWORD type [in] Type of operation
1588 * Output: EAX: NtStatus
1589 * EDX: TRUE if success, FALSE if failure
1592 DWORD *stack = PTR_SEG_OFF_TO_LIN(LOWORD(context->Edx),
1593 HIWORD(context->Edx));
1594 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0], W32S_OFFSET);
1595 DWORD size = stack[1];
1596 DWORD type = stack[2];
1597 DWORD result;
1599 TRACE("VirtualFree16(%lx, %lx, %lx)\n",
1600 (DWORD)base, size, type);
1602 result = VirtualFree(base, size, type);
1604 if (result)
1605 context->Edx = TRUE,
1606 context->Eax = STATUS_SUCCESS;
1607 else
1608 context->Edx = FALSE,
1609 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1611 break;
1614 case 0x001F: /* FWorkingSetSize */
1616 * Input: EDX: 0 if Get, 1 if Set
1618 * ECX: Get: Buffer to receive Working Set Size
1619 * Set: Buffer containing Working Set Size
1621 * Output: NtStatus
1624 DWORD *ptr = (DWORD *)W32S_APP2WINE(context->Ecx, W32S_OFFSET);
1625 BOOL set = context->Edx;
1627 TRACE("FWorkingSetSize(%lx, %lx)\n", (DWORD)ptr, (DWORD)set);
1629 if (set)
1630 /* We do it differently ... */;
1631 else
1632 *ptr = 0x100;
1634 context->Eax = STATUS_SUCCESS;
1636 break;
1639 default:
1640 VXD_BARF( context, "W32S" );