Added Finnish keyboard layout.
[wine/hacks.git] / msdos / vxd.c
blob29dd3f8f92525249911752338389ca2654e85206
1 /*
2 * VxD emulation
4 * Copyright 1995 Anand Kumria
5 */
7 #include <fcntl.h>
8 #include <memory.h>
9 #include "winbase.h"
10 #include "winuser.h"
11 #include "wine/winbase16.h"
12 #include "wine/winuser16.h"
13 #include "msdos.h"
14 #include "miscemu.h"
15 #include "selectors.h"
16 #include "neexe.h"
17 #include "task.h"
18 #include "process.h"
19 #include "file.h"
20 #include "debug.h"
23 #define VXD_BARF(context,name) \
24 DUMP( "vxd %s: unknown/not implemented parameters:\n" \
25 "vxd %s: AX %04x, BX %04x, CX %04x, DX %04x, " \
26 "SI %04x, DI %04x, DS %04x, ES %04x\n", \
27 (name), (name), AX_reg(context), BX_reg(context), \
28 CX_reg(context), DX_reg(context), SI_reg(context), \
29 DI_reg(context), (WORD)DS_reg(context), (WORD)ES_reg(context) )
32 static WORD VXD_WinVersion(void)
34 WORD version = LOWORD(GetVersion16());
35 return (version >> 8) | (version << 8);
38 /***********************************************************************
39 * VXD_VMM
41 void VXD_VMM ( CONTEXT *context )
43 unsigned service = AX_reg(context);
45 TRACE(vxd,"[%04x] VMM \n", (UINT16)service);
47 switch(service)
49 case 0x0000: /* version */
50 AX_reg(context) = VXD_WinVersion();
51 RESET_CFLAG(context);
52 break;
54 case 0x026d: /* Get_Debug_Flag '/m' */
55 case 0x026e: /* Get_Debug_Flag '/n' */
56 AL_reg(context) = 0;
57 RESET_CFLAG(context);
58 break;
60 default:
61 VXD_BARF( context, "VMM" );
65 /***********************************************************************
66 * VXD_PageFile
68 void WINAPI VXD_PageFile( CONTEXT *context )
70 unsigned service = AX_reg(context);
72 /* taken from Ralf Brown's Interrupt List */
74 TRACE(vxd,"[%04x] PageFile\n", (UINT16)service );
76 switch(service)
78 case 0x00: /* get version, is this windows version? */
79 TRACE(vxd,"returning version\n");
80 AX_reg(context) = VXD_WinVersion();
81 RESET_CFLAG(context);
82 break;
84 case 0x01: /* get swap file info */
85 TRACE(vxd,"VxD PageFile: returning swap file info\n");
86 AX_reg(context) = 0x00; /* paging disabled */
87 ECX_reg(context) = 0; /* maximum size of paging file */
88 /* FIXME: do I touch DS:SI or DS:DI? */
89 RESET_CFLAG(context);
90 break;
92 case 0x02: /* delete permanent swap on exit */
93 TRACE(vxd,"VxD PageFile: supposed to delete swap\n");
94 RESET_CFLAG(context);
95 break;
97 case 0x03: /* current temporary swap file size */
98 TRACE(vxd,"VxD PageFile: what is current temp. swap size\n");
99 RESET_CFLAG(context);
100 break;
102 case 0x04: /* read or write?? INTERRUP.D */
103 case 0x05: /* cancel?? INTERRUP.D */
104 case 0x06: /* test I/O valid INTERRUP.D */
105 default:
106 VXD_BARF( context, "pagefile" );
107 break;
111 /***********************************************************************
112 * VXD_Reboot
114 void VXD_Reboot ( CONTEXT *context )
116 unsigned service = AX_reg(context);
118 TRACE(vxd,"[%04x] VMM \n", (UINT16)service);
120 switch(service)
122 case 0x0000: /* version */
123 AX_reg(context) = VXD_WinVersion();
124 RESET_CFLAG(context);
125 break;
127 default:
128 VXD_BARF( context, "REBOOT" );
132 /***********************************************************************
133 * VXD_VDD
135 void VXD_VDD ( CONTEXT *context )
137 unsigned service = AX_reg(context);
139 TRACE(vxd,"[%04x] VDD \n", (UINT16)service);
141 switch(service)
143 case 0x0000: /* version */
144 AX_reg(context) = VXD_WinVersion();
145 RESET_CFLAG(context);
146 break;
148 default:
149 VXD_BARF( context, "VDD" );
153 /***********************************************************************
154 * VXD_VMD
156 void VXD_VMD ( CONTEXT *context )
158 unsigned service = AX_reg(context);
160 TRACE(vxd,"[%04x] VMD \n", (UINT16)service);
162 switch(service)
164 case 0x0000: /* version */
165 AX_reg(context) = VXD_WinVersion();
166 RESET_CFLAG(context);
167 break;
169 default:
170 VXD_BARF( context, "VMD" );
174 /***********************************************************************
175 * VXD_Shell
177 void WINAPI VXD_Shell( CONTEXT *context )
179 unsigned service = DX_reg(context);
181 TRACE(vxd,"[%04x] Shell\n", (UINT16)service);
183 switch (service) /* Ralf Brown says EDX, but I use DX instead */
185 case 0x0000:
186 TRACE(vxd,"returning version\n");
187 AX_reg(context) = VXD_WinVersion();
188 EBX_reg(context) = 1; /* system VM Handle */
189 break;
191 case 0x0001:
192 case 0x0002:
193 case 0x0003:
194 case 0x0004:
195 case 0x0005:
196 VXD_BARF( context, "shell" );
197 break;
199 case 0x0006: /* SHELL_Get_VM_State */
200 TRACE(vxd,"VxD Shell: returning VM state\n");
201 /* Actually we don't, not yet. We have to return a structure
202 * and I am not to sure how to set it up and return it yet,
203 * so for now let's do nothing. I can (hopefully) get this
204 * by the next release
206 /* RESET_CFLAG(context); */
207 break;
209 case 0x0007:
210 case 0x0008:
211 case 0x0009:
212 case 0x000A:
213 case 0x000B:
214 case 0x000C:
215 case 0x000D:
216 case 0x000E:
217 case 0x000F:
218 case 0x0010:
219 case 0x0011:
220 case 0x0012:
221 case 0x0013:
222 case 0x0014:
223 case 0x0015:
224 case 0x0016:
225 VXD_BARF( context, "SHELL" );
226 break;
228 /* the new Win95 shell API */
229 case 0x0100: /* get version */
230 AX_reg(context) = VXD_WinVersion();
231 break;
233 case 0x0104: /* retrieve Hook_Properties list */
234 case 0x0105: /* call Hook_Properties callbacks */
235 VXD_BARF( context, "SHELL" );
236 break;
238 case 0x0106: /* install timeout callback */
239 TRACE( vxd, "VxD Shell: ignoring shell callback (%ld sec.)\n",
240 EBX_reg( context ) );
241 SET_CFLAG(context);
242 break;
244 case 0x0107: /* get version of any VxD */
245 default:
246 VXD_BARF( context, "SHELL" );
247 break;
252 /***********************************************************************
253 * VXD_Comm
255 void WINAPI VXD_Comm( CONTEXT *context )
257 unsigned service = AX_reg(context);
259 TRACE(vxd,"[%04x] Comm\n", (UINT16)service);
261 switch (service)
263 case 0x0000: /* get version */
264 TRACE(vxd,"returning version\n");
265 AX_reg(context) = VXD_WinVersion();
266 RESET_CFLAG(context);
267 break;
269 case 0x0001: /* set port global */
270 case 0x0002: /* get focus */
271 case 0x0003: /* virtualise port */
272 default:
273 VXD_BARF( context, "comm" );
277 /***********************************************************************
278 * VXD_Timer
280 void VXD_Timer( CONTEXT *context )
282 unsigned service = AX_reg(context);
284 TRACE(vxd,"[%04x] Virtual Timer\n", (UINT16)service);
286 switch(service)
288 case 0x0000: /* version */
289 AX_reg(context) = VXD_WinVersion();
290 RESET_CFLAG(context);
291 break;
293 case 0x0100: /* clock tick time, in 840nsecs */
294 EAX_reg(context) = GetTickCount();
296 EDX_reg(context) = EAX_reg(context) >> 22;
297 EAX_reg(context) <<= 10; /* not very precise */
298 break;
300 case 0x0101: /* current Windows time, msecs */
301 case 0x0102: /* current VM time, msecs */
302 EAX_reg(context) = GetTickCount();
303 break;
305 default:
306 VXD_BARF( context, "VTD" );
310 /***********************************************************************
311 * VXD_TimerAPI
313 static DWORD System_Time = 0;
314 static WORD System_Time_Selector = 0;
315 static void System_Time_Tick( WORD timer ) { System_Time += 55; }
316 void VXD_TimerAPI ( CONTEXT *context )
318 unsigned service = AX_reg(context);
320 TRACE(vxd,"[%04x] TimerAPI \n", (UINT16)service);
322 switch(service)
324 case 0x0000: /* version */
325 AX_reg(context) = VXD_WinVersion();
326 RESET_CFLAG(context);
327 break;
329 case 0x0009: /* get system time selector */
330 if ( !System_Time_Selector )
332 System_Time_Selector = SELECTOR_AllocBlock( &System_Time, sizeof(DWORD),
333 SEGMENT_DATA, FALSE, TRUE );
334 CreateSystemTimer( 55, System_Time_Tick );
337 AX_reg(context) = System_Time_Selector;
338 RESET_CFLAG(context);
339 break;
341 default:
342 VXD_BARF( context, "VTDAPI" );
346 /***********************************************************************
347 * VXD_ConfigMG
349 void VXD_ConfigMG ( CONTEXT *context )
351 unsigned service = AX_reg(context);
353 TRACE(vxd,"[%04x] ConfigMG \n", (UINT16)service);
355 switch(service)
357 case 0x0000: /* version */
358 AX_reg(context) = VXD_WinVersion();
359 RESET_CFLAG(context);
360 break;
362 default:
363 VXD_BARF( context, "CONFIGMG" );
367 /***********************************************************************
368 * VXD_Enable
370 void VXD_Enable ( CONTEXT *context )
372 unsigned service = AX_reg(context);
374 TRACE(vxd,"[%04x] Enable \n", (UINT16)service);
376 switch(service)
378 case 0x0000: /* version */
379 AX_reg(context) = VXD_WinVersion();
380 RESET_CFLAG(context);
381 break;
383 default:
384 VXD_BARF( context, "ENABLE" );
388 /***********************************************************************
389 * VXD_APM
391 void VXD_APM ( CONTEXT *context )
393 unsigned service = AX_reg(context);
395 TRACE(vxd,"[%04x] APM \n", (UINT16)service);
397 switch(service)
399 case 0x0000: /* version */
400 AX_reg(context) = VXD_WinVersion();
401 RESET_CFLAG(context);
402 break;
404 default:
405 VXD_BARF( context, "APM" );
409 /***********************************************************************
410 * VXD_Win32s
412 * This is an implementation of the services of the Win32s VxD.
413 * Since official documentation of these does not seem to be available,
414 * certain arguments of some of the services remain unclear.
416 * FIXME: The following services are currently unimplemented:
417 * Exception handling (0x01, 0x1C)
418 * Debugger support (0x0C, 0x14, 0x17)
419 * Low-level memory access (0x02, 0x03, 0x0A, 0x0B)
420 * Memory Statistics (0x1B)
423 * We have a specific problem running Win32s on Linux (and probably also
424 * the other x86 unixes), since Win32s tries to allocate its main 'flat
425 * code/data segment' selectors with a base of 0xffff0000 (and limit 4GB).
426 * The rationale for this seems to be that they want one the one hand to
427 * be able to leave the Win 3.1 memory (starting with the main DOS memory)
428 * at linear address 0, but want at other hand to have offset 0 of the
429 * flat data/code segment point to an unmapped page (to catch NULL pointer
430 * accesses). Hence they allocate the flat segments with a base of 0xffff0000
431 * so that the Win 3.1 memory area at linear address zero shows up in the
432 * flat segments at offset 0x10000 (since linear addresses wrap around at
433 * 4GB). To compensate for that discrepancy between flat segment offsets
434 * and plain linear addresses, all flat pointers passed between the 32-bit
435 * and the 16-bit parts of Win32s are shifted by 0x10000 in the appropriate
436 * direction by the glue code (mainly) in W32SKRNL and WIN32S16.
438 * The problem for us is now that Linux does not allow a LDT selector with
439 * base 0xffff0000 to be created, since it would 'see' a part of the kernel
440 * address space. To address this problem we introduce *another* offset:
441 * We add 0x10000 to every linear address we get as an argument from Win32s.
442 * This means especially that the flat code/data selectors get actually
443 * allocated with base 0x0, so that flat offsets and (real) linear addresses
444 * do again agree! In fact, every call e.g. of a Win32s VxD service now
445 * has all pointer arguments (which are offsets in the flat data segement)
446 * first reduced by 0x10000 by the W32SKRNL glue code, and then again
447 * increased by 0x10000 by *our* code.
449 * Note that to keep everything consistent, this offset has to be applied by
450 * every Wine function that operates on 'linear addresses' passed to it by
451 * Win32s. Fortunately, since Win32s does not directly call any Wine 32-bit
452 * API routines, this affects only two locations: this VxD and the DPMI
453 * handler. (NOTE: Should any Win32s application pass a linear address to
454 * any routine apart from those, e.g. some other VxD handler, that code
455 * would have to take the offset into account as well!)
457 * The application of the offset is triggered by marking the current process
458 * as a Win32s process by setting the PDB32_WIN32S_PROC flag in the process
459 * database. This is done the first time any application calls the GetVersion()
460 * service of the Win32s VxD. (Note that the flag is never removed.)
464 void VXD_Win32s( CONTEXT *context )
466 switch (AX_reg(context))
468 case 0x0000: /* Get Version */
470 * Input: None
472 * Output: EAX: LoWord: Win32s Version (1.30)
473 * HiWord: VxD Version (200)
475 * EBX: Build (172)
477 * ECX: ??? (1)
479 * EDX: Debugging Flags
481 * EDI: Error Flag
482 * 0 if OK,
483 * 1 if VMCPD VxD not found
486 TRACE(vxd, "GetVersion()\n");
488 EAX_reg(context) = VXD_WinVersion() | (200 << 16);
489 EBX_reg(context) = 0;
490 ECX_reg(context) = 0;
491 EDX_reg(context) = 0;
492 EDI_reg(context) = 0;
495 * If this is the first time we are called for this process,
496 * hack the memory image of WIN32S16 so that it doesn't try
497 * to access the GDT directly ...
499 * The first code segment of WIN32S16 (version 1.30) contains
500 * an unexported function somewhere between the exported functions
501 * SetFS and StackLinearToSegmented that tries to find a selector
502 * in the LDT that maps to the memory image of the LDT itself.
503 * If it succeeds, it stores this selector into a global variable
504 * which will be used to speed up execution by using this selector
505 * to modify the LDT directly instead of using the DPMI calls.
507 * To perform this search of the LDT, this function uses the
508 * sgdt and sldt instructions to find the linear address of
509 * the (GDT and then) LDT. While those instructions themselves
510 * execute without problem, the linear address that sgdt returns
511 * points (at least under Linux) to the kernel address space, so
512 * that any subsequent access leads to a segfault.
514 * Fortunately, WIN32S16 still contains as a fallback option the
515 * mechanism of using DPMI calls to modify LDT selectors instead
516 * of direct writes to the LDT. Thus we can circumvent the problem
517 * by simply replacing the first byte of the offending function
518 * with an 'retf' instruction. This means that the global variable
519 * supposed to contain the LDT alias selector will remain zero,
520 * and hence WIN32S16 will fall back to using DPMI calls.
522 * The heuristic we employ to _find_ that function is as follows:
523 * We search between the addresses of the exported symbols SetFS
524 * and StackLinearToSegmented for the byte sequence '0F 01 04'
525 * (this is the opcode of 'sgdt [si]'). We then search backwards
526 * from this address for the last occurrance of 'CB' (retf) that marks
527 * the end of the preceeding function. The following byte (which
528 * should now be the first byte of the function we are looking for)
529 * will be replaced by 'CB' (retf).
531 * This heuristic works for the retail as well as the debug version
532 * of Win32s version 1.30. For versions earlier than that this
533 * hack should not be necessary at all, since the whole mechanism
534 * ('PERF130') was introduced only in 1.30 to improve the overall
535 * performance of Win32s.
538 if (!(PROCESS_Current()->flags & PDB32_WIN32S_PROC))
540 HMODULE16 hModule = GetModuleHandle16("win32s16");
541 SEGPTR func1 = (SEGPTR)WIN32_GetProcAddress16(hModule, "SetFS");
542 SEGPTR func2 = (SEGPTR)WIN32_GetProcAddress16(hModule,
543 "StackLinearToSegmented");
545 if ( hModule && func1 && func2
546 && SELECTOROF(func1) == SELECTOROF(func2))
548 BYTE *start = PTR_SEG_TO_LIN(func1);
549 BYTE *end = PTR_SEG_TO_LIN(func2);
550 BYTE *p, *retv = NULL;
551 int found = 0;
553 for (p = start; p < end; p++)
554 if (*p == 0xCB) found = 0, retv = p;
555 else if (*p == 0x0F) found = 1;
556 else if (*p == 0x01 && found == 1) found = 2;
557 else if (*p == 0x04 && found == 2) { found = 3; break; }
558 else found = 0;
560 if (found == 3 && retv)
562 TRACE(vxd, "PERF130 hack: "
563 "Replacing byte %02X at offset %04X:%04X\n",
564 *(retv+1), SELECTOROF(func1),
565 OFFSETOF(func1) + retv+1-start);
567 *(retv+1) = (BYTE)0xCB;
573 * Mark process as Win32s, so that subsequent DPMI calls
574 * will perform the W32S_APP2WINE/W32S_WINE2APP address shift.
577 PROCESS_Current()->flags |= PDB32_WIN32S_PROC;
578 break;
581 case 0x0001: /* Install Exception Handling */
583 * Input: EBX: Flat address of W32SKRNL Exception Data
585 * ECX: LoWord: Flat Code Selector
586 * HiWord: Flat Data Selector
588 * EDX: Flat address of W32SKRNL Exception Handler
589 * (this is equal to W32S_BackTo32 + 0x40)
591 * ESI: SEGPTR KERNEL.HASGPHANDLER
593 * EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10)
595 * Output: EAX: 0 if OK
598 TRACE(vxd, "[0001] EBX=%lx ECX=%lx EDX=%lx ESI=%lx EDI=%lx\n",
599 EBX_reg(context), ECX_reg(context), EDX_reg(context),
600 ESI_reg(context), EDI_reg(context));
602 /* FIXME */
604 EAX_reg(context) = 0;
605 break;
608 case 0x0002: /* Set Page Access Flags */
610 * Input: EBX: New access flags
611 * Bit 2: User Page if set, Supervisor Page if clear
612 * Bit 1: Read-Write if set, Read-Only if clear
614 * ECX: Size of memory area to change
616 * EDX: Flat start address of memory area
618 * Output: EAX: Size of area changed
621 TRACE(vxd, "[0002] EBX=%lx ECX=%lx EDX=%lx\n",
622 EBX_reg(context), ECX_reg(context), EDX_reg(context));
624 /* FIXME */
626 EAX_reg(context) = ECX_reg(context);
627 break;
630 case 0x0003: /* Get Page Access Flags */
632 * Input: EDX: Flat address of page to query
634 * Output: EAX: Page access flags
635 * Bit 2: User Page if set, Supervisor Page if clear
636 * Bit 1: Read-Write if set, Read-Only if clear
639 TRACE(vxd, "[0003] EDX=%lx\n", EDX_reg(context));
641 /* FIXME */
643 EAX_reg(context) = 6;
644 break;
647 case 0x0004: /* Map Module */
649 * Input: ECX: IMTE (offset in Module Table) of new module
651 * EDX: Flat address of Win32s Module Table
653 * Output: EAX: 0 if OK
656 if (!EDX_reg(context) || CX_reg(context) == 0xFFFF)
658 TRACE(vxd, "MapModule: Initialization call\n");
659 EAX_reg(context) = 0;
661 else
664 * Structure of a Win32s Module Table Entry:
666 struct Win32sModule
668 DWORD flags;
669 DWORD flatBaseAddr;
670 LPCSTR moduleName;
671 LPCSTR pathName;
672 LPCSTR unknown;
673 LPBYTE baseAddr;
674 DWORD hModule;
675 DWORD relocDelta;
679 * Note: This function should set up a demand-paged memory image
680 * of the given module. Since mmap does not allow file offsets
681 * not aligned at 1024 bytes, we simply load the image fully
682 * into memory.
685 struct Win32sModule *moduleTable =
686 (struct Win32sModule *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
687 struct Win32sModule *module = moduleTable + ECX_reg(context);
689 IMAGE_NT_HEADERS *nt_header = PE_HEADER(module->baseAddr);
690 IMAGE_SECTION_HEADER *pe_seg = PE_SECTIONS(module->baseAddr);
692 HFILE image = _lopen(module->pathName, OF_READ);
693 BOOL error = (image == INVALID_HANDLE_VALUE);
694 UINT i;
696 TRACE(vxd, "MapModule: Loading %s\n", module->pathName);
698 for (i = 0;
699 !error && i < nt_header->FileHeader.NumberOfSections;
700 i++, pe_seg++)
701 if(!(pe_seg->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA))
703 DWORD off = pe_seg->PointerToRawData;
704 DWORD len = pe_seg->SizeOfRawData;
705 LPBYTE addr = module->baseAddr + pe_seg->VirtualAddress;
707 TRACE(vxd, "MapModule: "
708 "Section %d at %08lx from %08lx len %08lx\n",
709 i, (DWORD)addr, off, len);
711 if ( _llseek(image, off, SEEK_SET) != off
712 || _lread(image, addr, len) != len)
713 error = TRUE;
716 _lclose(image);
718 if (error)
719 ERR(vxd, "MapModule: Unable to load %s\n", module->pathName);
721 else if (module->relocDelta != 0)
723 IMAGE_DATA_DIRECTORY *dir = nt_header->OptionalHeader.DataDirectory
724 + IMAGE_DIRECTORY_ENTRY_BASERELOC;
725 IMAGE_BASE_RELOCATION *r = (IMAGE_BASE_RELOCATION *)
726 (dir->Size? module->baseAddr + dir->VirtualAddress : 0);
728 TRACE(vxd, "MapModule: Reloc delta %08lx\n", module->relocDelta);
730 while (r && r->VirtualAddress)
732 LPBYTE page = module->baseAddr + r->VirtualAddress;
733 int count = (r->SizeOfBlock - 8) / 2;
735 TRACE(vxd, "MapModule: %d relocations for page %08lx\n",
736 count, (DWORD)page);
738 for(i = 0; i < count; i++)
740 int offset = r->TypeOffset[i] & 0xFFF;
741 int type = r->TypeOffset[i] >> 12;
742 switch(type)
744 case IMAGE_REL_BASED_ABSOLUTE:
745 break;
746 case IMAGE_REL_BASED_HIGH:
747 *(WORD *)(page+offset) += HIWORD(module->relocDelta);
748 break;
749 case IMAGE_REL_BASED_LOW:
750 *(WORD *)(page+offset) += LOWORD(module->relocDelta);
751 break;
752 case IMAGE_REL_BASED_HIGHLOW:
753 *(DWORD*)(page+offset) += module->relocDelta;
754 break;
755 default:
756 WARN(vxd, "MapModule: Unsupported fixup type\n");
757 break;
761 r = (IMAGE_BASE_RELOCATION *)((LPBYTE)r + r->SizeOfBlock);
765 EAX_reg(context) = 0;
766 RESET_CFLAG(context);
768 break;
771 case 0x0005: /* UnMap Module */
773 * Input: EDX: Flat address of module image
775 * Output: EAX: 1 if OK
778 TRACE(vxd, "UnMapModule: %lx\n", (DWORD)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET));
780 /* As we didn't map anything, there's nothing to unmap ... */
782 EAX_reg(context) = 1;
783 break;
786 case 0x0006: /* VirtualAlloc */
788 * Input: ECX: Current Process
790 * EDX: Flat address of arguments on stack
792 * DWORD *retv [out] Flat base address of allocated region
793 * LPVOID base [in] Flat address of region to reserve/commit
794 * DWORD size [in] Size of region
795 * DWORD type [in] Type of allocation
796 * DWORD prot [in] Type of access protection
798 * Output: EAX: NtStatus
801 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
802 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
803 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
804 DWORD size = stack[2];
805 DWORD type = stack[3];
806 DWORD prot = stack[4];
807 DWORD result;
809 TRACE(vxd, "VirtualAlloc(%lx, %lx, %lx, %lx, %lx)\n",
810 (DWORD)retv, (DWORD)base, size, type, prot);
812 if (type & 0x80000000)
814 WARN(vxd, "VirtualAlloc: strange type %lx\n", type);
815 type &= 0x7fffffff;
818 if (!base && (type & MEM_COMMIT) && prot == PAGE_READONLY)
820 WARN(vxd, "VirtualAlloc: NLS hack, allowing write access!\n");
821 prot = PAGE_READWRITE;
824 result = (DWORD)VirtualAlloc(base, size, type, prot);
826 if (W32S_WINE2APP(result, W32S_OFFSET))
827 *retv = W32S_WINE2APP(result, W32S_OFFSET),
828 EAX_reg(context) = STATUS_SUCCESS;
829 else
830 *retv = 0,
831 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
833 break;
836 case 0x0007: /* VirtualFree */
838 * Input: ECX: Current Process
840 * EDX: Flat address of arguments on stack
842 * DWORD *retv [out] TRUE if success, FALSE if failure
843 * LPVOID base [in] Flat address of region
844 * DWORD size [in] Size of region
845 * DWORD type [in] Type of operation
847 * Output: EAX: NtStatus
850 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
851 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
852 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
853 DWORD size = stack[2];
854 DWORD type = stack[3];
855 DWORD result;
857 TRACE(vxd, "VirtualFree(%lx, %lx, %lx, %lx)\n",
858 (DWORD)retv, (DWORD)base, size, type);
860 result = VirtualFree(base, size, type);
862 if (result)
863 *retv = TRUE,
864 EAX_reg(context) = STATUS_SUCCESS;
865 else
866 *retv = FALSE,
867 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
869 break;
872 case 0x0008: /* VirtualProtect */
874 * Input: ECX: Current Process
876 * EDX: Flat address of arguments on stack
878 * DWORD *retv [out] TRUE if success, FALSE if failure
879 * LPVOID base [in] Flat address of region
880 * DWORD size [in] Size of region
881 * DWORD new_prot [in] Desired access protection
882 * DWORD *old_prot [out] Previous access protection
884 * Output: EAX: NtStatus
887 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
888 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
889 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
890 DWORD size = stack[2];
891 DWORD new_prot = stack[3];
892 DWORD *old_prot = (DWORD *)W32S_APP2WINE(stack[4], W32S_OFFSET);
893 DWORD result;
895 TRACE(vxd, "VirtualProtect(%lx, %lx, %lx, %lx, %lx)\n",
896 (DWORD)retv, (DWORD)base, size, new_prot, (DWORD)old_prot);
898 result = VirtualProtect(base, size, new_prot, old_prot);
900 if (result)
901 *retv = TRUE,
902 EAX_reg(context) = STATUS_SUCCESS;
903 else
904 *retv = FALSE,
905 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
907 break;
910 case 0x0009: /* VirtualQuery */
912 * Input: ECX: Current Process
914 * EDX: Flat address of arguments on stack
916 * DWORD *retv [out] Nr. bytes returned
917 * LPVOID base [in] Flat address of region
918 * LPMEMORY_BASIC_INFORMATION info [out] Info buffer
919 * DWORD len [in] Size of buffer
921 * Output: EAX: NtStatus
924 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
925 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
926 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
927 LPMEMORY_BASIC_INFORMATION info =
928 (LPMEMORY_BASIC_INFORMATION)W32S_APP2WINE(stack[2], W32S_OFFSET);
929 DWORD len = stack[3];
930 DWORD result;
932 TRACE(vxd, "VirtualQuery(%lx, %lx, %lx, %lx)\n",
933 (DWORD)retv, (DWORD)base, (DWORD)info, len);
935 result = VirtualQuery(base, info, len);
937 *retv = result;
938 EAX_reg(context) = STATUS_SUCCESS;
940 break;
943 case 0x000A: /* SetVirtMemProcess */
945 * Input: ECX: Process Handle
947 * EDX: Flat address of region
949 * Output: EAX: NtStatus
952 TRACE(vxd, "[000a] ECX=%lx EDX=%lx\n",
953 ECX_reg(context), EDX_reg(context));
955 /* FIXME */
957 EAX_reg(context) = STATUS_SUCCESS;
958 break;
961 case 0x000B: /* ??? some kind of cleanup */
963 * Input: ECX: Process Handle
965 * Output: EAX: NtStatus
968 TRACE(vxd, "[000b] ECX=%lx\n", ECX_reg(context));
970 /* FIXME */
972 EAX_reg(context) = STATUS_SUCCESS;
973 break;
976 case 0x000C: /* Set Debug Flags */
978 * Input: EDX: Debug Flags
980 * Output: EDX: Previous Debug Flags
983 FIXME(vxd, "[000c] EDX=%lx\n", EDX_reg(context));
985 /* FIXME */
987 EDX_reg(context) = 0;
988 break;
991 case 0x000D: /* NtCreateSection */
993 * Input: EDX: Flat address of arguments on stack
995 * HANDLE32 *retv [out] Handle of Section created
996 * DWORD flags1 [in] (?? unknown ??)
997 * DWORD atom [in] Name of Section to create
998 * LARGE_INTEGER *size [in] Size of Section
999 * DWORD protect [in] Access protection
1000 * DWORD flags2 [in] (?? unknown ??)
1001 * HFILE32 hFile [in] Handle of file to map
1002 * DWORD psp [in] (Win32s: PSP that hFile belongs to)
1004 * Output: EAX: NtStatus
1007 DWORD *stack = (DWORD *) W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1008 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1009 DWORD flags1 = stack[1];
1010 DWORD atom = stack[2];
1011 LARGE_INTEGER *size = (LARGE_INTEGER *)W32S_APP2WINE(stack[3], W32S_OFFSET);
1012 DWORD protect = stack[4];
1013 DWORD flags2 = stack[5];
1014 HFILE hFile = FILE_GetHandle(stack[6]);
1015 DWORD psp = stack[7];
1017 HANDLE result = INVALID_HANDLE_VALUE;
1018 char name[128];
1020 TRACE(vxd, "NtCreateSection(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1021 (DWORD)retv, flags1, atom, (DWORD)size, protect, flags2,
1022 (DWORD)hFile, psp);
1024 if (!atom || GlobalGetAtomNameA(atom, name, sizeof(name)))
1026 TRACE(vxd, "NtCreateSection: name=%s\n", atom? name : NULL);
1028 result = CreateFileMappingA(hFile, NULL, protect,
1029 size? size->HighPart : 0,
1030 size? size->LowPart : 0,
1031 atom? name : NULL);
1034 if (result == INVALID_HANDLE_VALUE)
1035 WARN(vxd, "NtCreateSection: failed!\n");
1036 else
1037 TRACE(vxd, "NtCreateSection: returned %lx\n", (DWORD)result);
1039 if (result != INVALID_HANDLE_VALUE)
1040 *retv = result,
1041 EAX_reg(context) = STATUS_SUCCESS;
1042 else
1043 *retv = result,
1044 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1046 break;
1049 case 0x000E: /* NtOpenSection */
1051 * Input: EDX: Flat address of arguments on stack
1053 * HANDLE32 *retv [out] Handle of Section opened
1054 * DWORD protect [in] Access protection
1055 * DWORD atom [in] Name of Section to create
1057 * Output: EAX: NtStatus
1060 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1061 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1062 DWORD protect = stack[1];
1063 DWORD atom = stack[2];
1065 HANDLE result = INVALID_HANDLE_VALUE;
1066 char name[128];
1068 TRACE(vxd, "NtOpenSection(%lx, %lx, %lx)\n",
1069 (DWORD)retv, protect, atom);
1071 if (atom && GlobalGetAtomNameA(atom, name, sizeof(name)))
1073 TRACE(vxd, "NtOpenSection: name=%s\n", name);
1075 result = OpenFileMappingA(protect, FALSE, name);
1078 if (result == INVALID_HANDLE_VALUE)
1079 WARN(vxd, "NtOpenSection: failed!\n");
1080 else
1081 TRACE(vxd, "NtOpenSection: returned %lx\n", (DWORD)result);
1083 if (result != INVALID_HANDLE_VALUE)
1084 *retv = result,
1085 EAX_reg(context) = STATUS_SUCCESS;
1086 else
1087 *retv = result,
1088 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1090 break;
1093 case 0x000F: /* NtCloseSection */
1095 * Input: EDX: Flat address of arguments on stack
1097 * HANDLE32 handle [in] Handle of Section to close
1098 * DWORD *id [out] Unique ID (?? unclear ??)
1100 * Output: EAX: NtStatus
1103 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1104 HANDLE handle = stack[0];
1105 DWORD *id = (DWORD *)W32S_APP2WINE(stack[1], W32S_OFFSET);
1107 TRACE(vxd, "NtCloseSection(%lx, %lx)\n", (DWORD)handle, (DWORD)id);
1109 CloseHandle(handle);
1110 if (id) *id = 0; /* FIXME */
1112 EAX_reg(context) = STATUS_SUCCESS;
1114 break;
1117 case 0x0010: /* NtDupSection */
1119 * Input: EDX: Flat address of arguments on stack
1121 * HANDLE32 handle [in] Handle of Section to duplicate
1123 * Output: EAX: NtStatus
1126 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1127 HANDLE handle = stack[0];
1128 HANDLE new_handle;
1130 TRACE(vxd, "NtDupSection(%lx)\n", (DWORD)handle);
1132 DuplicateHandle( GetCurrentProcess(), handle,
1133 GetCurrentProcess(), &new_handle,
1134 0, FALSE, DUPLICATE_SAME_ACCESS );
1135 EAX_reg(context) = STATUS_SUCCESS;
1137 break;
1140 case 0x0011: /* NtMapViewOfSection */
1142 * Input: EDX: Flat address of arguments on stack
1144 * HANDLE32 SectionHandle [in] Section to be mapped
1145 * DWORD ProcessHandle [in] Process to be mapped into
1146 * DWORD * BaseAddress [in/out] Address to be mapped at
1147 * DWORD ZeroBits [in] (?? unclear ??)
1148 * DWORD CommitSize [in] (?? unclear ??)
1149 * LARGE_INTEGER *SectionOffset [in] Offset within section
1150 * DWORD * ViewSize [in] Size of view
1151 * DWORD InheritDisposition [in] (?? unclear ??)
1152 * DWORD AllocationType [in] (?? unclear ??)
1153 * DWORD Protect [in] Access protection
1155 * Output: EAX: NtStatus
1158 DWORD * stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1159 HANDLE SectionHandle = stack[0];
1160 DWORD ProcessHandle = stack[1]; /* ignored */
1161 DWORD * BaseAddress = (DWORD *)W32S_APP2WINE(stack[2], W32S_OFFSET);
1162 DWORD ZeroBits = stack[3];
1163 DWORD CommitSize = stack[4];
1164 LARGE_INTEGER *SectionOffset = (LARGE_INTEGER *)W32S_APP2WINE(stack[5], W32S_OFFSET);
1165 DWORD * ViewSize = (DWORD *)W32S_APP2WINE(stack[6], W32S_OFFSET);
1166 DWORD InheritDisposition = stack[7];
1167 DWORD AllocationType = stack[8];
1168 DWORD Protect = stack[9];
1170 LPBYTE address = (LPBYTE)(BaseAddress?
1171 W32S_APP2WINE(*BaseAddress, W32S_OFFSET) : 0);
1172 DWORD access = 0, result;
1174 switch (Protect & ~(PAGE_GUARD|PAGE_NOCACHE))
1176 case PAGE_READONLY: access = FILE_MAP_READ; break;
1177 case PAGE_READWRITE: access = FILE_MAP_WRITE; break;
1178 case PAGE_WRITECOPY: access = FILE_MAP_COPY; break;
1180 case PAGE_EXECUTE_READ: access = FILE_MAP_READ; break;
1181 case PAGE_EXECUTE_READWRITE: access = FILE_MAP_WRITE; break;
1182 case PAGE_EXECUTE_WRITECOPY: access = FILE_MAP_COPY; break;
1185 TRACE(vxd, "NtMapViewOfSection"
1186 "(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1187 (DWORD)SectionHandle, ProcessHandle, (DWORD)BaseAddress,
1188 ZeroBits, CommitSize, (DWORD)SectionOffset, (DWORD)ViewSize,
1189 InheritDisposition, AllocationType, Protect);
1190 TRACE(vxd, "NtMapViewOfSection: "
1191 "base=%lx, offset=%lx, size=%lx, access=%lx\n",
1192 (DWORD)address, SectionOffset? SectionOffset->LowPart : 0,
1193 ViewSize? *ViewSize : 0, access);
1195 result = (DWORD)MapViewOfFileEx(SectionHandle, access,
1196 SectionOffset? SectionOffset->HighPart : 0,
1197 SectionOffset? SectionOffset->LowPart : 0,
1198 ViewSize? *ViewSize : 0, address);
1200 TRACE(vxd, "NtMapViewOfSection: result=%lx\n", result);
1202 if (W32S_WINE2APP(result, W32S_OFFSET))
1204 if (BaseAddress) *BaseAddress = W32S_WINE2APP(result, W32S_OFFSET);
1205 EAX_reg(context) = STATUS_SUCCESS;
1207 else
1208 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1210 break;
1213 case 0x0012: /* NtUnmapViewOfSection */
1215 * Input: EDX: Flat address of arguments on stack
1217 * DWORD ProcessHandle [in] Process (defining address space)
1218 * LPBYTE BaseAddress [in] Base address of view to be unmapped
1220 * Output: EAX: NtStatus
1223 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1224 DWORD ProcessHandle = stack[0]; /* ignored */
1225 LPBYTE BaseAddress = (LPBYTE)W32S_APP2WINE(stack[1], W32S_OFFSET);
1227 TRACE(vxd, "NtUnmapViewOfSection(%lx, %lx)\n",
1228 ProcessHandle, (DWORD)BaseAddress);
1230 UnmapViewOfFile(BaseAddress);
1232 EAX_reg(context) = STATUS_SUCCESS;
1234 break;
1237 case 0x0013: /* NtFlushVirtualMemory */
1239 * Input: EDX: Flat address of arguments on stack
1241 * DWORD ProcessHandle [in] Process (defining address space)
1242 * LPBYTE *BaseAddress [in?] Base address of range to be flushed
1243 * DWORD *ViewSize [in?] Number of bytes to be flushed
1244 * DWORD *unknown [???] (?? unknown ??)
1246 * Output: EAX: NtStatus
1249 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1250 DWORD ProcessHandle = stack[0]; /* ignored */
1251 DWORD *BaseAddress = (DWORD *)W32S_APP2WINE(stack[1], W32S_OFFSET);
1252 DWORD *ViewSize = (DWORD *)W32S_APP2WINE(stack[2], W32S_OFFSET);
1253 DWORD *unknown = (DWORD *)W32S_APP2WINE(stack[3], W32S_OFFSET);
1255 LPBYTE address = (LPBYTE)(BaseAddress? W32S_APP2WINE(*BaseAddress, W32S_OFFSET) : 0);
1256 DWORD size = ViewSize? *ViewSize : 0;
1258 TRACE(vxd, "NtFlushVirtualMemory(%lx, %lx, %lx, %lx)\n",
1259 ProcessHandle, (DWORD)BaseAddress, (DWORD)ViewSize,
1260 (DWORD)unknown);
1261 TRACE(vxd, "NtFlushVirtualMemory: base=%lx, size=%lx\n",
1262 (DWORD)address, size);
1264 FlushViewOfFile(address, size);
1266 EAX_reg(context) = STATUS_SUCCESS;
1268 break;
1271 case 0x0014: /* Get/Set Debug Registers */
1273 * Input: ECX: 0 if Get, 1 if Set
1275 * EDX: Get: Flat address of buffer to receive values of
1276 * debug registers DR0 .. DR7
1277 * Set: Flat address of buffer containing values of
1278 * debug registers DR0 .. DR7 to be set
1279 * Output: None
1282 FIXME(vxd, "[0014] ECX=%lx EDX=%lx\n",
1283 ECX_reg(context), EDX_reg(context));
1285 /* FIXME */
1286 break;
1289 case 0x0015: /* Set Coprocessor Emulation Flag */
1291 * Input: EDX: 0 to deactivate, 1 to activate coprocessor emulation
1293 * Output: None
1296 TRACE(vxd, "[0015] EDX=%lx\n", EDX_reg(context));
1298 /* We don't care, as we always have a coprocessor anyway */
1299 break;
1302 case 0x0016: /* Init Win32S VxD PSP */
1304 * If called to query required PSP size:
1306 * Input: EBX: 0
1307 * Output: EDX: Required size of Win32s VxD PSP
1309 * If called to initialize allocated PSP:
1311 * Input: EBX: LoWord: Selector of Win32s VxD PSP
1312 * HiWord: Paragraph of Win32s VxD PSP (DOSMEM)
1313 * Output: None
1316 if (EBX_reg(context) == 0)
1317 EDX_reg(context) = 0x80;
1318 else
1320 PDB16 *psp = PTR_SEG_OFF_TO_LIN(BX_reg(context), 0);
1321 psp->nbFiles = 32;
1322 psp->fileHandlesPtr = MAKELONG(HIWORD(EBX_reg(context)), 0x5c);
1323 memset((LPBYTE)psp + 0x5c, '\xFF', 32);
1325 break;
1328 case 0x0017: /* Set Break Point */
1330 * Input: EBX: Offset of Break Point
1331 * CX: Selector of Break Point
1333 * Output: None
1336 FIXME(vxd, "[0017] EBX=%lx CX=%x\n",
1337 EBX_reg(context), CX_reg(context));
1339 /* FIXME */
1340 break;
1343 case 0x0018: /* VirtualLock */
1345 * Input: ECX: Current Process
1347 * EDX: Flat address of arguments on stack
1349 * DWORD *retv [out] TRUE if success, FALSE if failure
1350 * LPVOID base [in] Flat address of range to lock
1351 * DWORD size [in] Size of range
1353 * Output: EAX: NtStatus
1356 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1357 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1358 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
1359 DWORD size = stack[2];
1360 DWORD result;
1362 TRACE(vxd, "VirtualLock(%lx, %lx, %lx)\n",
1363 (DWORD)retv, (DWORD)base, size);
1365 result = VirtualLock(base, size);
1367 if (result)
1368 *retv = TRUE,
1369 EAX_reg(context) = STATUS_SUCCESS;
1370 else
1371 *retv = FALSE,
1372 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1374 break;
1377 case 0x0019: /* VirtualUnlock */
1379 * Input: ECX: Current Process
1381 * EDX: Flat address of arguments on stack
1383 * DWORD *retv [out] TRUE if success, FALSE if failure
1384 * LPVOID base [in] Flat address of range to unlock
1385 * DWORD size [in] Size of range
1387 * Output: EAX: NtStatus
1390 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1391 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1392 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
1393 DWORD size = stack[2];
1394 DWORD result;
1396 TRACE(vxd, "VirtualUnlock(%lx, %lx, %lx)\n",
1397 (DWORD)retv, (DWORD)base, size);
1399 result = VirtualUnlock(base, size);
1401 if (result)
1402 *retv = TRUE,
1403 EAX_reg(context) = STATUS_SUCCESS;
1404 else
1405 *retv = FALSE,
1406 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1408 break;
1411 case 0x001A: /* KGetSystemInfo */
1413 * Input: None
1415 * Output: ECX: Start of sparse memory arena
1416 * EDX: End of sparse memory arena
1419 TRACE(vxd, "KGetSystemInfo()\n");
1422 * Note: Win32s reserves 0GB - 2GB for Win 3.1 and uses 2GB - 4GB as
1423 * sparse memory arena. We do it the other way around, since
1424 * we have to reserve 3GB - 4GB for Linux, and thus use
1425 * 0GB - 3GB as sparse memory arena.
1427 * FIXME: What about other OSes ?
1430 ECX_reg(context) = W32S_WINE2APP(0x00000000, W32S_OFFSET);
1431 EDX_reg(context) = W32S_WINE2APP(0xbfffffff, W32S_OFFSET);
1432 break;
1435 case 0x001B: /* KGlobalMemStat */
1437 * Input: ESI: Flat address of buffer to receive memory info
1439 * Output: None
1442 struct Win32sMemoryInfo
1444 DWORD DIPhys_Count; /* Total physical pages */
1445 DWORD DIFree_Count; /* Free physical pages */
1446 DWORD DILin_Total_Count; /* Total virtual pages (private arena) */
1447 DWORD DILin_Total_Free; /* Free virtual pages (private arena) */
1449 DWORD SparseTotal; /* Total size of sparse arena (bytes ?) */
1450 DWORD SparseFree; /* Free size of sparse arena (bytes ?) */
1453 struct Win32sMemoryInfo *info =
1454 (struct Win32sMemoryInfo *)W32S_APP2WINE(ESI_reg(context), W32S_OFFSET);
1456 FIXME(vxd, "KGlobalMemStat(%lx)\n", (DWORD)info);
1458 /* FIXME */
1460 break;
1463 case 0x001C: /* Enable/Disable Exceptions */
1465 * Input: ECX: 0 to disable, 1 to enable exception handling
1467 * Output: None
1470 TRACE(vxd, "[001c] ECX=%lx\n", ECX_reg(context));
1472 /* FIXME */
1473 break;
1476 case 0x001D: /* VirtualAlloc called from 16-bit code */
1478 * Input: EDX: Segmented address of arguments on stack
1480 * LPVOID base [in] Flat address of region to reserve/commit
1481 * DWORD size [in] Size of region
1482 * DWORD type [in] Type of allocation
1483 * DWORD prot [in] Type of access protection
1485 * Output: EAX: NtStatus
1486 * EDX: Flat base address of allocated region
1489 DWORD *stack = PTR_SEG_OFF_TO_LIN(LOWORD(EDX_reg(context)),
1490 HIWORD(EDX_reg(context)));
1491 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0], W32S_OFFSET);
1492 DWORD size = stack[1];
1493 DWORD type = stack[2];
1494 DWORD prot = stack[3];
1495 DWORD result;
1497 TRACE(vxd, "VirtualAlloc16(%lx, %lx, %lx, %lx)\n",
1498 (DWORD)base, size, type, prot);
1500 if (type & 0x80000000)
1502 WARN(vxd, "VirtualAlloc16: strange type %lx\n", type);
1503 type &= 0x7fffffff;
1506 result = (DWORD)VirtualAlloc(base, size, type, prot);
1508 if (W32S_WINE2APP(result, W32S_OFFSET))
1509 EDX_reg(context) = W32S_WINE2APP(result, W32S_OFFSET),
1510 EAX_reg(context) = STATUS_SUCCESS;
1511 else
1512 EDX_reg(context) = 0,
1513 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1514 TRACE(vxd, "VirtualAlloc16: returning base %lx\n", EDX_reg(context));
1516 break;
1519 case 0x001E: /* VirtualFree called from 16-bit code */
1521 * Input: EDX: Segmented address of arguments on stack
1523 * LPVOID base [in] Flat address of region
1524 * DWORD size [in] Size of region
1525 * DWORD type [in] Type of operation
1527 * Output: EAX: NtStatus
1528 * EDX: TRUE if success, FALSE if failure
1531 DWORD *stack = PTR_SEG_OFF_TO_LIN(LOWORD(EDX_reg(context)),
1532 HIWORD(EDX_reg(context)));
1533 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0], W32S_OFFSET);
1534 DWORD size = stack[1];
1535 DWORD type = stack[2];
1536 DWORD result;
1538 TRACE(vxd, "VirtualFree16(%lx, %lx, %lx)\n",
1539 (DWORD)base, size, type);
1541 result = VirtualFree(base, size, type);
1543 if (result)
1544 EDX_reg(context) = TRUE,
1545 EAX_reg(context) = STATUS_SUCCESS;
1546 else
1547 EDX_reg(context) = FALSE,
1548 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1550 break;
1553 case 0x001F: /* FWorkingSetSize */
1555 * Input: EDX: 0 if Get, 1 if Set
1557 * ECX: Get: Buffer to receive Working Set Size
1558 * Set: Buffer containing Working Set Size
1560 * Output: NtStatus
1563 DWORD *ptr = (DWORD *)W32S_APP2WINE(ECX_reg(context), W32S_OFFSET);
1564 BOOL set = EDX_reg(context);
1566 TRACE(vxd, "FWorkingSetSize(%lx, %lx)\n", (DWORD)ptr, (DWORD)set);
1568 if (set)
1569 /* We do it differently ... */;
1570 else
1571 *ptr = 0x100;
1573 EAX_reg(context) = STATUS_SUCCESS;
1575 break;
1578 default:
1579 VXD_BARF( context, "W32S" );