Must include 'stdlib.h'.
[wine/dcerpc.git] / msdos / vxd.c
blobd5c7546431efd005d3143f49c6df57923223e70d
1 /*
2 * VxD emulation
4 * Copyright 1995 Anand Kumria
5 */
7 #include <fcntl.h>
8 #include <memory.h>
9 #include <sys/types.h>
10 #include <unistd.h>
11 #include "winbase.h"
12 #include "windef.h"
13 #include "wingdi.h"
14 #include "winuser.h"
15 #include "wine/winbase16.h"
16 #include "wine/winuser16.h"
17 #include "msdos.h"
18 #include "miscemu.h"
19 #include "selectors.h"
20 #include "neexe.h"
21 #include "task.h"
22 #include "process.h"
23 #include "file.h"
24 #include "debugtools.h"
26 DEFAULT_DEBUG_CHANNEL(vxd)
29 #define VXD_BARF(context,name) \
30 DPRINTF( "vxd %s: unknown/not implemented parameters:\n" \
31 "vxd %s: AX %04x, BX %04x, CX %04x, DX %04x, " \
32 "SI %04x, DI %04x, DS %04x, ES %04x\n", \
33 (name), (name), AX_reg(context), BX_reg(context), \
34 CX_reg(context), DX_reg(context), SI_reg(context), \
35 DI_reg(context), (WORD)DS_reg(context), (WORD)ES_reg(context) )
38 static WORD VXD_WinVersion(void)
40 WORD version = LOWORD(GetVersion16());
41 return (version >> 8) | (version << 8);
44 /***********************************************************************
45 * VXD_VMM
47 void WINAPI VXD_VMM ( CONTEXT86 *context )
49 unsigned service = AX_reg(context);
51 TRACE("[%04x] VMM \n", (UINT16)service);
53 switch(service)
55 case 0x0000: /* version */
56 AX_reg(context) = VXD_WinVersion();
57 RESET_CFLAG(context);
58 break;
60 case 0x026d: /* Get_Debug_Flag '/m' */
61 case 0x026e: /* Get_Debug_Flag '/n' */
62 AL_reg(context) = 0;
63 RESET_CFLAG(context);
64 break;
66 default:
67 VXD_BARF( context, "VMM" );
71 /***********************************************************************
72 * VXD_PageFile
74 void WINAPI VXD_PageFile( CONTEXT86 *context )
76 unsigned service = AX_reg(context);
78 /* taken from Ralf Brown's Interrupt List */
80 TRACE("[%04x] PageFile\n", (UINT16)service );
82 switch(service)
84 case 0x00: /* get version, is this windows version? */
85 TRACE("returning version\n");
86 AX_reg(context) = VXD_WinVersion();
87 RESET_CFLAG(context);
88 break;
90 case 0x01: /* get swap file info */
91 TRACE("VxD PageFile: returning swap file info\n");
92 AX_reg(context) = 0x00; /* paging disabled */
93 ECX_reg(context) = 0; /* maximum size of paging file */
94 /* FIXME: do I touch DS:SI or DS:DI? */
95 RESET_CFLAG(context);
96 break;
98 case 0x02: /* delete permanent swap on exit */
99 TRACE("VxD PageFile: supposed to delete swap\n");
100 RESET_CFLAG(context);
101 break;
103 case 0x03: /* current temporary swap file size */
104 TRACE("VxD PageFile: what is current temp. swap size\n");
105 RESET_CFLAG(context);
106 break;
108 case 0x04: /* read or write?? INTERRUP.D */
109 case 0x05: /* cancel?? INTERRUP.D */
110 case 0x06: /* test I/O valid INTERRUP.D */
111 default:
112 VXD_BARF( context, "pagefile" );
113 break;
117 /***********************************************************************
118 * VXD_Reboot
120 void WINAPI VXD_Reboot ( CONTEXT86 *context )
122 unsigned service = AX_reg(context);
124 TRACE("[%04x] VMM \n", (UINT16)service);
126 switch(service)
128 case 0x0000: /* version */
129 AX_reg(context) = VXD_WinVersion();
130 RESET_CFLAG(context);
131 break;
133 default:
134 VXD_BARF( context, "REBOOT" );
138 /***********************************************************************
139 * VXD_VDD
141 void WINAPI VXD_VDD ( CONTEXT86 *context )
143 unsigned service = AX_reg(context);
145 TRACE("[%04x] VDD \n", (UINT16)service);
147 switch(service)
149 case 0x0000: /* version */
150 AX_reg(context) = VXD_WinVersion();
151 RESET_CFLAG(context);
152 break;
154 default:
155 VXD_BARF( context, "VDD" );
159 /***********************************************************************
160 * VXD_VMD
162 void WINAPI VXD_VMD ( CONTEXT86 *context )
164 unsigned service = AX_reg(context);
166 TRACE("[%04x] VMD \n", (UINT16)service);
168 switch(service)
170 case 0x0000: /* version */
171 AX_reg(context) = VXD_WinVersion();
172 RESET_CFLAG(context);
173 break;
175 default:
176 VXD_BARF( context, "VMD" );
180 /***********************************************************************
181 * VXD_VXDLoader
183 void WINAPI VXD_VXDLoader( CONTEXT86 *context )
185 unsigned service = AX_reg(context);
187 TRACE("[%04x] VXDLoader\n", (UINT16)service);
189 switch (service)
191 case 0x0000: /* get version */
192 TRACE("returning version\n");
193 AX_reg(context) = 0x0000;
194 DX_reg(context) = VXD_WinVersion();
195 RESET_CFLAG(context);
196 break;
198 case 0x0001: /* load device */
199 FIXME("load device %04lx:%04x (%s)\n",
200 DS_reg(context), DX_reg(context),
201 debugstr_a(PTR_SEG_OFF_TO_LIN(DS_reg(context), DX_reg(context))));
202 AX_reg(context) = 0x0000;
203 ES_reg(context) = 0x0000;
204 DI_reg(context) = 0x0000;
205 RESET_CFLAG(context);
206 break;
208 case 0x0002: /* unload device */
209 FIXME("unload device (%08lx)\n", EBX_reg(context));
210 AX_reg(context) = 0x0000;
211 RESET_CFLAG(context);
212 break;
214 default:
215 VXD_BARF( context, "VXDLDR" );
216 AX_reg(context) = 0x000B; /* invalid function number */
217 SET_CFLAG(context);
218 break;
222 /***********************************************************************
223 * VXD_Shell
225 void WINAPI VXD_Shell( CONTEXT86 *context )
227 unsigned service = DX_reg(context);
229 TRACE("[%04x] Shell\n", (UINT16)service);
231 switch (service) /* Ralf Brown says EDX, but I use DX instead */
233 case 0x0000:
234 TRACE("returning version\n");
235 AX_reg(context) = VXD_WinVersion();
236 EBX_reg(context) = 1; /* system VM Handle */
237 break;
239 case 0x0001:
240 case 0x0002:
241 case 0x0003:
242 /* SHELL_SYSMODAL_Message
243 ebx virtual maschine handle
244 eax message box flags
245 ecx address of message
246 edi address of caption
247 return response in eax
249 case 0x0004:
250 /* SHELL_Message
251 ebx virtual maschine handle
252 eax message box flags
253 ecx address of message
254 edi address of caption
255 esi address callback
256 edx reference data for callback
257 return response in eax
259 case 0x0005:
260 VXD_BARF( context, "shell" );
261 break;
263 case 0x0006: /* SHELL_Get_VM_State */
264 TRACE("VxD Shell: returning VM state\n");
265 /* Actually we don't, not yet. We have to return a structure
266 * and I am not to sure how to set it up and return it yet,
267 * so for now let's do nothing. I can (hopefully) get this
268 * by the next release
270 /* RESET_CFLAG(context); */
271 break;
273 case 0x0007:
274 case 0x0008:
275 case 0x0009:
276 case 0x000A:
277 case 0x000B:
278 case 0x000C:
279 case 0x000D:
280 case 0x000E:
281 case 0x000F:
282 case 0x0010:
283 case 0x0011:
284 case 0x0012:
285 case 0x0013:
286 case 0x0014:
287 case 0x0015:
288 case 0x0016:
289 VXD_BARF( context, "SHELL" );
290 break;
292 /* the new Win95 shell API */
293 case 0x0100: /* get version */
294 AX_reg(context) = VXD_WinVersion();
295 break;
297 case 0x0104: /* retrieve Hook_Properties list */
298 case 0x0105: /* call Hook_Properties callbacks */
299 VXD_BARF( context, "SHELL" );
300 break;
302 case 0x0106: /* install timeout callback */
303 TRACE("VxD Shell: ignoring shell callback (%ld sec.)\n",
304 EBX_reg( context ) );
305 SET_CFLAG(context);
306 break;
308 case 0x0107: /* get version of any VxD */
309 default:
310 VXD_BARF( context, "SHELL" );
311 break;
316 /***********************************************************************
317 * VXD_Comm
319 void WINAPI VXD_Comm( CONTEXT86 *context )
321 unsigned service = AX_reg(context);
323 TRACE("[%04x] Comm\n", (UINT16)service);
325 switch (service)
327 case 0x0000: /* get version */
328 TRACE("returning version\n");
329 AX_reg(context) = VXD_WinVersion();
330 RESET_CFLAG(context);
331 break;
333 case 0x0001: /* set port global */
334 case 0x0002: /* get focus */
335 case 0x0003: /* virtualise port */
336 default:
337 VXD_BARF( context, "comm" );
341 /***********************************************************************
342 * VXD_Timer
344 void WINAPI VXD_Timer( CONTEXT86 *context )
346 unsigned service = AX_reg(context);
348 TRACE("[%04x] Virtual Timer\n", (UINT16)service);
350 switch(service)
352 case 0x0000: /* version */
353 AX_reg(context) = VXD_WinVersion();
354 RESET_CFLAG(context);
355 break;
357 case 0x0100: /* clock tick time, in 840nsecs */
358 EAX_reg(context) = GetTickCount();
360 EDX_reg(context) = EAX_reg(context) >> 22;
361 EAX_reg(context) <<= 10; /* not very precise */
362 break;
364 case 0x0101: /* current Windows time, msecs */
365 case 0x0102: /* current VM time, msecs */
366 EAX_reg(context) = GetTickCount();
367 break;
369 default:
370 VXD_BARF( context, "VTD" );
374 /***********************************************************************
375 * VXD_TimerAPI
377 static DWORD System_Time = 0;
378 static WORD System_Time_Selector = 0;
379 static void System_Time_Tick( WORD timer ) { System_Time += 55; }
380 void WINAPI VXD_TimerAPI ( CONTEXT86 *context )
382 unsigned service = AX_reg(context);
384 TRACE("[%04x] TimerAPI \n", (UINT16)service);
386 switch(service)
388 case 0x0000: /* version */
389 AX_reg(context) = VXD_WinVersion();
390 RESET_CFLAG(context);
391 break;
393 case 0x0009: /* get system time selector */
394 if ( !System_Time_Selector )
396 System_Time_Selector = SELECTOR_AllocBlock( &System_Time, sizeof(DWORD),
397 SEGMENT_DATA, FALSE, TRUE );
398 CreateSystemTimer( 55, System_Time_Tick );
401 AX_reg(context) = System_Time_Selector;
402 RESET_CFLAG(context);
403 break;
405 default:
406 VXD_BARF( context, "VTDAPI" );
410 /***********************************************************************
411 * VXD_ConfigMG
413 void WINAPI VXD_ConfigMG ( CONTEXT86 *context )
415 unsigned service = AX_reg(context);
417 TRACE("[%04x] ConfigMG \n", (UINT16)service);
419 switch(service)
421 case 0x0000: /* version */
422 AX_reg(context) = VXD_WinVersion();
423 RESET_CFLAG(context);
424 break;
426 default:
427 VXD_BARF( context, "CONFIGMG" );
431 /***********************************************************************
432 * VXD_Enable
434 void WINAPI VXD_Enable ( CONTEXT86 *context )
436 unsigned service = AX_reg(context);
438 TRACE("[%04x] Enable \n", (UINT16)service);
440 switch(service)
442 case 0x0000: /* version */
443 AX_reg(context) = VXD_WinVersion();
444 RESET_CFLAG(context);
445 break;
447 default:
448 VXD_BARF( context, "ENABLE" );
452 /***********************************************************************
453 * VXD_APM
455 void WINAPI VXD_APM ( CONTEXT86 *context )
457 unsigned service = AX_reg(context);
459 TRACE("[%04x] APM \n", (UINT16)service);
461 switch(service)
463 case 0x0000: /* version */
464 AX_reg(context) = VXD_WinVersion();
465 RESET_CFLAG(context);
466 break;
468 default:
469 VXD_BARF( context, "APM" );
473 /***********************************************************************
474 * VXD_Win32s
476 * This is an implementation of the services of the Win32s VxD.
477 * Since official documentation of these does not seem to be available,
478 * certain arguments of some of the services remain unclear.
480 * FIXME: The following services are currently unimplemented:
481 * Exception handling (0x01, 0x1C)
482 * Debugger support (0x0C, 0x14, 0x17)
483 * Low-level memory access (0x02, 0x03, 0x0A, 0x0B)
484 * Memory Statistics (0x1B)
487 * We have a specific problem running Win32s on Linux (and probably also
488 * the other x86 unixes), since Win32s tries to allocate its main 'flat
489 * code/data segment' selectors with a base of 0xffff0000 (and limit 4GB).
490 * The rationale for this seems to be that they want one the one hand to
491 * be able to leave the Win 3.1 memory (starting with the main DOS memory)
492 * at linear address 0, but want at other hand to have offset 0 of the
493 * flat data/code segment point to an unmapped page (to catch NULL pointer
494 * accesses). Hence they allocate the flat segments with a base of 0xffff0000
495 * so that the Win 3.1 memory area at linear address zero shows up in the
496 * flat segments at offset 0x10000 (since linear addresses wrap around at
497 * 4GB). To compensate for that discrepancy between flat segment offsets
498 * and plain linear addresses, all flat pointers passed between the 32-bit
499 * and the 16-bit parts of Win32s are shifted by 0x10000 in the appropriate
500 * direction by the glue code (mainly) in W32SKRNL and WIN32S16.
502 * The problem for us is now that Linux does not allow a LDT selector with
503 * base 0xffff0000 to be created, since it would 'see' a part of the kernel
504 * address space. To address this problem we introduce *another* offset:
505 * We add 0x10000 to every linear address we get as an argument from Win32s.
506 * This means especially that the flat code/data selectors get actually
507 * allocated with base 0x0, so that flat offsets and (real) linear addresses
508 * do again agree! In fact, every call e.g. of a Win32s VxD service now
509 * has all pointer arguments (which are offsets in the flat data segement)
510 * first reduced by 0x10000 by the W32SKRNL glue code, and then again
511 * increased by 0x10000 by *our* code.
513 * Note that to keep everything consistent, this offset has to be applied by
514 * every Wine function that operates on 'linear addresses' passed to it by
515 * Win32s. Fortunately, since Win32s does not directly call any Wine 32-bit
516 * API routines, this affects only two locations: this VxD and the DPMI
517 * handler. (NOTE: Should any Win32s application pass a linear address to
518 * any routine apart from those, e.g. some other VxD handler, that code
519 * would have to take the offset into account as well!)
521 * The application of the offset is triggered by marking the current process
522 * as a Win32s process by setting the PDB32_WIN32S_PROC flag in the process
523 * database. This is done the first time any application calls the GetVersion()
524 * service of the Win32s VxD. (Note that the flag is never removed.)
528 void WINAPI VXD_Win32s( CONTEXT86 *context )
530 switch (AX_reg(context))
532 case 0x0000: /* Get Version */
534 * Input: None
536 * Output: EAX: LoWord: Win32s Version (1.30)
537 * HiWord: VxD Version (200)
539 * EBX: Build (172)
541 * ECX: ??? (1)
543 * EDX: Debugging Flags
545 * EDI: Error Flag
546 * 0 if OK,
547 * 1 if VMCPD VxD not found
550 TRACE("GetVersion()\n");
552 EAX_reg(context) = VXD_WinVersion() | (200 << 16);
553 EBX_reg(context) = 0;
554 ECX_reg(context) = 0;
555 EDX_reg(context) = 0;
556 EDI_reg(context) = 0;
559 * If this is the first time we are called for this process,
560 * hack the memory image of WIN32S16 so that it doesn't try
561 * to access the GDT directly ...
563 * The first code segment of WIN32S16 (version 1.30) contains
564 * an unexported function somewhere between the exported functions
565 * SetFS and StackLinearToSegmented that tries to find a selector
566 * in the LDT that maps to the memory image of the LDT itself.
567 * If it succeeds, it stores this selector into a global variable
568 * which will be used to speed up execution by using this selector
569 * to modify the LDT directly instead of using the DPMI calls.
571 * To perform this search of the LDT, this function uses the
572 * sgdt and sldt instructions to find the linear address of
573 * the (GDT and then) LDT. While those instructions themselves
574 * execute without problem, the linear address that sgdt returns
575 * points (at least under Linux) to the kernel address space, so
576 * that any subsequent access leads to a segfault.
578 * Fortunately, WIN32S16 still contains as a fallback option the
579 * mechanism of using DPMI calls to modify LDT selectors instead
580 * of direct writes to the LDT. Thus we can circumvent the problem
581 * by simply replacing the first byte of the offending function
582 * with an 'retf' instruction. This means that the global variable
583 * supposed to contain the LDT alias selector will remain zero,
584 * and hence WIN32S16 will fall back to using DPMI calls.
586 * The heuristic we employ to _find_ that function is as follows:
587 * We search between the addresses of the exported symbols SetFS
588 * and StackLinearToSegmented for the byte sequence '0F 01 04'
589 * (this is the opcode of 'sgdt [si]'). We then search backwards
590 * from this address for the last occurrance of 'CB' (retf) that marks
591 * the end of the preceeding function. The following byte (which
592 * should now be the first byte of the function we are looking for)
593 * will be replaced by 'CB' (retf).
595 * This heuristic works for the retail as well as the debug version
596 * of Win32s version 1.30. For versions earlier than that this
597 * hack should not be necessary at all, since the whole mechanism
598 * ('PERF130') was introduced only in 1.30 to improve the overall
599 * performance of Win32s.
602 if (!(PROCESS_Current()->flags & PDB32_WIN32S_PROC))
604 HMODULE16 hModule = GetModuleHandle16("win32s16");
605 SEGPTR func1 = (SEGPTR)WIN32_GetProcAddress16(hModule, "SetFS");
606 SEGPTR func2 = (SEGPTR)WIN32_GetProcAddress16(hModule,
607 "StackLinearToSegmented");
609 if ( hModule && func1 && func2
610 && SELECTOROF(func1) == SELECTOROF(func2))
612 BYTE *start = PTR_SEG_TO_LIN(func1);
613 BYTE *end = PTR_SEG_TO_LIN(func2);
614 BYTE *p, *retv = NULL;
615 int found = 0;
617 for (p = start; p < end; p++)
618 if (*p == 0xCB) found = 0, retv = p;
619 else if (*p == 0x0F) found = 1;
620 else if (*p == 0x01 && found == 1) found = 2;
621 else if (*p == 0x04 && found == 2) { found = 3; break; }
622 else found = 0;
624 if (found == 3 && retv)
626 TRACE("PERF130 hack: "
627 "Replacing byte %02X at offset %04X:%04X\n",
628 *(retv+1), SELECTOROF(func1),
629 OFFSETOF(func1) + retv+1-start);
631 *(retv+1) = (BYTE)0xCB;
637 * Mark process as Win32s, so that subsequent DPMI calls
638 * will perform the W32S_APP2WINE/W32S_WINE2APP address shift.
641 PROCESS_Current()->flags |= PDB32_WIN32S_PROC;
642 break;
645 case 0x0001: /* Install Exception Handling */
647 * Input: EBX: Flat address of W32SKRNL Exception Data
649 * ECX: LoWord: Flat Code Selector
650 * HiWord: Flat Data Selector
652 * EDX: Flat address of W32SKRNL Exception Handler
653 * (this is equal to W32S_BackTo32 + 0x40)
655 * ESI: SEGPTR KERNEL.HASGPHANDLER
657 * EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10)
659 * Output: EAX: 0 if OK
662 TRACE("[0001] EBX=%lx ECX=%lx EDX=%lx ESI=%lx EDI=%lx\n",
663 EBX_reg(context), ECX_reg(context), EDX_reg(context),
664 ESI_reg(context), EDI_reg(context));
666 /* FIXME */
668 EAX_reg(context) = 0;
669 break;
672 case 0x0002: /* Set Page Access Flags */
674 * Input: EBX: New access flags
675 * Bit 2: User Page if set, Supervisor Page if clear
676 * Bit 1: Read-Write if set, Read-Only if clear
678 * ECX: Size of memory area to change
680 * EDX: Flat start address of memory area
682 * Output: EAX: Size of area changed
685 TRACE("[0002] EBX=%lx ECX=%lx EDX=%lx\n",
686 EBX_reg(context), ECX_reg(context), EDX_reg(context));
688 /* FIXME */
690 EAX_reg(context) = ECX_reg(context);
691 break;
694 case 0x0003: /* Get Page Access Flags */
696 * Input: EDX: Flat address of page to query
698 * Output: EAX: Page access flags
699 * Bit 2: User Page if set, Supervisor Page if clear
700 * Bit 1: Read-Write if set, Read-Only if clear
703 TRACE("[0003] EDX=%lx\n", EDX_reg(context));
705 /* FIXME */
707 EAX_reg(context) = 6;
708 break;
711 case 0x0004: /* Map Module */
713 * Input: ECX: IMTE (offset in Module Table) of new module
715 * EDX: Flat address of Win32s Module Table
717 * Output: EAX: 0 if OK
720 if (!EDX_reg(context) || CX_reg(context) == 0xFFFF)
722 TRACE("MapModule: Initialization call\n");
723 EAX_reg(context) = 0;
725 else
728 * Structure of a Win32s Module Table Entry:
730 struct Win32sModule
732 DWORD flags;
733 DWORD flatBaseAddr;
734 LPCSTR moduleName;
735 LPCSTR pathName;
736 LPCSTR unknown;
737 LPBYTE baseAddr;
738 DWORD hModule;
739 DWORD relocDelta;
743 * Note: This function should set up a demand-paged memory image
744 * of the given module. Since mmap does not allow file offsets
745 * not aligned at 1024 bytes, we simply load the image fully
746 * into memory.
749 struct Win32sModule *moduleTable =
750 (struct Win32sModule *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
751 struct Win32sModule *module = moduleTable + ECX_reg(context);
753 IMAGE_NT_HEADERS *nt_header = PE_HEADER(module->baseAddr);
754 IMAGE_SECTION_HEADER *pe_seg = PE_SECTIONS(module->baseAddr);
756 HFILE image = _lopen(module->pathName, OF_READ);
757 BOOL error = (image == INVALID_HANDLE_VALUE);
758 UINT i;
760 TRACE("MapModule: Loading %s\n", module->pathName);
762 for (i = 0;
763 !error && i < nt_header->FileHeader.NumberOfSections;
764 i++, pe_seg++)
765 if(!(pe_seg->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA))
767 DWORD off = pe_seg->PointerToRawData;
768 DWORD len = pe_seg->SizeOfRawData;
769 LPBYTE addr = module->baseAddr + pe_seg->VirtualAddress;
771 TRACE("MapModule: "
772 "Section %d at %08lx from %08lx len %08lx\n",
773 i, (DWORD)addr, off, len);
775 if ( _llseek(image, off, SEEK_SET) != off
776 || _lread(image, addr, len) != len)
777 error = TRUE;
780 _lclose(image);
782 if (error)
783 ERR("MapModule: Unable to load %s\n", module->pathName);
785 else if (module->relocDelta != 0)
787 IMAGE_DATA_DIRECTORY *dir = nt_header->OptionalHeader.DataDirectory
788 + IMAGE_DIRECTORY_ENTRY_BASERELOC;
789 IMAGE_BASE_RELOCATION *r = (IMAGE_BASE_RELOCATION *)
790 (dir->Size? module->baseAddr + dir->VirtualAddress : 0);
792 TRACE("MapModule: Reloc delta %08lx\n", module->relocDelta);
794 while (r && r->VirtualAddress)
796 LPBYTE page = module->baseAddr + r->VirtualAddress;
797 int count = (r->SizeOfBlock - 8) / 2;
799 TRACE("MapModule: %d relocations for page %08lx\n",
800 count, (DWORD)page);
802 for(i = 0; i < count; i++)
804 int offset = r->TypeOffset[i] & 0xFFF;
805 int type = r->TypeOffset[i] >> 12;
806 switch(type)
808 case IMAGE_REL_BASED_ABSOLUTE:
809 break;
810 case IMAGE_REL_BASED_HIGH:
811 *(WORD *)(page+offset) += HIWORD(module->relocDelta);
812 break;
813 case IMAGE_REL_BASED_LOW:
814 *(WORD *)(page+offset) += LOWORD(module->relocDelta);
815 break;
816 case IMAGE_REL_BASED_HIGHLOW:
817 *(DWORD*)(page+offset) += module->relocDelta;
818 break;
819 default:
820 WARN("MapModule: Unsupported fixup type\n");
821 break;
825 r = (IMAGE_BASE_RELOCATION *)((LPBYTE)r + r->SizeOfBlock);
829 EAX_reg(context) = 0;
830 RESET_CFLAG(context);
832 break;
835 case 0x0005: /* UnMap Module */
837 * Input: EDX: Flat address of module image
839 * Output: EAX: 1 if OK
842 TRACE("UnMapModule: %lx\n", (DWORD)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET));
844 /* As we didn't map anything, there's nothing to unmap ... */
846 EAX_reg(context) = 1;
847 break;
850 case 0x0006: /* VirtualAlloc */
852 * Input: ECX: Current Process
854 * EDX: Flat address of arguments on stack
856 * DWORD *retv [out] Flat base address of allocated region
857 * LPVOID base [in] Flat address of region to reserve/commit
858 * DWORD size [in] Size of region
859 * DWORD type [in] Type of allocation
860 * DWORD prot [in] Type of access protection
862 * Output: EAX: NtStatus
865 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
866 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
867 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
868 DWORD size = stack[2];
869 DWORD type = stack[3];
870 DWORD prot = stack[4];
871 DWORD result;
873 TRACE("VirtualAlloc(%lx, %lx, %lx, %lx, %lx)\n",
874 (DWORD)retv, (DWORD)base, size, type, prot);
876 if (type & 0x80000000)
878 WARN("VirtualAlloc: strange type %lx\n", type);
879 type &= 0x7fffffff;
882 if (!base && (type & MEM_COMMIT) && prot == PAGE_READONLY)
884 WARN("VirtualAlloc: NLS hack, allowing write access!\n");
885 prot = PAGE_READWRITE;
888 result = (DWORD)VirtualAlloc(base, size, type, prot);
890 if (W32S_WINE2APP(result, W32S_OFFSET))
891 *retv = W32S_WINE2APP(result, W32S_OFFSET),
892 EAX_reg(context) = STATUS_SUCCESS;
893 else
894 *retv = 0,
895 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
897 break;
900 case 0x0007: /* VirtualFree */
902 * Input: ECX: Current Process
904 * EDX: Flat address of arguments on stack
906 * DWORD *retv [out] TRUE if success, FALSE if failure
907 * LPVOID base [in] Flat address of region
908 * DWORD size [in] Size of region
909 * DWORD type [in] Type of operation
911 * Output: EAX: NtStatus
914 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
915 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
916 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
917 DWORD size = stack[2];
918 DWORD type = stack[3];
919 DWORD result;
921 TRACE("VirtualFree(%lx, %lx, %lx, %lx)\n",
922 (DWORD)retv, (DWORD)base, size, type);
924 result = VirtualFree(base, size, type);
926 if (result)
927 *retv = TRUE,
928 EAX_reg(context) = STATUS_SUCCESS;
929 else
930 *retv = FALSE,
931 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
933 break;
936 case 0x0008: /* VirtualProtect */
938 * Input: ECX: Current Process
940 * EDX: Flat address of arguments on stack
942 * DWORD *retv [out] TRUE if success, FALSE if failure
943 * LPVOID base [in] Flat address of region
944 * DWORD size [in] Size of region
945 * DWORD new_prot [in] Desired access protection
946 * DWORD *old_prot [out] Previous access protection
948 * Output: EAX: NtStatus
951 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
952 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
953 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
954 DWORD size = stack[2];
955 DWORD new_prot = stack[3];
956 DWORD *old_prot = (DWORD *)W32S_APP2WINE(stack[4], W32S_OFFSET);
957 DWORD result;
959 TRACE("VirtualProtect(%lx, %lx, %lx, %lx, %lx)\n",
960 (DWORD)retv, (DWORD)base, size, new_prot, (DWORD)old_prot);
962 result = VirtualProtect(base, size, new_prot, old_prot);
964 if (result)
965 *retv = TRUE,
966 EAX_reg(context) = STATUS_SUCCESS;
967 else
968 *retv = FALSE,
969 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
971 break;
974 case 0x0009: /* VirtualQuery */
976 * Input: ECX: Current Process
978 * EDX: Flat address of arguments on stack
980 * DWORD *retv [out] Nr. bytes returned
981 * LPVOID base [in] Flat address of region
982 * LPMEMORY_BASIC_INFORMATION info [out] Info buffer
983 * DWORD len [in] Size of buffer
985 * Output: EAX: NtStatus
988 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
989 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
990 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
991 LPMEMORY_BASIC_INFORMATION info =
992 (LPMEMORY_BASIC_INFORMATION)W32S_APP2WINE(stack[2], W32S_OFFSET);
993 DWORD len = stack[3];
994 DWORD result;
996 TRACE("VirtualQuery(%lx, %lx, %lx, %lx)\n",
997 (DWORD)retv, (DWORD)base, (DWORD)info, len);
999 result = VirtualQuery(base, info, len);
1001 *retv = result;
1002 EAX_reg(context) = STATUS_SUCCESS;
1004 break;
1007 case 0x000A: /* SetVirtMemProcess */
1009 * Input: ECX: Process Handle
1011 * EDX: Flat address of region
1013 * Output: EAX: NtStatus
1016 TRACE("[000a] ECX=%lx EDX=%lx\n",
1017 ECX_reg(context), EDX_reg(context));
1019 /* FIXME */
1021 EAX_reg(context) = STATUS_SUCCESS;
1022 break;
1025 case 0x000B: /* ??? some kind of cleanup */
1027 * Input: ECX: Process Handle
1029 * Output: EAX: NtStatus
1032 TRACE("[000b] ECX=%lx\n", ECX_reg(context));
1034 /* FIXME */
1036 EAX_reg(context) = STATUS_SUCCESS;
1037 break;
1040 case 0x000C: /* Set Debug Flags */
1042 * Input: EDX: Debug Flags
1044 * Output: EDX: Previous Debug Flags
1047 FIXME("[000c] EDX=%lx\n", EDX_reg(context));
1049 /* FIXME */
1051 EDX_reg(context) = 0;
1052 break;
1055 case 0x000D: /* NtCreateSection */
1057 * Input: EDX: Flat address of arguments on stack
1059 * HANDLE32 *retv [out] Handle of Section created
1060 * DWORD flags1 [in] (?? unknown ??)
1061 * DWORD atom [in] Name of Section to create
1062 * LARGE_INTEGER *size [in] Size of Section
1063 * DWORD protect [in] Access protection
1064 * DWORD flags2 [in] (?? unknown ??)
1065 * HFILE32 hFile [in] Handle of file to map
1066 * DWORD psp [in] (Win32s: PSP that hFile belongs to)
1068 * Output: EAX: NtStatus
1071 DWORD *stack = (DWORD *) W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1072 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1073 DWORD flags1 = stack[1];
1074 DWORD atom = stack[2];
1075 LARGE_INTEGER *size = (LARGE_INTEGER *)W32S_APP2WINE(stack[3], W32S_OFFSET);
1076 DWORD protect = stack[4];
1077 DWORD flags2 = stack[5];
1078 HFILE hFile = FILE_GetHandle(stack[6]);
1079 DWORD psp = stack[7];
1081 HANDLE result = INVALID_HANDLE_VALUE;
1082 char name[128];
1084 TRACE("NtCreateSection(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1085 (DWORD)retv, flags1, atom, (DWORD)size, protect, flags2,
1086 (DWORD)hFile, psp);
1088 if (!atom || GlobalGetAtomNameA(atom, name, sizeof(name)))
1090 TRACE("NtCreateSection: name=%s\n", atom? name : NULL);
1092 result = CreateFileMappingA(hFile, NULL, protect,
1093 size? size->s.HighPart : 0,
1094 size? size->s.LowPart : 0,
1095 atom? name : NULL);
1098 if (result == INVALID_HANDLE_VALUE)
1099 WARN("NtCreateSection: failed!\n");
1100 else
1101 TRACE("NtCreateSection: returned %lx\n", (DWORD)result);
1103 if (result != INVALID_HANDLE_VALUE)
1104 *retv = result,
1105 EAX_reg(context) = STATUS_SUCCESS;
1106 else
1107 *retv = result,
1108 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1110 break;
1113 case 0x000E: /* NtOpenSection */
1115 * Input: EDX: Flat address of arguments on stack
1117 * HANDLE32 *retv [out] Handle of Section opened
1118 * DWORD protect [in] Access protection
1119 * DWORD atom [in] Name of Section to create
1121 * Output: EAX: NtStatus
1124 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1125 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1126 DWORD protect = stack[1];
1127 DWORD atom = stack[2];
1129 HANDLE result = INVALID_HANDLE_VALUE;
1130 char name[128];
1132 TRACE("NtOpenSection(%lx, %lx, %lx)\n",
1133 (DWORD)retv, protect, atom);
1135 if (atom && GlobalGetAtomNameA(atom, name, sizeof(name)))
1137 TRACE("NtOpenSection: name=%s\n", name);
1139 result = OpenFileMappingA(protect, FALSE, name);
1142 if (result == INVALID_HANDLE_VALUE)
1143 WARN("NtOpenSection: failed!\n");
1144 else
1145 TRACE("NtOpenSection: returned %lx\n", (DWORD)result);
1147 if (result != INVALID_HANDLE_VALUE)
1148 *retv = result,
1149 EAX_reg(context) = STATUS_SUCCESS;
1150 else
1151 *retv = result,
1152 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1154 break;
1157 case 0x000F: /* NtCloseSection */
1159 * Input: EDX: Flat address of arguments on stack
1161 * HANDLE32 handle [in] Handle of Section to close
1162 * DWORD *id [out] Unique ID (?? unclear ??)
1164 * Output: EAX: NtStatus
1167 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1168 HANDLE handle = stack[0];
1169 DWORD *id = (DWORD *)W32S_APP2WINE(stack[1], W32S_OFFSET);
1171 TRACE("NtCloseSection(%lx, %lx)\n", (DWORD)handle, (DWORD)id);
1173 CloseHandle(handle);
1174 if (id) *id = 0; /* FIXME */
1176 EAX_reg(context) = STATUS_SUCCESS;
1178 break;
1181 case 0x0010: /* NtDupSection */
1183 * Input: EDX: Flat address of arguments on stack
1185 * HANDLE32 handle [in] Handle of Section to duplicate
1187 * Output: EAX: NtStatus
1190 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1191 HANDLE handle = stack[0];
1192 HANDLE new_handle;
1194 TRACE("NtDupSection(%lx)\n", (DWORD)handle);
1196 DuplicateHandle( GetCurrentProcess(), handle,
1197 GetCurrentProcess(), &new_handle,
1198 0, FALSE, DUPLICATE_SAME_ACCESS );
1199 EAX_reg(context) = STATUS_SUCCESS;
1201 break;
1204 case 0x0011: /* NtMapViewOfSection */
1206 * Input: EDX: Flat address of arguments on stack
1208 * HANDLE32 SectionHandle [in] Section to be mapped
1209 * DWORD ProcessHandle [in] Process to be mapped into
1210 * DWORD * BaseAddress [in/out] Address to be mapped at
1211 * DWORD ZeroBits [in] (?? unclear ??)
1212 * DWORD CommitSize [in] (?? unclear ??)
1213 * LARGE_INTEGER *SectionOffset [in] Offset within section
1214 * DWORD * ViewSize [in] Size of view
1215 * DWORD InheritDisposition [in] (?? unclear ??)
1216 * DWORD AllocationType [in] (?? unclear ??)
1217 * DWORD Protect [in] Access protection
1219 * Output: EAX: NtStatus
1222 DWORD * stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1223 HANDLE SectionHandle = stack[0];
1224 DWORD ProcessHandle = stack[1]; /* ignored */
1225 DWORD * BaseAddress = (DWORD *)W32S_APP2WINE(stack[2], W32S_OFFSET);
1226 DWORD ZeroBits = stack[3];
1227 DWORD CommitSize = stack[4];
1228 LARGE_INTEGER *SectionOffset = (LARGE_INTEGER *)W32S_APP2WINE(stack[5], W32S_OFFSET);
1229 DWORD * ViewSize = (DWORD *)W32S_APP2WINE(stack[6], W32S_OFFSET);
1230 DWORD InheritDisposition = stack[7];
1231 DWORD AllocationType = stack[8];
1232 DWORD Protect = stack[9];
1234 LPBYTE address = (LPBYTE)(BaseAddress?
1235 W32S_APP2WINE(*BaseAddress, W32S_OFFSET) : 0);
1236 DWORD access = 0, result;
1238 switch (Protect & ~(PAGE_GUARD|PAGE_NOCACHE))
1240 case PAGE_READONLY: access = FILE_MAP_READ; break;
1241 case PAGE_READWRITE: access = FILE_MAP_WRITE; break;
1242 case PAGE_WRITECOPY: access = FILE_MAP_COPY; break;
1244 case PAGE_EXECUTE_READ: access = FILE_MAP_READ; break;
1245 case PAGE_EXECUTE_READWRITE: access = FILE_MAP_WRITE; break;
1246 case PAGE_EXECUTE_WRITECOPY: access = FILE_MAP_COPY; break;
1249 TRACE("NtMapViewOfSection"
1250 "(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1251 (DWORD)SectionHandle, ProcessHandle, (DWORD)BaseAddress,
1252 ZeroBits, CommitSize, (DWORD)SectionOffset, (DWORD)ViewSize,
1253 InheritDisposition, AllocationType, Protect);
1254 TRACE("NtMapViewOfSection: "
1255 "base=%lx, offset=%lx, size=%lx, access=%lx\n",
1256 (DWORD)address, SectionOffset? SectionOffset->s.LowPart : 0,
1257 ViewSize? *ViewSize : 0, access);
1259 result = (DWORD)MapViewOfFileEx(SectionHandle, access,
1260 SectionOffset? SectionOffset->s.HighPart : 0,
1261 SectionOffset? SectionOffset->s.LowPart : 0,
1262 ViewSize? *ViewSize : 0, address);
1264 TRACE("NtMapViewOfSection: result=%lx\n", result);
1266 if (W32S_WINE2APP(result, W32S_OFFSET))
1268 if (BaseAddress) *BaseAddress = W32S_WINE2APP(result, W32S_OFFSET);
1269 EAX_reg(context) = STATUS_SUCCESS;
1271 else
1272 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1274 break;
1277 case 0x0012: /* NtUnmapViewOfSection */
1279 * Input: EDX: Flat address of arguments on stack
1281 * DWORD ProcessHandle [in] Process (defining address space)
1282 * LPBYTE BaseAddress [in] Base address of view to be unmapped
1284 * Output: EAX: NtStatus
1287 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1288 DWORD ProcessHandle = stack[0]; /* ignored */
1289 LPBYTE BaseAddress = (LPBYTE)W32S_APP2WINE(stack[1], W32S_OFFSET);
1291 TRACE("NtUnmapViewOfSection(%lx, %lx)\n",
1292 ProcessHandle, (DWORD)BaseAddress);
1294 UnmapViewOfFile(BaseAddress);
1296 EAX_reg(context) = STATUS_SUCCESS;
1298 break;
1301 case 0x0013: /* NtFlushVirtualMemory */
1303 * Input: EDX: Flat address of arguments on stack
1305 * DWORD ProcessHandle [in] Process (defining address space)
1306 * LPBYTE *BaseAddress [in?] Base address of range to be flushed
1307 * DWORD *ViewSize [in?] Number of bytes to be flushed
1308 * DWORD *unknown [???] (?? unknown ??)
1310 * Output: EAX: NtStatus
1313 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1314 DWORD ProcessHandle = stack[0]; /* ignored */
1315 DWORD *BaseAddress = (DWORD *)W32S_APP2WINE(stack[1], W32S_OFFSET);
1316 DWORD *ViewSize = (DWORD *)W32S_APP2WINE(stack[2], W32S_OFFSET);
1317 DWORD *unknown = (DWORD *)W32S_APP2WINE(stack[3], W32S_OFFSET);
1319 LPBYTE address = (LPBYTE)(BaseAddress? W32S_APP2WINE(*BaseAddress, W32S_OFFSET) : 0);
1320 DWORD size = ViewSize? *ViewSize : 0;
1322 TRACE("NtFlushVirtualMemory(%lx, %lx, %lx, %lx)\n",
1323 ProcessHandle, (DWORD)BaseAddress, (DWORD)ViewSize,
1324 (DWORD)unknown);
1325 TRACE("NtFlushVirtualMemory: base=%lx, size=%lx\n",
1326 (DWORD)address, size);
1328 FlushViewOfFile(address, size);
1330 EAX_reg(context) = STATUS_SUCCESS;
1332 break;
1335 case 0x0014: /* Get/Set Debug Registers */
1337 * Input: ECX: 0 if Get, 1 if Set
1339 * EDX: Get: Flat address of buffer to receive values of
1340 * debug registers DR0 .. DR7
1341 * Set: Flat address of buffer containing values of
1342 * debug registers DR0 .. DR7 to be set
1343 * Output: None
1346 FIXME("[0014] ECX=%lx EDX=%lx\n",
1347 ECX_reg(context), EDX_reg(context));
1349 /* FIXME */
1350 break;
1353 case 0x0015: /* Set Coprocessor Emulation Flag */
1355 * Input: EDX: 0 to deactivate, 1 to activate coprocessor emulation
1357 * Output: None
1360 TRACE("[0015] EDX=%lx\n", EDX_reg(context));
1362 /* We don't care, as we always have a coprocessor anyway */
1363 break;
1366 case 0x0016: /* Init Win32S VxD PSP */
1368 * If called to query required PSP size:
1370 * Input: EBX: 0
1371 * Output: EDX: Required size of Win32s VxD PSP
1373 * If called to initialize allocated PSP:
1375 * Input: EBX: LoWord: Selector of Win32s VxD PSP
1376 * HiWord: Paragraph of Win32s VxD PSP (DOSMEM)
1377 * Output: None
1380 if (EBX_reg(context) == 0)
1381 EDX_reg(context) = 0x80;
1382 else
1384 PDB16 *psp = PTR_SEG_OFF_TO_LIN(BX_reg(context), 0);
1385 psp->nbFiles = 32;
1386 psp->fileHandlesPtr = MAKELONG(HIWORD(EBX_reg(context)), 0x5c);
1387 memset((LPBYTE)psp + 0x5c, '\xFF', 32);
1389 break;
1392 case 0x0017: /* Set Break Point */
1394 * Input: EBX: Offset of Break Point
1395 * CX: Selector of Break Point
1397 * Output: None
1400 FIXME("[0017] EBX=%lx CX=%x\n",
1401 EBX_reg(context), CX_reg(context));
1403 /* FIXME */
1404 break;
1407 case 0x0018: /* VirtualLock */
1409 * Input: ECX: Current Process
1411 * EDX: Flat address of arguments on stack
1413 * DWORD *retv [out] TRUE if success, FALSE if failure
1414 * LPVOID base [in] Flat address of range to lock
1415 * DWORD size [in] Size of range
1417 * Output: EAX: NtStatus
1420 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1421 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1422 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
1423 DWORD size = stack[2];
1424 DWORD result;
1426 TRACE("VirtualLock(%lx, %lx, %lx)\n",
1427 (DWORD)retv, (DWORD)base, size);
1429 result = VirtualLock(base, size);
1431 if (result)
1432 *retv = TRUE,
1433 EAX_reg(context) = STATUS_SUCCESS;
1434 else
1435 *retv = FALSE,
1436 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1438 break;
1441 case 0x0019: /* VirtualUnlock */
1443 * Input: ECX: Current Process
1445 * EDX: Flat address of arguments on stack
1447 * DWORD *retv [out] TRUE if success, FALSE if failure
1448 * LPVOID base [in] Flat address of range to unlock
1449 * DWORD size [in] Size of range
1451 * Output: EAX: NtStatus
1454 DWORD *stack = (DWORD *)W32S_APP2WINE(EDX_reg(context), W32S_OFFSET);
1455 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1456 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
1457 DWORD size = stack[2];
1458 DWORD result;
1460 TRACE("VirtualUnlock(%lx, %lx, %lx)\n",
1461 (DWORD)retv, (DWORD)base, size);
1463 result = VirtualUnlock(base, size);
1465 if (result)
1466 *retv = TRUE,
1467 EAX_reg(context) = STATUS_SUCCESS;
1468 else
1469 *retv = FALSE,
1470 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1472 break;
1475 case 0x001A: /* KGetSystemInfo */
1477 * Input: None
1479 * Output: ECX: Start of sparse memory arena
1480 * EDX: End of sparse memory arena
1483 TRACE("KGetSystemInfo()\n");
1486 * Note: Win32s reserves 0GB - 2GB for Win 3.1 and uses 2GB - 4GB as
1487 * sparse memory arena. We do it the other way around, since
1488 * we have to reserve 3GB - 4GB for Linux, and thus use
1489 * 0GB - 3GB as sparse memory arena.
1491 * FIXME: What about other OSes ?
1494 ECX_reg(context) = W32S_WINE2APP(0x00000000, W32S_OFFSET);
1495 EDX_reg(context) = W32S_WINE2APP(0xbfffffff, W32S_OFFSET);
1496 break;
1499 case 0x001B: /* KGlobalMemStat */
1501 * Input: ESI: Flat address of buffer to receive memory info
1503 * Output: None
1506 struct Win32sMemoryInfo
1508 DWORD DIPhys_Count; /* Total physical pages */
1509 DWORD DIFree_Count; /* Free physical pages */
1510 DWORD DILin_Total_Count; /* Total virtual pages (private arena) */
1511 DWORD DILin_Total_Free; /* Free virtual pages (private arena) */
1513 DWORD SparseTotal; /* Total size of sparse arena (bytes ?) */
1514 DWORD SparseFree; /* Free size of sparse arena (bytes ?) */
1517 struct Win32sMemoryInfo *info =
1518 (struct Win32sMemoryInfo *)W32S_APP2WINE(ESI_reg(context), W32S_OFFSET);
1520 FIXME("KGlobalMemStat(%lx)\n", (DWORD)info);
1522 /* FIXME */
1524 break;
1527 case 0x001C: /* Enable/Disable Exceptions */
1529 * Input: ECX: 0 to disable, 1 to enable exception handling
1531 * Output: None
1534 TRACE("[001c] ECX=%lx\n", ECX_reg(context));
1536 /* FIXME */
1537 break;
1540 case 0x001D: /* VirtualAlloc called from 16-bit code */
1542 * Input: EDX: Segmented address of arguments on stack
1544 * LPVOID base [in] Flat address of region to reserve/commit
1545 * DWORD size [in] Size of region
1546 * DWORD type [in] Type of allocation
1547 * DWORD prot [in] Type of access protection
1549 * Output: EAX: NtStatus
1550 * EDX: Flat base address of allocated region
1553 DWORD *stack = PTR_SEG_OFF_TO_LIN(LOWORD(EDX_reg(context)),
1554 HIWORD(EDX_reg(context)));
1555 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0], W32S_OFFSET);
1556 DWORD size = stack[1];
1557 DWORD type = stack[2];
1558 DWORD prot = stack[3];
1559 DWORD result;
1561 TRACE("VirtualAlloc16(%lx, %lx, %lx, %lx)\n",
1562 (DWORD)base, size, type, prot);
1564 if (type & 0x80000000)
1566 WARN("VirtualAlloc16: strange type %lx\n", type);
1567 type &= 0x7fffffff;
1570 result = (DWORD)VirtualAlloc(base, size, type, prot);
1572 if (W32S_WINE2APP(result, W32S_OFFSET))
1573 EDX_reg(context) = W32S_WINE2APP(result, W32S_OFFSET),
1574 EAX_reg(context) = STATUS_SUCCESS;
1575 else
1576 EDX_reg(context) = 0,
1577 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1578 TRACE("VirtualAlloc16: returning base %lx\n", EDX_reg(context));
1580 break;
1583 case 0x001E: /* VirtualFree called from 16-bit code */
1585 * Input: EDX: Segmented address of arguments on stack
1587 * LPVOID base [in] Flat address of region
1588 * DWORD size [in] Size of region
1589 * DWORD type [in] Type of operation
1591 * Output: EAX: NtStatus
1592 * EDX: TRUE if success, FALSE if failure
1595 DWORD *stack = PTR_SEG_OFF_TO_LIN(LOWORD(EDX_reg(context)),
1596 HIWORD(EDX_reg(context)));
1597 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0], W32S_OFFSET);
1598 DWORD size = stack[1];
1599 DWORD type = stack[2];
1600 DWORD result;
1602 TRACE("VirtualFree16(%lx, %lx, %lx)\n",
1603 (DWORD)base, size, type);
1605 result = VirtualFree(base, size, type);
1607 if (result)
1608 EDX_reg(context) = TRUE,
1609 EAX_reg(context) = STATUS_SUCCESS;
1610 else
1611 EDX_reg(context) = FALSE,
1612 EAX_reg(context) = STATUS_NO_MEMORY; /* FIXME */
1614 break;
1617 case 0x001F: /* FWorkingSetSize */
1619 * Input: EDX: 0 if Get, 1 if Set
1621 * ECX: Get: Buffer to receive Working Set Size
1622 * Set: Buffer containing Working Set Size
1624 * Output: NtStatus
1627 DWORD *ptr = (DWORD *)W32S_APP2WINE(ECX_reg(context), W32S_OFFSET);
1628 BOOL set = EDX_reg(context);
1630 TRACE("FWorkingSetSize(%lx, %lx)\n", (DWORD)ptr, (DWORD)set);
1632 if (set)
1633 /* We do it differently ... */;
1634 else
1635 *ptr = 0x100;
1637 EAX_reg(context) = STATUS_SUCCESS;
1639 break;
1642 default:
1643 VXD_BARF( context, "W32S" );