Authors: Chris Morgan <cmorgan@wpi.edu>, James Abbatiello <abbejy@wpi.edu>
[wine/multimedia.git] / msdos / vxd.c
bloba3ca0ff6f777102bd97e8a1da6a7fdcd75be450f
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"
22 DEFAULT_DEBUG_CHANNEL(vxd)
25 #define VXD_BARF(context,name) \
26 DUMP( "vxd %s: unknown/not implemented parameters:\n" \
27 "vxd %s: AX %04x, BX %04x, CX %04x, DX %04x, " \
28 "SI %04x, DI %04x, DS %04x, ES %04x\n", \
29 (name), (name), AX_reg(context), BX_reg(context), \
30 CX_reg(context), DX_reg(context), SI_reg(context), \
31 DI_reg(context), (WORD)DS_reg(context), (WORD)ES_reg(context) )
34 static WORD VXD_WinVersion(void)
36 WORD version = LOWORD(GetVersion16());
37 return (version >> 8) | (version << 8);
40 /***********************************************************************
41 * VXD_VMM
43 void VXD_VMM ( CONTEXT *context )
45 unsigned service = AX_reg(context);
47 TRACE(vxd,"[%04x] VMM \n", (UINT16)service);
49 switch(service)
51 case 0x0000: /* version */
52 AX_reg(context) = VXD_WinVersion();
53 RESET_CFLAG(context);
54 break;
56 case 0x026d: /* Get_Debug_Flag '/m' */
57 case 0x026e: /* Get_Debug_Flag '/n' */
58 AL_reg(context) = 0;
59 RESET_CFLAG(context);
60 break;
62 default:
63 VXD_BARF( context, "VMM" );
67 /***********************************************************************
68 * VXD_PageFile
70 void WINAPI VXD_PageFile( CONTEXT *context )
72 unsigned service = AX_reg(context);
74 /* taken from Ralf Brown's Interrupt List */
76 TRACE(vxd,"[%04x] PageFile\n", (UINT16)service );
78 switch(service)
80 case 0x00: /* get version, is this windows version? */
81 TRACE(vxd,"returning version\n");
82 AX_reg(context) = VXD_WinVersion();
83 RESET_CFLAG(context);
84 break;
86 case 0x01: /* get swap file info */
87 TRACE(vxd,"VxD PageFile: returning swap file info\n");
88 AX_reg(context) = 0x00; /* paging disabled */
89 ECX_reg(context) = 0; /* maximum size of paging file */
90 /* FIXME: do I touch DS:SI or DS:DI? */
91 RESET_CFLAG(context);
92 break;
94 case 0x02: /* delete permanent swap on exit */
95 TRACE(vxd,"VxD PageFile: supposed to delete swap\n");
96 RESET_CFLAG(context);
97 break;
99 case 0x03: /* current temporary swap file size */
100 TRACE(vxd,"VxD PageFile: what is current temp. swap size\n");
101 RESET_CFLAG(context);
102 break;
104 case 0x04: /* read or write?? INTERRUP.D */
105 case 0x05: /* cancel?? INTERRUP.D */
106 case 0x06: /* test I/O valid INTERRUP.D */
107 default:
108 VXD_BARF( context, "pagefile" );
109 break;
113 /***********************************************************************
114 * VXD_Reboot
116 void VXD_Reboot ( CONTEXT *context )
118 unsigned service = AX_reg(context);
120 TRACE(vxd,"[%04x] VMM \n", (UINT16)service);
122 switch(service)
124 case 0x0000: /* version */
125 AX_reg(context) = VXD_WinVersion();
126 RESET_CFLAG(context);
127 break;
129 default:
130 VXD_BARF( context, "REBOOT" );
134 /***********************************************************************
135 * VXD_VDD
137 void VXD_VDD ( CONTEXT *context )
139 unsigned service = AX_reg(context);
141 TRACE(vxd,"[%04x] VDD \n", (UINT16)service);
143 switch(service)
145 case 0x0000: /* version */
146 AX_reg(context) = VXD_WinVersion();
147 RESET_CFLAG(context);
148 break;
150 default:
151 VXD_BARF( context, "VDD" );
155 /***********************************************************************
156 * VXD_VMD
158 void VXD_VMD ( CONTEXT *context )
160 unsigned service = AX_reg(context);
162 TRACE(vxd,"[%04x] VMD \n", (UINT16)service);
164 switch(service)
166 case 0x0000: /* version */
167 AX_reg(context) = VXD_WinVersion();
168 RESET_CFLAG(context);
169 break;
171 default:
172 VXD_BARF( context, "VMD" );
176 /***********************************************************************
177 * VXD_Shell
179 void WINAPI VXD_Shell( CONTEXT *context )
181 unsigned service = DX_reg(context);
183 TRACE(vxd,"[%04x] Shell\n", (UINT16)service);
185 switch (service) /* Ralf Brown says EDX, but I use DX instead */
187 case 0x0000:
188 TRACE(vxd,"returning version\n");
189 AX_reg(context) = VXD_WinVersion();
190 EBX_reg(context) = 1; /* system VM Handle */
191 break;
193 case 0x0001:
194 case 0x0002:
195 case 0x0003:
196 case 0x0004:
197 case 0x0005:
198 VXD_BARF( context, "shell" );
199 break;
201 case 0x0006: /* SHELL_Get_VM_State */
202 TRACE(vxd,"VxD Shell: returning VM state\n");
203 /* Actually we don't, not yet. We have to return a structure
204 * and I am not to sure how to set it up and return it yet,
205 * so for now let's do nothing. I can (hopefully) get this
206 * by the next release
208 /* RESET_CFLAG(context); */
209 break;
211 case 0x0007:
212 case 0x0008:
213 case 0x0009:
214 case 0x000A:
215 case 0x000B:
216 case 0x000C:
217 case 0x000D:
218 case 0x000E:
219 case 0x000F:
220 case 0x0010:
221 case 0x0011:
222 case 0x0012:
223 case 0x0013:
224 case 0x0014:
225 case 0x0015:
226 case 0x0016:
227 VXD_BARF( context, "SHELL" );
228 break;
230 /* the new Win95 shell API */
231 case 0x0100: /* get version */
232 AX_reg(context) = VXD_WinVersion();
233 break;
235 case 0x0104: /* retrieve Hook_Properties list */
236 case 0x0105: /* call Hook_Properties callbacks */
237 VXD_BARF( context, "SHELL" );
238 break;
240 case 0x0106: /* install timeout callback */
241 TRACE( vxd, "VxD Shell: ignoring shell callback (%ld sec.)\n",
242 EBX_reg( context ) );
243 SET_CFLAG(context);
244 break;
246 case 0x0107: /* get version of any VxD */
247 default:
248 VXD_BARF( context, "SHELL" );
249 break;
254 /***********************************************************************
255 * VXD_Comm
257 void WINAPI VXD_Comm( CONTEXT *context )
259 unsigned service = AX_reg(context);
261 TRACE(vxd,"[%04x] Comm\n", (UINT16)service);
263 switch (service)
265 case 0x0000: /* get version */
266 TRACE(vxd,"returning version\n");
267 AX_reg(context) = VXD_WinVersion();
268 RESET_CFLAG(context);
269 break;
271 case 0x0001: /* set port global */
272 case 0x0002: /* get focus */
273 case 0x0003: /* virtualise port */
274 default:
275 VXD_BARF( context, "comm" );
279 /***********************************************************************
280 * VXD_Timer
282 void VXD_Timer( CONTEXT *context )
284 unsigned service = AX_reg(context);
286 TRACE(vxd,"[%04x] Virtual Timer\n", (UINT16)service);
288 switch(service)
290 case 0x0000: /* version */
291 AX_reg(context) = VXD_WinVersion();
292 RESET_CFLAG(context);
293 break;
295 case 0x0100: /* clock tick time, in 840nsecs */
296 EAX_reg(context) = GetTickCount();
298 EDX_reg(context) = EAX_reg(context) >> 22;
299 EAX_reg(context) <<= 10; /* not very precise */
300 break;
302 case 0x0101: /* current Windows time, msecs */
303 case 0x0102: /* current VM time, msecs */
304 EAX_reg(context) = GetTickCount();
305 break;
307 default:
308 VXD_BARF( context, "VTD" );
312 /***********************************************************************
313 * VXD_TimerAPI
315 static DWORD System_Time = 0;
316 static WORD System_Time_Selector = 0;
317 static void System_Time_Tick( WORD timer ) { System_Time += 55; }
318 void VXD_TimerAPI ( CONTEXT *context )
320 unsigned service = AX_reg(context);
322 TRACE(vxd,"[%04x] TimerAPI \n", (UINT16)service);
324 switch(service)
326 case 0x0000: /* version */
327 AX_reg(context) = VXD_WinVersion();
328 RESET_CFLAG(context);
329 break;
331 case 0x0009: /* get system time selector */
332 if ( !System_Time_Selector )
334 System_Time_Selector = SELECTOR_AllocBlock( &System_Time, sizeof(DWORD),
335 SEGMENT_DATA, FALSE, TRUE );
336 CreateSystemTimer( 55, System_Time_Tick );
339 AX_reg(context) = System_Time_Selector;
340 RESET_CFLAG(context);
341 break;
343 default:
344 VXD_BARF( context, "VTDAPI" );
348 /***********************************************************************
349 * VXD_ConfigMG
351 void VXD_ConfigMG ( CONTEXT *context )
353 unsigned service = AX_reg(context);
355 TRACE(vxd,"[%04x] ConfigMG \n", (UINT16)service);
357 switch(service)
359 case 0x0000: /* version */
360 AX_reg(context) = VXD_WinVersion();
361 RESET_CFLAG(context);
362 break;
364 default:
365 VXD_BARF( context, "CONFIGMG" );
369 /***********************************************************************
370 * VXD_Enable
372 void VXD_Enable ( CONTEXT *context )
374 unsigned service = AX_reg(context);
376 TRACE(vxd,"[%04x] Enable \n", (UINT16)service);
378 switch(service)
380 case 0x0000: /* version */
381 AX_reg(context) = VXD_WinVersion();
382 RESET_CFLAG(context);
383 break;
385 default:
386 VXD_BARF( context, "ENABLE" );
390 /***********************************************************************
391 * VXD_APM
393 void VXD_APM ( CONTEXT *context )
395 unsigned service = AX_reg(context);
397 TRACE(vxd,"[%04x] APM \n", (UINT16)service);
399 switch(service)
401 case 0x0000: /* version */
402 AX_reg(context) = VXD_WinVersion();
403 RESET_CFLAG(context);
404 break;
406 default:
407 VXD_BARF( context, "APM" );
411 /***********************************************************************
412 * VXD_Win32s
414 * This is an implementation of the services of the Win32s VxD.
415 * Since official documentation of these does not seem to be available,
416 * certain arguments of some of the services remain unclear.
418 * FIXME: The following services are currently unimplemented:
419 * Exception handling (0x01, 0x1C)
420 * Debugger support (0x0C, 0x14, 0x17)
421 * Low-level memory access (0x02, 0x03, 0x0A, 0x0B)
422 * Memory Statistics (0x1B)
425 * We have a specific problem running Win32s on Linux (and probably also
426 * the other x86 unixes), since Win32s tries to allocate its main 'flat
427 * code/data segment' selectors with a base of 0xffff0000 (and limit 4GB).
428 * The rationale for this seems to be that they want one the one hand to
429 * be able to leave the Win 3.1 memory (starting with the main DOS memory)
430 * at linear address 0, but want at other hand to have offset 0 of the
431 * flat data/code segment point to an unmapped page (to catch NULL pointer
432 * accesses). Hence they allocate the flat segments with a base of 0xffff0000
433 * so that the Win 3.1 memory area at linear address zero shows up in the
434 * flat segments at offset 0x10000 (since linear addresses wrap around at
435 * 4GB). To compensate for that discrepancy between flat segment offsets
436 * and plain linear addresses, all flat pointers passed between the 32-bit
437 * and the 16-bit parts of Win32s are shifted by 0x10000 in the appropriate
438 * direction by the glue code (mainly) in W32SKRNL and WIN32S16.
440 * The problem for us is now that Linux does not allow a LDT selector with
441 * base 0xffff0000 to be created, since it would 'see' a part of the kernel
442 * address space. To address this problem we introduce *another* offset:
443 * We add 0x10000 to every linear address we get as an argument from Win32s.
444 * This means especially that the flat code/data selectors get actually
445 * allocated with base 0x0, so that flat offsets and (real) linear addresses
446 * do again agree! In fact, every call e.g. of a Win32s VxD service now
447 * has all pointer arguments (which are offsets in the flat data segement)
448 * first reduced by 0x10000 by the W32SKRNL glue code, and then again
449 * increased by 0x10000 by *our* code.
451 * Note that to keep everything consistent, this offset has to be applied by
452 * every Wine function that operates on 'linear addresses' passed to it by
453 * Win32s. Fortunately, since Win32s does not directly call any Wine 32-bit
454 * API routines, this affects only two locations: this VxD and the DPMI
455 * handler. (NOTE: Should any Win32s application pass a linear address to
456 * any routine apart from those, e.g. some other VxD handler, that code
457 * would have to take the offset into account as well!)
459 * The application of the offset is triggered by marking the current process
460 * as a Win32s process by setting the PDB32_WIN32S_PROC flag in the process
461 * database. This is done the first time any application calls the GetVersion()
462 * service of the Win32s VxD. (Note that the flag is never removed.)
466 void VXD_Win32s( CONTEXT *context )
468 switch (AX_reg(context))
470 case 0x0000: /* Get Version */
472 * Input: None
474 * Output: EAX: LoWord: Win32s Version (1.30)
475 * HiWord: VxD Version (200)
477 * EBX: Build (172)
479 * ECX: ??? (1)
481 * EDX: Debugging Flags
483 * EDI: Error Flag
484 * 0 if OK,
485 * 1 if VMCPD VxD not found
488 TRACE(vxd, "GetVersion()\n");
490 EAX_reg(context) = VXD_WinVersion() | (200 << 16);
491 EBX_reg(context) = 0;
492 ECX_reg(context) = 0;
493 EDX_reg(context) = 0;
494 EDI_reg(context) = 0;
497 * If this is the first time we are called for this process,
498 * hack the memory image of WIN32S16 so that it doesn't try
499 * to access the GDT directly ...
501 * The first code segment of WIN32S16 (version 1.30) contains
502 * an unexported function somewhere between the exported functions
503 * SetFS and StackLinearToSegmented that tries to find a selector
504 * in the LDT that maps to the memory image of the LDT itself.
505 * If it succeeds, it stores this selector into a global variable
506 * which will be used to speed up execution by using this selector
507 * to modify the LDT directly instead of using the DPMI calls.
509 * To perform this search of the LDT, this function uses the
510 * sgdt and sldt instructions to find the linear address of
511 * the (GDT and then) LDT. While those instructions themselves
512 * execute without problem, the linear address that sgdt returns
513 * points (at least under Linux) to the kernel address space, so
514 * that any subsequent access leads to a segfault.
516 * Fortunately, WIN32S16 still contains as a fallback option the
517 * mechanism of using DPMI calls to modify LDT selectors instead
518 * of direct writes to the LDT. Thus we can circumvent the problem
519 * by simply replacing the first byte of the offending function
520 * with an 'retf' instruction. This means that the global variable
521 * supposed to contain the LDT alias selector will remain zero,
522 * and hence WIN32S16 will fall back to using DPMI calls.
524 * The heuristic we employ to _find_ that function is as follows:
525 * We search between the addresses of the exported symbols SetFS
526 * and StackLinearToSegmented for the byte sequence '0F 01 04'
527 * (this is the opcode of 'sgdt [si]'). We then search backwards
528 * from this address for the last occurrance of 'CB' (retf) that marks
529 * the end of the preceeding function. The following byte (which
530 * should now be the first byte of the function we are looking for)
531 * will be replaced by 'CB' (retf).
533 * This heuristic works for the retail as well as the debug version
534 * of Win32s version 1.30. For versions earlier than that this
535 * hack should not be necessary at all, since the whole mechanism
536 * ('PERF130') was introduced only in 1.30 to improve the overall
537 * performance of Win32s.
540 if (!(PROCESS_Current()->flags & PDB32_WIN32S_PROC))
542 HMODULE16 hModule = GetModuleHandle16("win32s16");
543 SEGPTR func1 = (SEGPTR)WIN32_GetProcAddress16(hModule, "SetFS");
544 SEGPTR func2 = (SEGPTR)WIN32_GetProcAddress16(hModule,
545 "StackLinearToSegmented");
547 if ( hModule && func1 && func2
548 && SELECTOROF(func1) == SELECTOROF(func2))
550 BYTE *start = PTR_SEG_TO_LIN(func1);
551 BYTE *end = PTR_SEG_TO_LIN(func2);
552 BYTE *p, *retv = NULL;
553 int found = 0;
555 for (p = start; p < end; p++)
556 if (*p == 0xCB) found = 0, retv = p;
557 else if (*p == 0x0F) found = 1;
558 else if (*p == 0x01 && found == 1) found = 2;
559 else if (*p == 0x04 && found == 2) { found = 3; break; }
560 else found = 0;
562 if (found == 3 && retv)
564 TRACE(vxd, "PERF130 hack: "
565 "Replacing byte %02X at offset %04X:%04X\n",
566 *(retv+1), SELECTOROF(func1),
567 OFFSETOF(func1) + retv+1-start);
569 *(retv+1) = (BYTE)0xCB;
575 * Mark process as Win32s, so that subsequent DPMI calls
576 * will perform the W32S_APP2WINE/W32S_WINE2APP address shift.
579 PROCESS_Current()->flags |= PDB32_WIN32S_PROC;
580 break;
583 case 0x0001: /* Install Exception Handling */
585 * Input: EBX: Flat address of W32SKRNL Exception Data
587 * ECX: LoWord: Flat Code Selector
588 * HiWord: Flat Data Selector
590 * EDX: Flat address of W32SKRNL Exception Handler
591 * (this is equal to W32S_BackTo32 + 0x40)
593 * ESI: SEGPTR KERNEL.HASGPHANDLER
595 * EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10)
597 * Output: EAX: 0 if OK
600 TRACE(vxd, "[0001] EBX=%lx ECX=%lx EDX=%lx ESI=%lx EDI=%lx\n",
601 EBX_reg(context), ECX_reg(context), EDX_reg(context),
602 ESI_reg(context), EDI_reg(context));
604 /* FIXME */
606 EAX_reg(context) = 0;
607 break;
610 case 0x0002: /* Set Page Access Flags */
612 * Input: EBX: New access flags
613 * Bit 2: User Page if set, Supervisor Page if clear
614 * Bit 1: Read-Write if set, Read-Only if clear
616 * ECX: Size of memory area to change
618 * EDX: Flat start address of memory area
620 * Output: EAX: Size of area changed
623 TRACE(vxd, "[0002] EBX=%lx ECX=%lx EDX=%lx\n",
624 EBX_reg(context), ECX_reg(context), EDX_reg(context));
626 /* FIXME */
628 EAX_reg(context) = ECX_reg(context);
629 break;
632 case 0x0003: /* Get Page Access Flags */
634 * Input: EDX: Flat address of page to query
636 * Output: EAX: Page access flags
637 * Bit 2: User Page if set, Supervisor Page if clear
638 * Bit 1: Read-Write if set, Read-Only if clear
641 TRACE(vxd, "[0003] EDX=%lx\n", EDX_reg(context));
643 /* FIXME */
645 EAX_reg(context) = 6;
646 break;
649 case 0x0004: /* Map Module */
651 * Input: ECX: IMTE (offset in Module Table) of new module
653 * EDX: Flat address of Win32s Module Table
655 * Output: EAX: 0 if OK
658 if (!EDX_reg(context) || CX_reg(context) == 0xFFFF)
660 TRACE(vxd, "MapModule: Initialization call\n");
661 EAX_reg(context) = 0;
663 else
666 * Structure of a Win32s Module Table Entry:
668 struct Win32sModule
670 DWORD flags;
671 DWORD flatBaseAddr;
672 LPCSTR moduleName;
673 LPCSTR pathName;
674 LPCSTR unknown;
675 LPBYTE baseAddr;
676 DWORD hModule;
677 DWORD relocDelta;
681 * Note: This function should set up a demand-paged memory image
682 * of the given module. Since mmap does not allow file offsets
683 * not aligned at 1024 bytes, we simply load the image fully
684 * into memory.
687 struct Win32sModule *moduleTable =
688 (struct Win32sModule *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
689 struct Win32sModule *module = moduleTable + ECX_reg(context);
691 IMAGE_NT_HEADERS *nt_header = PE_HEADER(module->baseAddr);
692 IMAGE_SECTION_HEADER *pe_seg = PE_SECTIONS(module->baseAddr);
694 HFILE image = _lopen(module->pathName, OF_READ);
695 BOOL error = (image == INVALID_HANDLE_VALUE);
696 UINT i;
698 TRACE(vxd, "MapModule: Loading %s\n", module->pathName);
700 for (i = 0;
701 !error && i < nt_header->FileHeader.NumberOfSections;
702 i++, pe_seg++)
703 if(!(pe_seg->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA))
705 DWORD off = pe_seg->PointerToRawData;
706 DWORD len = pe_seg->SizeOfRawData;
707 LPBYTE addr = module->baseAddr + pe_seg->VirtualAddress;
709 TRACE(vxd, "MapModule: "
710 "Section %d at %08lx from %08lx len %08lx\n",
711 i, (DWORD)addr, off, len);
713 if ( _llseek(image, off, SEEK_SET) != off
714 || _lread(image, addr, len) != len)
715 error = TRUE;
718 _lclose(image);
720 if (error)
721 ERR(vxd, "MapModule: Unable to load %s\n", module->pathName);
723 else if (module->relocDelta != 0)
725 IMAGE_DATA_DIRECTORY *dir = nt_header->OptionalHeader.DataDirectory
726 + IMAGE_DIRECTORY_ENTRY_BASERELOC;
727 IMAGE_BASE_RELOCATION *r = (IMAGE_BASE_RELOCATION *)
728 (dir->Size? module->baseAddr + dir->VirtualAddress : 0);
730 TRACE(vxd, "MapModule: Reloc delta %08lx\n", module->relocDelta);
732 while (r && r->VirtualAddress)
734 LPBYTE page = module->baseAddr + r->VirtualAddress;
735 int count = (r->SizeOfBlock - 8) / 2;
737 TRACE(vxd, "MapModule: %d relocations for page %08lx\n",
738 count, (DWORD)page);
740 for(i = 0; i < count; i++)
742 int offset = r->TypeOffset[i] & 0xFFF;
743 int type = r->TypeOffset[i] >> 12;
744 switch(type)
746 case IMAGE_REL_BASED_ABSOLUTE:
747 break;
748 case IMAGE_REL_BASED_HIGH:
749 *(WORD *)(page+offset) += HIWORD(module->relocDelta);
750 break;
751 case IMAGE_REL_BASED_LOW:
752 *(WORD *)(page+offset) += LOWORD(module->relocDelta);
753 break;
754 case IMAGE_REL_BASED_HIGHLOW:
755 *(DWORD*)(page+offset) += module->relocDelta;
756 break;
757 default:
758 WARN(vxd, "MapModule: Unsupported fixup type\n");
759 break;
763 r = (IMAGE_BASE_RELOCATION *)((LPBYTE)r + r->SizeOfBlock);
767 EAX_reg(context) = 0;
768 RESET_CFLAG(context);
770 break;
773 case 0x0005: /* UnMap Module */
775 * Input: EDX: Flat address of module image
777 * Output: EAX: 1 if OK
780 TRACE(vxd, "UnMapModule: %lx\n", (DWORD)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET));
782 /* As we didn't map anything, there's nothing to unmap ... */
784 EAX_reg(context) = 1;
785 break;
788 case 0x0006: /* VirtualAlloc */
790 * Input: ECX: Current Process
792 * EDX: Flat address of arguments on stack
794 * DWORD *retv [out] Flat base address of allocated region
795 * LPVOID base [in] Flat address of region to reserve/commit
796 * DWORD size [in] Size of region
797 * DWORD type [in] Type of allocation
798 * DWORD prot [in] Type of access protection
800 * Output: EAX: NtStatus
803 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
804 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
805 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
806 DWORD size = stack[2];
807 DWORD type = stack[3];
808 DWORD prot = stack[4];
809 DWORD result;
811 TRACE(vxd, "VirtualAlloc(%lx, %lx, %lx, %lx, %lx)\n",
812 (DWORD)retv, (DWORD)base, size, type, prot);
814 if (type & 0x80000000)
816 WARN(vxd, "VirtualAlloc: strange type %lx\n", type);
817 type &= 0x7fffffff;
820 if (!base && (type & MEM_COMMIT) && prot == PAGE_READONLY)
822 WARN(vxd, "VirtualAlloc: NLS hack, allowing write access!\n");
823 prot = PAGE_READWRITE;
826 result = (DWORD)VirtualAlloc(base, size, type, prot);
828 if (W32S_WINE2APP(result, W32S_OFFSET))
829 *retv = W32S_WINE2APP(result, W32S_OFFSET),
830 EAX_reg(context) = STATUS_SUCCESS;
831 else
832 *retv = 0,
833 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
835 break;
838 case 0x0007: /* VirtualFree */
840 * Input: ECX: Current Process
842 * EDX: Flat address of arguments on stack
844 * DWORD *retv [out] TRUE if success, FALSE if failure
845 * LPVOID base [in] Flat address of region
846 * DWORD size [in] Size of region
847 * DWORD type [in] Type of operation
849 * Output: EAX: NtStatus
852 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
853 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
854 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
855 DWORD size = stack[2];
856 DWORD type = stack[3];
857 DWORD result;
859 TRACE(vxd, "VirtualFree(%lx, %lx, %lx, %lx)\n",
860 (DWORD)retv, (DWORD)base, size, type);
862 result = VirtualFree(base, size, type);
864 if (result)
865 *retv = TRUE,
866 EAX_reg(context) = STATUS_SUCCESS;
867 else
868 *retv = FALSE,
869 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
871 break;
874 case 0x0008: /* VirtualProtect */
876 * Input: ECX: Current Process
878 * EDX: Flat address of arguments on stack
880 * DWORD *retv [out] TRUE if success, FALSE if failure
881 * LPVOID base [in] Flat address of region
882 * DWORD size [in] Size of region
883 * DWORD new_prot [in] Desired access protection
884 * DWORD *old_prot [out] Previous access protection
886 * Output: EAX: NtStatus
889 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
890 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
891 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
892 DWORD size = stack[2];
893 DWORD new_prot = stack[3];
894 DWORD *old_prot = (DWORD *)W32S_APP2WINE(stack[4], W32S_OFFSET);
895 DWORD result;
897 TRACE(vxd, "VirtualProtect(%lx, %lx, %lx, %lx, %lx)\n",
898 (DWORD)retv, (DWORD)base, size, new_prot, (DWORD)old_prot);
900 result = VirtualProtect(base, size, new_prot, old_prot);
902 if (result)
903 *retv = TRUE,
904 EAX_reg(context) = STATUS_SUCCESS;
905 else
906 *retv = FALSE,
907 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
909 break;
912 case 0x0009: /* VirtualQuery */
914 * Input: ECX: Current Process
916 * EDX: Flat address of arguments on stack
918 * DWORD *retv [out] Nr. bytes returned
919 * LPVOID base [in] Flat address of region
920 * LPMEMORY_BASIC_INFORMATION info [out] Info buffer
921 * DWORD len [in] Size of buffer
923 * Output: EAX: NtStatus
926 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
927 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
928 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
929 LPMEMORY_BASIC_INFORMATION info =
930 (LPMEMORY_BASIC_INFORMATION)W32S_APP2WINE(stack[2], W32S_OFFSET);
931 DWORD len = stack[3];
932 DWORD result;
934 TRACE(vxd, "VirtualQuery(%lx, %lx, %lx, %lx)\n",
935 (DWORD)retv, (DWORD)base, (DWORD)info, len);
937 result = VirtualQuery(base, info, len);
939 *retv = result;
940 EAX_reg(context) = STATUS_SUCCESS;
942 break;
945 case 0x000A: /* SetVirtMemProcess */
947 * Input: ECX: Process Handle
949 * EDX: Flat address of region
951 * Output: EAX: NtStatus
954 TRACE(vxd, "[000a] ECX=%lx EDX=%lx\n",
955 ECX_reg(context), EDX_reg(context));
957 /* FIXME */
959 EAX_reg(context) = STATUS_SUCCESS;
960 break;
963 case 0x000B: /* ??? some kind of cleanup */
965 * Input: ECX: Process Handle
967 * Output: EAX: NtStatus
970 TRACE(vxd, "[000b] ECX=%lx\n", ECX_reg(context));
972 /* FIXME */
974 EAX_reg(context) = STATUS_SUCCESS;
975 break;
978 case 0x000C: /* Set Debug Flags */
980 * Input: EDX: Debug Flags
982 * Output: EDX: Previous Debug Flags
985 FIXME(vxd, "[000c] EDX=%lx\n", EDX_reg(context));
987 /* FIXME */
989 EDX_reg(context) = 0;
990 break;
993 case 0x000D: /* NtCreateSection */
995 * Input: EDX: Flat address of arguments on stack
997 * HANDLE32 *retv [out] Handle of Section created
998 * DWORD flags1 [in] (?? unknown ??)
999 * DWORD atom [in] Name of Section to create
1000 * LARGE_INTEGER *size [in] Size of Section
1001 * DWORD protect [in] Access protection
1002 * DWORD flags2 [in] (?? unknown ??)
1003 * HFILE32 hFile [in] Handle of file to map
1004 * DWORD psp [in] (Win32s: PSP that hFile belongs to)
1006 * Output: EAX: NtStatus
1009 DWORD *stack = (DWORD *) W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1010 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1011 DWORD flags1 = stack[1];
1012 DWORD atom = stack[2];
1013 LARGE_INTEGER *size = (LARGE_INTEGER *)W32S_APP2WINE(stack[3], W32S_OFFSET);
1014 DWORD protect = stack[4];
1015 DWORD flags2 = stack[5];
1016 HFILE hFile = FILE_GetHandle(stack[6]);
1017 DWORD psp = stack[7];
1019 HANDLE result = INVALID_HANDLE_VALUE;
1020 char name[128];
1022 TRACE(vxd, "NtCreateSection(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1023 (DWORD)retv, flags1, atom, (DWORD)size, protect, flags2,
1024 (DWORD)hFile, psp);
1026 if (!atom || GlobalGetAtomNameA(atom, name, sizeof(name)))
1028 TRACE(vxd, "NtCreateSection: name=%s\n", atom? name : NULL);
1030 result = CreateFileMappingA(hFile, NULL, protect,
1031 size? size->HighPart : 0,
1032 size? size->LowPart : 0,
1033 atom? name : NULL);
1036 if (result == INVALID_HANDLE_VALUE)
1037 WARN(vxd, "NtCreateSection: failed!\n");
1038 else
1039 TRACE(vxd, "NtCreateSection: returned %lx\n", (DWORD)result);
1041 if (result != INVALID_HANDLE_VALUE)
1042 *retv = result,
1043 EAX_reg(context) = STATUS_SUCCESS;
1044 else
1045 *retv = result,
1046 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1048 break;
1051 case 0x000E: /* NtOpenSection */
1053 * Input: EDX: Flat address of arguments on stack
1055 * HANDLE32 *retv [out] Handle of Section opened
1056 * DWORD protect [in] Access protection
1057 * DWORD atom [in] Name of Section to create
1059 * Output: EAX: NtStatus
1062 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1063 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1064 DWORD protect = stack[1];
1065 DWORD atom = stack[2];
1067 HANDLE result = INVALID_HANDLE_VALUE;
1068 char name[128];
1070 TRACE(vxd, "NtOpenSection(%lx, %lx, %lx)\n",
1071 (DWORD)retv, protect, atom);
1073 if (atom && GlobalGetAtomNameA(atom, name, sizeof(name)))
1075 TRACE(vxd, "NtOpenSection: name=%s\n", name);
1077 result = OpenFileMappingA(protect, FALSE, name);
1080 if (result == INVALID_HANDLE_VALUE)
1081 WARN(vxd, "NtOpenSection: failed!\n");
1082 else
1083 TRACE(vxd, "NtOpenSection: returned %lx\n", (DWORD)result);
1085 if (result != INVALID_HANDLE_VALUE)
1086 *retv = result,
1087 EAX_reg(context) = STATUS_SUCCESS;
1088 else
1089 *retv = result,
1090 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1092 break;
1095 case 0x000F: /* NtCloseSection */
1097 * Input: EDX: Flat address of arguments on stack
1099 * HANDLE32 handle [in] Handle of Section to close
1100 * DWORD *id [out] Unique ID (?? unclear ??)
1102 * Output: EAX: NtStatus
1105 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1106 HANDLE handle = stack[0];
1107 DWORD *id = (DWORD *)W32S_APP2WINE(stack[1], W32S_OFFSET);
1109 TRACE(vxd, "NtCloseSection(%lx, %lx)\n", (DWORD)handle, (DWORD)id);
1111 CloseHandle(handle);
1112 if (id) *id = 0; /* FIXME */
1114 EAX_reg(context) = STATUS_SUCCESS;
1116 break;
1119 case 0x0010: /* NtDupSection */
1121 * Input: EDX: Flat address of arguments on stack
1123 * HANDLE32 handle [in] Handle of Section to duplicate
1125 * Output: EAX: NtStatus
1128 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1129 HANDLE handle = stack[0];
1130 HANDLE new_handle;
1132 TRACE(vxd, "NtDupSection(%lx)\n", (DWORD)handle);
1134 DuplicateHandle( GetCurrentProcess(), handle,
1135 GetCurrentProcess(), &new_handle,
1136 0, FALSE, DUPLICATE_SAME_ACCESS );
1137 EAX_reg(context) = STATUS_SUCCESS;
1139 break;
1142 case 0x0011: /* NtMapViewOfSection */
1144 * Input: EDX: Flat address of arguments on stack
1146 * HANDLE32 SectionHandle [in] Section to be mapped
1147 * DWORD ProcessHandle [in] Process to be mapped into
1148 * DWORD * BaseAddress [in/out] Address to be mapped at
1149 * DWORD ZeroBits [in] (?? unclear ??)
1150 * DWORD CommitSize [in] (?? unclear ??)
1151 * LARGE_INTEGER *SectionOffset [in] Offset within section
1152 * DWORD * ViewSize [in] Size of view
1153 * DWORD InheritDisposition [in] (?? unclear ??)
1154 * DWORD AllocationType [in] (?? unclear ??)
1155 * DWORD Protect [in] Access protection
1157 * Output: EAX: NtStatus
1160 DWORD * stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1161 HANDLE SectionHandle = stack[0];
1162 DWORD ProcessHandle = stack[1]; /* ignored */
1163 DWORD * BaseAddress = (DWORD *)W32S_APP2WINE(stack[2], W32S_OFFSET);
1164 DWORD ZeroBits = stack[3];
1165 DWORD CommitSize = stack[4];
1166 LARGE_INTEGER *SectionOffset = (LARGE_INTEGER *)W32S_APP2WINE(stack[5], W32S_OFFSET);
1167 DWORD * ViewSize = (DWORD *)W32S_APP2WINE(stack[6], W32S_OFFSET);
1168 DWORD InheritDisposition = stack[7];
1169 DWORD AllocationType = stack[8];
1170 DWORD Protect = stack[9];
1172 LPBYTE address = (LPBYTE)(BaseAddress?
1173 W32S_APP2WINE(*BaseAddress, W32S_OFFSET) : 0);
1174 DWORD access = 0, result;
1176 switch (Protect & ~(PAGE_GUARD|PAGE_NOCACHE))
1178 case PAGE_READONLY: access = FILE_MAP_READ; break;
1179 case PAGE_READWRITE: access = FILE_MAP_WRITE; break;
1180 case PAGE_WRITECOPY: access = FILE_MAP_COPY; break;
1182 case PAGE_EXECUTE_READ: access = FILE_MAP_READ; break;
1183 case PAGE_EXECUTE_READWRITE: access = FILE_MAP_WRITE; break;
1184 case PAGE_EXECUTE_WRITECOPY: access = FILE_MAP_COPY; break;
1187 TRACE(vxd, "NtMapViewOfSection"
1188 "(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1189 (DWORD)SectionHandle, ProcessHandle, (DWORD)BaseAddress,
1190 ZeroBits, CommitSize, (DWORD)SectionOffset, (DWORD)ViewSize,
1191 InheritDisposition, AllocationType, Protect);
1192 TRACE(vxd, "NtMapViewOfSection: "
1193 "base=%lx, offset=%lx, size=%lx, access=%lx\n",
1194 (DWORD)address, SectionOffset? SectionOffset->LowPart : 0,
1195 ViewSize? *ViewSize : 0, access);
1197 result = (DWORD)MapViewOfFileEx(SectionHandle, access,
1198 SectionOffset? SectionOffset->HighPart : 0,
1199 SectionOffset? SectionOffset->LowPart : 0,
1200 ViewSize? *ViewSize : 0, address);
1202 TRACE(vxd, "NtMapViewOfSection: result=%lx\n", result);
1204 if (W32S_WINE2APP(result, W32S_OFFSET))
1206 if (BaseAddress) *BaseAddress = W32S_WINE2APP(result, W32S_OFFSET);
1207 EAX_reg(context) = STATUS_SUCCESS;
1209 else
1210 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1212 break;
1215 case 0x0012: /* NtUnmapViewOfSection */
1217 * Input: EDX: Flat address of arguments on stack
1219 * DWORD ProcessHandle [in] Process (defining address space)
1220 * LPBYTE BaseAddress [in] Base address of view to be unmapped
1222 * Output: EAX: NtStatus
1225 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1226 DWORD ProcessHandle = stack[0]; /* ignored */
1227 LPBYTE BaseAddress = (LPBYTE)W32S_APP2WINE(stack[1], W32S_OFFSET);
1229 TRACE(vxd, "NtUnmapViewOfSection(%lx, %lx)\n",
1230 ProcessHandle, (DWORD)BaseAddress);
1232 UnmapViewOfFile(BaseAddress);
1234 EAX_reg(context) = STATUS_SUCCESS;
1236 break;
1239 case 0x0013: /* NtFlushVirtualMemory */
1241 * Input: EDX: Flat address of arguments on stack
1243 * DWORD ProcessHandle [in] Process (defining address space)
1244 * LPBYTE *BaseAddress [in?] Base address of range to be flushed
1245 * DWORD *ViewSize [in?] Number of bytes to be flushed
1246 * DWORD *unknown [???] (?? unknown ??)
1248 * Output: EAX: NtStatus
1251 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1252 DWORD ProcessHandle = stack[0]; /* ignored */
1253 DWORD *BaseAddress = (DWORD *)W32S_APP2WINE(stack[1], W32S_OFFSET);
1254 DWORD *ViewSize = (DWORD *)W32S_APP2WINE(stack[2], W32S_OFFSET);
1255 DWORD *unknown = (DWORD *)W32S_APP2WINE(stack[3], W32S_OFFSET);
1257 LPBYTE address = (LPBYTE)(BaseAddress? W32S_APP2WINE(*BaseAddress, W32S_OFFSET) : 0);
1258 DWORD size = ViewSize? *ViewSize : 0;
1260 TRACE(vxd, "NtFlushVirtualMemory(%lx, %lx, %lx, %lx)\n",
1261 ProcessHandle, (DWORD)BaseAddress, (DWORD)ViewSize,
1262 (DWORD)unknown);
1263 TRACE(vxd, "NtFlushVirtualMemory: base=%lx, size=%lx\n",
1264 (DWORD)address, size);
1266 FlushViewOfFile(address, size);
1268 EAX_reg(context) = STATUS_SUCCESS;
1270 break;
1273 case 0x0014: /* Get/Set Debug Registers */
1275 * Input: ECX: 0 if Get, 1 if Set
1277 * EDX: Get: Flat address of buffer to receive values of
1278 * debug registers DR0 .. DR7
1279 * Set: Flat address of buffer containing values of
1280 * debug registers DR0 .. DR7 to be set
1281 * Output: None
1284 FIXME(vxd, "[0014] ECX=%lx EDX=%lx\n",
1285 ECX_reg(context), EDX_reg(context));
1287 /* FIXME */
1288 break;
1291 case 0x0015: /* Set Coprocessor Emulation Flag */
1293 * Input: EDX: 0 to deactivate, 1 to activate coprocessor emulation
1295 * Output: None
1298 TRACE(vxd, "[0015] EDX=%lx\n", EDX_reg(context));
1300 /* We don't care, as we always have a coprocessor anyway */
1301 break;
1304 case 0x0016: /* Init Win32S VxD PSP */
1306 * If called to query required PSP size:
1308 * Input: EBX: 0
1309 * Output: EDX: Required size of Win32s VxD PSP
1311 * If called to initialize allocated PSP:
1313 * Input: EBX: LoWord: Selector of Win32s VxD PSP
1314 * HiWord: Paragraph of Win32s VxD PSP (DOSMEM)
1315 * Output: None
1318 if (EBX_reg(context) == 0)
1319 EDX_reg(context) = 0x80;
1320 else
1322 PDB16 *psp = PTR_SEG_OFF_TO_LIN(BX_reg(context), 0);
1323 psp->nbFiles = 32;
1324 psp->fileHandlesPtr = MAKELONG(HIWORD(EBX_reg(context)), 0x5c);
1325 memset((LPBYTE)psp + 0x5c, '\xFF', 32);
1327 break;
1330 case 0x0017: /* Set Break Point */
1332 * Input: EBX: Offset of Break Point
1333 * CX: Selector of Break Point
1335 * Output: None
1338 FIXME(vxd, "[0017] EBX=%lx CX=%x\n",
1339 EBX_reg(context), CX_reg(context));
1341 /* FIXME */
1342 break;
1345 case 0x0018: /* VirtualLock */
1347 * Input: ECX: Current Process
1349 * EDX: Flat address of arguments on stack
1351 * DWORD *retv [out] TRUE if success, FALSE if failure
1352 * LPVOID base [in] Flat address of range to lock
1353 * DWORD size [in] Size of range
1355 * Output: EAX: NtStatus
1358 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1359 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1360 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
1361 DWORD size = stack[2];
1362 DWORD result;
1364 TRACE(vxd, "VirtualLock(%lx, %lx, %lx)\n",
1365 (DWORD)retv, (DWORD)base, size);
1367 result = VirtualLock(base, size);
1369 if (result)
1370 *retv = TRUE,
1371 EAX_reg(context) = STATUS_SUCCESS;
1372 else
1373 *retv = FALSE,
1374 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1376 break;
1379 case 0x0019: /* VirtualUnlock */
1381 * Input: ECX: Current Process
1383 * EDX: Flat address of arguments on stack
1385 * DWORD *retv [out] TRUE if success, FALSE if failure
1386 * LPVOID base [in] Flat address of range to unlock
1387 * DWORD size [in] Size of range
1389 * Output: EAX: NtStatus
1392 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1393 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1394 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
1395 DWORD size = stack[2];
1396 DWORD result;
1398 TRACE(vxd, "VirtualUnlock(%lx, %lx, %lx)\n",
1399 (DWORD)retv, (DWORD)base, size);
1401 result = VirtualUnlock(base, size);
1403 if (result)
1404 *retv = TRUE,
1405 EAX_reg(context) = STATUS_SUCCESS;
1406 else
1407 *retv = FALSE,
1408 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1410 break;
1413 case 0x001A: /* KGetSystemInfo */
1415 * Input: None
1417 * Output: ECX: Start of sparse memory arena
1418 * EDX: End of sparse memory arena
1421 TRACE(vxd, "KGetSystemInfo()\n");
1424 * Note: Win32s reserves 0GB - 2GB for Win 3.1 and uses 2GB - 4GB as
1425 * sparse memory arena. We do it the other way around, since
1426 * we have to reserve 3GB - 4GB for Linux, and thus use
1427 * 0GB - 3GB as sparse memory arena.
1429 * FIXME: What about other OSes ?
1432 ECX_reg(context) = W32S_WINE2APP(0x00000000, W32S_OFFSET);
1433 EDX_reg(context) = W32S_WINE2APP(0xbfffffff, W32S_OFFSET);
1434 break;
1437 case 0x001B: /* KGlobalMemStat */
1439 * Input: ESI: Flat address of buffer to receive memory info
1441 * Output: None
1444 struct Win32sMemoryInfo
1446 DWORD DIPhys_Count; /* Total physical pages */
1447 DWORD DIFree_Count; /* Free physical pages */
1448 DWORD DILin_Total_Count; /* Total virtual pages (private arena) */
1449 DWORD DILin_Total_Free; /* Free virtual pages (private arena) */
1451 DWORD SparseTotal; /* Total size of sparse arena (bytes ?) */
1452 DWORD SparseFree; /* Free size of sparse arena (bytes ?) */
1455 struct Win32sMemoryInfo *info =
1456 (struct Win32sMemoryInfo *)W32S_APP2WINE(ESI_reg(context), W32S_OFFSET);
1458 FIXME(vxd, "KGlobalMemStat(%lx)\n", (DWORD)info);
1460 /* FIXME */
1462 break;
1465 case 0x001C: /* Enable/Disable Exceptions */
1467 * Input: ECX: 0 to disable, 1 to enable exception handling
1469 * Output: None
1472 TRACE(vxd, "[001c] ECX=%lx\n", ECX_reg(context));
1474 /* FIXME */
1475 break;
1478 case 0x001D: /* VirtualAlloc called from 16-bit code */
1480 * Input: EDX: Segmented address of arguments on stack
1482 * LPVOID base [in] Flat address of region to reserve/commit
1483 * DWORD size [in] Size of region
1484 * DWORD type [in] Type of allocation
1485 * DWORD prot [in] Type of access protection
1487 * Output: EAX: NtStatus
1488 * EDX: Flat base address of allocated region
1491 DWORD *stack = PTR_SEG_OFF_TO_LIN(LOWORD(EDX_reg(context)),
1492 HIWORD(EDX_reg(context)));
1493 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0], W32S_OFFSET);
1494 DWORD size = stack[1];
1495 DWORD type = stack[2];
1496 DWORD prot = stack[3];
1497 DWORD result;
1499 TRACE(vxd, "VirtualAlloc16(%lx, %lx, %lx, %lx)\n",
1500 (DWORD)base, size, type, prot);
1502 if (type & 0x80000000)
1504 WARN(vxd, "VirtualAlloc16: strange type %lx\n", type);
1505 type &= 0x7fffffff;
1508 result = (DWORD)VirtualAlloc(base, size, type, prot);
1510 if (W32S_WINE2APP(result, W32S_OFFSET))
1511 EDX_reg(context) = W32S_WINE2APP(result, W32S_OFFSET),
1512 EAX_reg(context) = STATUS_SUCCESS;
1513 else
1514 EDX_reg(context) = 0,
1515 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1516 TRACE(vxd, "VirtualAlloc16: returning base %lx\n", EDX_reg(context));
1518 break;
1521 case 0x001E: /* VirtualFree called from 16-bit code */
1523 * Input: EDX: Segmented address of arguments on stack
1525 * LPVOID base [in] Flat address of region
1526 * DWORD size [in] Size of region
1527 * DWORD type [in] Type of operation
1529 * Output: EAX: NtStatus
1530 * EDX: TRUE if success, FALSE if failure
1533 DWORD *stack = PTR_SEG_OFF_TO_LIN(LOWORD(EDX_reg(context)),
1534 HIWORD(EDX_reg(context)));
1535 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0], W32S_OFFSET);
1536 DWORD size = stack[1];
1537 DWORD type = stack[2];
1538 DWORD result;
1540 TRACE(vxd, "VirtualFree16(%lx, %lx, %lx)\n",
1541 (DWORD)base, size, type);
1543 result = VirtualFree(base, size, type);
1545 if (result)
1546 EDX_reg(context) = TRUE,
1547 EAX_reg(context) = STATUS_SUCCESS;
1548 else
1549 EDX_reg(context) = FALSE,
1550 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1552 break;
1555 case 0x001F: /* FWorkingSetSize */
1557 * Input: EDX: 0 if Get, 1 if Set
1559 * ECX: Get: Buffer to receive Working Set Size
1560 * Set: Buffer containing Working Set Size
1562 * Output: NtStatus
1565 DWORD *ptr = (DWORD *)W32S_APP2WINE(ECX_reg(context), W32S_OFFSET);
1566 BOOL set = EDX_reg(context);
1568 TRACE(vxd, "FWorkingSetSize(%lx, %lx)\n", (DWORD)ptr, (DWORD)set);
1570 if (set)
1571 /* We do it differently ... */;
1572 else
1573 *ptr = 0x100;
1575 EAX_reg(context) = STATUS_SUCCESS;
1577 break;
1580 default:
1581 VXD_BARF( context, "W32S" );