Added the ability to see names of the virtual key codes.
[wine.git] / msdos / vxd.c
blobadb00de9363dafe77acf886e1ee181504922a86c
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),
396 SEGMENT_DATA, FALSE, TRUE );
397 CreateSystemTimer( 55, System_Time_Tick );
400 AX_reg(context) = System_Time_Selector;
401 RESET_CFLAG(context);
402 break;
404 default:
405 VXD_BARF( context, "VTDAPI" );
409 /***********************************************************************
410 * VXD_ConfigMG
412 void WINAPI VXD_ConfigMG ( CONTEXT86 *context )
414 unsigned service = AX_reg(context);
416 TRACE("[%04x] ConfigMG\n", (UINT16)service);
418 switch(service)
420 case 0x0000: /* version */
421 AX_reg(context) = VXD_WinVersion();
422 RESET_CFLAG(context);
423 break;
425 default:
426 VXD_BARF( context, "CONFIGMG" );
430 /***********************************************************************
431 * VXD_Enable
433 void WINAPI VXD_Enable ( CONTEXT86 *context )
435 unsigned service = AX_reg(context);
437 TRACE("[%04x] Enable\n", (UINT16)service);
439 switch(service)
441 case 0x0000: /* version */
442 AX_reg(context) = VXD_WinVersion();
443 RESET_CFLAG(context);
444 break;
446 default:
447 VXD_BARF( context, "ENABLE" );
451 /***********************************************************************
452 * VXD_APM
454 void WINAPI VXD_APM ( CONTEXT86 *context )
456 unsigned service = AX_reg(context);
458 TRACE("[%04x] APM\n", (UINT16)service);
460 switch(service)
462 case 0x0000: /* version */
463 AX_reg(context) = VXD_WinVersion();
464 RESET_CFLAG(context);
465 break;
467 default:
468 VXD_BARF( context, "APM" );
472 /***********************************************************************
473 * VXD_Win32s
475 * This is an implementation of the services of the Win32s VxD.
476 * Since official documentation of these does not seem to be available,
477 * certain arguments of some of the services remain unclear.
479 * FIXME: The following services are currently unimplemented:
480 * Exception handling (0x01, 0x1C)
481 * Debugger support (0x0C, 0x14, 0x17)
482 * Low-level memory access (0x02, 0x03, 0x0A, 0x0B)
483 * Memory Statistics (0x1B)
486 * We have a specific problem running Win32s on Linux (and probably also
487 * the other x86 unixes), since Win32s tries to allocate its main 'flat
488 * code/data segment' selectors with a base of 0xffff0000 (and limit 4GB).
489 * The rationale for this seems to be that they want one the one hand to
490 * be able to leave the Win 3.1 memory (starting with the main DOS memory)
491 * at linear address 0, but want at other hand to have offset 0 of the
492 * flat data/code segment point to an unmapped page (to catch NULL pointer
493 * accesses). Hence they allocate the flat segments with a base of 0xffff0000
494 * so that the Win 3.1 memory area at linear address zero shows up in the
495 * flat segments at offset 0x10000 (since linear addresses wrap around at
496 * 4GB). To compensate for that discrepancy between flat segment offsets
497 * and plain linear addresses, all flat pointers passed between the 32-bit
498 * and the 16-bit parts of Win32s are shifted by 0x10000 in the appropriate
499 * direction by the glue code (mainly) in W32SKRNL and WIN32S16.
501 * The problem for us is now that Linux does not allow a LDT selector with
502 * base 0xffff0000 to be created, since it would 'see' a part of the kernel
503 * address space. To address this problem we introduce *another* offset:
504 * We add 0x10000 to every linear address we get as an argument from Win32s.
505 * This means especially that the flat code/data selectors get actually
506 * allocated with base 0x0, so that flat offsets and (real) linear addresses
507 * do again agree! In fact, every call e.g. of a Win32s VxD service now
508 * has all pointer arguments (which are offsets in the flat data segement)
509 * first reduced by 0x10000 by the W32SKRNL glue code, and then again
510 * increased by 0x10000 by *our* code.
512 * Note that to keep everything consistent, this offset has to be applied by
513 * every Wine function that operates on 'linear addresses' passed to it by
514 * Win32s. Fortunately, since Win32s does not directly call any Wine 32-bit
515 * API routines, this affects only two locations: this VxD and the DPMI
516 * handler. (NOTE: Should any Win32s application pass a linear address to
517 * any routine apart from those, e.g. some other VxD handler, that code
518 * would have to take the offset into account as well!)
520 * The application of the offset is triggered by marking the current process
521 * as a Win32s process by setting the PDB32_WIN32S_PROC flag in the process
522 * database. This is done the first time any application calls the GetVersion()
523 * service of the Win32s VxD. (Note that the flag is never removed.)
527 void WINAPI VXD_Win32s( CONTEXT86 *context )
529 switch (AX_reg(context))
531 case 0x0000: /* Get Version */
533 * Input: None
535 * Output: EAX: LoWord: Win32s Version (1.30)
536 * HiWord: VxD Version (200)
538 * EBX: Build (172)
540 * ECX: ??? (1)
542 * EDX: Debugging Flags
544 * EDI: Error Flag
545 * 0 if OK,
546 * 1 if VMCPD VxD not found
549 TRACE("GetVersion()\n");
551 context->Eax = VXD_WinVersion() | (200 << 16);
552 context->Ebx = 0;
553 context->Ecx = 0;
554 context->Edx = 0;
555 context->Edi = 0;
558 * If this is the first time we are called for this process,
559 * hack the memory image of WIN32S16 so that it doesn't try
560 * to access the GDT directly ...
562 * The first code segment of WIN32S16 (version 1.30) contains
563 * an unexported function somewhere between the exported functions
564 * SetFS and StackLinearToSegmented that tries to find a selector
565 * in the LDT that maps to the memory image of the LDT itself.
566 * If it succeeds, it stores this selector into a global variable
567 * which will be used to speed up execution by using this selector
568 * to modify the LDT directly instead of using the DPMI calls.
570 * To perform this search of the LDT, this function uses the
571 * sgdt and sldt instructions to find the linear address of
572 * the (GDT and then) LDT. While those instructions themselves
573 * execute without problem, the linear address that sgdt returns
574 * points (at least under Linux) to the kernel address space, so
575 * that any subsequent access leads to a segfault.
577 * Fortunately, WIN32S16 still contains as a fallback option the
578 * mechanism of using DPMI calls to modify LDT selectors instead
579 * of direct writes to the LDT. Thus we can circumvent the problem
580 * by simply replacing the first byte of the offending function
581 * with an 'retf' instruction. This means that the global variable
582 * supposed to contain the LDT alias selector will remain zero,
583 * and hence WIN32S16 will fall back to using DPMI calls.
585 * The heuristic we employ to _find_ that function is as follows:
586 * We search between the addresses of the exported symbols SetFS
587 * and StackLinearToSegmented for the byte sequence '0F 01 04'
588 * (this is the opcode of 'sgdt [si]'). We then search backwards
589 * from this address for the last occurrance of 'CB' (retf) that marks
590 * the end of the preceeding function. The following byte (which
591 * should now be the first byte of the function we are looking for)
592 * will be replaced by 'CB' (retf).
594 * This heuristic works for the retail as well as the debug version
595 * of Win32s version 1.30. For versions earlier than that this
596 * hack should not be necessary at all, since the whole mechanism
597 * ('PERF130') was introduced only in 1.30 to improve the overall
598 * performance of Win32s.
601 if (!(PROCESS_Current()->flags & PDB32_WIN32S_PROC))
603 HMODULE16 hModule = GetModuleHandle16("win32s16");
604 SEGPTR func1 = (SEGPTR)WIN32_GetProcAddress16(hModule, "SetFS");
605 SEGPTR func2 = (SEGPTR)WIN32_GetProcAddress16(hModule,
606 "StackLinearToSegmented");
608 if ( hModule && func1 && func2
609 && SELECTOROF(func1) == SELECTOROF(func2))
611 BYTE *start = PTR_SEG_TO_LIN(func1);
612 BYTE *end = PTR_SEG_TO_LIN(func2);
613 BYTE *p, *retv = NULL;
614 int found = 0;
616 for (p = start; p < end; p++)
617 if (*p == 0xCB) found = 0, retv = p;
618 else if (*p == 0x0F) found = 1;
619 else if (*p == 0x01 && found == 1) found = 2;
620 else if (*p == 0x04 && found == 2) { found = 3; break; }
621 else found = 0;
623 if (found == 3 && retv)
625 TRACE("PERF130 hack: "
626 "Replacing byte %02X at offset %04X:%04X\n",
627 *(retv+1), SELECTOROF(func1),
628 OFFSETOF(func1) + retv+1-start);
630 *(retv+1) = (BYTE)0xCB;
636 * Mark process as Win32s, so that subsequent DPMI calls
637 * will perform the W32S_APP2WINE/W32S_WINE2APP address shift.
640 PROCESS_Current()->flags |= PDB32_WIN32S_PROC;
641 break;
644 case 0x0001: /* Install Exception Handling */
646 * Input: EBX: Flat address of W32SKRNL Exception Data
648 * ECX: LoWord: Flat Code Selector
649 * HiWord: Flat Data Selector
651 * EDX: Flat address of W32SKRNL Exception Handler
652 * (this is equal to W32S_BackTo32 + 0x40)
654 * ESI: SEGPTR KERNEL.HASGPHANDLER
656 * EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10)
658 * Output: EAX: 0 if OK
661 TRACE("[0001] EBX=%lx ECX=%lx EDX=%lx ESI=%lx EDI=%lx\n",
662 context->Ebx, context->Ecx, context->Edx,
663 context->Esi, context->Edi);
665 /* FIXME */
667 context->Eax = 0;
668 break;
671 case 0x0002: /* Set Page Access Flags */
673 * Input: EBX: New access flags
674 * Bit 2: User Page if set, Supervisor Page if clear
675 * Bit 1: Read-Write if set, Read-Only if clear
677 * ECX: Size of memory area to change
679 * EDX: Flat start address of memory area
681 * Output: EAX: Size of area changed
684 TRACE("[0002] EBX=%lx ECX=%lx EDX=%lx\n",
685 context->Ebx, context->Ecx, context->Edx);
687 /* FIXME */
689 context->Eax = context->Ecx;
690 break;
693 case 0x0003: /* Get Page Access Flags */
695 * Input: EDX: Flat address of page to query
697 * Output: EAX: Page access flags
698 * Bit 2: User Page if set, Supervisor Page if clear
699 * Bit 1: Read-Write if set, Read-Only if clear
702 TRACE("[0003] EDX=%lx\n", context->Edx);
704 /* FIXME */
706 context->Eax = 6;
707 break;
710 case 0x0004: /* Map Module */
712 * Input: ECX: IMTE (offset in Module Table) of new module
714 * EDX: Flat address of Win32s Module Table
716 * Output: EAX: 0 if OK
719 if (!context->Edx || CX_reg(context) == 0xFFFF)
721 TRACE("MapModule: Initialization call\n");
722 context->Eax = 0;
724 else
727 * Structure of a Win32s Module Table Entry:
729 struct Win32sModule
731 DWORD flags;
732 DWORD flatBaseAddr;
733 LPCSTR moduleName;
734 LPCSTR pathName;
735 LPCSTR unknown;
736 LPBYTE baseAddr;
737 DWORD hModule;
738 DWORD relocDelta;
742 * Note: This function should set up a demand-paged memory image
743 * of the given module. Since mmap does not allow file offsets
744 * not aligned at 1024 bytes, we simply load the image fully
745 * into memory.
748 struct Win32sModule *moduleTable =
749 (struct Win32sModule *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
750 struct Win32sModule *module = moduleTable + context->Ecx;
752 IMAGE_NT_HEADERS *nt_header = PE_HEADER(module->baseAddr);
753 IMAGE_SECTION_HEADER *pe_seg = PE_SECTIONS(module->baseAddr);
755 HFILE image = _lopen(module->pathName, OF_READ);
756 BOOL error = (image == HFILE_ERROR);
757 UINT i;
759 TRACE("MapModule: Loading %s\n", module->pathName);
761 for (i = 0;
762 !error && i < nt_header->FileHeader.NumberOfSections;
763 i++, pe_seg++)
764 if(!(pe_seg->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA))
766 DWORD off = pe_seg->PointerToRawData;
767 DWORD len = pe_seg->SizeOfRawData;
768 LPBYTE addr = module->baseAddr + pe_seg->VirtualAddress;
770 TRACE("MapModule: "
771 "Section %d at %08lx from %08lx len %08lx\n",
772 i, (DWORD)addr, off, len);
774 if ( _llseek(image, off, SEEK_SET) != off
775 || _lread(image, addr, len) != len)
776 error = TRUE;
779 _lclose(image);
781 if (error)
782 ERR("MapModule: Unable to load %s\n", module->pathName);
784 else if (module->relocDelta != 0)
786 IMAGE_DATA_DIRECTORY *dir = nt_header->OptionalHeader.DataDirectory
787 + IMAGE_DIRECTORY_ENTRY_BASERELOC;
788 IMAGE_BASE_RELOCATION *r = (IMAGE_BASE_RELOCATION *)
789 (dir->Size? module->baseAddr + dir->VirtualAddress : 0);
791 TRACE("MapModule: Reloc delta %08lx\n", module->relocDelta);
793 while (r && r->VirtualAddress)
795 LPBYTE page = module->baseAddr + r->VirtualAddress;
796 int count = (r->SizeOfBlock - 8) / 2;
798 TRACE("MapModule: %d relocations for page %08lx\n",
799 count, (DWORD)page);
801 for(i = 0; i < count; i++)
803 int offset = r->TypeOffset[i] & 0xFFF;
804 int type = r->TypeOffset[i] >> 12;
805 switch(type)
807 case IMAGE_REL_BASED_ABSOLUTE:
808 break;
809 case IMAGE_REL_BASED_HIGH:
810 *(WORD *)(page+offset) += HIWORD(module->relocDelta);
811 break;
812 case IMAGE_REL_BASED_LOW:
813 *(WORD *)(page+offset) += LOWORD(module->relocDelta);
814 break;
815 case IMAGE_REL_BASED_HIGHLOW:
816 *(DWORD*)(page+offset) += module->relocDelta;
817 break;
818 default:
819 WARN("MapModule: Unsupported fixup type\n");
820 break;
824 r = (IMAGE_BASE_RELOCATION *)((LPBYTE)r + r->SizeOfBlock);
828 context->Eax = 0;
829 RESET_CFLAG(context);
831 break;
834 case 0x0005: /* UnMap Module */
836 * Input: EDX: Flat address of module image
838 * Output: EAX: 1 if OK
841 TRACE("UnMapModule: %lx\n", (DWORD)W32S_APP2WINE(context->Edx, W32S_OFFSET));
843 /* As we didn't map anything, there's nothing to unmap ... */
845 context->Eax = 1;
846 break;
849 case 0x0006: /* VirtualAlloc */
851 * Input: ECX: Current Process
853 * EDX: Flat address of arguments on stack
855 * DWORD *retv [out] Flat base address of allocated region
856 * LPVOID base [in] Flat address of region to reserve/commit
857 * DWORD size [in] Size of region
858 * DWORD type [in] Type of allocation
859 * DWORD prot [in] Type of access protection
861 * Output: EAX: NtStatus
864 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
865 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
866 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
867 DWORD size = stack[2];
868 DWORD type = stack[3];
869 DWORD prot = stack[4];
870 DWORD result;
872 TRACE("VirtualAlloc(%lx, %lx, %lx, %lx, %lx)\n",
873 (DWORD)retv, (DWORD)base, size, type, prot);
875 if (type & 0x80000000)
877 WARN("VirtualAlloc: strange type %lx\n", type);
878 type &= 0x7fffffff;
881 if (!base && (type & MEM_COMMIT) && prot == PAGE_READONLY)
883 WARN("VirtualAlloc: NLS hack, allowing write access!\n");
884 prot = PAGE_READWRITE;
887 result = (DWORD)VirtualAlloc(base, size, type, prot);
889 if (W32S_WINE2APP(result, W32S_OFFSET))
890 *retv = W32S_WINE2APP(result, W32S_OFFSET),
891 context->Eax = STATUS_SUCCESS;
892 else
893 *retv = 0,
894 context->Eax = STATUS_NO_MEMORY; /* FIXME */
896 break;
899 case 0x0007: /* VirtualFree */
901 * Input: ECX: Current Process
903 * EDX: Flat address of arguments on stack
905 * DWORD *retv [out] TRUE if success, FALSE if failure
906 * LPVOID base [in] Flat address of region
907 * DWORD size [in] Size of region
908 * DWORD type [in] Type of operation
910 * Output: EAX: NtStatus
913 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
914 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
915 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
916 DWORD size = stack[2];
917 DWORD type = stack[3];
918 DWORD result;
920 TRACE("VirtualFree(%lx, %lx, %lx, %lx)\n",
921 (DWORD)retv, (DWORD)base, size, type);
923 result = VirtualFree(base, size, type);
925 if (result)
926 *retv = TRUE,
927 context->Eax = STATUS_SUCCESS;
928 else
929 *retv = FALSE,
930 context->Eax = STATUS_NO_MEMORY; /* FIXME */
932 break;
935 case 0x0008: /* VirtualProtect */
937 * Input: ECX: Current Process
939 * EDX: Flat address of arguments on stack
941 * DWORD *retv [out] TRUE if success, FALSE if failure
942 * LPVOID base [in] Flat address of region
943 * DWORD size [in] Size of region
944 * DWORD new_prot [in] Desired access protection
945 * DWORD *old_prot [out] Previous access protection
947 * Output: EAX: NtStatus
950 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
951 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
952 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
953 DWORD size = stack[2];
954 DWORD new_prot = stack[3];
955 DWORD *old_prot = (DWORD *)W32S_APP2WINE(stack[4], W32S_OFFSET);
956 DWORD result;
958 TRACE("VirtualProtect(%lx, %lx, %lx, %lx, %lx)\n",
959 (DWORD)retv, (DWORD)base, size, new_prot, (DWORD)old_prot);
961 result = VirtualProtect(base, size, new_prot, old_prot);
963 if (result)
964 *retv = TRUE,
965 context->Eax = STATUS_SUCCESS;
966 else
967 *retv = FALSE,
968 context->Eax = STATUS_NO_MEMORY; /* FIXME */
970 break;
973 case 0x0009: /* VirtualQuery */
975 * Input: ECX: Current Process
977 * EDX: Flat address of arguments on stack
979 * DWORD *retv [out] Nr. bytes returned
980 * LPVOID base [in] Flat address of region
981 * LPMEMORY_BASIC_INFORMATION info [out] Info buffer
982 * DWORD len [in] Size of buffer
984 * Output: EAX: NtStatus
987 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
988 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
989 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
990 LPMEMORY_BASIC_INFORMATION info =
991 (LPMEMORY_BASIC_INFORMATION)W32S_APP2WINE(stack[2], W32S_OFFSET);
992 DWORD len = stack[3];
993 DWORD result;
995 TRACE("VirtualQuery(%lx, %lx, %lx, %lx)\n",
996 (DWORD)retv, (DWORD)base, (DWORD)info, len);
998 result = VirtualQuery(base, info, len);
1000 *retv = result;
1001 context->Eax = STATUS_SUCCESS;
1003 break;
1006 case 0x000A: /* SetVirtMemProcess */
1008 * Input: ECX: Process Handle
1010 * EDX: Flat address of region
1012 * Output: EAX: NtStatus
1015 TRACE("[000a] ECX=%lx EDX=%lx\n",
1016 context->Ecx, context->Edx);
1018 /* FIXME */
1020 context->Eax = STATUS_SUCCESS;
1021 break;
1024 case 0x000B: /* ??? some kind of cleanup */
1026 * Input: ECX: Process Handle
1028 * Output: EAX: NtStatus
1031 TRACE("[000b] ECX=%lx\n", context->Ecx);
1033 /* FIXME */
1035 context->Eax = STATUS_SUCCESS;
1036 break;
1039 case 0x000C: /* Set Debug Flags */
1041 * Input: EDX: Debug Flags
1043 * Output: EDX: Previous Debug Flags
1046 FIXME("[000c] EDX=%lx\n", context->Edx);
1048 /* FIXME */
1050 context->Edx = 0;
1051 break;
1054 case 0x000D: /* NtCreateSection */
1056 * Input: EDX: Flat address of arguments on stack
1058 * HANDLE32 *retv [out] Handle of Section created
1059 * DWORD flags1 [in] (?? unknown ??)
1060 * DWORD atom [in] Name of Section to create
1061 * LARGE_INTEGER *size [in] Size of Section
1062 * DWORD protect [in] Access protection
1063 * DWORD flags2 [in] (?? unknown ??)
1064 * HFILE32 hFile [in] Handle of file to map
1065 * DWORD psp [in] (Win32s: PSP that hFile belongs to)
1067 * Output: EAX: NtStatus
1070 DWORD *stack = (DWORD *) W32S_APP2WINE(context->Edx, W32S_OFFSET);
1071 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1072 DWORD flags1 = stack[1];
1073 DWORD atom = stack[2];
1074 LARGE_INTEGER *size = (LARGE_INTEGER *)W32S_APP2WINE(stack[3], W32S_OFFSET);
1075 DWORD protect = stack[4];
1076 DWORD flags2 = stack[5];
1077 HFILE hFile = FILE_GetHandle(stack[6]);
1078 DWORD psp = stack[7];
1080 HANDLE result = INVALID_HANDLE_VALUE;
1081 char name[128];
1083 TRACE("NtCreateSection(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1084 (DWORD)retv, flags1, atom, (DWORD)size, protect, flags2,
1085 (DWORD)hFile, psp);
1087 if (!atom || GlobalGetAtomNameA(atom, name, sizeof(name)))
1089 TRACE("NtCreateSection: name=%s\n", atom? name : NULL);
1091 result = CreateFileMappingA(hFile, NULL, protect,
1092 size? size->s.HighPart : 0,
1093 size? size->s.LowPart : 0,
1094 atom? name : NULL);
1097 if (result == INVALID_HANDLE_VALUE)
1098 WARN("NtCreateSection: failed!\n");
1099 else
1100 TRACE("NtCreateSection: returned %lx\n", (DWORD)result);
1102 if (result != INVALID_HANDLE_VALUE)
1103 *retv = result,
1104 context->Eax = STATUS_SUCCESS;
1105 else
1106 *retv = result,
1107 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1109 break;
1112 case 0x000E: /* NtOpenSection */
1114 * Input: EDX: Flat address of arguments on stack
1116 * HANDLE32 *retv [out] Handle of Section opened
1117 * DWORD protect [in] Access protection
1118 * DWORD atom [in] Name of Section to create
1120 * Output: EAX: NtStatus
1123 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
1124 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1125 DWORD protect = stack[1];
1126 DWORD atom = stack[2];
1128 HANDLE result = INVALID_HANDLE_VALUE;
1129 char name[128];
1131 TRACE("NtOpenSection(%lx, %lx, %lx)\n",
1132 (DWORD)retv, protect, atom);
1134 if (atom && GlobalGetAtomNameA(atom, name, sizeof(name)))
1136 TRACE("NtOpenSection: name=%s\n", name);
1138 result = OpenFileMappingA(protect, FALSE, name);
1141 if (result == INVALID_HANDLE_VALUE)
1142 WARN("NtOpenSection: failed!\n");
1143 else
1144 TRACE("NtOpenSection: returned %lx\n", (DWORD)result);
1146 if (result != INVALID_HANDLE_VALUE)
1147 *retv = result,
1148 context->Eax = STATUS_SUCCESS;
1149 else
1150 *retv = result,
1151 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1153 break;
1156 case 0x000F: /* NtCloseSection */
1158 * Input: EDX: Flat address of arguments on stack
1160 * HANDLE32 handle [in] Handle of Section to close
1161 * DWORD *id [out] Unique ID (?? unclear ??)
1163 * Output: EAX: NtStatus
1166 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
1167 HANDLE handle = stack[0];
1168 DWORD *id = (DWORD *)W32S_APP2WINE(stack[1], W32S_OFFSET);
1170 TRACE("NtCloseSection(%lx, %lx)\n", (DWORD)handle, (DWORD)id);
1172 CloseHandle(handle);
1173 if (id) *id = 0; /* FIXME */
1175 context->Eax = STATUS_SUCCESS;
1177 break;
1180 case 0x0010: /* NtDupSection */
1182 * Input: EDX: Flat address of arguments on stack
1184 * HANDLE32 handle [in] Handle of Section to duplicate
1186 * Output: EAX: NtStatus
1189 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
1190 HANDLE handle = stack[0];
1191 HANDLE new_handle;
1193 TRACE("NtDupSection(%lx)\n", (DWORD)handle);
1195 DuplicateHandle( GetCurrentProcess(), handle,
1196 GetCurrentProcess(), &new_handle,
1197 0, FALSE, DUPLICATE_SAME_ACCESS );
1198 context->Eax = STATUS_SUCCESS;
1200 break;
1203 case 0x0011: /* NtMapViewOfSection */
1205 * Input: EDX: Flat address of arguments on stack
1207 * HANDLE32 SectionHandle [in] Section to be mapped
1208 * DWORD ProcessHandle [in] Process to be mapped into
1209 * DWORD * BaseAddress [in/out] Address to be mapped at
1210 * DWORD ZeroBits [in] (?? unclear ??)
1211 * DWORD CommitSize [in] (?? unclear ??)
1212 * LARGE_INTEGER *SectionOffset [in] Offset within section
1213 * DWORD * ViewSize [in] Size of view
1214 * DWORD InheritDisposition [in] (?? unclear ??)
1215 * DWORD AllocationType [in] (?? unclear ??)
1216 * DWORD Protect [in] Access protection
1218 * Output: EAX: NtStatus
1221 DWORD * stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
1222 HANDLE SectionHandle = stack[0];
1223 DWORD ProcessHandle = stack[1]; /* ignored */
1224 DWORD * BaseAddress = (DWORD *)W32S_APP2WINE(stack[2], W32S_OFFSET);
1225 DWORD ZeroBits = stack[3];
1226 DWORD CommitSize = stack[4];
1227 LARGE_INTEGER *SectionOffset = (LARGE_INTEGER *)W32S_APP2WINE(stack[5], W32S_OFFSET);
1228 DWORD * ViewSize = (DWORD *)W32S_APP2WINE(stack[6], W32S_OFFSET);
1229 DWORD InheritDisposition = stack[7];
1230 DWORD AllocationType = stack[8];
1231 DWORD Protect = stack[9];
1233 LPBYTE address = (LPBYTE)(BaseAddress?
1234 W32S_APP2WINE(*BaseAddress, W32S_OFFSET) : 0);
1235 DWORD access = 0, result;
1237 switch (Protect & ~(PAGE_GUARD|PAGE_NOCACHE))
1239 case PAGE_READONLY: access = FILE_MAP_READ; break;
1240 case PAGE_READWRITE: access = FILE_MAP_WRITE; break;
1241 case PAGE_WRITECOPY: access = FILE_MAP_COPY; break;
1243 case PAGE_EXECUTE_READ: access = FILE_MAP_READ; break;
1244 case PAGE_EXECUTE_READWRITE: access = FILE_MAP_WRITE; break;
1245 case PAGE_EXECUTE_WRITECOPY: access = FILE_MAP_COPY; break;
1248 TRACE("NtMapViewOfSection"
1249 "(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1250 (DWORD)SectionHandle, ProcessHandle, (DWORD)BaseAddress,
1251 ZeroBits, CommitSize, (DWORD)SectionOffset, (DWORD)ViewSize,
1252 InheritDisposition, AllocationType, Protect);
1253 TRACE("NtMapViewOfSection: "
1254 "base=%lx, offset=%lx, size=%lx, access=%lx\n",
1255 (DWORD)address, SectionOffset? SectionOffset->s.LowPart : 0,
1256 ViewSize? *ViewSize : 0, access);
1258 result = (DWORD)MapViewOfFileEx(SectionHandle, access,
1259 SectionOffset? SectionOffset->s.HighPart : 0,
1260 SectionOffset? SectionOffset->s.LowPart : 0,
1261 ViewSize? *ViewSize : 0, address);
1263 TRACE("NtMapViewOfSection: result=%lx\n", result);
1265 if (W32S_WINE2APP(result, W32S_OFFSET))
1267 if (BaseAddress) *BaseAddress = W32S_WINE2APP(result, W32S_OFFSET);
1268 context->Eax = STATUS_SUCCESS;
1270 else
1271 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1273 break;
1276 case 0x0012: /* NtUnmapViewOfSection */
1278 * Input: EDX: Flat address of arguments on stack
1280 * DWORD ProcessHandle [in] Process (defining address space)
1281 * LPBYTE BaseAddress [in] Base address of view to be unmapped
1283 * Output: EAX: NtStatus
1286 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
1287 DWORD ProcessHandle = stack[0]; /* ignored */
1288 LPBYTE BaseAddress = (LPBYTE)W32S_APP2WINE(stack[1], W32S_OFFSET);
1290 TRACE("NtUnmapViewOfSection(%lx, %lx)\n",
1291 ProcessHandle, (DWORD)BaseAddress);
1293 UnmapViewOfFile(BaseAddress);
1295 context->Eax = STATUS_SUCCESS;
1297 break;
1300 case 0x0013: /* NtFlushVirtualMemory */
1302 * Input: EDX: Flat address of arguments on stack
1304 * DWORD ProcessHandle [in] Process (defining address space)
1305 * LPBYTE *BaseAddress [in?] Base address of range to be flushed
1306 * DWORD *ViewSize [in?] Number of bytes to be flushed
1307 * DWORD *unknown [???] (?? unknown ??)
1309 * Output: EAX: NtStatus
1312 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
1313 DWORD ProcessHandle = stack[0]; /* ignored */
1314 DWORD *BaseAddress = (DWORD *)W32S_APP2WINE(stack[1], W32S_OFFSET);
1315 DWORD *ViewSize = (DWORD *)W32S_APP2WINE(stack[2], W32S_OFFSET);
1316 DWORD *unknown = (DWORD *)W32S_APP2WINE(stack[3], W32S_OFFSET);
1318 LPBYTE address = (LPBYTE)(BaseAddress? W32S_APP2WINE(*BaseAddress, W32S_OFFSET) : 0);
1319 DWORD size = ViewSize? *ViewSize : 0;
1321 TRACE("NtFlushVirtualMemory(%lx, %lx, %lx, %lx)\n",
1322 ProcessHandle, (DWORD)BaseAddress, (DWORD)ViewSize,
1323 (DWORD)unknown);
1324 TRACE("NtFlushVirtualMemory: base=%lx, size=%lx\n",
1325 (DWORD)address, size);
1327 FlushViewOfFile(address, size);
1329 context->Eax = STATUS_SUCCESS;
1331 break;
1334 case 0x0014: /* Get/Set Debug Registers */
1336 * Input: ECX: 0 if Get, 1 if Set
1338 * EDX: Get: Flat address of buffer to receive values of
1339 * debug registers DR0 .. DR7
1340 * Set: Flat address of buffer containing values of
1341 * debug registers DR0 .. DR7 to be set
1342 * Output: None
1345 FIXME("[0014] ECX=%lx EDX=%lx\n",
1346 context->Ecx, context->Edx);
1348 /* FIXME */
1349 break;
1352 case 0x0015: /* Set Coprocessor Emulation Flag */
1354 * Input: EDX: 0 to deactivate, 1 to activate coprocessor emulation
1356 * Output: None
1359 TRACE("[0015] EDX=%lx\n", context->Edx);
1361 /* We don't care, as we always have a coprocessor anyway */
1362 break;
1365 case 0x0016: /* Init Win32S VxD PSP */
1367 * If called to query required PSP size:
1369 * Input: EBX: 0
1370 * Output: EDX: Required size of Win32s VxD PSP
1372 * If called to initialize allocated PSP:
1374 * Input: EBX: LoWord: Selector of Win32s VxD PSP
1375 * HiWord: Paragraph of Win32s VxD PSP (DOSMEM)
1376 * Output: None
1379 if (context->Ebx == 0)
1380 context->Edx = 0x80;
1381 else
1383 PDB16 *psp = PTR_SEG_OFF_TO_LIN(BX_reg(context), 0);
1384 psp->nbFiles = 32;
1385 psp->fileHandlesPtr = MAKELONG(HIWORD(context->Ebx), 0x5c);
1386 memset((LPBYTE)psp + 0x5c, '\xFF', 32);
1388 break;
1391 case 0x0017: /* Set Break Point */
1393 * Input: EBX: Offset of Break Point
1394 * CX: Selector of Break Point
1396 * Output: None
1399 FIXME("[0017] EBX=%lx CX=%x\n",
1400 context->Ebx, CX_reg(context));
1402 /* FIXME */
1403 break;
1406 case 0x0018: /* VirtualLock */
1408 * Input: ECX: Current Process
1410 * EDX: Flat address of arguments on stack
1412 * DWORD *retv [out] TRUE if success, FALSE if failure
1413 * LPVOID base [in] Flat address of range to lock
1414 * DWORD size [in] Size of range
1416 * Output: EAX: NtStatus
1419 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
1420 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1421 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
1422 DWORD size = stack[2];
1423 DWORD result;
1425 TRACE("VirtualLock(%lx, %lx, %lx)\n",
1426 (DWORD)retv, (DWORD)base, size);
1428 result = VirtualLock(base, size);
1430 if (result)
1431 *retv = TRUE,
1432 context->Eax = STATUS_SUCCESS;
1433 else
1434 *retv = FALSE,
1435 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1437 break;
1440 case 0x0019: /* VirtualUnlock */
1442 * Input: ECX: Current Process
1444 * EDX: Flat address of arguments on stack
1446 * DWORD *retv [out] TRUE if success, FALSE if failure
1447 * LPVOID base [in] Flat address of range to unlock
1448 * DWORD size [in] Size of range
1450 * Output: EAX: NtStatus
1453 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
1454 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1455 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
1456 DWORD size = stack[2];
1457 DWORD result;
1459 TRACE("VirtualUnlock(%lx, %lx, %lx)\n",
1460 (DWORD)retv, (DWORD)base, size);
1462 result = VirtualUnlock(base, size);
1464 if (result)
1465 *retv = TRUE,
1466 context->Eax = STATUS_SUCCESS;
1467 else
1468 *retv = FALSE,
1469 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1471 break;
1474 case 0x001A: /* KGetSystemInfo */
1476 * Input: None
1478 * Output: ECX: Start of sparse memory arena
1479 * EDX: End of sparse memory arena
1482 TRACE("KGetSystemInfo()\n");
1485 * Note: Win32s reserves 0GB - 2GB for Win 3.1 and uses 2GB - 4GB as
1486 * sparse memory arena. We do it the other way around, since
1487 * we have to reserve 3GB - 4GB for Linux, and thus use
1488 * 0GB - 3GB as sparse memory arena.
1490 * FIXME: What about other OSes ?
1493 context->Ecx = W32S_WINE2APP(0x00000000, W32S_OFFSET);
1494 context->Edx = W32S_WINE2APP(0xbfffffff, W32S_OFFSET);
1495 break;
1498 case 0x001B: /* KGlobalMemStat */
1500 * Input: ESI: Flat address of buffer to receive memory info
1502 * Output: None
1505 struct Win32sMemoryInfo
1507 DWORD DIPhys_Count; /* Total physical pages */
1508 DWORD DIFree_Count; /* Free physical pages */
1509 DWORD DILin_Total_Count; /* Total virtual pages (private arena) */
1510 DWORD DILin_Total_Free; /* Free virtual pages (private arena) */
1512 DWORD SparseTotal; /* Total size of sparse arena (bytes ?) */
1513 DWORD SparseFree; /* Free size of sparse arena (bytes ?) */
1516 struct Win32sMemoryInfo *info =
1517 (struct Win32sMemoryInfo *)W32S_APP2WINE(context->Esi, W32S_OFFSET);
1519 FIXME("KGlobalMemStat(%lx)\n", (DWORD)info);
1521 /* FIXME */
1523 break;
1526 case 0x001C: /* Enable/Disable Exceptions */
1528 * Input: ECX: 0 to disable, 1 to enable exception handling
1530 * Output: None
1533 TRACE("[001c] ECX=%lx\n", context->Ecx);
1535 /* FIXME */
1536 break;
1539 case 0x001D: /* VirtualAlloc called from 16-bit code */
1541 * Input: EDX: Segmented address of arguments on stack
1543 * LPVOID base [in] Flat address of region to reserve/commit
1544 * DWORD size [in] Size of region
1545 * DWORD type [in] Type of allocation
1546 * DWORD prot [in] Type of access protection
1548 * Output: EAX: NtStatus
1549 * EDX: Flat base address of allocated region
1552 DWORD *stack = PTR_SEG_OFF_TO_LIN(LOWORD(context->Edx),
1553 HIWORD(context->Edx));
1554 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0], W32S_OFFSET);
1555 DWORD size = stack[1];
1556 DWORD type = stack[2];
1557 DWORD prot = stack[3];
1558 DWORD result;
1560 TRACE("VirtualAlloc16(%lx, %lx, %lx, %lx)\n",
1561 (DWORD)base, size, type, prot);
1563 if (type & 0x80000000)
1565 WARN("VirtualAlloc16: strange type %lx\n", type);
1566 type &= 0x7fffffff;
1569 result = (DWORD)VirtualAlloc(base, size, type, prot);
1571 if (W32S_WINE2APP(result, W32S_OFFSET))
1572 context->Edx = W32S_WINE2APP(result, W32S_OFFSET),
1573 context->Eax = STATUS_SUCCESS;
1574 else
1575 context->Edx = 0,
1576 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1577 TRACE("VirtualAlloc16: returning base %lx\n", context->Edx);
1579 break;
1582 case 0x001E: /* VirtualFree called from 16-bit code */
1584 * Input: EDX: Segmented address of arguments on stack
1586 * LPVOID base [in] Flat address of region
1587 * DWORD size [in] Size of region
1588 * DWORD type [in] Type of operation
1590 * Output: EAX: NtStatus
1591 * EDX: TRUE if success, FALSE if failure
1594 DWORD *stack = PTR_SEG_OFF_TO_LIN(LOWORD(context->Edx),
1595 HIWORD(context->Edx));
1596 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0], W32S_OFFSET);
1597 DWORD size = stack[1];
1598 DWORD type = stack[2];
1599 DWORD result;
1601 TRACE("VirtualFree16(%lx, %lx, %lx)\n",
1602 (DWORD)base, size, type);
1604 result = VirtualFree(base, size, type);
1606 if (result)
1607 context->Edx = TRUE,
1608 context->Eax = STATUS_SUCCESS;
1609 else
1610 context->Edx = FALSE,
1611 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1613 break;
1616 case 0x001F: /* FWorkingSetSize */
1618 * Input: EDX: 0 if Get, 1 if Set
1620 * ECX: Get: Buffer to receive Working Set Size
1621 * Set: Buffer containing Working Set Size
1623 * Output: NtStatus
1626 DWORD *ptr = (DWORD *)W32S_APP2WINE(context->Ecx, W32S_OFFSET);
1627 BOOL set = context->Edx;
1629 TRACE("FWorkingSetSize(%lx, %lx)\n", (DWORD)ptr, (DWORD)set);
1631 if (set)
1632 /* We do it differently ... */;
1633 else
1634 *ptr = 0x100;
1636 context->Eax = STATUS_SUCCESS;
1638 break;
1641 default:
1642 VXD_BARF( context, "W32S" );