LCMapString32A: Implemented flags NORM_IGNORENONSPACE and
[wine.git] / msdos / vxd.c
blob8022a5489416f49519b6cea81e6f2d8e5dff8cac
1 /*
2 * VxD emulation
4 * Copyright 1995 Anand Kumria
5 */
7 #include <fcntl.h>
8 #include <memory.h>
9 #include "windows.h"
10 #include "winbase.h"
11 #include "msdos.h"
12 #include "miscemu.h"
13 #include "selectors.h"
14 #include "module.h"
15 #include "task.h"
16 #include "process.h"
17 #include "file.h"
18 #include "debug.h"
21 #define VXD_BARF(context,name) \
22 DUMP( "vxd %s: unknown/not implemented parameters:\n" \
23 "vxd %s: AX %04x, BX %04x, CX %04x, DX %04x, " \
24 "SI %04x, DI %04x, DS %04x, ES %04x\n", \
25 (name), (name), AX_reg(context), BX_reg(context), \
26 CX_reg(context), DX_reg(context), SI_reg(context), \
27 DI_reg(context), (WORD)DS_reg(context), (WORD)ES_reg(context) )
30 static WORD VXD_WinVersion(void)
32 WORD version = LOWORD(GetVersion16());
33 return (version >> 8) | (version << 8);
36 /***********************************************************************
37 * VXD_VMM
39 void VXD_VMM ( CONTEXT *context )
41 unsigned service = AX_reg(context);
43 TRACE(vxd,"[%04x] VMM \n", (UINT16)service);
45 switch(service)
47 case 0x0000: /* version */
48 AX_reg(context) = VXD_WinVersion();
49 RESET_CFLAG(context);
50 break;
52 case 0x026d: /* Get_Debug_Flag '/m' */
53 case 0x026e: /* Get_Debug_Flag '/n' */
54 AL_reg(context) = 0;
55 RESET_CFLAG(context);
56 break;
58 default:
59 VXD_BARF( context, "VMM" );
63 /***********************************************************************
64 * VXD_PageFile
66 void WINAPI VXD_PageFile( CONTEXT *context )
68 unsigned service = AX_reg(context);
70 /* taken from Ralf Brown's Interrupt List */
72 TRACE(vxd,"[%04x] PageFile\n", (UINT16)service );
74 switch(service)
76 case 0x00: /* get version, is this windows version? */
77 TRACE(vxd,"returning version\n");
78 AX_reg(context) = VXD_WinVersion();
79 RESET_CFLAG(context);
80 break;
82 case 0x01: /* get swap file info */
83 TRACE(vxd,"VxD PageFile: returning swap file info\n");
84 AX_reg(context) = 0x00; /* paging disabled */
85 ECX_reg(context) = 0; /* maximum size of paging file */
86 /* FIXME: do I touch DS:SI or DS:DI? */
87 RESET_CFLAG(context);
88 break;
90 case 0x02: /* delete permanent swap on exit */
91 TRACE(vxd,"VxD PageFile: supposed to delete swap\n");
92 RESET_CFLAG(context);
93 break;
95 case 0x03: /* current temporary swap file size */
96 TRACE(vxd,"VxD PageFile: what is current temp. swap size\n");
97 RESET_CFLAG(context);
98 break;
100 case 0x04: /* read or write?? INTERRUP.D */
101 case 0x05: /* cancel?? INTERRUP.D */
102 case 0x06: /* test I/O valid INTERRUP.D */
103 default:
104 VXD_BARF( context, "pagefile" );
105 break;
109 /***********************************************************************
110 * VXD_Reboot
112 void VXD_Reboot ( CONTEXT *context )
114 unsigned service = AX_reg(context);
116 TRACE(vxd,"[%04x] VMM \n", (UINT16)service);
118 switch(service)
120 case 0x0000: /* version */
121 AX_reg(context) = VXD_WinVersion();
122 RESET_CFLAG(context);
123 break;
125 default:
126 VXD_BARF( context, "REBOOT" );
130 /***********************************************************************
131 * VXD_VDD
133 void VXD_VDD ( CONTEXT *context )
135 unsigned service = AX_reg(context);
137 TRACE(vxd,"[%04x] VDD \n", (UINT16)service);
139 switch(service)
141 case 0x0000: /* version */
142 AX_reg(context) = VXD_WinVersion();
143 RESET_CFLAG(context);
144 break;
146 default:
147 VXD_BARF( context, "VDD" );
151 /***********************************************************************
152 * VXD_VMD
154 void VXD_VMD ( CONTEXT *context )
156 unsigned service = AX_reg(context);
158 TRACE(vxd,"[%04x] VMD \n", (UINT16)service);
160 switch(service)
162 case 0x0000: /* version */
163 AX_reg(context) = VXD_WinVersion();
164 RESET_CFLAG(context);
165 break;
167 default:
168 VXD_BARF( context, "VMD" );
172 /***********************************************************************
173 * VXD_Shell
175 void WINAPI VXD_Shell( CONTEXT *context )
177 unsigned service = DX_reg(context);
179 TRACE(vxd,"[%04x] Shell\n", (UINT16)service);
181 switch (service) /* Ralf Brown says EDX, but I use DX instead */
183 case 0x0000:
184 TRACE(vxd,"returning version\n");
185 AX_reg(context) = VXD_WinVersion();
186 EBX_reg(context) = 1; /* system VM Handle */
187 break;
189 case 0x0001:
190 case 0x0002:
191 case 0x0003:
192 case 0x0004:
193 case 0x0005:
194 VXD_BARF( context, "shell" );
195 break;
197 case 0x0006: /* SHELL_Get_VM_State */
198 TRACE(vxd,"VxD Shell: returning VM state\n");
199 /* Actually we don't, not yet. We have to return a structure
200 * and I am not to sure how to set it up and return it yet,
201 * so for now let's do nothing. I can (hopefully) get this
202 * by the next release
204 /* RESET_CFLAG(context); */
205 break;
207 case 0x0007:
208 case 0x0008:
209 case 0x0009:
210 case 0x000A:
211 case 0x000B:
212 case 0x000C:
213 case 0x000D:
214 case 0x000E:
215 case 0x000F:
216 case 0x0010:
217 case 0x0011:
218 case 0x0012:
219 case 0x0013:
220 case 0x0014:
221 case 0x0015:
222 case 0x0016:
223 VXD_BARF( context, "SHELL" );
224 break;
226 /* the new Win95 shell API */
227 case 0x0100: /* get version */
228 AX_reg(context) = VXD_WinVersion();
229 break;
231 case 0x0104: /* retrieve Hook_Properties list */
232 case 0x0105: /* call Hook_Properties callbacks */
233 VXD_BARF( context, "SHELL" );
234 break;
236 case 0x0106: /* install timeout callback */
237 TRACE( vxd, "VxD Shell: ignoring shell callback (%ld sec.)\n",
238 EBX_reg( context ) );
239 SET_CFLAG(context);
240 break;
242 case 0x0107: /* get version of any VxD */
243 default:
244 VXD_BARF( context, "SHELL" );
245 break;
250 /***********************************************************************
251 * VXD_Comm
253 void WINAPI VXD_Comm( CONTEXT *context )
255 unsigned service = AX_reg(context);
257 TRACE(vxd,"[%04x] Comm\n", (UINT16)service);
259 switch (service)
261 case 0x0000: /* get version */
262 TRACE(vxd,"returning version\n");
263 AX_reg(context) = VXD_WinVersion();
264 RESET_CFLAG(context);
265 break;
267 case 0x0001: /* set port global */
268 case 0x0002: /* get focus */
269 case 0x0003: /* virtualise port */
270 default:
271 VXD_BARF( context, "comm" );
275 /***********************************************************************
276 * VXD_Timer
278 void VXD_Timer( CONTEXT *context )
280 unsigned service = AX_reg(context);
282 TRACE(vxd,"[%04x] Virtual Timer\n", (UINT16)service);
284 switch(service)
286 case 0x0000: /* version */
287 AX_reg(context) = VXD_WinVersion();
288 RESET_CFLAG(context);
289 break;
291 case 0x0100: /* clock tick time, in 840nsecs */
292 EAX_reg(context) = GetTickCount();
294 EDX_reg(context) = EAX_reg(context) >> 22;
295 EAX_reg(context) <<= 10; /* not very precise */
296 break;
298 case 0x0101: /* current Windows time, msecs */
299 case 0x0102: /* current VM time, msecs */
300 EAX_reg(context) = GetTickCount();
301 break;
303 default:
304 VXD_BARF( context, "VTD" );
308 /***********************************************************************
309 * VXD_TimerAPI
311 static DWORD System_Time = 0;
312 static WORD System_Time_Selector = 0;
313 static void System_Time_Tick( WORD timer ) { System_Time += 55; }
314 void VXD_TimerAPI ( CONTEXT *context )
316 unsigned service = AX_reg(context);
318 TRACE(vxd,"[%04x] TimerAPI \n", (UINT16)service);
320 switch(service)
322 case 0x0000: /* version */
323 AX_reg(context) = VXD_WinVersion();
324 RESET_CFLAG(context);
325 break;
327 case 0x0009: /* get system time selector */
328 if ( !System_Time_Selector )
330 System_Time_Selector = SELECTOR_AllocBlock( &System_Time, sizeof(DWORD),
331 SEGMENT_DATA, FALSE, TRUE );
332 CreateSystemTimer( 55, System_Time_Tick );
335 AX_reg(context) = System_Time_Selector;
336 RESET_CFLAG(context);
337 break;
339 default:
340 VXD_BARF( context, "VTDAPI" );
344 /***********************************************************************
345 * VXD_ConfigMG
347 void VXD_ConfigMG ( CONTEXT *context )
349 unsigned service = AX_reg(context);
351 TRACE(vxd,"[%04x] ConfigMG \n", (UINT16)service);
353 switch(service)
355 case 0x0000: /* version */
356 AX_reg(context) = VXD_WinVersion();
357 RESET_CFLAG(context);
358 break;
360 default:
361 VXD_BARF( context, "CONFIGMG" );
365 /***********************************************************************
366 * VXD_Enable
368 void VXD_Enable ( CONTEXT *context )
370 unsigned service = AX_reg(context);
372 TRACE(vxd,"[%04x] Enable \n", (UINT16)service);
374 switch(service)
376 case 0x0000: /* version */
377 AX_reg(context) = VXD_WinVersion();
378 RESET_CFLAG(context);
379 break;
381 default:
382 VXD_BARF( context, "ENABLE" );
386 /***********************************************************************
387 * VXD_APM
389 void VXD_APM ( CONTEXT *context )
391 unsigned service = AX_reg(context);
393 TRACE(vxd,"[%04x] APM \n", (UINT16)service);
395 switch(service)
397 case 0x0000: /* version */
398 AX_reg(context) = VXD_WinVersion();
399 RESET_CFLAG(context);
400 break;
402 default:
403 VXD_BARF( context, "APM" );
407 /***********************************************************************
408 * VXD_Win32s
410 * This is an implementation of the services of the Win32s VxD.
411 * Since official documentation of these does not seem to be available,
412 * certain arguments of some of the services remain unclear.
414 * FIXME: The following services are currently unimplemented:
415 * Exception handling (0x01, 0x1C)
416 * Debugger support (0x0C, 0x14, 0x17)
417 * Low-level memory access (0x02, 0x03, 0x0A, 0x0B)
418 * Memory Statistics (0x1B)
421 * We have a specific problem running Win32s on Linux (and probably also
422 * the other x86 unixes), since Win32s tries to allocate its main 'flat
423 * code/data segment' selectors with a base of 0xffff0000 (and limit 4GB).
424 * The rationale for this seems to be that they want one the one hand to
425 * be able to leave the Win 3.1 memory (starting with the main DOS memory)
426 * at linear address 0, but want at other hand to have offset 0 of the
427 * flat data/code segment point to an unmapped page (to catch NULL pointer
428 * accesses). Hence they allocate the flat segments with a base of 0xffff0000
429 * so that the Win 3.1 memory area at linear address zero shows up in the
430 * flat segments at offset 0x10000 (since linear addresses wrap around at
431 * 4GB). To compensate for that discrepancy between flat segment offsets
432 * and plain linear addresses, all flat pointers passed between the 32-bit
433 * and the 16-bit parts of Win32s are shifted by 0x10000 in the appropriate
434 * direction by the glue code (mainly) in W32SKRNL and WIN32S16.
436 * The problem for us is now that Linux does not allow a LDT selector with
437 * base 0xffff0000 to be created, since it would 'see' a part of the kernel
438 * address space. To address this problem we introduce *another* offset:
439 * We add 0x10000 to every linear address we get as an argument from Win32s.
440 * This means especially that the flat code/data selectors get actually
441 * allocated with base 0x0, so that flat offsets and (real) linear addresses
442 * do again agree! In fact, every call e.g. of a Win32s VxD service now
443 * has all pointer arguments (which are offsets in the flat data segement)
444 * first reduced by 0x10000 by the W32SKRNL glue code, and then again
445 * increased by 0x10000 by *our* code.
447 * Note that to keep everything consistent, this offset has to be applied by
448 * every Wine function that operates on 'linear addresses' passed to it by
449 * Win32s. Fortunately, since Win32s does not directly call any Wine 32-bit
450 * API routines, this affects only two locations: this VxD and the DPMI
451 * handler. (NOTE: Should any Win32s application pass a linear address to
452 * any routine apart from those, e.g. some other VxD handler, that code
453 * would have to take the offset into account as well!)
455 * The application of the offset is triggered by marking the current process
456 * as a Win32s process by setting the PDB32_WIN32S_PROC flag in the process
457 * database. This is done the first time any application calls the GetVersion()
458 * service of the Win32s VxD. (Note that the flag is never removed.)
462 void VXD_Win32s( CONTEXT *context )
464 switch (AX_reg(context))
466 case 0x0000: /* Get Version */
468 * Input: None
470 * Output: EAX: LoWord: Win32s Version (1.30)
471 * HiWord: VxD Version (200)
473 * EBX: Build (172)
475 * ECX: ??? (1)
477 * EDX: Debugging Flags
479 * EDI: Error Flag
480 * 0 if OK,
481 * 1 if VMCPD VxD not found
484 TRACE(vxd, "GetVersion()\n");
486 EAX_reg(context) = VXD_WinVersion() | (200 << 16);
487 EBX_reg(context) = 0;
488 ECX_reg(context) = 0;
489 EDX_reg(context) = 0;
490 EDI_reg(context) = 0;
493 * If this is the first time we are called for this process,
494 * hack the memory image of WIN32S16 so that it doesn't try
495 * to access the GDT directly ...
497 * The first code segment of WIN32S16 (version 1.30) contains
498 * an unexported function somewhere between the exported functions
499 * SetFS and StackLinearToSegmented that tries to find a selector
500 * in the LDT that maps to the memory image of the LDT itself.
501 * If it succeeds, it stores this selector into a global variable
502 * which will be used to speed up execution by using this selector
503 * to modify the LDT directly instead of using the DPMI calls.
505 * To perform this search of the LDT, this function uses the
506 * sgdt and sldt instructions to find the linear address of
507 * the (GDT and then) LDT. While those instructions themselves
508 * execute without problem, the linear address that sgdt returns
509 * points (at least under Linux) to the kernel address space, so
510 * that any subsequent access leads to a segfault.
512 * Fortunately, WIN32S16 still contains as a fallback option the
513 * mechanism of using DPMI calls to modify LDT selectors instead
514 * of direct writes to the LDT. Thus we can circumvent the problem
515 * by simply replacing the first byte of the offending function
516 * with an 'retf' instruction. This means that the global variable
517 * supposed to contain the LDT alias selector will remain zero,
518 * and hence WIN32S16 will fall back to using DPMI calls.
520 * The heuristic we employ to _find_ that function is as follows:
521 * We search between the addresses of the exported symbols SetFS
522 * and StackLinearToSegmented for the byte sequence '0F 01 04'
523 * (this is the opcode of 'sgdt [si]'). We then search backwards
524 * from this address for the last occurrance of 'CB' (retf) that marks
525 * the end of the preceeding function. The following byte (which
526 * should now be the first byte of the function we are looking for)
527 * will be replaced by 'CB' (retf).
529 * This heuristic works for the retail as well as the debug version
530 * of Win32s version 1.30. For versions earlier than that this
531 * hack should not be necessary at all, since the whole mechanism
532 * ('PERF130') was introduced only in 1.30 to improve the overall
533 * performance of Win32s.
536 if (!(PROCESS_Current()->flags & PDB32_WIN32S_PROC))
538 HMODULE16 hModule = GetModuleHandle16("win32s16");
539 SEGPTR func1 = (SEGPTR)WIN32_GetProcAddress16(hModule, "SetFS");
540 SEGPTR func2 = (SEGPTR)WIN32_GetProcAddress16(hModule,
541 "StackLinearToSegmented");
543 if ( hModule && func1 && func2
544 && SELECTOROF(func1) == SELECTOROF(func2))
546 BYTE *start = PTR_SEG_TO_LIN(func1);
547 BYTE *end = PTR_SEG_TO_LIN(func2);
548 BYTE *p, *retv = NULL;
549 int found = 0;
551 for (p = start; p < end; p++)
552 if (*p == 0xCB) found = 0, retv = p;
553 else if (*p == 0x0F) found = 1;
554 else if (*p == 0x01 && found == 1) found = 2;
555 else if (*p == 0x04 && found == 2) { found = 3; break; }
556 else found = 0;
558 if (found == 3 && retv)
560 TRACE(vxd, "PERF130 hack: "
561 "Replacing byte %02X at offset %04X:%04X\n",
562 *(retv+1), SELECTOROF(func1),
563 OFFSETOF(func1) + retv+1-start);
565 *(retv+1) = (BYTE)0xCB;
571 * Mark process as Win32s, so that subsequent DPMI calls
572 * will perform the W32S_APP2WINE/W32S_WINE2APP address shift.
575 PROCESS_Current()->flags |= PDB32_WIN32S_PROC;
576 break;
579 case 0x0001: /* Install Exception Handling */
581 * Input: EBX: Flat address of W32SKRNL Exception Data
583 * ECX: LoWord: Flat Code Selector
584 * HiWord: Flat Data Selector
586 * EDX: Flat address of W32SKRNL Exception Handler
587 * (this is equal to W32S_BackTo32 + 0x40)
589 * ESI: SEGPTR KERNEL.HASGPHANDLER
591 * EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10)
593 * Output: EAX: 0 if OK
596 TRACE(vxd, "[0001] EBX=%lx ECX=%lx EDX=%lx ESI=%lx EDI=%lx\n",
597 EBX_reg(context), ECX_reg(context), EDX_reg(context),
598 ESI_reg(context), EDI_reg(context));
600 /* FIXME */
602 EAX_reg(context) = 0;
603 break;
606 case 0x0002: /* Set Page Access Flags */
608 * Input: EBX: New access flags
609 * Bit 2: User Page if set, Supervisor Page if clear
610 * Bit 1: Read-Write if set, Read-Only if clear
612 * ECX: Size of memory area to change
614 * EDX: Flat start address of memory area
616 * Output: EAX: Size of area changed
619 TRACE(vxd, "[0002] EBX=%lx ECX=%lx EDX=%lx\n",
620 EBX_reg(context), ECX_reg(context), EDX_reg(context));
622 /* FIXME */
624 EAX_reg(context) = ECX_reg(context);
625 break;
628 case 0x0003: /* Get Page Access Flags */
630 * Input: EDX: Flat address of page to query
632 * Output: EAX: Page access flags
633 * Bit 2: User Page if set, Supervisor Page if clear
634 * Bit 1: Read-Write if set, Read-Only if clear
637 TRACE(vxd, "[0003] EDX=%lx\n", EDX_reg(context));
639 /* FIXME */
641 EAX_reg(context) = 6;
642 break;
645 case 0x0004: /* Map Module */
647 * Input: ECX: IMTE (offset in Module Table) of new module
649 * EDX: Flat address of Win32s Module Table
651 * Output: EAX: 0 if OK
654 if (!EDX_reg(context) || CX_reg(context) == 0xFFFF)
656 TRACE(vxd, "MapModule: Initialization call\n");
657 EAX_reg(context) = 0;
659 else
662 * Structure of a Win32s Module Table Entry:
664 struct Win32sModule
666 DWORD flags;
667 DWORD flatBaseAddr;
668 LPCSTR moduleName;
669 LPCSTR pathName;
670 LPCSTR unknown;
671 LPBYTE baseAddr;
672 DWORD hModule;
673 DWORD relocDelta;
677 * Note: This function should set up a demand-paged memory image
678 * of the given module. Since mmap does not allow file offsets
679 * not aligned at 1024 bytes, we simply load the image fully
680 * into memory.
683 struct Win32sModule *moduleTable =
684 (struct Win32sModule *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
685 struct Win32sModule *module = moduleTable + ECX_reg(context);
687 IMAGE_NT_HEADERS *nt_header = PE_HEADER(module->baseAddr);
688 IMAGE_SECTION_HEADER *pe_seg = PE_SECTIONS(module->baseAddr);
690 HFILE32 image = _lopen32(module->pathName, OF_READ);
691 BOOL32 error = (image == INVALID_HANDLE_VALUE32);
692 UINT32 i;
694 TRACE(vxd, "MapModule: Loading %s\n", module->pathName);
696 for (i = 0;
697 !error && i < nt_header->FileHeader.NumberOfSections;
698 i++, pe_seg++)
699 if(!(pe_seg->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA))
701 DWORD off = pe_seg->PointerToRawData;
702 DWORD len = pe_seg->SizeOfRawData;
703 LPBYTE addr = module->baseAddr + pe_seg->VirtualAddress;
705 TRACE(vxd, "MapModule: "
706 "Section %d at %08lx from %08lx len %08lx\n",
707 i, (DWORD)addr, off, len);
709 if ( _llseek32(image, off, SEEK_SET) != off
710 || _lread32(image, addr, len) != len)
711 error = TRUE;
714 _lclose32(image);
716 if (error)
717 ERR(vxd, "MapModule: Unable to load %s\n", module->pathName);
719 else if (module->relocDelta != 0)
721 IMAGE_DATA_DIRECTORY *dir = nt_header->OptionalHeader.DataDirectory
722 + IMAGE_DIRECTORY_ENTRY_BASERELOC;
723 IMAGE_BASE_RELOCATION *r = (IMAGE_BASE_RELOCATION *)
724 (dir->Size? module->baseAddr + dir->VirtualAddress : 0);
726 TRACE(vxd, "MapModule: Reloc delta %08lx\n", module->relocDelta);
728 while (r && r->VirtualAddress)
730 LPBYTE page = module->baseAddr + r->VirtualAddress;
731 int count = (r->SizeOfBlock - 8) / 2;
733 TRACE(vxd, "MapModule: %d relocations for page %08lx\n",
734 count, (DWORD)page);
736 for(i = 0; i < count; i++)
738 int offset = r->TypeOffset[i] & 0xFFF;
739 int type = r->TypeOffset[i] >> 12;
740 switch(type)
742 case IMAGE_REL_BASED_ABSOLUTE:
743 break;
744 case IMAGE_REL_BASED_HIGH:
745 *(WORD *)(page+offset) += HIWORD(module->relocDelta);
746 break;
747 case IMAGE_REL_BASED_LOW:
748 *(WORD *)(page+offset) += LOWORD(module->relocDelta);
749 break;
750 case IMAGE_REL_BASED_HIGHLOW:
751 *(DWORD*)(page+offset) += module->relocDelta;
752 break;
753 default:
754 WARN(vxd, "MapModule: Unsupported fixup type\n");
755 break;
759 r = (IMAGE_BASE_RELOCATION *)((LPBYTE)r + r->SizeOfBlock);
763 EAX_reg(context) = 0;
764 RESET_CFLAG(context);
766 break;
769 case 0x0005: /* UnMap Module */
771 * Input: EDX: Flat address of module image
773 * Output: EAX: 1 if OK
776 TRACE(vxd, "UnMapModule: %lx\n", (DWORD)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET));
778 /* As we didn't map anything, there's nothing to unmap ... */
780 EAX_reg(context) = 1;
781 break;
784 case 0x0006: /* VirtualAlloc */
786 * Input: ECX: Current Process
788 * EDX: Flat address of arguments on stack
790 * DWORD *retv [out] Flat base address of allocated region
791 * LPVOID base [in] Flat address of region to reserve/commit
792 * DWORD size [in] Size of region
793 * DWORD type [in] Type of allocation
794 * DWORD prot [in] Type of access protection
796 * Output: EAX: NtStatus
799 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
800 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
801 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
802 DWORD size = stack[2];
803 DWORD type = stack[3];
804 DWORD prot = stack[4];
805 DWORD result;
807 TRACE(vxd, "VirtualAlloc(%lx, %lx, %lx, %lx, %lx)\n",
808 (DWORD)retv, (DWORD)base, size, type, prot);
810 if (type & 0x80000000)
812 WARN(vxd, "VirtualAlloc: strange type %lx\n", type);
813 type &= 0x7fffffff;
816 if (!base && (type & MEM_COMMIT) && prot == PAGE_READONLY)
818 WARN(vxd, "VirtualAlloc: NLS hack, allowing write access!\n");
819 prot = PAGE_READWRITE;
822 result = (DWORD)VirtualAlloc(base, size, type, prot);
824 if (W32S_WINE2APP(result, W32S_OFFSET))
825 *retv = W32S_WINE2APP(result, W32S_OFFSET),
826 EAX_reg(context) = STATUS_SUCCESS;
827 else
828 *retv = 0,
829 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
831 break;
834 case 0x0007: /* VirtualFree */
836 * Input: ECX: Current Process
838 * EDX: Flat address of arguments on stack
840 * DWORD *retv [out] TRUE if success, FALSE if failure
841 * LPVOID base [in] Flat address of region
842 * DWORD size [in] Size of region
843 * DWORD type [in] Type of operation
845 * Output: EAX: NtStatus
848 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
849 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
850 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
851 DWORD size = stack[2];
852 DWORD type = stack[3];
853 DWORD result;
855 TRACE(vxd, "VirtualFree(%lx, %lx, %lx, %lx)\n",
856 (DWORD)retv, (DWORD)base, size, type);
858 result = VirtualFree(base, size, type);
860 if (result)
861 *retv = TRUE,
862 EAX_reg(context) = STATUS_SUCCESS;
863 else
864 *retv = FALSE,
865 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
867 break;
870 case 0x0008: /* VirtualProtect */
872 * Input: ECX: Current Process
874 * EDX: Flat address of arguments on stack
876 * DWORD *retv [out] TRUE if success, FALSE if failure
877 * LPVOID base [in] Flat address of region
878 * DWORD size [in] Size of region
879 * DWORD new_prot [in] Desired access protection
880 * DWORD *old_prot [out] Previous access protection
882 * Output: EAX: NtStatus
885 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
886 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
887 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
888 DWORD size = stack[2];
889 DWORD new_prot = stack[3];
890 DWORD *old_prot = (DWORD *)W32S_APP2WINE(stack[4], W32S_OFFSET);
891 DWORD result;
893 TRACE(vxd, "VirtualProtect(%lx, %lx, %lx, %lx, %lx)\n",
894 (DWORD)retv, (DWORD)base, size, new_prot, (DWORD)old_prot);
896 result = VirtualProtect(base, size, new_prot, old_prot);
898 if (result)
899 *retv = TRUE,
900 EAX_reg(context) = STATUS_SUCCESS;
901 else
902 *retv = FALSE,
903 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
905 break;
908 case 0x0009: /* VirtualQuery */
910 * Input: ECX: Current Process
912 * EDX: Flat address of arguments on stack
914 * DWORD *retv [out] Nr. bytes returned
915 * LPVOID base [in] Flat address of region
916 * LPMEMORY_BASIC_INFORMATION info [out] Info buffer
917 * DWORD len [in] Size of buffer
919 * Output: EAX: NtStatus
922 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
923 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
924 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
925 LPMEMORY_BASIC_INFORMATION info =
926 (LPMEMORY_BASIC_INFORMATION)W32S_APP2WINE(stack[2], W32S_OFFSET);
927 DWORD len = stack[3];
928 DWORD result;
930 TRACE(vxd, "VirtualQuery(%lx, %lx, %lx, %lx)\n",
931 (DWORD)retv, (DWORD)base, (DWORD)info, len);
933 result = VirtualQuery(base, info, len);
935 *retv = result;
936 EAX_reg(context) = STATUS_SUCCESS;
938 break;
941 case 0x000A: /* SetVirtMemProcess */
943 * Input: ECX: Process Handle
945 * EDX: Flat address of region
947 * Output: EAX: NtStatus
950 TRACE(vxd, "[000a] ECX=%lx EDX=%lx\n",
951 ECX_reg(context), EDX_reg(context));
953 /* FIXME */
955 EAX_reg(context) = STATUS_SUCCESS;
956 break;
959 case 0x000B: /* ??? some kind of cleanup */
961 * Input: ECX: Process Handle
963 * Output: EAX: NtStatus
966 TRACE(vxd, "[000b] ECX=%lx\n", ECX_reg(context));
968 /* FIXME */
970 EAX_reg(context) = STATUS_SUCCESS;
971 break;
974 case 0x000C: /* Set Debug Flags */
976 * Input: EDX: Debug Flags
978 * Output: EDX: Previous Debug Flags
981 FIXME(vxd, "[000c] EDX=%lx\n", EDX_reg(context));
983 /* FIXME */
985 EDX_reg(context) = 0;
986 break;
989 case 0x000D: /* NtCreateSection */
991 * Input: EDX: Flat address of arguments on stack
993 * HANDLE32 *retv [out] Handle of Section created
994 * DWORD flags1 [in] (?? unknown ??)
995 * DWORD atom [in] Name of Section to create
996 * LARGE_INTEGER *size [in] Size of Section
997 * DWORD protect [in] Access protection
998 * DWORD flags2 [in] (?? unknown ??)
999 * HFILE32 hFile [in] Handle of file to map
1000 * DWORD psp [in] (Win32s: PSP that hFile belongs to)
1002 * Output: EAX: NtStatus
1005 DWORD *stack = (DWORD *) W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1006 HANDLE32 *retv = (HANDLE32 *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1007 DWORD flags1 = stack[1];
1008 DWORD atom = stack[2];
1009 LARGE_INTEGER *size = (LARGE_INTEGER *)W32S_APP2WINE(stack[3], W32S_OFFSET);
1010 DWORD protect = stack[4];
1011 DWORD flags2 = stack[5];
1012 HFILE32 hFile = FILE_GetHandle32(stack[6]);
1013 DWORD psp = stack[7];
1015 HANDLE32 result = INVALID_HANDLE_VALUE32;
1016 char name[128];
1018 TRACE(vxd, "NtCreateSection(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1019 (DWORD)retv, flags1, atom, (DWORD)size, protect, flags2,
1020 (DWORD)hFile, psp);
1022 if (!atom || GlobalGetAtomName32A(atom, name, sizeof(name)))
1024 TRACE(vxd, "NtCreateSection: name=%s\n", atom? name : NULL);
1026 result = CreateFileMapping32A(hFile, NULL, protect,
1027 size? size->HighPart : 0,
1028 size? size->LowPart : 0,
1029 atom? name : NULL);
1032 if (result == INVALID_HANDLE_VALUE32)
1033 WARN(vxd, "NtCreateSection: failed!\n");
1034 else
1035 TRACE(vxd, "NtCreateSection: returned %lx\n", (DWORD)result);
1037 if (result != INVALID_HANDLE_VALUE32)
1038 *retv = result,
1039 EAX_reg(context) = STATUS_SUCCESS;
1040 else
1041 *retv = result,
1042 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1044 break;
1047 case 0x000E: /* NtOpenSection */
1049 * Input: EDX: Flat address of arguments on stack
1051 * HANDLE32 *retv [out] Handle of Section opened
1052 * DWORD protect [in] Access protection
1053 * DWORD atom [in] Name of Section to create
1055 * Output: EAX: NtStatus
1058 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1059 HANDLE32 *retv = (HANDLE32 *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1060 DWORD protect = stack[1];
1061 DWORD atom = stack[2];
1063 HANDLE32 result = INVALID_HANDLE_VALUE32;
1064 char name[128];
1066 TRACE(vxd, "NtOpenSection(%lx, %lx, %lx)\n",
1067 (DWORD)retv, protect, atom);
1069 if (atom && GlobalGetAtomName32A(atom, name, sizeof(name)))
1071 TRACE(vxd, "NtOpenSection: name=%s\n", name);
1073 result = OpenFileMapping32A(protect, FALSE, name);
1076 if (result == INVALID_HANDLE_VALUE32)
1077 WARN(vxd, "NtOpenSection: failed!\n");
1078 else
1079 TRACE(vxd, "NtOpenSection: returned %lx\n", (DWORD)result);
1081 if (result != INVALID_HANDLE_VALUE32)
1082 *retv = result,
1083 EAX_reg(context) = STATUS_SUCCESS;
1084 else
1085 *retv = result,
1086 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1088 break;
1091 case 0x000F: /* NtCloseSection */
1093 * Input: EDX: Flat address of arguments on stack
1095 * HANDLE32 handle [in] Handle of Section to close
1096 * DWORD *id [out] Unique ID (?? unclear ??)
1098 * Output: EAX: NtStatus
1101 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1102 HANDLE32 handle = stack[0];
1103 DWORD *id = (DWORD *)W32S_APP2WINE(stack[1], W32S_OFFSET);
1105 TRACE(vxd, "NtCloseSection(%lx, %lx)\n", (DWORD)handle, (DWORD)id);
1107 CloseHandle(handle);
1108 if (id) *id = 0; /* FIXME */
1110 EAX_reg(context) = STATUS_SUCCESS;
1112 break;
1115 case 0x0010: /* NtDupSection */
1117 * Input: EDX: Flat address of arguments on stack
1119 * HANDLE32 handle [in] Handle of Section to duplicate
1121 * Output: EAX: NtStatus
1124 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1125 HANDLE32 handle = stack[0];
1126 HANDLE32 new_handle;
1128 TRACE(vxd, "NtDupSection(%lx)\n", (DWORD)handle);
1130 DuplicateHandle( GetCurrentProcess(), handle,
1131 GetCurrentProcess(), &new_handle,
1132 0, FALSE, DUPLICATE_SAME_ACCESS );
1133 EAX_reg(context) = STATUS_SUCCESS;
1135 break;
1138 case 0x0011: /* NtMapViewOfSection */
1140 * Input: EDX: Flat address of arguments on stack
1142 * HANDLE32 SectionHandle [in] Section to be mapped
1143 * DWORD ProcessHandle [in] Process to be mapped into
1144 * DWORD * BaseAddress [in/out] Address to be mapped at
1145 * DWORD ZeroBits [in] (?? unclear ??)
1146 * DWORD CommitSize [in] (?? unclear ??)
1147 * LARGE_INTEGER *SectionOffset [in] Offset within section
1148 * DWORD * ViewSize [in] Size of view
1149 * DWORD InheritDisposition [in] (?? unclear ??)
1150 * DWORD AllocationType [in] (?? unclear ??)
1151 * DWORD Protect [in] Access protection
1153 * Output: EAX: NtStatus
1156 DWORD * stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1157 HANDLE32 SectionHandle = stack[0];
1158 DWORD ProcessHandle = stack[1]; /* ignored */
1159 DWORD * BaseAddress = (DWORD *)W32S_APP2WINE(stack[2], W32S_OFFSET);
1160 DWORD ZeroBits = stack[3];
1161 DWORD CommitSize = stack[4];
1162 LARGE_INTEGER *SectionOffset = (LARGE_INTEGER *)W32S_APP2WINE(stack[5], W32S_OFFSET);
1163 DWORD * ViewSize = (DWORD *)W32S_APP2WINE(stack[6], W32S_OFFSET);
1164 DWORD InheritDisposition = stack[7];
1165 DWORD AllocationType = stack[8];
1166 DWORD Protect = stack[9];
1168 LPBYTE address = (LPBYTE)(BaseAddress?
1169 W32S_APP2WINE(*BaseAddress, W32S_OFFSET) : 0);
1170 DWORD access = 0, result;
1172 switch (Protect & ~(PAGE_GUARD|PAGE_NOCACHE))
1174 case PAGE_READONLY: access = FILE_MAP_READ; break;
1175 case PAGE_READWRITE: access = FILE_MAP_WRITE; break;
1176 case PAGE_WRITECOPY: access = FILE_MAP_COPY; break;
1178 case PAGE_EXECUTE_READ: access = FILE_MAP_READ; break;
1179 case PAGE_EXECUTE_READWRITE: access = FILE_MAP_WRITE; break;
1180 case PAGE_EXECUTE_WRITECOPY: access = FILE_MAP_COPY; break;
1183 TRACE(vxd, "NtMapViewOfSection"
1184 "(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1185 (DWORD)SectionHandle, ProcessHandle, (DWORD)BaseAddress,
1186 ZeroBits, CommitSize, (DWORD)SectionOffset, (DWORD)ViewSize,
1187 InheritDisposition, AllocationType, Protect);
1188 TRACE(vxd, "NtMapViewOfSection: "
1189 "base=%lx, offset=%lx, size=%lx, access=%lx\n",
1190 (DWORD)address, SectionOffset? SectionOffset->LowPart : 0,
1191 ViewSize? *ViewSize : 0, access);
1193 result = (DWORD)MapViewOfFileEx(SectionHandle, access,
1194 SectionOffset? SectionOffset->HighPart : 0,
1195 SectionOffset? SectionOffset->LowPart : 0,
1196 ViewSize? *ViewSize : 0, address);
1198 TRACE(vxd, "NtMapViewOfSection: result=%lx\n", result);
1200 if (W32S_WINE2APP(result, W32S_OFFSET))
1202 if (BaseAddress) *BaseAddress = W32S_WINE2APP(result, W32S_OFFSET);
1203 EAX_reg(context) = STATUS_SUCCESS;
1205 else
1206 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1208 break;
1211 case 0x0012: /* NtUnmapViewOfSection */
1213 * Input: EDX: Flat address of arguments on stack
1215 * DWORD ProcessHandle [in] Process (defining address space)
1216 * LPBYTE BaseAddress [in] Base address of view to be unmapped
1218 * Output: EAX: NtStatus
1221 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1222 DWORD ProcessHandle = stack[0]; /* ignored */
1223 LPBYTE BaseAddress = (LPBYTE)W32S_APP2WINE(stack[1], W32S_OFFSET);
1225 TRACE(vxd, "NtUnmapViewOfSection(%lx, %lx)\n",
1226 ProcessHandle, (DWORD)BaseAddress);
1228 UnmapViewOfFile(BaseAddress);
1230 EAX_reg(context) = STATUS_SUCCESS;
1232 break;
1235 case 0x0013: /* NtFlushVirtualMemory */
1237 * Input: EDX: Flat address of arguments on stack
1239 * DWORD ProcessHandle [in] Process (defining address space)
1240 * LPBYTE *BaseAddress [in?] Base address of range to be flushed
1241 * DWORD *ViewSize [in?] Number of bytes to be flushed
1242 * DWORD *unknown [???] (?? unknown ??)
1244 * Output: EAX: NtStatus
1247 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1248 DWORD ProcessHandle = stack[0]; /* ignored */
1249 DWORD *BaseAddress = (DWORD *)W32S_APP2WINE(stack[1], W32S_OFFSET);
1250 DWORD *ViewSize = (DWORD *)W32S_APP2WINE(stack[2], W32S_OFFSET);
1251 DWORD *unknown = (DWORD *)W32S_APP2WINE(stack[3], W32S_OFFSET);
1253 LPBYTE address = (LPBYTE)(BaseAddress? W32S_APP2WINE(*BaseAddress, W32S_OFFSET) : 0);
1254 DWORD size = ViewSize? *ViewSize : 0;
1256 TRACE(vxd, "NtFlushVirtualMemory(%lx, %lx, %lx, %lx)\n",
1257 ProcessHandle, (DWORD)BaseAddress, (DWORD)ViewSize,
1258 (DWORD)unknown);
1259 TRACE(vxd, "NtFlushVirtualMemory: base=%lx, size=%lx\n",
1260 (DWORD)address, size);
1262 FlushViewOfFile(address, size);
1264 EAX_reg(context) = STATUS_SUCCESS;
1266 break;
1269 case 0x0014: /* Get/Set Debug Registers */
1271 * Input: ECX: 0 if Get, 1 if Set
1273 * EDX: Get: Flat address of buffer to receive values of
1274 * debug registers DR0 .. DR7
1275 * Set: Flat address of buffer containing values of
1276 * debug registers DR0 .. DR7 to be set
1277 * Output: None
1280 FIXME(vxd, "[0014] ECX=%lx EDX=%lx\n",
1281 ECX_reg(context), EDX_reg(context));
1283 /* FIXME */
1284 break;
1287 case 0x0015: /* Set Coprocessor Emulation Flag */
1289 * Input: EDX: 0 to deactivate, 1 to activate coprocessor emulation
1291 * Output: None
1294 TRACE(vxd, "[0015] EDX=%lx\n", EDX_reg(context));
1296 /* We don't care, as we always have a coprocessor anyway */
1297 break;
1300 case 0x0016: /* Init Win32S VxD PSP */
1302 * If called to query required PSP size:
1304 * Input: EBX: 0
1305 * Output: EDX: Required size of Win32s VxD PSP
1307 * If called to initialize allocated PSP:
1309 * Input: EBX: LoWord: Selector of Win32s VxD PSP
1310 * HiWord: Paragraph of Win32s VxD PSP (DOSMEM)
1311 * Output: None
1314 if (EBX_reg(context) == 0)
1315 EDX_reg(context) = 0x80;
1316 else
1318 PDB *psp = PTR_SEG_OFF_TO_LIN(BX_reg(context), 0);
1319 psp->nbFiles = 32;
1320 psp->fileHandlesPtr = MAKELONG(HIWORD(EBX_reg(context)), 0x5c);
1321 memset((LPBYTE)psp + 0x5c, '\xFF', 32);
1323 break;
1326 case 0x0017: /* Set Break Point */
1328 * Input: EBX: Offset of Break Point
1329 * CX: Selector of Break Point
1331 * Output: None
1334 FIXME(vxd, "[0017] EBX=%lx CX=%x\n",
1335 EBX_reg(context), CX_reg(context));
1337 /* FIXME */
1338 break;
1341 case 0x0018: /* VirtualLock */
1343 * Input: ECX: Current Process
1345 * EDX: Flat address of arguments on stack
1347 * DWORD *retv [out] TRUE if success, FALSE if failure
1348 * LPVOID base [in] Flat address of range to lock
1349 * DWORD size [in] Size of range
1351 * Output: EAX: NtStatus
1354 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1355 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1356 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
1357 DWORD size = stack[2];
1358 DWORD result;
1360 TRACE(vxd, "VirtualLock(%lx, %lx, %lx)\n",
1361 (DWORD)retv, (DWORD)base, size);
1363 result = VirtualLock(base, size);
1365 if (result)
1366 *retv = TRUE,
1367 EAX_reg(context) = STATUS_SUCCESS;
1368 else
1369 *retv = FALSE,
1370 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1372 break;
1375 case 0x0019: /* VirtualUnlock */
1377 * Input: ECX: Current Process
1379 * EDX: Flat address of arguments on stack
1381 * DWORD *retv [out] TRUE if success, FALSE if failure
1382 * LPVOID base [in] Flat address of range to unlock
1383 * DWORD size [in] Size of range
1385 * Output: EAX: NtStatus
1388 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1389 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1390 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
1391 DWORD size = stack[2];
1392 DWORD result;
1394 TRACE(vxd, "VirtualUnlock(%lx, %lx, %lx)\n",
1395 (DWORD)retv, (DWORD)base, size);
1397 result = VirtualUnlock(base, size);
1399 if (result)
1400 *retv = TRUE,
1401 EAX_reg(context) = STATUS_SUCCESS;
1402 else
1403 *retv = FALSE,
1404 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1406 break;
1409 case 0x001A: /* KGetSystemInfo */
1411 * Input: None
1413 * Output: ECX: Start of sparse memory arena
1414 * EDX: End of sparse memory arena
1417 TRACE(vxd, "KGetSystemInfo()\n");
1420 * Note: Win32s reserves 0GB - 2GB for Win 3.1 and uses 2GB - 4GB as
1421 * sparse memory arena. We do it the other way around, since
1422 * we have to reserve 3GB - 4GB for Linux, and thus use
1423 * 0GB - 3GB as sparse memory arena.
1425 * FIXME: What about other OSes ?
1428 ECX_reg(context) = W32S_WINE2APP(0x00000000, W32S_OFFSET);
1429 EDX_reg(context) = W32S_WINE2APP(0xbfffffff, W32S_OFFSET);
1430 break;
1433 case 0x001B: /* KGlobalMemStat */
1435 * Input: ESI: Flat address of buffer to receive memory info
1437 * Output: None
1440 struct Win32sMemoryInfo
1442 DWORD DIPhys_Count; /* Total physical pages */
1443 DWORD DIFree_Count; /* Free physical pages */
1444 DWORD DILin_Total_Count; /* Total virtual pages (private arena) */
1445 DWORD DILin_Total_Free; /* Free virtual pages (private arena) */
1447 DWORD SparseTotal; /* Total size of sparse arena (bytes ?) */
1448 DWORD SparseFree; /* Free size of sparse arena (bytes ?) */
1451 struct Win32sMemoryInfo *info =
1452 (struct Win32sMemoryInfo *)W32S_APP2WINE(ESI_reg(context), W32S_OFFSET);
1454 FIXME(vxd, "KGlobalMemStat(%lx)\n", (DWORD)info);
1456 /* FIXME */
1458 break;
1461 case 0x001C: /* Enable/Disable Exceptions */
1463 * Input: ECX: 0 to disable, 1 to enable exception handling
1465 * Output: None
1468 TRACE(vxd, "[001c] ECX=%lx\n", ECX_reg(context));
1470 /* FIXME */
1471 break;
1474 case 0x001D: /* VirtualAlloc called from 16-bit code */
1476 * Input: EDX: Segmented address of arguments on stack
1478 * LPVOID base [in] Flat address of region to reserve/commit
1479 * DWORD size [in] Size of region
1480 * DWORD type [in] Type of allocation
1481 * DWORD prot [in] Type of access protection
1483 * Output: EAX: NtStatus
1484 * EDX: Flat base address of allocated region
1487 DWORD *stack = PTR_SEG_OFF_TO_LIN(LOWORD(EDX_reg(context)),
1488 HIWORD(EDX_reg(context)));
1489 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0], W32S_OFFSET);
1490 DWORD size = stack[1];
1491 DWORD type = stack[2];
1492 DWORD prot = stack[3];
1493 DWORD result;
1495 TRACE(vxd, "VirtualAlloc16(%lx, %lx, %lx, %lx)\n",
1496 (DWORD)base, size, type, prot);
1498 if (type & 0x80000000)
1500 WARN(vxd, "VirtualAlloc16: strange type %lx\n", type);
1501 type &= 0x7fffffff;
1504 result = (DWORD)VirtualAlloc(base, size, type, prot);
1506 if (W32S_WINE2APP(result, W32S_OFFSET))
1507 EDX_reg(context) = W32S_WINE2APP(result, W32S_OFFSET),
1508 EAX_reg(context) = STATUS_SUCCESS;
1509 else
1510 EDX_reg(context) = 0,
1511 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1512 TRACE(vxd, "VirtualAlloc16: returning base %lx\n", EDX_reg(context));
1514 break;
1517 case 0x001E: /* VirtualFree called from 16-bit code */
1519 * Input: EDX: Segmented address of arguments on stack
1521 * LPVOID base [in] Flat address of region
1522 * DWORD size [in] Size of region
1523 * DWORD type [in] Type of operation
1525 * Output: EAX: NtStatus
1526 * EDX: TRUE if success, FALSE if failure
1529 DWORD *stack = PTR_SEG_OFF_TO_LIN(LOWORD(EDX_reg(context)),
1530 HIWORD(EDX_reg(context)));
1531 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0], W32S_OFFSET);
1532 DWORD size = stack[1];
1533 DWORD type = stack[2];
1534 DWORD result;
1536 TRACE(vxd, "VirtualFree16(%lx, %lx, %lx)\n",
1537 (DWORD)base, size, type);
1539 result = VirtualFree(base, size, type);
1541 if (result)
1542 EDX_reg(context) = TRUE,
1543 EAX_reg(context) = STATUS_SUCCESS;
1544 else
1545 EDX_reg(context) = FALSE,
1546 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1548 break;
1551 case 0x001F: /* FWorkingSetSize */
1553 * Input: EDX: 0 if Get, 1 if Set
1555 * ECX: Get: Buffer to receive Working Set Size
1556 * Set: Buffer containing Working Set Size
1558 * Output: NtStatus
1561 DWORD *ptr = (DWORD *)W32S_APP2WINE(ECX_reg(context), W32S_OFFSET);
1562 BOOL32 set = EDX_reg(context);
1564 TRACE(vxd, "FWorkingSetSize(%lx, %lx)\n", (DWORD)ptr, (DWORD)set);
1566 if (set)
1567 /* We do it differently ... */;
1568 else
1569 *ptr = 0x100;
1571 EAX_reg(context) = STATUS_SUCCESS;
1573 break;
1576 default:
1577 VXD_BARF( context, "W32S" );