Removed use of per-thread wait_struct, cleaned up a bit.
[wine.git] / msdos / vxd.c
blob10c569b0694841a15173288aa2e13227252e7abe
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 "neexe.h"
16 #include "task.h"
17 #include "process.h"
18 #include "file.h"
19 #include "debug.h"
22 #define VXD_BARF(context,name) \
23 DUMP( "vxd %s: unknown/not implemented parameters:\n" \
24 "vxd %s: AX %04x, BX %04x, CX %04x, DX %04x, " \
25 "SI %04x, DI %04x, DS %04x, ES %04x\n", \
26 (name), (name), AX_reg(context), BX_reg(context), \
27 CX_reg(context), DX_reg(context), SI_reg(context), \
28 DI_reg(context), (WORD)DS_reg(context), (WORD)ES_reg(context) )
31 static WORD VXD_WinVersion(void)
33 WORD version = LOWORD(GetVersion16());
34 return (version >> 8) | (version << 8);
37 /***********************************************************************
38 * VXD_VMM
40 void VXD_VMM ( CONTEXT *context )
42 unsigned service = AX_reg(context);
44 TRACE(vxd,"[%04x] VMM \n", (UINT16)service);
46 switch(service)
48 case 0x0000: /* version */
49 AX_reg(context) = VXD_WinVersion();
50 RESET_CFLAG(context);
51 break;
53 case 0x026d: /* Get_Debug_Flag '/m' */
54 case 0x026e: /* Get_Debug_Flag '/n' */
55 AL_reg(context) = 0;
56 RESET_CFLAG(context);
57 break;
59 default:
60 VXD_BARF( context, "VMM" );
64 /***********************************************************************
65 * VXD_PageFile
67 void WINAPI VXD_PageFile( CONTEXT *context )
69 unsigned service = AX_reg(context);
71 /* taken from Ralf Brown's Interrupt List */
73 TRACE(vxd,"[%04x] PageFile\n", (UINT16)service );
75 switch(service)
77 case 0x00: /* get version, is this windows version? */
78 TRACE(vxd,"returning version\n");
79 AX_reg(context) = VXD_WinVersion();
80 RESET_CFLAG(context);
81 break;
83 case 0x01: /* get swap file info */
84 TRACE(vxd,"VxD PageFile: returning swap file info\n");
85 AX_reg(context) = 0x00; /* paging disabled */
86 ECX_reg(context) = 0; /* maximum size of paging file */
87 /* FIXME: do I touch DS:SI or DS:DI? */
88 RESET_CFLAG(context);
89 break;
91 case 0x02: /* delete permanent swap on exit */
92 TRACE(vxd,"VxD PageFile: supposed to delete swap\n");
93 RESET_CFLAG(context);
94 break;
96 case 0x03: /* current temporary swap file size */
97 TRACE(vxd,"VxD PageFile: what is current temp. swap size\n");
98 RESET_CFLAG(context);
99 break;
101 case 0x04: /* read or write?? INTERRUP.D */
102 case 0x05: /* cancel?? INTERRUP.D */
103 case 0x06: /* test I/O valid INTERRUP.D */
104 default:
105 VXD_BARF( context, "pagefile" );
106 break;
110 /***********************************************************************
111 * VXD_Reboot
113 void VXD_Reboot ( CONTEXT *context )
115 unsigned service = AX_reg(context);
117 TRACE(vxd,"[%04x] VMM \n", (UINT16)service);
119 switch(service)
121 case 0x0000: /* version */
122 AX_reg(context) = VXD_WinVersion();
123 RESET_CFLAG(context);
124 break;
126 default:
127 VXD_BARF( context, "REBOOT" );
131 /***********************************************************************
132 * VXD_VDD
134 void VXD_VDD ( CONTEXT *context )
136 unsigned service = AX_reg(context);
138 TRACE(vxd,"[%04x] VDD \n", (UINT16)service);
140 switch(service)
142 case 0x0000: /* version */
143 AX_reg(context) = VXD_WinVersion();
144 RESET_CFLAG(context);
145 break;
147 default:
148 VXD_BARF( context, "VDD" );
152 /***********************************************************************
153 * VXD_VMD
155 void VXD_VMD ( CONTEXT *context )
157 unsigned service = AX_reg(context);
159 TRACE(vxd,"[%04x] VMD \n", (UINT16)service);
161 switch(service)
163 case 0x0000: /* version */
164 AX_reg(context) = VXD_WinVersion();
165 RESET_CFLAG(context);
166 break;
168 default:
169 VXD_BARF( context, "VMD" );
173 /***********************************************************************
174 * VXD_Shell
176 void WINAPI VXD_Shell( CONTEXT *context )
178 unsigned service = DX_reg(context);
180 TRACE(vxd,"[%04x] Shell\n", (UINT16)service);
182 switch (service) /* Ralf Brown says EDX, but I use DX instead */
184 case 0x0000:
185 TRACE(vxd,"returning version\n");
186 AX_reg(context) = VXD_WinVersion();
187 EBX_reg(context) = 1; /* system VM Handle */
188 break;
190 case 0x0001:
191 case 0x0002:
192 case 0x0003:
193 case 0x0004:
194 case 0x0005:
195 VXD_BARF( context, "shell" );
196 break;
198 case 0x0006: /* SHELL_Get_VM_State */
199 TRACE(vxd,"VxD Shell: returning VM state\n");
200 /* Actually we don't, not yet. We have to return a structure
201 * and I am not to sure how to set it up and return it yet,
202 * so for now let's do nothing. I can (hopefully) get this
203 * by the next release
205 /* RESET_CFLAG(context); */
206 break;
208 case 0x0007:
209 case 0x0008:
210 case 0x0009:
211 case 0x000A:
212 case 0x000B:
213 case 0x000C:
214 case 0x000D:
215 case 0x000E:
216 case 0x000F:
217 case 0x0010:
218 case 0x0011:
219 case 0x0012:
220 case 0x0013:
221 case 0x0014:
222 case 0x0015:
223 case 0x0016:
224 VXD_BARF( context, "SHELL" );
225 break;
227 /* the new Win95 shell API */
228 case 0x0100: /* get version */
229 AX_reg(context) = VXD_WinVersion();
230 break;
232 case 0x0104: /* retrieve Hook_Properties list */
233 case 0x0105: /* call Hook_Properties callbacks */
234 VXD_BARF( context, "SHELL" );
235 break;
237 case 0x0106: /* install timeout callback */
238 TRACE( vxd, "VxD Shell: ignoring shell callback (%ld sec.)\n",
239 EBX_reg( context ) );
240 SET_CFLAG(context);
241 break;
243 case 0x0107: /* get version of any VxD */
244 default:
245 VXD_BARF( context, "SHELL" );
246 break;
251 /***********************************************************************
252 * VXD_Comm
254 void WINAPI VXD_Comm( CONTEXT *context )
256 unsigned service = AX_reg(context);
258 TRACE(vxd,"[%04x] Comm\n", (UINT16)service);
260 switch (service)
262 case 0x0000: /* get version */
263 TRACE(vxd,"returning version\n");
264 AX_reg(context) = VXD_WinVersion();
265 RESET_CFLAG(context);
266 break;
268 case 0x0001: /* set port global */
269 case 0x0002: /* get focus */
270 case 0x0003: /* virtualise port */
271 default:
272 VXD_BARF( context, "comm" );
276 /***********************************************************************
277 * VXD_Timer
279 void VXD_Timer( CONTEXT *context )
281 unsigned service = AX_reg(context);
283 TRACE(vxd,"[%04x] Virtual Timer\n", (UINT16)service);
285 switch(service)
287 case 0x0000: /* version */
288 AX_reg(context) = VXD_WinVersion();
289 RESET_CFLAG(context);
290 break;
292 case 0x0100: /* clock tick time, in 840nsecs */
293 EAX_reg(context) = GetTickCount();
295 EDX_reg(context) = EAX_reg(context) >> 22;
296 EAX_reg(context) <<= 10; /* not very precise */
297 break;
299 case 0x0101: /* current Windows time, msecs */
300 case 0x0102: /* current VM time, msecs */
301 EAX_reg(context) = GetTickCount();
302 break;
304 default:
305 VXD_BARF( context, "VTD" );
309 /***********************************************************************
310 * VXD_TimerAPI
312 static DWORD System_Time = 0;
313 static WORD System_Time_Selector = 0;
314 static void System_Time_Tick( WORD timer ) { System_Time += 55; }
315 void VXD_TimerAPI ( CONTEXT *context )
317 unsigned service = AX_reg(context);
319 TRACE(vxd,"[%04x] TimerAPI \n", (UINT16)service);
321 switch(service)
323 case 0x0000: /* version */
324 AX_reg(context) = VXD_WinVersion();
325 RESET_CFLAG(context);
326 break;
328 case 0x0009: /* get system time selector */
329 if ( !System_Time_Selector )
331 System_Time_Selector = SELECTOR_AllocBlock( &System_Time, sizeof(DWORD),
332 SEGMENT_DATA, FALSE, TRUE );
333 CreateSystemTimer( 55, System_Time_Tick );
336 AX_reg(context) = System_Time_Selector;
337 RESET_CFLAG(context);
338 break;
340 default:
341 VXD_BARF( context, "VTDAPI" );
345 /***********************************************************************
346 * VXD_ConfigMG
348 void VXD_ConfigMG ( CONTEXT *context )
350 unsigned service = AX_reg(context);
352 TRACE(vxd,"[%04x] ConfigMG \n", (UINT16)service);
354 switch(service)
356 case 0x0000: /* version */
357 AX_reg(context) = VXD_WinVersion();
358 RESET_CFLAG(context);
359 break;
361 default:
362 VXD_BARF( context, "CONFIGMG" );
366 /***********************************************************************
367 * VXD_Enable
369 void VXD_Enable ( CONTEXT *context )
371 unsigned service = AX_reg(context);
373 TRACE(vxd,"[%04x] Enable \n", (UINT16)service);
375 switch(service)
377 case 0x0000: /* version */
378 AX_reg(context) = VXD_WinVersion();
379 RESET_CFLAG(context);
380 break;
382 default:
383 VXD_BARF( context, "ENABLE" );
387 /***********************************************************************
388 * VXD_APM
390 void VXD_APM ( CONTEXT *context )
392 unsigned service = AX_reg(context);
394 TRACE(vxd,"[%04x] APM \n", (UINT16)service);
396 switch(service)
398 case 0x0000: /* version */
399 AX_reg(context) = VXD_WinVersion();
400 RESET_CFLAG(context);
401 break;
403 default:
404 VXD_BARF( context, "APM" );
408 /***********************************************************************
409 * VXD_Win32s
411 * This is an implementation of the services of the Win32s VxD.
412 * Since official documentation of these does not seem to be available,
413 * certain arguments of some of the services remain unclear.
415 * FIXME: The following services are currently unimplemented:
416 * Exception handling (0x01, 0x1C)
417 * Debugger support (0x0C, 0x14, 0x17)
418 * Low-level memory access (0x02, 0x03, 0x0A, 0x0B)
419 * Memory Statistics (0x1B)
422 * We have a specific problem running Win32s on Linux (and probably also
423 * the other x86 unixes), since Win32s tries to allocate its main 'flat
424 * code/data segment' selectors with a base of 0xffff0000 (and limit 4GB).
425 * The rationale for this seems to be that they want one the one hand to
426 * be able to leave the Win 3.1 memory (starting with the main DOS memory)
427 * at linear address 0, but want at other hand to have offset 0 of the
428 * flat data/code segment point to an unmapped page (to catch NULL pointer
429 * accesses). Hence they allocate the flat segments with a base of 0xffff0000
430 * so that the Win 3.1 memory area at linear address zero shows up in the
431 * flat segments at offset 0x10000 (since linear addresses wrap around at
432 * 4GB). To compensate for that discrepancy between flat segment offsets
433 * and plain linear addresses, all flat pointers passed between the 32-bit
434 * and the 16-bit parts of Win32s are shifted by 0x10000 in the appropriate
435 * direction by the glue code (mainly) in W32SKRNL and WIN32S16.
437 * The problem for us is now that Linux does not allow a LDT selector with
438 * base 0xffff0000 to be created, since it would 'see' a part of the kernel
439 * address space. To address this problem we introduce *another* offset:
440 * We add 0x10000 to every linear address we get as an argument from Win32s.
441 * This means especially that the flat code/data selectors get actually
442 * allocated with base 0x0, so that flat offsets and (real) linear addresses
443 * do again agree! In fact, every call e.g. of a Win32s VxD service now
444 * has all pointer arguments (which are offsets in the flat data segement)
445 * first reduced by 0x10000 by the W32SKRNL glue code, and then again
446 * increased by 0x10000 by *our* code.
448 * Note that to keep everything consistent, this offset has to be applied by
449 * every Wine function that operates on 'linear addresses' passed to it by
450 * Win32s. Fortunately, since Win32s does not directly call any Wine 32-bit
451 * API routines, this affects only two locations: this VxD and the DPMI
452 * handler. (NOTE: Should any Win32s application pass a linear address to
453 * any routine apart from those, e.g. some other VxD handler, that code
454 * would have to take the offset into account as well!)
456 * The application of the offset is triggered by marking the current process
457 * as a Win32s process by setting the PDB32_WIN32S_PROC flag in the process
458 * database. This is done the first time any application calls the GetVersion()
459 * service of the Win32s VxD. (Note that the flag is never removed.)
463 void VXD_Win32s( CONTEXT *context )
465 switch (AX_reg(context))
467 case 0x0000: /* Get Version */
469 * Input: None
471 * Output: EAX: LoWord: Win32s Version (1.30)
472 * HiWord: VxD Version (200)
474 * EBX: Build (172)
476 * ECX: ??? (1)
478 * EDX: Debugging Flags
480 * EDI: Error Flag
481 * 0 if OK,
482 * 1 if VMCPD VxD not found
485 TRACE(vxd, "GetVersion()\n");
487 EAX_reg(context) = VXD_WinVersion() | (200 << 16);
488 EBX_reg(context) = 0;
489 ECX_reg(context) = 0;
490 EDX_reg(context) = 0;
491 EDI_reg(context) = 0;
494 * If this is the first time we are called for this process,
495 * hack the memory image of WIN32S16 so that it doesn't try
496 * to access the GDT directly ...
498 * The first code segment of WIN32S16 (version 1.30) contains
499 * an unexported function somewhere between the exported functions
500 * SetFS and StackLinearToSegmented that tries to find a selector
501 * in the LDT that maps to the memory image of the LDT itself.
502 * If it succeeds, it stores this selector into a global variable
503 * which will be used to speed up execution by using this selector
504 * to modify the LDT directly instead of using the DPMI calls.
506 * To perform this search of the LDT, this function uses the
507 * sgdt and sldt instructions to find the linear address of
508 * the (GDT and then) LDT. While those instructions themselves
509 * execute without problem, the linear address that sgdt returns
510 * points (at least under Linux) to the kernel address space, so
511 * that any subsequent access leads to a segfault.
513 * Fortunately, WIN32S16 still contains as a fallback option the
514 * mechanism of using DPMI calls to modify LDT selectors instead
515 * of direct writes to the LDT. Thus we can circumvent the problem
516 * by simply replacing the first byte of the offending function
517 * with an 'retf' instruction. This means that the global variable
518 * supposed to contain the LDT alias selector will remain zero,
519 * and hence WIN32S16 will fall back to using DPMI calls.
521 * The heuristic we employ to _find_ that function is as follows:
522 * We search between the addresses of the exported symbols SetFS
523 * and StackLinearToSegmented for the byte sequence '0F 01 04'
524 * (this is the opcode of 'sgdt [si]'). We then search backwards
525 * from this address for the last occurrance of 'CB' (retf) that marks
526 * the end of the preceeding function. The following byte (which
527 * should now be the first byte of the function we are looking for)
528 * will be replaced by 'CB' (retf).
530 * This heuristic works for the retail as well as the debug version
531 * of Win32s version 1.30. For versions earlier than that this
532 * hack should not be necessary at all, since the whole mechanism
533 * ('PERF130') was introduced only in 1.30 to improve the overall
534 * performance of Win32s.
537 if (!(PROCESS_Current()->flags & PDB32_WIN32S_PROC))
539 HMODULE16 hModule = GetModuleHandle16("win32s16");
540 SEGPTR func1 = (SEGPTR)WIN32_GetProcAddress16(hModule, "SetFS");
541 SEGPTR func2 = (SEGPTR)WIN32_GetProcAddress16(hModule,
542 "StackLinearToSegmented");
544 if ( hModule && func1 && func2
545 && SELECTOROF(func1) == SELECTOROF(func2))
547 BYTE *start = PTR_SEG_TO_LIN(func1);
548 BYTE *end = PTR_SEG_TO_LIN(func2);
549 BYTE *p, *retv = NULL;
550 int found = 0;
552 for (p = start; p < end; p++)
553 if (*p == 0xCB) found = 0, retv = p;
554 else if (*p == 0x0F) found = 1;
555 else if (*p == 0x01 && found == 1) found = 2;
556 else if (*p == 0x04 && found == 2) { found = 3; break; }
557 else found = 0;
559 if (found == 3 && retv)
561 TRACE(vxd, "PERF130 hack: "
562 "Replacing byte %02X at offset %04X:%04X\n",
563 *(retv+1), SELECTOROF(func1),
564 OFFSETOF(func1) + retv+1-start);
566 *(retv+1) = (BYTE)0xCB;
572 * Mark process as Win32s, so that subsequent DPMI calls
573 * will perform the W32S_APP2WINE/W32S_WINE2APP address shift.
576 PROCESS_Current()->flags |= PDB32_WIN32S_PROC;
577 break;
580 case 0x0001: /* Install Exception Handling */
582 * Input: EBX: Flat address of W32SKRNL Exception Data
584 * ECX: LoWord: Flat Code Selector
585 * HiWord: Flat Data Selector
587 * EDX: Flat address of W32SKRNL Exception Handler
588 * (this is equal to W32S_BackTo32 + 0x40)
590 * ESI: SEGPTR KERNEL.HASGPHANDLER
592 * EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10)
594 * Output: EAX: 0 if OK
597 TRACE(vxd, "[0001] EBX=%lx ECX=%lx EDX=%lx ESI=%lx EDI=%lx\n",
598 EBX_reg(context), ECX_reg(context), EDX_reg(context),
599 ESI_reg(context), EDI_reg(context));
601 /* FIXME */
603 EAX_reg(context) = 0;
604 break;
607 case 0x0002: /* Set Page Access Flags */
609 * Input: EBX: New access flags
610 * Bit 2: User Page if set, Supervisor Page if clear
611 * Bit 1: Read-Write if set, Read-Only if clear
613 * ECX: Size of memory area to change
615 * EDX: Flat start address of memory area
617 * Output: EAX: Size of area changed
620 TRACE(vxd, "[0002] EBX=%lx ECX=%lx EDX=%lx\n",
621 EBX_reg(context), ECX_reg(context), EDX_reg(context));
623 /* FIXME */
625 EAX_reg(context) = ECX_reg(context);
626 break;
629 case 0x0003: /* Get Page Access Flags */
631 * Input: EDX: Flat address of page to query
633 * Output: EAX: Page access flags
634 * Bit 2: User Page if set, Supervisor Page if clear
635 * Bit 1: Read-Write if set, Read-Only if clear
638 TRACE(vxd, "[0003] EDX=%lx\n", EDX_reg(context));
640 /* FIXME */
642 EAX_reg(context) = 6;
643 break;
646 case 0x0004: /* Map Module */
648 * Input: ECX: IMTE (offset in Module Table) of new module
650 * EDX: Flat address of Win32s Module Table
652 * Output: EAX: 0 if OK
655 if (!EDX_reg(context) || CX_reg(context) == 0xFFFF)
657 TRACE(vxd, "MapModule: Initialization call\n");
658 EAX_reg(context) = 0;
660 else
663 * Structure of a Win32s Module Table Entry:
665 struct Win32sModule
667 DWORD flags;
668 DWORD flatBaseAddr;
669 LPCSTR moduleName;
670 LPCSTR pathName;
671 LPCSTR unknown;
672 LPBYTE baseAddr;
673 DWORD hModule;
674 DWORD relocDelta;
678 * Note: This function should set up a demand-paged memory image
679 * of the given module. Since mmap does not allow file offsets
680 * not aligned at 1024 bytes, we simply load the image fully
681 * into memory.
684 struct Win32sModule *moduleTable =
685 (struct Win32sModule *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
686 struct Win32sModule *module = moduleTable + ECX_reg(context);
688 IMAGE_NT_HEADERS *nt_header = PE_HEADER(module->baseAddr);
689 IMAGE_SECTION_HEADER *pe_seg = PE_SECTIONS(module->baseAddr);
691 HFILE32 image = _lopen32(module->pathName, OF_READ);
692 BOOL32 error = (image == INVALID_HANDLE_VALUE32);
693 UINT32 i;
695 TRACE(vxd, "MapModule: Loading %s\n", module->pathName);
697 for (i = 0;
698 !error && i < nt_header->FileHeader.NumberOfSections;
699 i++, pe_seg++)
700 if(!(pe_seg->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA))
702 DWORD off = pe_seg->PointerToRawData;
703 DWORD len = pe_seg->SizeOfRawData;
704 LPBYTE addr = module->baseAddr + pe_seg->VirtualAddress;
706 TRACE(vxd, "MapModule: "
707 "Section %d at %08lx from %08lx len %08lx\n",
708 i, (DWORD)addr, off, len);
710 if ( _llseek32(image, off, SEEK_SET) != off
711 || _lread32(image, addr, len) != len)
712 error = TRUE;
715 _lclose32(image);
717 if (error)
718 ERR(vxd, "MapModule: Unable to load %s\n", module->pathName);
720 else if (module->relocDelta != 0)
722 IMAGE_DATA_DIRECTORY *dir = nt_header->OptionalHeader.DataDirectory
723 + IMAGE_DIRECTORY_ENTRY_BASERELOC;
724 IMAGE_BASE_RELOCATION *r = (IMAGE_BASE_RELOCATION *)
725 (dir->Size? module->baseAddr + dir->VirtualAddress : 0);
727 TRACE(vxd, "MapModule: Reloc delta %08lx\n", module->relocDelta);
729 while (r && r->VirtualAddress)
731 LPBYTE page = module->baseAddr + r->VirtualAddress;
732 int count = (r->SizeOfBlock - 8) / 2;
734 TRACE(vxd, "MapModule: %d relocations for page %08lx\n",
735 count, (DWORD)page);
737 for(i = 0; i < count; i++)
739 int offset = r->TypeOffset[i] & 0xFFF;
740 int type = r->TypeOffset[i] >> 12;
741 switch(type)
743 case IMAGE_REL_BASED_ABSOLUTE:
744 break;
745 case IMAGE_REL_BASED_HIGH:
746 *(WORD *)(page+offset) += HIWORD(module->relocDelta);
747 break;
748 case IMAGE_REL_BASED_LOW:
749 *(WORD *)(page+offset) += LOWORD(module->relocDelta);
750 break;
751 case IMAGE_REL_BASED_HIGHLOW:
752 *(DWORD*)(page+offset) += module->relocDelta;
753 break;
754 default:
755 WARN(vxd, "MapModule: Unsupported fixup type\n");
756 break;
760 r = (IMAGE_BASE_RELOCATION *)((LPBYTE)r + r->SizeOfBlock);
764 EAX_reg(context) = 0;
765 RESET_CFLAG(context);
767 break;
770 case 0x0005: /* UnMap Module */
772 * Input: EDX: Flat address of module image
774 * Output: EAX: 1 if OK
777 TRACE(vxd, "UnMapModule: %lx\n", (DWORD)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET));
779 /* As we didn't map anything, there's nothing to unmap ... */
781 EAX_reg(context) = 1;
782 break;
785 case 0x0006: /* VirtualAlloc */
787 * Input: ECX: Current Process
789 * EDX: Flat address of arguments on stack
791 * DWORD *retv [out] Flat base address of allocated region
792 * LPVOID base [in] Flat address of region to reserve/commit
793 * DWORD size [in] Size of region
794 * DWORD type [in] Type of allocation
795 * DWORD prot [in] Type of access protection
797 * Output: EAX: NtStatus
800 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
801 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
802 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
803 DWORD size = stack[2];
804 DWORD type = stack[3];
805 DWORD prot = stack[4];
806 DWORD result;
808 TRACE(vxd, "VirtualAlloc(%lx, %lx, %lx, %lx, %lx)\n",
809 (DWORD)retv, (DWORD)base, size, type, prot);
811 if (type & 0x80000000)
813 WARN(vxd, "VirtualAlloc: strange type %lx\n", type);
814 type &= 0x7fffffff;
817 if (!base && (type & MEM_COMMIT) && prot == PAGE_READONLY)
819 WARN(vxd, "VirtualAlloc: NLS hack, allowing write access!\n");
820 prot = PAGE_READWRITE;
823 result = (DWORD)VirtualAlloc(base, size, type, prot);
825 if (W32S_WINE2APP(result, W32S_OFFSET))
826 *retv = W32S_WINE2APP(result, W32S_OFFSET),
827 EAX_reg(context) = STATUS_SUCCESS;
828 else
829 *retv = 0,
830 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
832 break;
835 case 0x0007: /* VirtualFree */
837 * Input: ECX: Current Process
839 * EDX: Flat address of arguments on stack
841 * DWORD *retv [out] TRUE if success, FALSE if failure
842 * LPVOID base [in] Flat address of region
843 * DWORD size [in] Size of region
844 * DWORD type [in] Type of operation
846 * Output: EAX: NtStatus
849 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
850 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
851 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
852 DWORD size = stack[2];
853 DWORD type = stack[3];
854 DWORD result;
856 TRACE(vxd, "VirtualFree(%lx, %lx, %lx, %lx)\n",
857 (DWORD)retv, (DWORD)base, size, type);
859 result = VirtualFree(base, size, type);
861 if (result)
862 *retv = TRUE,
863 EAX_reg(context) = STATUS_SUCCESS;
864 else
865 *retv = FALSE,
866 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
868 break;
871 case 0x0008: /* VirtualProtect */
873 * Input: ECX: Current Process
875 * EDX: Flat address of arguments on stack
877 * DWORD *retv [out] TRUE if success, FALSE if failure
878 * LPVOID base [in] Flat address of region
879 * DWORD size [in] Size of region
880 * DWORD new_prot [in] Desired access protection
881 * DWORD *old_prot [out] Previous access protection
883 * Output: EAX: NtStatus
886 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
887 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
888 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
889 DWORD size = stack[2];
890 DWORD new_prot = stack[3];
891 DWORD *old_prot = (DWORD *)W32S_APP2WINE(stack[4], W32S_OFFSET);
892 DWORD result;
894 TRACE(vxd, "VirtualProtect(%lx, %lx, %lx, %lx, %lx)\n",
895 (DWORD)retv, (DWORD)base, size, new_prot, (DWORD)old_prot);
897 result = VirtualProtect(base, size, new_prot, old_prot);
899 if (result)
900 *retv = TRUE,
901 EAX_reg(context) = STATUS_SUCCESS;
902 else
903 *retv = FALSE,
904 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
906 break;
909 case 0x0009: /* VirtualQuery */
911 * Input: ECX: Current Process
913 * EDX: Flat address of arguments on stack
915 * DWORD *retv [out] Nr. bytes returned
916 * LPVOID base [in] Flat address of region
917 * LPMEMORY_BASIC_INFORMATION info [out] Info buffer
918 * DWORD len [in] Size of buffer
920 * Output: EAX: NtStatus
923 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
924 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
925 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
926 LPMEMORY_BASIC_INFORMATION info =
927 (LPMEMORY_BASIC_INFORMATION)W32S_APP2WINE(stack[2], W32S_OFFSET);
928 DWORD len = stack[3];
929 DWORD result;
931 TRACE(vxd, "VirtualQuery(%lx, %lx, %lx, %lx)\n",
932 (DWORD)retv, (DWORD)base, (DWORD)info, len);
934 result = VirtualQuery(base, info, len);
936 *retv = result;
937 EAX_reg(context) = STATUS_SUCCESS;
939 break;
942 case 0x000A: /* SetVirtMemProcess */
944 * Input: ECX: Process Handle
946 * EDX: Flat address of region
948 * Output: EAX: NtStatus
951 TRACE(vxd, "[000a] ECX=%lx EDX=%lx\n",
952 ECX_reg(context), EDX_reg(context));
954 /* FIXME */
956 EAX_reg(context) = STATUS_SUCCESS;
957 break;
960 case 0x000B: /* ??? some kind of cleanup */
962 * Input: ECX: Process Handle
964 * Output: EAX: NtStatus
967 TRACE(vxd, "[000b] ECX=%lx\n", ECX_reg(context));
969 /* FIXME */
971 EAX_reg(context) = STATUS_SUCCESS;
972 break;
975 case 0x000C: /* Set Debug Flags */
977 * Input: EDX: Debug Flags
979 * Output: EDX: Previous Debug Flags
982 FIXME(vxd, "[000c] EDX=%lx\n", EDX_reg(context));
984 /* FIXME */
986 EDX_reg(context) = 0;
987 break;
990 case 0x000D: /* NtCreateSection */
992 * Input: EDX: Flat address of arguments on stack
994 * HANDLE32 *retv [out] Handle of Section created
995 * DWORD flags1 [in] (?? unknown ??)
996 * DWORD atom [in] Name of Section to create
997 * LARGE_INTEGER *size [in] Size of Section
998 * DWORD protect [in] Access protection
999 * DWORD flags2 [in] (?? unknown ??)
1000 * HFILE32 hFile [in] Handle of file to map
1001 * DWORD psp [in] (Win32s: PSP that hFile belongs to)
1003 * Output: EAX: NtStatus
1006 DWORD *stack = (DWORD *) W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1007 HANDLE32 *retv = (HANDLE32 *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1008 DWORD flags1 = stack[1];
1009 DWORD atom = stack[2];
1010 LARGE_INTEGER *size = (LARGE_INTEGER *)W32S_APP2WINE(stack[3], W32S_OFFSET);
1011 DWORD protect = stack[4];
1012 DWORD flags2 = stack[5];
1013 HFILE32 hFile = FILE_GetHandle32(stack[6]);
1014 DWORD psp = stack[7];
1016 HANDLE32 result = INVALID_HANDLE_VALUE32;
1017 char name[128];
1019 TRACE(vxd, "NtCreateSection(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1020 (DWORD)retv, flags1, atom, (DWORD)size, protect, flags2,
1021 (DWORD)hFile, psp);
1023 if (!atom || GlobalGetAtomName32A(atom, name, sizeof(name)))
1025 TRACE(vxd, "NtCreateSection: name=%s\n", atom? name : NULL);
1027 result = CreateFileMapping32A(hFile, NULL, protect,
1028 size? size->HighPart : 0,
1029 size? size->LowPart : 0,
1030 atom? name : NULL);
1033 if (result == INVALID_HANDLE_VALUE32)
1034 WARN(vxd, "NtCreateSection: failed!\n");
1035 else
1036 TRACE(vxd, "NtCreateSection: returned %lx\n", (DWORD)result);
1038 if (result != INVALID_HANDLE_VALUE32)
1039 *retv = result,
1040 EAX_reg(context) = STATUS_SUCCESS;
1041 else
1042 *retv = result,
1043 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1045 break;
1048 case 0x000E: /* NtOpenSection */
1050 * Input: EDX: Flat address of arguments on stack
1052 * HANDLE32 *retv [out] Handle of Section opened
1053 * DWORD protect [in] Access protection
1054 * DWORD atom [in] Name of Section to create
1056 * Output: EAX: NtStatus
1059 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1060 HANDLE32 *retv = (HANDLE32 *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1061 DWORD protect = stack[1];
1062 DWORD atom = stack[2];
1064 HANDLE32 result = INVALID_HANDLE_VALUE32;
1065 char name[128];
1067 TRACE(vxd, "NtOpenSection(%lx, %lx, %lx)\n",
1068 (DWORD)retv, protect, atom);
1070 if (atom && GlobalGetAtomName32A(atom, name, sizeof(name)))
1072 TRACE(vxd, "NtOpenSection: name=%s\n", name);
1074 result = OpenFileMapping32A(protect, FALSE, name);
1077 if (result == INVALID_HANDLE_VALUE32)
1078 WARN(vxd, "NtOpenSection: failed!\n");
1079 else
1080 TRACE(vxd, "NtOpenSection: returned %lx\n", (DWORD)result);
1082 if (result != INVALID_HANDLE_VALUE32)
1083 *retv = result,
1084 EAX_reg(context) = STATUS_SUCCESS;
1085 else
1086 *retv = result,
1087 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1089 break;
1092 case 0x000F: /* NtCloseSection */
1094 * Input: EDX: Flat address of arguments on stack
1096 * HANDLE32 handle [in] Handle of Section to close
1097 * DWORD *id [out] Unique ID (?? unclear ??)
1099 * Output: EAX: NtStatus
1102 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1103 HANDLE32 handle = stack[0];
1104 DWORD *id = (DWORD *)W32S_APP2WINE(stack[1], W32S_OFFSET);
1106 TRACE(vxd, "NtCloseSection(%lx, %lx)\n", (DWORD)handle, (DWORD)id);
1108 CloseHandle(handle);
1109 if (id) *id = 0; /* FIXME */
1111 EAX_reg(context) = STATUS_SUCCESS;
1113 break;
1116 case 0x0010: /* NtDupSection */
1118 * Input: EDX: Flat address of arguments on stack
1120 * HANDLE32 handle [in] Handle of Section to duplicate
1122 * Output: EAX: NtStatus
1125 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1126 HANDLE32 handle = stack[0];
1127 HANDLE32 new_handle;
1129 TRACE(vxd, "NtDupSection(%lx)\n", (DWORD)handle);
1131 DuplicateHandle( GetCurrentProcess(), handle,
1132 GetCurrentProcess(), &new_handle,
1133 0, FALSE, DUPLICATE_SAME_ACCESS );
1134 EAX_reg(context) = STATUS_SUCCESS;
1136 break;
1139 case 0x0011: /* NtMapViewOfSection */
1141 * Input: EDX: Flat address of arguments on stack
1143 * HANDLE32 SectionHandle [in] Section to be mapped
1144 * DWORD ProcessHandle [in] Process to be mapped into
1145 * DWORD * BaseAddress [in/out] Address to be mapped at
1146 * DWORD ZeroBits [in] (?? unclear ??)
1147 * DWORD CommitSize [in] (?? unclear ??)
1148 * LARGE_INTEGER *SectionOffset [in] Offset within section
1149 * DWORD * ViewSize [in] Size of view
1150 * DWORD InheritDisposition [in] (?? unclear ??)
1151 * DWORD AllocationType [in] (?? unclear ??)
1152 * DWORD Protect [in] Access protection
1154 * Output: EAX: NtStatus
1157 DWORD * stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1158 HANDLE32 SectionHandle = stack[0];
1159 DWORD ProcessHandle = stack[1]; /* ignored */
1160 DWORD * BaseAddress = (DWORD *)W32S_APP2WINE(stack[2], W32S_OFFSET);
1161 DWORD ZeroBits = stack[3];
1162 DWORD CommitSize = stack[4];
1163 LARGE_INTEGER *SectionOffset = (LARGE_INTEGER *)W32S_APP2WINE(stack[5], W32S_OFFSET);
1164 DWORD * ViewSize = (DWORD *)W32S_APP2WINE(stack[6], W32S_OFFSET);
1165 DWORD InheritDisposition = stack[7];
1166 DWORD AllocationType = stack[8];
1167 DWORD Protect = stack[9];
1169 LPBYTE address = (LPBYTE)(BaseAddress?
1170 W32S_APP2WINE(*BaseAddress, W32S_OFFSET) : 0);
1171 DWORD access = 0, result;
1173 switch (Protect & ~(PAGE_GUARD|PAGE_NOCACHE))
1175 case PAGE_READONLY: access = FILE_MAP_READ; break;
1176 case PAGE_READWRITE: access = FILE_MAP_WRITE; break;
1177 case PAGE_WRITECOPY: access = FILE_MAP_COPY; break;
1179 case PAGE_EXECUTE_READ: access = FILE_MAP_READ; break;
1180 case PAGE_EXECUTE_READWRITE: access = FILE_MAP_WRITE; break;
1181 case PAGE_EXECUTE_WRITECOPY: access = FILE_MAP_COPY; break;
1184 TRACE(vxd, "NtMapViewOfSection"
1185 "(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1186 (DWORD)SectionHandle, ProcessHandle, (DWORD)BaseAddress,
1187 ZeroBits, CommitSize, (DWORD)SectionOffset, (DWORD)ViewSize,
1188 InheritDisposition, AllocationType, Protect);
1189 TRACE(vxd, "NtMapViewOfSection: "
1190 "base=%lx, offset=%lx, size=%lx, access=%lx\n",
1191 (DWORD)address, SectionOffset? SectionOffset->LowPart : 0,
1192 ViewSize? *ViewSize : 0, access);
1194 result = (DWORD)MapViewOfFileEx(SectionHandle, access,
1195 SectionOffset? SectionOffset->HighPart : 0,
1196 SectionOffset? SectionOffset->LowPart : 0,
1197 ViewSize? *ViewSize : 0, address);
1199 TRACE(vxd, "NtMapViewOfSection: result=%lx\n", result);
1201 if (W32S_WINE2APP(result, W32S_OFFSET))
1203 if (BaseAddress) *BaseAddress = W32S_WINE2APP(result, W32S_OFFSET);
1204 EAX_reg(context) = STATUS_SUCCESS;
1206 else
1207 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1209 break;
1212 case 0x0012: /* NtUnmapViewOfSection */
1214 * Input: EDX: Flat address of arguments on stack
1216 * DWORD ProcessHandle [in] Process (defining address space)
1217 * LPBYTE BaseAddress [in] Base address of view to be unmapped
1219 * Output: EAX: NtStatus
1222 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1223 DWORD ProcessHandle = stack[0]; /* ignored */
1224 LPBYTE BaseAddress = (LPBYTE)W32S_APP2WINE(stack[1], W32S_OFFSET);
1226 TRACE(vxd, "NtUnmapViewOfSection(%lx, %lx)\n",
1227 ProcessHandle, (DWORD)BaseAddress);
1229 UnmapViewOfFile(BaseAddress);
1231 EAX_reg(context) = STATUS_SUCCESS;
1233 break;
1236 case 0x0013: /* NtFlushVirtualMemory */
1238 * Input: EDX: Flat address of arguments on stack
1240 * DWORD ProcessHandle [in] Process (defining address space)
1241 * LPBYTE *BaseAddress [in?] Base address of range to be flushed
1242 * DWORD *ViewSize [in?] Number of bytes to be flushed
1243 * DWORD *unknown [???] (?? unknown ??)
1245 * Output: EAX: NtStatus
1248 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1249 DWORD ProcessHandle = stack[0]; /* ignored */
1250 DWORD *BaseAddress = (DWORD *)W32S_APP2WINE(stack[1], W32S_OFFSET);
1251 DWORD *ViewSize = (DWORD *)W32S_APP2WINE(stack[2], W32S_OFFSET);
1252 DWORD *unknown = (DWORD *)W32S_APP2WINE(stack[3], W32S_OFFSET);
1254 LPBYTE address = (LPBYTE)(BaseAddress? W32S_APP2WINE(*BaseAddress, W32S_OFFSET) : 0);
1255 DWORD size = ViewSize? *ViewSize : 0;
1257 TRACE(vxd, "NtFlushVirtualMemory(%lx, %lx, %lx, %lx)\n",
1258 ProcessHandle, (DWORD)BaseAddress, (DWORD)ViewSize,
1259 (DWORD)unknown);
1260 TRACE(vxd, "NtFlushVirtualMemory: base=%lx, size=%lx\n",
1261 (DWORD)address, size);
1263 FlushViewOfFile(address, size);
1265 EAX_reg(context) = STATUS_SUCCESS;
1267 break;
1270 case 0x0014: /* Get/Set Debug Registers */
1272 * Input: ECX: 0 if Get, 1 if Set
1274 * EDX: Get: Flat address of buffer to receive values of
1275 * debug registers DR0 .. DR7
1276 * Set: Flat address of buffer containing values of
1277 * debug registers DR0 .. DR7 to be set
1278 * Output: None
1281 FIXME(vxd, "[0014] ECX=%lx EDX=%lx\n",
1282 ECX_reg(context), EDX_reg(context));
1284 /* FIXME */
1285 break;
1288 case 0x0015: /* Set Coprocessor Emulation Flag */
1290 * Input: EDX: 0 to deactivate, 1 to activate coprocessor emulation
1292 * Output: None
1295 TRACE(vxd, "[0015] EDX=%lx\n", EDX_reg(context));
1297 /* We don't care, as we always have a coprocessor anyway */
1298 break;
1301 case 0x0016: /* Init Win32S VxD PSP */
1303 * If called to query required PSP size:
1305 * Input: EBX: 0
1306 * Output: EDX: Required size of Win32s VxD PSP
1308 * If called to initialize allocated PSP:
1310 * Input: EBX: LoWord: Selector of Win32s VxD PSP
1311 * HiWord: Paragraph of Win32s VxD PSP (DOSMEM)
1312 * Output: None
1315 if (EBX_reg(context) == 0)
1316 EDX_reg(context) = 0x80;
1317 else
1319 PDB *psp = PTR_SEG_OFF_TO_LIN(BX_reg(context), 0);
1320 psp->nbFiles = 32;
1321 psp->fileHandlesPtr = MAKELONG(HIWORD(EBX_reg(context)), 0x5c);
1322 memset((LPBYTE)psp + 0x5c, '\xFF', 32);
1324 break;
1327 case 0x0017: /* Set Break Point */
1329 * Input: EBX: Offset of Break Point
1330 * CX: Selector of Break Point
1332 * Output: None
1335 FIXME(vxd, "[0017] EBX=%lx CX=%x\n",
1336 EBX_reg(context), CX_reg(context));
1338 /* FIXME */
1339 break;
1342 case 0x0018: /* VirtualLock */
1344 * Input: ECX: Current Process
1346 * EDX: Flat address of arguments on stack
1348 * DWORD *retv [out] TRUE if success, FALSE if failure
1349 * LPVOID base [in] Flat address of range to lock
1350 * DWORD size [in] Size of range
1352 * Output: EAX: NtStatus
1355 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1356 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1357 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
1358 DWORD size = stack[2];
1359 DWORD result;
1361 TRACE(vxd, "VirtualLock(%lx, %lx, %lx)\n",
1362 (DWORD)retv, (DWORD)base, size);
1364 result = VirtualLock(base, size);
1366 if (result)
1367 *retv = TRUE,
1368 EAX_reg(context) = STATUS_SUCCESS;
1369 else
1370 *retv = FALSE,
1371 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1373 break;
1376 case 0x0019: /* VirtualUnlock */
1378 * Input: ECX: Current Process
1380 * EDX: Flat address of arguments on stack
1382 * DWORD *retv [out] TRUE if success, FALSE if failure
1383 * LPVOID base [in] Flat address of range to unlock
1384 * DWORD size [in] Size of range
1386 * Output: EAX: NtStatus
1389 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1390 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1391 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
1392 DWORD size = stack[2];
1393 DWORD result;
1395 TRACE(vxd, "VirtualUnlock(%lx, %lx, %lx)\n",
1396 (DWORD)retv, (DWORD)base, size);
1398 result = VirtualUnlock(base, size);
1400 if (result)
1401 *retv = TRUE,
1402 EAX_reg(context) = STATUS_SUCCESS;
1403 else
1404 *retv = FALSE,
1405 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1407 break;
1410 case 0x001A: /* KGetSystemInfo */
1412 * Input: None
1414 * Output: ECX: Start of sparse memory arena
1415 * EDX: End of sparse memory arena
1418 TRACE(vxd, "KGetSystemInfo()\n");
1421 * Note: Win32s reserves 0GB - 2GB for Win 3.1 and uses 2GB - 4GB as
1422 * sparse memory arena. We do it the other way around, since
1423 * we have to reserve 3GB - 4GB for Linux, and thus use
1424 * 0GB - 3GB as sparse memory arena.
1426 * FIXME: What about other OSes ?
1429 ECX_reg(context) = W32S_WINE2APP(0x00000000, W32S_OFFSET);
1430 EDX_reg(context) = W32S_WINE2APP(0xbfffffff, W32S_OFFSET);
1431 break;
1434 case 0x001B: /* KGlobalMemStat */
1436 * Input: ESI: Flat address of buffer to receive memory info
1438 * Output: None
1441 struct Win32sMemoryInfo
1443 DWORD DIPhys_Count; /* Total physical pages */
1444 DWORD DIFree_Count; /* Free physical pages */
1445 DWORD DILin_Total_Count; /* Total virtual pages (private arena) */
1446 DWORD DILin_Total_Free; /* Free virtual pages (private arena) */
1448 DWORD SparseTotal; /* Total size of sparse arena (bytes ?) */
1449 DWORD SparseFree; /* Free size of sparse arena (bytes ?) */
1452 struct Win32sMemoryInfo *info =
1453 (struct Win32sMemoryInfo *)W32S_APP2WINE(ESI_reg(context), W32S_OFFSET);
1455 FIXME(vxd, "KGlobalMemStat(%lx)\n", (DWORD)info);
1457 /* FIXME */
1459 break;
1462 case 0x001C: /* Enable/Disable Exceptions */
1464 * Input: ECX: 0 to disable, 1 to enable exception handling
1466 * Output: None
1469 TRACE(vxd, "[001c] ECX=%lx\n", ECX_reg(context));
1471 /* FIXME */
1472 break;
1475 case 0x001D: /* VirtualAlloc called from 16-bit code */
1477 * Input: EDX: Segmented address of arguments on stack
1479 * LPVOID base [in] Flat address of region to reserve/commit
1480 * DWORD size [in] Size of region
1481 * DWORD type [in] Type of allocation
1482 * DWORD prot [in] Type of access protection
1484 * Output: EAX: NtStatus
1485 * EDX: Flat base address of allocated region
1488 DWORD *stack = PTR_SEG_OFF_TO_LIN(LOWORD(EDX_reg(context)),
1489 HIWORD(EDX_reg(context)));
1490 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0], W32S_OFFSET);
1491 DWORD size = stack[1];
1492 DWORD type = stack[2];
1493 DWORD prot = stack[3];
1494 DWORD result;
1496 TRACE(vxd, "VirtualAlloc16(%lx, %lx, %lx, %lx)\n",
1497 (DWORD)base, size, type, prot);
1499 if (type & 0x80000000)
1501 WARN(vxd, "VirtualAlloc16: strange type %lx\n", type);
1502 type &= 0x7fffffff;
1505 result = (DWORD)VirtualAlloc(base, size, type, prot);
1507 if (W32S_WINE2APP(result, W32S_OFFSET))
1508 EDX_reg(context) = W32S_WINE2APP(result, W32S_OFFSET),
1509 EAX_reg(context) = STATUS_SUCCESS;
1510 else
1511 EDX_reg(context) = 0,
1512 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1513 TRACE(vxd, "VirtualAlloc16: returning base %lx\n", EDX_reg(context));
1515 break;
1518 case 0x001E: /* VirtualFree called from 16-bit code */
1520 * Input: EDX: Segmented address of arguments on stack
1522 * LPVOID base [in] Flat address of region
1523 * DWORD size [in] Size of region
1524 * DWORD type [in] Type of operation
1526 * Output: EAX: NtStatus
1527 * EDX: TRUE if success, FALSE if failure
1530 DWORD *stack = PTR_SEG_OFF_TO_LIN(LOWORD(EDX_reg(context)),
1531 HIWORD(EDX_reg(context)));
1532 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0], W32S_OFFSET);
1533 DWORD size = stack[1];
1534 DWORD type = stack[2];
1535 DWORD result;
1537 TRACE(vxd, "VirtualFree16(%lx, %lx, %lx)\n",
1538 (DWORD)base, size, type);
1540 result = VirtualFree(base, size, type);
1542 if (result)
1543 EDX_reg(context) = TRUE,
1544 EAX_reg(context) = STATUS_SUCCESS;
1545 else
1546 EDX_reg(context) = FALSE,
1547 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1549 break;
1552 case 0x001F: /* FWorkingSetSize */
1554 * Input: EDX: 0 if Get, 1 if Set
1556 * ECX: Get: Buffer to receive Working Set Size
1557 * Set: Buffer containing Working Set Size
1559 * Output: NtStatus
1562 DWORD *ptr = (DWORD *)W32S_APP2WINE(ECX_reg(context), W32S_OFFSET);
1563 BOOL32 set = EDX_reg(context);
1565 TRACE(vxd, "FWorkingSetSize(%lx, %lx)\n", (DWORD)ptr, (DWORD)set);
1567 if (set)
1568 /* We do it differently ... */;
1569 else
1570 *ptr = 0x100;
1572 EAX_reg(context) = STATUS_SUCCESS;
1574 break;
1577 default:
1578 VXD_BARF( context, "W32S" );