Added a first-cut version of MapVirtualKeyExW() that has the same
[wine] / msdos / vxd.c
1 /*
2  * VxD emulation
3  *
4  * Copyright 1995 Anand Kumria
5  */
6
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 "task.h"
21 #include "process.h"
22 #include "file.h"
23 #include "debugtools.h"
24
25 DEFAULT_DEBUG_CHANNEL(vxd);
26
27
28 #define VXD_BARF(context,name) \
29     DPRINTF( "vxd %s: unknown/not implemented parameters:\n" \
30                      "vxd %s: AX %04x, BX %04x, CX %04x, DX %04x, " \
31                      "SI %04x, DI %04x, DS %04x, ES %04x\n", \
32              (name), (name), AX_reg(context), BX_reg(context), \
33              CX_reg(context), DX_reg(context), SI_reg(context), \
34              DI_reg(context), (WORD)context->SegDs, (WORD)context->SegEs )
35
36
37 static WORD VXD_WinVersion(void)
38 {
39     WORD version = LOWORD(GetVersion16());
40     return (version >> 8) | (version << 8);
41 }
42
43 /***********************************************************************
44  *           VXD_VMM
45  */
46 void WINAPI VXD_VMM ( CONTEXT86 *context )
47 {
48     unsigned service = AX_reg(context);
49
50     TRACE("[%04x] VMM\n", (UINT16)service);
51
52     switch(service)
53     {
54     case 0x0000: /* version */
55         AX_reg(context) = VXD_WinVersion();
56         RESET_CFLAG(context);
57         break;
58
59     case 0x026d: /* Get_Debug_Flag '/m' */
60     case 0x026e: /* Get_Debug_Flag '/n' */
61         AL_reg(context) = 0;
62         RESET_CFLAG(context);
63         break;
64
65     default:
66         VXD_BARF( context, "VMM" );
67     }
68 }
69
70 /***********************************************************************
71  *           VXD_PageFile
72  */
73 void WINAPI VXD_PageFile( CONTEXT86 *context )
74 {
75     unsigned    service = AX_reg(context);
76
77     /* taken from Ralf Brown's Interrupt List */
78
79     TRACE("[%04x] PageFile\n", (UINT16)service );
80
81     switch(service)
82     {
83     case 0x00: /* get version, is this windows version? */
84         TRACE("returning version\n");
85         AX_reg(context) = VXD_WinVersion();
86         RESET_CFLAG(context);
87         break;
88
89     case 0x01: /* get swap file info */
90         TRACE("VxD PageFile: returning swap file info\n");
91         AX_reg(context) = 0x00; /* paging disabled */
92         context->Ecx = 0;   /* maximum size of paging file */   
93         /* FIXME: do I touch DS:SI or DS:DI? */
94         RESET_CFLAG(context);
95         break;
96
97     case 0x02: /* delete permanent swap on exit */
98         TRACE("VxD PageFile: supposed to delete swap\n");
99         RESET_CFLAG(context);
100         break;
101
102     case 0x03: /* current temporary swap file size */
103         TRACE("VxD PageFile: what is current temp. swap size\n");
104         RESET_CFLAG(context);
105         break;
106
107     case 0x04: /* read or write?? INTERRUP.D */
108     case 0x05: /* cancel?? INTERRUP.D */
109     case 0x06: /* test I/O valid INTERRUP.D */
110     default:
111         VXD_BARF( context, "pagefile" );
112         break;
113     }
114 }
115
116 /***********************************************************************
117  *           VXD_Reboot
118  */
119 void WINAPI VXD_Reboot ( CONTEXT86 *context )
120 {
121     unsigned service = AX_reg(context);
122
123     TRACE("[%04x] Reboot\n", (UINT16)service);
124
125     switch(service)
126     {
127     case 0x0000: /* version */
128         AX_reg(context) = VXD_WinVersion();
129         RESET_CFLAG(context);
130         break;
131
132     default:
133         VXD_BARF( context, "REBOOT" );
134     }
135 }
136
137 /***********************************************************************
138  *           VXD_VDD
139  */
140 void WINAPI VXD_VDD ( CONTEXT86 *context )
141 {
142     unsigned service = AX_reg(context);
143
144     TRACE("[%04x] VDD\n", (UINT16)service);
145
146     switch(service)
147     {
148     case 0x0000: /* version */
149         AX_reg(context) = VXD_WinVersion();
150         RESET_CFLAG(context);
151         break;
152
153     default:
154         VXD_BARF( context, "VDD" );
155     }
156 }
157
158 /***********************************************************************
159  *           VXD_VMD
160  */
161 void WINAPI VXD_VMD ( CONTEXT86 *context )
162 {
163     unsigned service = AX_reg(context);
164
165     TRACE("[%04x] VMD\n", (UINT16)service);
166
167     switch(service)
168     {
169     case 0x0000: /* version */
170         AX_reg(context) = VXD_WinVersion();
171         RESET_CFLAG(context);
172         break;
173
174     default:
175         VXD_BARF( context, "VMD" );
176     }
177 }
178
179 /***********************************************************************
180  *           VXD_VXDLoader
181  */
182 void WINAPI VXD_VXDLoader( CONTEXT86 *context )
183 {
184     unsigned service = AX_reg(context);
185
186     TRACE("[%04x] VXDLoader\n", (UINT16)service);
187
188     switch (service)
189     {
190     case 0x0000: /* get version */
191         TRACE("returning version\n");
192         AX_reg(context) = 0x0000;
193         DX_reg(context) = VXD_WinVersion();
194         RESET_CFLAG(context);
195         break;
196
197     case 0x0001: /* load device */
198         FIXME("load device %04lx:%04x (%s)\n",
199               context->SegDs, DX_reg(context),
200               debugstr_a(PTR_SEG_OFF_TO_LIN(context->SegDs, DX_reg(context))));
201         AX_reg(context) = 0x0000;
202         context->SegEs = 0x0000;
203         DI_reg(context) = 0x0000;
204         RESET_CFLAG(context);
205         break;
206
207     case 0x0002: /* unload device */
208         FIXME("unload device (%08lx)\n", context->Ebx);
209         AX_reg(context) = 0x0000;
210         RESET_CFLAG(context);
211         break;
212
213     default:
214         VXD_BARF( context, "VXDLDR" );
215         AX_reg(context) = 0x000B; /* invalid function number */
216         SET_CFLAG(context);
217         break;
218     }   
219 }
220
221 /***********************************************************************
222  *           VXD_Shell
223  */
224 void WINAPI VXD_Shell( CONTEXT86 *context )
225 {
226     unsigned    service = DX_reg(context);
227
228     TRACE("[%04x] Shell\n", (UINT16)service);
229
230     switch (service) /* Ralf Brown says EDX, but I use DX instead */
231     {
232     case 0x0000:
233         TRACE("returning version\n");
234         AX_reg(context) = VXD_WinVersion();
235         context->Ebx = 1; /* system VM Handle */
236         break;
237
238     case 0x0001:
239     case 0x0002:
240     case 0x0003:
241         /* SHELL_SYSMODAL_Message
242         ebx virtual maschine handle
243         eax message box flags
244         ecx address of message
245         edi address of caption
246         return response in eax
247         */
248     case 0x0004:
249         /* SHELL_Message
250         ebx virtual maschine handle
251         eax message box flags
252         ecx address of message
253         edi address of caption
254         esi address callback
255         edx reference data for callback
256         return response in eax
257         */
258     case 0x0005:
259         VXD_BARF( context, "shell" );
260         break;
261
262     case 0x0006: /* SHELL_Get_VM_State */
263         TRACE("VxD Shell: returning VM state\n");
264         /* Actually we don't, not yet. We have to return a structure
265          * and I am not to sure how to set it up and return it yet,
266          * so for now let's do nothing. I can (hopefully) get this
267          * by the next release
268          */
269         /* RESET_CFLAG(context); */
270         break;
271
272     case 0x0007:
273     case 0x0008:
274     case 0x0009:
275     case 0x000A:
276     case 0x000B:
277     case 0x000C:
278     case 0x000D:
279     case 0x000E:
280     case 0x000F:
281     case 0x0010:
282     case 0x0011:
283     case 0x0012:
284     case 0x0013:
285     case 0x0014:
286     case 0x0015:
287     case 0x0016:
288         VXD_BARF( context, "SHELL" );
289         break;
290
291     /* the new Win95 shell API */
292     case 0x0100:     /* get version */
293         AX_reg(context) = VXD_WinVersion();
294         break;
295
296     case 0x0104:   /* retrieve Hook_Properties list */
297     case 0x0105:   /* call Hook_Properties callbacks */
298         VXD_BARF( context, "SHELL" );
299         break;
300
301     case 0x0106:   /* install timeout callback */
302         TRACE("VxD Shell: ignoring shell callback (%ld sec.)\n", context->Ebx);
303         SET_CFLAG(context);
304         break;
305
306     case 0x0107:   /* get version of any VxD */
307     default:
308         VXD_BARF( context, "SHELL" );
309         break;
310     }
311 }
312
313
314 /***********************************************************************
315  *           VXD_Comm
316  */
317 void WINAPI VXD_Comm( CONTEXT86 *context )
318 {
319     unsigned    service = AX_reg(context);
320
321     TRACE("[%04x] Comm\n", (UINT16)service);
322
323     switch (service)
324     {
325     case 0x0000: /* get version */
326         TRACE("returning version\n");
327         AX_reg(context) = VXD_WinVersion();
328         RESET_CFLAG(context);
329         break;
330
331     case 0x0001: /* set port global */
332     case 0x0002: /* get focus */
333     case 0x0003: /* virtualise port */
334     default:
335         VXD_BARF( context, "comm" );
336     }
337 }
338
339 /***********************************************************************
340  *           VXD_Timer
341  */
342 void WINAPI VXD_Timer( CONTEXT86 *context )
343 {
344     unsigned service = AX_reg(context);
345
346     TRACE("[%04x] Virtual Timer\n", (UINT16)service);
347
348     switch(service)
349     {
350     case 0x0000: /* version */
351         AX_reg(context) = VXD_WinVersion();
352         RESET_CFLAG(context);
353         break;
354
355     case 0x0100: /* clock tick time, in 840nsecs */
356         context->Eax = GetTickCount();
357
358         context->Edx = context->Eax >> 22;
359         context->Eax <<= 10; /* not very precise */
360         break;
361
362     case 0x0101: /* current Windows time, msecs */
363     case 0x0102: /* current VM time, msecs */
364         context->Eax = GetTickCount();
365         break;
366
367     default:
368         VXD_BARF( context, "VTD" );
369     }
370 }
371
372 /***********************************************************************
373  *           VXD_TimerAPI
374  */
375 static DWORD System_Time = 0;
376 static WORD  System_Time_Selector = 0;
377 static void  System_Time_Tick( WORD timer ) { System_Time += 55; }
378 void WINAPI VXD_TimerAPI ( CONTEXT86 *context )
379 {
380     unsigned service = AX_reg(context);
381
382     TRACE("[%04x] TimerAPI\n", (UINT16)service);
383
384     switch(service)
385     {
386     case 0x0000: /* version */
387         AX_reg(context) = VXD_WinVersion();
388         RESET_CFLAG(context);
389         break;
390
391     case 0x0009: /* get system time selector */
392         if ( !System_Time_Selector )
393         {
394             System_Time_Selector = SELECTOR_AllocBlock( &System_Time, sizeof(DWORD), WINE_LDT_FLAGS_DATA );
395             CreateSystemTimer( 55, System_Time_Tick );
396         }
397
398         AX_reg(context) = System_Time_Selector;
399         RESET_CFLAG(context);
400         break;
401
402     default:
403         VXD_BARF( context, "VTDAPI" );
404     }
405 }
406
407 /***********************************************************************
408  *           VXD_ConfigMG
409  */
410 void WINAPI VXD_ConfigMG ( CONTEXT86 *context )
411 {
412     unsigned service = AX_reg(context);
413
414     TRACE("[%04x] ConfigMG\n", (UINT16)service);
415
416     switch(service)
417     {
418     case 0x0000: /* version */
419         AX_reg(context) = VXD_WinVersion();
420         RESET_CFLAG(context);
421         break;
422
423     default:
424         VXD_BARF( context, "CONFIGMG" );
425     }
426 }
427
428 /***********************************************************************
429  *           VXD_Enable
430  */
431 void WINAPI VXD_Enable ( CONTEXT86 *context )
432 {
433     unsigned service = AX_reg(context);
434
435     TRACE("[%04x] Enable\n", (UINT16)service);
436
437     switch(service)
438     {
439     case 0x0000: /* version */
440         AX_reg(context) = VXD_WinVersion();
441         RESET_CFLAG(context);
442         break;
443
444     default:
445         VXD_BARF( context, "ENABLE" );
446     }
447 }
448
449 /***********************************************************************
450  *           VXD_APM
451  */
452 void WINAPI VXD_APM ( CONTEXT86 *context )
453 {
454     unsigned service = AX_reg(context);
455
456     TRACE("[%04x] APM\n", (UINT16)service);
457
458     switch(service)
459     {
460     case 0x0000: /* version */
461         AX_reg(context) = VXD_WinVersion();
462         RESET_CFLAG(context);
463         break;
464
465     default:
466         VXD_BARF( context, "APM" );
467     }
468 }
469
470 /***********************************************************************
471  *           VXD_Win32s
472  *
473  * This is an implementation of the services of the Win32s VxD.
474  * Since official documentation of these does not seem to be available,
475  * certain arguments of some of the services remain unclear.  
476  *
477  * FIXME: The following services are currently unimplemented: 
478  *        Exception handling      (0x01, 0x1C)
479  *        Debugger support        (0x0C, 0x14, 0x17)
480  *        Low-level memory access (0x02, 0x03, 0x0A, 0x0B)
481  *        Memory Statistics       (0x1B)
482  *        
483  *
484  * We have a specific problem running Win32s on Linux (and probably also
485  * the other x86 unixes), since Win32s tries to allocate its main 'flat
486  * code/data segment' selectors with a base of 0xffff0000 (and limit 4GB).
487  * The rationale for this seems to be that they want one the one hand to 
488  * be able to leave the Win 3.1 memory (starting with the main DOS memory) 
489  * at linear address 0, but want at other hand to have offset 0 of the
490  * flat data/code segment point to an unmapped page (to catch NULL pointer
491  * accesses). Hence they allocate the flat segments with a base of 0xffff0000
492  * so that the Win 3.1 memory area at linear address zero shows up in the
493  * flat segments at offset 0x10000 (since linear addresses wrap around at
494  * 4GB). To compensate for that discrepancy between flat segment offsets
495  * and plain linear addresses, all flat pointers passed between the 32-bit
496  * and the 16-bit parts of Win32s are shifted by 0x10000 in the appropriate
497  * direction by the glue code (mainly) in W32SKRNL and WIN32S16.
498  *
499  * The problem for us is now that Linux does not allow a LDT selector with
500  * base 0xffff0000 to be created, since it would 'see' a part of the kernel
501  * address space. To address this problem we introduce *another* offset:
502  * We add 0x10000 to every linear address we get as an argument from Win32s.
503  * This means especially that the flat code/data selectors get actually
504  * allocated with base 0x0, so that flat offsets and (real) linear addresses
505  * do again agree!  In fact, every call e.g. of a Win32s VxD service now
506  * has all pointer arguments (which are offsets in the flat data segement)
507  * first reduced by 0x10000 by the W32SKRNL glue code, and then again
508  * increased by 0x10000 by *our* code.
509  *
510  * Note that to keep everything consistent, this offset has to be applied by
511  * every Wine function that operates on 'linear addresses' passed to it by
512  * Win32s. Fortunately, since Win32s does not directly call any Wine 32-bit
513  * API routines, this affects only two locations: this VxD and the DPMI
514  * handler. (NOTE: Should any Win32s application pass a linear address to
515  * any routine apart from those, e.g. some other VxD handler, that code
516  * would have to take the offset into account as well!)
517  *
518  * The application of the offset is triggered by marking the current process
519  * as a Win32s process by setting the PDB32_WIN32S_PROC flag in the process
520  * database. This is done the first time any application calls the GetVersion()
521  * service of the Win32s VxD. (Note that the flag is never removed.)
522  * 
523  */
524
525 void WINAPI VXD_Win32s( CONTEXT86 *context )
526 {
527     switch (AX_reg(context))
528     {
529     case 0x0000: /* Get Version */
530         /*
531          * Input:   None
532          *
533          * Output:  EAX: LoWord: Win32s Version (1.30)
534          *               HiWord: VxD Version (200)
535          *
536          *          EBX: Build (172)
537          *
538          *          ECX: ???   (1)
539          *
540          *          EDX: Debugging Flags
541          *
542          *          EDI: Error Flag 
543          *               0 if OK,
544          *               1 if VMCPD VxD not found
545          */
546
547         TRACE("GetVersion()\n");
548         
549         context->Eax = VXD_WinVersion() | (200 << 16);
550         context->Ebx = 0;
551         context->Ecx = 0;
552         context->Edx = 0;
553         context->Edi = 0;
554
555         /* 
556          * If this is the first time we are called for this process,
557          * hack the memory image of WIN32S16 so that it doesn't try
558          * to access the GDT directly ...
559          *
560          * The first code segment of WIN32S16 (version 1.30) contains 
561          * an unexported function somewhere between the exported functions
562          * SetFS and StackLinearToSegmented that tries to find a selector
563          * in the LDT that maps to the memory image of the LDT itself.
564          * If it succeeds, it stores this selector into a global variable
565          * which will be used to speed up execution by using this selector
566          * to modify the LDT directly instead of using the DPMI calls.
567          *
568          * To perform this search of the LDT, this function uses the
569          * sgdt and sldt instructions to find the linear address of
570          * the (GDT and then) LDT. While those instructions themselves
571          * execute without problem, the linear address that sgdt returns
572          * points (at least under Linux) to the kernel address space, so
573          * that any subsequent access leads to a segfault.
574          *
575          * Fortunately, WIN32S16 still contains as a fallback option the
576          * mechanism of using DPMI calls to modify LDT selectors instead
577          * of direct writes to the LDT. Thus we can circumvent the problem
578          * by simply replacing the first byte of the offending function
579          * with an 'retf' instruction. This means that the global variable
580          * supposed to contain the LDT alias selector will remain zero,
581          * and hence WIN32S16 will fall back to using DPMI calls.
582          *
583          * The heuristic we employ to _find_ that function is as follows:
584          * We search between the addresses of the exported symbols SetFS
585          * and StackLinearToSegmented for the byte sequence '0F 01 04'
586          * (this is the opcode of 'sgdt [si]'). We then search backwards
587          * from this address for the last occurrance of 'CB' (retf) that marks
588          * the end of the preceeding function. The following byte (which
589          * should now be the first byte of the function we are looking for)
590          * will be replaced by 'CB' (retf).
591          *
592          * This heuristic works for the retail as well as the debug version
593          * of Win32s version 1.30. For versions earlier than that this
594          * hack should not be necessary at all, since the whole mechanism
595          * ('PERF130') was introduced only in 1.30 to improve the overall
596          * performance of Win32s.
597          */
598
599         if (!(PROCESS_Current()->flags & PDB32_WIN32S_PROC))
600         {
601             HMODULE16 hModule = GetModuleHandle16("win32s16");
602             SEGPTR func1 = (SEGPTR)GetProcAddress16(hModule, "SetFS");
603             SEGPTR func2 = (SEGPTR)GetProcAddress16(hModule, "StackLinearToSegmented");
604
605             if (   hModule && func1 && func2 
606                 && SELECTOROF(func1) == SELECTOROF(func2))
607             {
608                 BYTE *start = PTR_SEG_TO_LIN(func1);
609                 BYTE *end   = PTR_SEG_TO_LIN(func2);
610                 BYTE *p, *retv = NULL;
611                 int found = 0;
612
613                 for (p = start; p < end; p++)
614                     if (*p == 0xCB) found = 0, retv = p;
615                     else if (*p == 0x0F) found = 1;
616                     else if (*p == 0x01 && found == 1) found = 2;
617                     else if (*p == 0x04 && found == 2) { found = 3; break; }
618                     else found = 0;
619
620                 if (found == 3 && retv)
621                 {
622                     TRACE("PERF130 hack: "
623                                "Replacing byte %02X at offset %04X:%04X\n",
624                                *(retv+1), SELECTOROF(func1), 
625                                           OFFSETOF(func1) + retv+1-start);
626
627                     *(retv+1) = (BYTE)0xCB;
628                 }
629             }
630         }
631
632         /* 
633          * Mark process as Win32s, so that subsequent DPMI calls
634          * will perform the W32S_APP2WINE/W32S_WINE2APP address shift.
635          */
636
637         PROCESS_Current()->flags |= PDB32_WIN32S_PROC;
638         break;
639
640
641     case 0x0001: /* Install Exception Handling */
642         /*
643          * Input:   EBX: Flat address of W32SKRNL Exception Data
644          *
645          *          ECX: LoWord: Flat Code Selector
646          *               HiWord: Flat Data Selector
647          *
648          *          EDX: Flat address of W32SKRNL Exception Handler 
649          *               (this is equal to W32S_BackTo32 + 0x40)
650          *
651          *          ESI: SEGPTR KERNEL.HASGPHANDLER
652          *
653          *          EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10)
654          *
655          * Output:  EAX: 0 if OK
656          */
657
658         TRACE("[0001] EBX=%lx ECX=%lx EDX=%lx ESI=%lx EDI=%lx\n", 
659                    context->Ebx, context->Ecx, context->Edx,
660                    context->Esi, context->Edi);
661
662         /* FIXME */
663
664         context->Eax = 0;
665         break;
666
667
668     case 0x0002: /* Set Page Access Flags */
669         /*
670          * Input:   EBX: New access flags
671          *               Bit 2: User Page if set, Supervisor Page if clear
672          *               Bit 1: Read-Write if set, Read-Only if clear
673          *
674          *          ECX: Size of memory area to change
675          *
676          *          EDX: Flat start address of memory area
677          *
678          * Output:  EAX: Size of area changed
679          */
680
681         TRACE("[0002] EBX=%lx ECX=%lx EDX=%lx\n", 
682                    context->Ebx, context->Ecx, context->Edx);
683
684         /* FIXME */
685
686         context->Eax = context->Ecx;
687         break;
688
689
690     case 0x0003: /* Get Page Access Flags */
691         /*
692          * Input:   EDX: Flat address of page to query
693          *
694          * Output:  EAX: Page access flags
695          *               Bit 2: User Page if set, Supervisor Page if clear
696          *               Bit 1: Read-Write if set, Read-Only if clear
697          */
698
699         TRACE("[0003] EDX=%lx\n", context->Edx);
700
701         /* FIXME */
702
703         context->Eax = 6;
704         break;
705
706
707     case 0x0004: /* Map Module */
708         /*
709          * Input:   ECX: IMTE (offset in Module Table) of new module
710          *
711          *          EDX: Flat address of Win32s Module Table
712          *
713          * Output:  EAX: 0 if OK
714          */
715
716     if (!context->Edx || CX_reg(context) == 0xFFFF)
717     {
718         TRACE("MapModule: Initialization call\n");
719         context->Eax = 0;
720     }
721     else
722     {
723         /*
724          * Structure of a Win32s Module Table Entry:
725          */
726         struct Win32sModule
727         {
728             DWORD  flags;
729             DWORD  flatBaseAddr;
730             LPCSTR moduleName;
731             LPCSTR pathName;
732             LPCSTR unknown;
733             LPBYTE baseAddr;
734             DWORD  hModule;
735             DWORD  relocDelta;
736         };
737
738         /* 
739          * Note: This function should set up a demand-paged memory image 
740          *       of the given module. Since mmap does not allow file offsets
741          *       not aligned at 1024 bytes, we simply load the image fully
742          *       into memory.
743          */
744
745         struct Win32sModule *moduleTable = 
746                             (struct Win32sModule *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
747         struct Win32sModule *module = moduleTable + context->Ecx;
748
749         IMAGE_NT_HEADERS *nt_header = PE_HEADER(module->baseAddr);
750         IMAGE_SECTION_HEADER *pe_seg = PE_SECTIONS(module->baseAddr);
751
752         HFILE image = _lopen(module->pathName, OF_READ);
753         BOOL error = (image == HFILE_ERROR);
754         UINT i;
755
756         TRACE("MapModule: Loading %s\n", module->pathName);
757
758         for (i = 0; 
759              !error && i < nt_header->FileHeader.NumberOfSections; 
760              i++, pe_seg++)
761             if(!(pe_seg->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA))
762             {
763                 DWORD  off  = pe_seg->PointerToRawData;
764                 DWORD  len  = pe_seg->SizeOfRawData;
765                 LPBYTE addr = module->baseAddr + pe_seg->VirtualAddress;
766
767                 TRACE("MapModule: "
768                            "Section %d at %08lx from %08lx len %08lx\n", 
769                            i, (DWORD)addr, off, len);
770
771                 if (   _llseek(image, off, SEEK_SET) != off
772                     || _lread(image, addr, len) != len)
773                     error = TRUE;
774             }
775         
776         _lclose(image);
777
778         if (error)
779             ERR("MapModule: Unable to load %s\n", module->pathName);
780
781         else if (module->relocDelta != 0)
782         {
783             IMAGE_DATA_DIRECTORY *dir = nt_header->OptionalHeader.DataDirectory
784                                       + IMAGE_DIRECTORY_ENTRY_BASERELOC;
785             IMAGE_BASE_RELOCATION *r = (IMAGE_BASE_RELOCATION *)
786                 (dir->Size? module->baseAddr + dir->VirtualAddress : 0);
787
788             TRACE("MapModule: Reloc delta %08lx\n", module->relocDelta);
789
790             while (r && r->VirtualAddress)
791             {
792                 LPBYTE page  = module->baseAddr + r->VirtualAddress;
793                 int    count = (r->SizeOfBlock - 8) / 2;
794
795                 TRACE("MapModule: %d relocations for page %08lx\n", 
796                            count, (DWORD)page);
797
798                 for(i = 0; i < count; i++)
799                 {
800                     int offset = r->TypeOffset[i] & 0xFFF;
801                     int type   = r->TypeOffset[i] >> 12;
802                     switch(type)
803                     {
804                     case IMAGE_REL_BASED_ABSOLUTE: 
805                         break;
806                     case IMAGE_REL_BASED_HIGH:
807                         *(WORD *)(page+offset) += HIWORD(module->relocDelta);
808                         break;
809                     case IMAGE_REL_BASED_LOW:
810                         *(WORD *)(page+offset) += LOWORD(module->relocDelta);
811                         break;
812                     case IMAGE_REL_BASED_HIGHLOW:
813                         *(DWORD*)(page+offset) += module->relocDelta;
814                         break;
815                     default:
816                         WARN("MapModule: Unsupported fixup type\n");
817                         break;
818                     }
819                 }
820
821                 r = (IMAGE_BASE_RELOCATION *)((LPBYTE)r + r->SizeOfBlock);
822             }
823         }
824
825         context->Eax = 0;
826         RESET_CFLAG(context);
827     }
828     break;
829
830
831     case 0x0005: /* UnMap Module */
832         /*
833          * Input:   EDX: Flat address of module image 
834          *
835          * Output:  EAX: 1 if OK
836          */
837         
838         TRACE("UnMapModule: %lx\n", (DWORD)W32S_APP2WINE(context->Edx, W32S_OFFSET));
839
840         /* As we didn't map anything, there's nothing to unmap ... */
841
842         context->Eax = 1;
843         break;
844
845
846     case 0x0006: /* VirtualAlloc */
847         /* 
848          * Input:   ECX: Current Process
849          *
850          *          EDX: Flat address of arguments on stack
851          * 
852          *   DWORD *retv     [out] Flat base address of allocated region
853          *   LPVOID base     [in]  Flat address of region to reserve/commit
854          *   DWORD  size     [in]  Size of region
855          *   DWORD  type     [in]  Type of allocation
856          *   DWORD  prot     [in]  Type of access protection
857          *
858          * Output:  EAX: NtStatus
859          */
860     {
861         DWORD *stack  = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
862         DWORD *retv   = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
863         LPVOID base   = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
864         DWORD  size   = stack[2];
865         DWORD  type   = stack[3];
866         DWORD  prot   = stack[4];
867         DWORD  result;
868
869         TRACE("VirtualAlloc(%lx, %lx, %lx, %lx, %lx)\n", 
870                    (DWORD)retv, (DWORD)base, size, type, prot);
871
872         if (type & 0x80000000)
873         {
874             WARN("VirtualAlloc: strange type %lx\n", type);
875             type &= 0x7fffffff;
876         }
877
878         if (!base && (type & MEM_COMMIT) && prot == PAGE_READONLY)
879         {
880             WARN("VirtualAlloc: NLS hack, allowing write access!\n");
881             prot = PAGE_READWRITE;
882         }
883
884         result = (DWORD)VirtualAlloc(base, size, type, prot);
885
886         if (W32S_WINE2APP(result, W32S_OFFSET))
887             *retv            = W32S_WINE2APP(result, W32S_OFFSET),
888             context->Eax = STATUS_SUCCESS;
889         else
890             *retv            = 0,
891             context->Eax = STATUS_NO_MEMORY;  /* FIXME */
892     }
893     break;
894
895
896     case 0x0007: /* VirtualFree */
897         /* 
898          * Input:   ECX: Current Process
899          *
900          *          EDX: Flat address of arguments on stack
901          * 
902          *   DWORD *retv     [out] TRUE if success, FALSE if failure
903          *   LPVOID base     [in]  Flat address of region
904          *   DWORD  size     [in]  Size of region
905          *   DWORD  type     [in]  Type of operation
906          *
907          * Output:  EAX: NtStatus
908          */
909     {
910         DWORD *stack  = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
911         DWORD *retv   = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
912         LPVOID base   = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
913         DWORD  size   = stack[2];
914         DWORD  type   = stack[3];
915         DWORD  result;
916
917         TRACE("VirtualFree(%lx, %lx, %lx, %lx)\n", 
918                    (DWORD)retv, (DWORD)base, size, type);
919
920         result = VirtualFree(base, size, type);
921
922         if (result)
923             *retv            = TRUE,
924             context->Eax = STATUS_SUCCESS;
925         else
926             *retv            = FALSE,
927             context->Eax = STATUS_NO_MEMORY;  /* FIXME */
928     }
929     break;
930
931
932     case 0x0008: /* VirtualProtect */
933         /* 
934          * Input:   ECX: Current Process
935          *
936          *          EDX: Flat address of arguments on stack
937          * 
938          *   DWORD *retv     [out] TRUE if success, FALSE if failure
939          *   LPVOID base     [in]  Flat address of region
940          *   DWORD  size     [in]  Size of region
941          *   DWORD  new_prot [in]  Desired access protection
942          *   DWORD *old_prot [out] Previous access protection
943          *
944          * Output:  EAX: NtStatus
945          */
946     {
947         DWORD *stack    = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
948         DWORD *retv     = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
949         LPVOID base     = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
950         DWORD  size     = stack[2];
951         DWORD  new_prot = stack[3];
952         DWORD *old_prot = (DWORD *)W32S_APP2WINE(stack[4], W32S_OFFSET);
953         DWORD  result;
954
955         TRACE("VirtualProtect(%lx, %lx, %lx, %lx, %lx)\n", 
956                    (DWORD)retv, (DWORD)base, size, new_prot, (DWORD)old_prot);
957
958         result = VirtualProtect(base, size, new_prot, old_prot);
959
960         if (result)
961             *retv            = TRUE,
962             context->Eax = STATUS_SUCCESS;
963         else
964             *retv            = FALSE,
965             context->Eax = STATUS_NO_MEMORY;  /* FIXME */
966     }
967     break;
968
969
970     case 0x0009: /* VirtualQuery */
971         /* 
972          * Input:   ECX: Current Process
973          *
974          *          EDX: Flat address of arguments on stack
975          * 
976          *   DWORD *retv                     [out] Nr. bytes returned
977          *   LPVOID base                     [in]  Flat address of region
978          *   LPMEMORY_BASIC_INFORMATION info [out] Info buffer
979          *   DWORD  len                      [in]  Size of buffer
980          *
981          * Output:  EAX: NtStatus
982          */
983     {
984         DWORD *stack  = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
985         DWORD *retv   = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
986         LPVOID base   = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
987         LPMEMORY_BASIC_INFORMATION info = 
988                         (LPMEMORY_BASIC_INFORMATION)W32S_APP2WINE(stack[2], W32S_OFFSET);
989         DWORD  len    = stack[3];
990         DWORD  result;
991
992         TRACE("VirtualQuery(%lx, %lx, %lx, %lx)\n", 
993                    (DWORD)retv, (DWORD)base, (DWORD)info, len);
994
995         result = VirtualQuery(base, info, len);
996
997         *retv            = result;
998         context->Eax = STATUS_SUCCESS;
999     }
1000     break;
1001
1002
1003     case 0x000A: /* SetVirtMemProcess */
1004         /*
1005          * Input:   ECX: Process Handle
1006          *
1007          *          EDX: Flat address of region
1008          *
1009          * Output:  EAX: NtStatus
1010          */
1011
1012         TRACE("[000a] ECX=%lx EDX=%lx\n",
1013                    context->Ecx, context->Edx);
1014
1015         /* FIXME */
1016
1017         context->Eax = STATUS_SUCCESS;
1018         break;
1019
1020
1021     case 0x000B: /* ??? some kind of cleanup */
1022         /*
1023          * Input:   ECX: Process Handle
1024          *
1025          * Output:  EAX: NtStatus
1026          */
1027
1028         TRACE("[000b] ECX=%lx\n", context->Ecx);
1029
1030         /* FIXME */
1031
1032         context->Eax = STATUS_SUCCESS;
1033         break;
1034
1035
1036     case 0x000C: /* Set Debug Flags */
1037         /*
1038          * Input:   EDX: Debug Flags
1039          *
1040          * Output:  EDX: Previous Debug Flags
1041          */
1042
1043         FIXME("[000c] EDX=%lx\n", context->Edx);
1044
1045         /* FIXME */
1046
1047         context->Edx = 0;
1048         break;
1049
1050
1051     case 0x000D: /* NtCreateSection */
1052         /* 
1053          * Input:   EDX: Flat address of arguments on stack
1054          * 
1055          *   HANDLE32 *retv      [out] Handle of Section created
1056          *   DWORD  flags1       [in]  (?? unknown ??)
1057          *   DWORD  atom         [in]  Name of Section to create
1058          *   LARGE_INTEGER *size [in]  Size of Section
1059          *   DWORD  protect      [in]  Access protection
1060          *   DWORD  flags2       [in]  (?? unknown ??)
1061          *   HFILE32 hFile       [in]  Handle of file to map
1062          *   DWORD  psp          [in]  (Win32s: PSP that hFile belongs to)
1063          *
1064          * Output:  EAX: NtStatus
1065          */
1066     {
1067         DWORD *stack    = (DWORD *)   W32S_APP2WINE(context->Edx, W32S_OFFSET);
1068         HANDLE *retv  = (HANDLE *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1069         DWORD  flags1   = stack[1];
1070         DWORD  atom     = stack[2];
1071         LARGE_INTEGER *size = (LARGE_INTEGER *)W32S_APP2WINE(stack[3], W32S_OFFSET);
1072         DWORD  protect  = stack[4];
1073         DWORD  flags2   = stack[5];
1074         HANDLE hFile    = DosFileHandleToWin32Handle(stack[6]);
1075         DWORD  psp      = stack[7];
1076
1077         HANDLE result = INVALID_HANDLE_VALUE;
1078         char name[128];
1079
1080         TRACE("NtCreateSection(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1081                    (DWORD)retv, flags1, atom, (DWORD)size, protect, flags2,
1082                    (DWORD)hFile, psp);
1083
1084         if (!atom || GlobalGetAtomNameA(atom, name, sizeof(name)))
1085         {
1086             TRACE("NtCreateSection: name=%s\n", atom? name : NULL);
1087
1088             result = CreateFileMappingA(hFile, NULL, protect, 
1089                                           size? size->s.HighPart : 0, 
1090                                           size? size->s.LowPart  : 0, 
1091                                           atom? name : NULL);
1092         }
1093
1094         if (result == INVALID_HANDLE_VALUE)
1095             WARN("NtCreateSection: failed!\n");
1096         else
1097             TRACE("NtCreateSection: returned %lx\n", (DWORD)result);
1098
1099         if (result != INVALID_HANDLE_VALUE)
1100             *retv            = result,
1101             context->Eax = STATUS_SUCCESS;
1102         else
1103             *retv            = result,
1104             context->Eax = STATUS_NO_MEMORY;   /* FIXME */
1105     }
1106     break;
1107
1108
1109     case 0x000E: /* NtOpenSection */
1110         /* 
1111          * Input:   EDX: Flat address of arguments on stack
1112          * 
1113          *   HANDLE32 *retv  [out] Handle of Section opened
1114          *   DWORD  protect  [in]  Access protection
1115          *   DWORD  atom     [in]  Name of Section to create
1116          *
1117          * Output:  EAX: NtStatus
1118          */
1119     {
1120         DWORD *stack    = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
1121         HANDLE *retv  = (HANDLE *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1122         DWORD  protect  = stack[1];
1123         DWORD  atom     = stack[2];
1124
1125         HANDLE result = INVALID_HANDLE_VALUE;
1126         char name[128];
1127
1128         TRACE("NtOpenSection(%lx, %lx, %lx)\n", 
1129                    (DWORD)retv, protect, atom);
1130
1131         if (atom && GlobalGetAtomNameA(atom, name, sizeof(name)))
1132         {
1133             TRACE("NtOpenSection: name=%s\n", name);
1134
1135             result = OpenFileMappingA(protect, FALSE, name);
1136         }
1137
1138         if (result == INVALID_HANDLE_VALUE)
1139             WARN("NtOpenSection: failed!\n");
1140         else
1141             TRACE("NtOpenSection: returned %lx\n", (DWORD)result);
1142
1143         if (result != INVALID_HANDLE_VALUE)
1144             *retv            = result,
1145             context->Eax = STATUS_SUCCESS;
1146         else
1147             *retv            = result,
1148             context->Eax = STATUS_NO_MEMORY;   /* FIXME */
1149     }
1150     break;
1151
1152
1153     case 0x000F: /* NtCloseSection */
1154         /* 
1155          * Input:   EDX: Flat address of arguments on stack
1156          * 
1157          *   HANDLE32 handle  [in]  Handle of Section to close
1158          *   DWORD *id        [out] Unique ID  (?? unclear ??)
1159          *
1160          * Output:  EAX: NtStatus
1161          */
1162     {
1163         DWORD *stack    = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
1164         HANDLE handle = stack[0];
1165         DWORD *id       = (DWORD *)W32S_APP2WINE(stack[1], W32S_OFFSET);
1166
1167         TRACE("NtCloseSection(%lx, %lx)\n", (DWORD)handle, (DWORD)id);
1168
1169         CloseHandle(handle);
1170         if (id) *id = 0; /* FIXME */
1171
1172         context->Eax = STATUS_SUCCESS;
1173     }
1174     break;
1175
1176
1177     case 0x0010: /* NtDupSection */
1178         /* 
1179          * Input:   EDX: Flat address of arguments on stack
1180          * 
1181          *   HANDLE32 handle  [in]  Handle of Section to duplicate
1182          *
1183          * Output:  EAX: NtStatus
1184          */
1185     {
1186         DWORD *stack    = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
1187         HANDLE handle = stack[0];
1188         HANDLE new_handle;
1189
1190         TRACE("NtDupSection(%lx)\n", (DWORD)handle);
1191  
1192         DuplicateHandle( GetCurrentProcess(), handle,
1193                          GetCurrentProcess(), &new_handle,
1194                          0, FALSE, DUPLICATE_SAME_ACCESS );
1195         context->Eax = STATUS_SUCCESS;
1196     }
1197     break;
1198
1199
1200     case 0x0011: /* NtMapViewOfSection */
1201         /* 
1202          * Input:   EDX: Flat address of arguments on stack
1203          * 
1204          *   HANDLE32 SectionHandle       [in]     Section to be mapped
1205          *   DWORD    ProcessHandle       [in]     Process to be mapped into
1206          *   DWORD *  BaseAddress         [in/out] Address to be mapped at
1207          *   DWORD    ZeroBits            [in]     (?? unclear ??)
1208          *   DWORD    CommitSize          [in]     (?? unclear ??)
1209          *   LARGE_INTEGER *SectionOffset [in]     Offset within section
1210          *   DWORD *  ViewSize            [in]     Size of view
1211          *   DWORD    InheritDisposition  [in]     (?? unclear ??)
1212          *   DWORD    AllocationType      [in]     (?? unclear ??)
1213          *   DWORD    Protect             [in]     Access protection
1214          *
1215          * Output:  EAX: NtStatus
1216          */
1217     {
1218         DWORD *  stack          = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
1219         HANDLE SectionHandle  = stack[0];
1220         DWORD    ProcessHandle  = stack[1]; /* ignored */
1221         DWORD *  BaseAddress    = (DWORD *)W32S_APP2WINE(stack[2], W32S_OFFSET);
1222         DWORD    ZeroBits       = stack[3];
1223         DWORD    CommitSize     = stack[4];
1224         LARGE_INTEGER *SectionOffset = (LARGE_INTEGER *)W32S_APP2WINE(stack[5], W32S_OFFSET);
1225         DWORD *  ViewSize       = (DWORD *)W32S_APP2WINE(stack[6], W32S_OFFSET);
1226         DWORD    InheritDisposition = stack[7];
1227         DWORD    AllocationType = stack[8];
1228         DWORD    Protect        = stack[9];
1229
1230         LPBYTE address = (LPBYTE)(BaseAddress?
1231                         W32S_APP2WINE(*BaseAddress, W32S_OFFSET) : 0);
1232         DWORD  access = 0, result;
1233
1234         switch (Protect & ~(PAGE_GUARD|PAGE_NOCACHE))
1235         {
1236             case PAGE_READONLY:           access = FILE_MAP_READ;  break;
1237             case PAGE_READWRITE:          access = FILE_MAP_WRITE; break;
1238             case PAGE_WRITECOPY:          access = FILE_MAP_COPY;  break;
1239
1240             case PAGE_EXECUTE_READ:       access = FILE_MAP_READ;  break;
1241             case PAGE_EXECUTE_READWRITE:  access = FILE_MAP_WRITE; break;
1242             case PAGE_EXECUTE_WRITECOPY:  access = FILE_MAP_COPY;  break;
1243         }
1244
1245         TRACE("NtMapViewOfSection"
1246                    "(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1247                    (DWORD)SectionHandle, ProcessHandle, (DWORD)BaseAddress, 
1248                    ZeroBits, CommitSize, (DWORD)SectionOffset, (DWORD)ViewSize,
1249                    InheritDisposition, AllocationType, Protect);
1250         TRACE("NtMapViewOfSection: "
1251                    "base=%lx, offset=%lx, size=%lx, access=%lx\n", 
1252                    (DWORD)address, SectionOffset? SectionOffset->s.LowPart : 0, 
1253                    ViewSize? *ViewSize : 0, access);
1254
1255         result = (DWORD)MapViewOfFileEx(SectionHandle, access, 
1256                             SectionOffset? SectionOffset->s.HighPart : 0, 
1257                             SectionOffset? SectionOffset->s.LowPart  : 0,
1258                             ViewSize? *ViewSize : 0, address);
1259
1260         TRACE("NtMapViewOfSection: result=%lx\n", result);
1261
1262         if (W32S_WINE2APP(result, W32S_OFFSET))
1263         {
1264             if (BaseAddress) *BaseAddress = W32S_WINE2APP(result, W32S_OFFSET);
1265             context->Eax = STATUS_SUCCESS;
1266         }
1267         else
1268             context->Eax = STATUS_NO_MEMORY; /* FIXME */
1269     }
1270     break;
1271
1272
1273     case 0x0012: /* NtUnmapViewOfSection */
1274         /* 
1275          * Input:   EDX: Flat address of arguments on stack
1276          * 
1277          *   DWORD  ProcessHandle  [in]  Process (defining address space)
1278          *   LPBYTE BaseAddress    [in]  Base address of view to be unmapped
1279          *
1280          * Output:  EAX: NtStatus
1281          */
1282     {
1283         DWORD *stack          = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
1284         DWORD  ProcessHandle  = stack[0]; /* ignored */
1285         LPBYTE BaseAddress    = (LPBYTE)W32S_APP2WINE(stack[1], W32S_OFFSET);
1286
1287         TRACE("NtUnmapViewOfSection(%lx, %lx)\n", 
1288                    ProcessHandle, (DWORD)BaseAddress);
1289
1290         UnmapViewOfFile(BaseAddress);
1291
1292         context->Eax = STATUS_SUCCESS;
1293     }
1294     break;
1295
1296
1297     case 0x0013: /* NtFlushVirtualMemory */
1298         /* 
1299          * Input:   EDX: Flat address of arguments on stack
1300          * 
1301          *   DWORD   ProcessHandle  [in]  Process (defining address space)
1302          *   LPBYTE *BaseAddress    [in?] Base address of range to be flushed
1303          *   DWORD  *ViewSize       [in?] Number of bytes to be flushed
1304          *   DWORD  *unknown        [???] (?? unknown ??)
1305          *
1306          * Output:  EAX: NtStatus
1307          */
1308     {
1309         DWORD *stack          = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
1310         DWORD  ProcessHandle  = stack[0]; /* ignored */
1311         DWORD *BaseAddress    = (DWORD *)W32S_APP2WINE(stack[1], W32S_OFFSET);
1312         DWORD *ViewSize       = (DWORD *)W32S_APP2WINE(stack[2], W32S_OFFSET);
1313         DWORD *unknown        = (DWORD *)W32S_APP2WINE(stack[3], W32S_OFFSET);
1314         
1315         LPBYTE address = (LPBYTE)(BaseAddress? W32S_APP2WINE(*BaseAddress, W32S_OFFSET) : 0);
1316         DWORD  size    = ViewSize? *ViewSize : 0;
1317
1318         TRACE("NtFlushVirtualMemory(%lx, %lx, %lx, %lx)\n", 
1319                    ProcessHandle, (DWORD)BaseAddress, (DWORD)ViewSize, 
1320                    (DWORD)unknown);
1321         TRACE("NtFlushVirtualMemory: base=%lx, size=%lx\n", 
1322                    (DWORD)address, size);
1323
1324         FlushViewOfFile(address, size);
1325
1326         context->Eax = STATUS_SUCCESS;
1327     }
1328     break;
1329
1330
1331     case 0x0014: /* Get/Set Debug Registers */
1332         /*
1333          * Input:   ECX: 0 if Get, 1 if Set
1334          *
1335          *          EDX: Get: Flat address of buffer to receive values of
1336          *                    debug registers DR0 .. DR7
1337          *               Set: Flat address of buffer containing values of
1338          *                    debug registers DR0 .. DR7 to be set
1339          * Output:  None
1340          */
1341
1342         FIXME("[0014] ECX=%lx EDX=%lx\n", 
1343                    context->Ecx, context->Edx);
1344
1345         /* FIXME */
1346         break;
1347
1348
1349     case 0x0015: /* Set Coprocessor Emulation Flag */
1350         /*
1351          * Input:   EDX: 0 to deactivate, 1 to activate coprocessor emulation
1352          *
1353          * Output:  None
1354          */
1355
1356         TRACE("[0015] EDX=%lx\n", context->Edx);
1357
1358         /* We don't care, as we always have a coprocessor anyway */
1359         break;
1360
1361
1362     case 0x0016: /* Init Win32S VxD PSP */
1363         /*
1364          * If called to query required PSP size:
1365          *
1366          *     Input:  EBX: 0
1367          *     Output: EDX: Required size of Win32s VxD PSP
1368          *
1369          * If called to initialize allocated PSP:
1370          *
1371          *     Input:  EBX: LoWord: Selector of Win32s VxD PSP
1372          *                  HiWord: Paragraph of Win32s VxD PSP (DOSMEM)
1373          *     Output: None
1374          */
1375  
1376         if (context->Ebx == 0)
1377             context->Edx = 0x80;
1378         else
1379         {
1380             PDB16 *psp = PTR_SEG_OFF_TO_LIN(BX_reg(context), 0);
1381             psp->nbFiles = 32;
1382             psp->fileHandlesPtr = MAKELONG(HIWORD(context->Ebx), 0x5c);
1383             memset((LPBYTE)psp + 0x5c, '\xFF', 32);
1384         }
1385         break;
1386
1387
1388     case 0x0017: /* Set Break Point */
1389         /*
1390          * Input:   EBX: Offset of Break Point
1391          *          CX:  Selector of Break Point
1392          *
1393          * Output:  None
1394          */
1395
1396         FIXME("[0017] EBX=%lx CX=%x\n", 
1397                    context->Ebx, CX_reg(context));
1398
1399         /* FIXME */
1400         break;
1401
1402
1403     case 0x0018: /* VirtualLock */
1404         /* 
1405          * Input:   ECX: Current Process
1406          *
1407          *          EDX: Flat address of arguments on stack
1408          * 
1409          *   DWORD *retv     [out] TRUE if success, FALSE if failure
1410          *   LPVOID base     [in]  Flat address of range to lock
1411          *   DWORD  size     [in]  Size of range
1412          *
1413          * Output:  EAX: NtStatus
1414          */
1415     {
1416         DWORD *stack  = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
1417         DWORD *retv   = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1418         LPVOID base   = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
1419         DWORD  size   = stack[2];
1420         DWORD  result;
1421
1422         TRACE("VirtualLock(%lx, %lx, %lx)\n", 
1423                    (DWORD)retv, (DWORD)base, size);
1424
1425         result = VirtualLock(base, size);
1426
1427         if (result)
1428             *retv            = TRUE,
1429             context->Eax = STATUS_SUCCESS;
1430         else
1431             *retv            = FALSE,
1432             context->Eax = STATUS_NO_MEMORY;  /* FIXME */
1433     }
1434     break;
1435
1436
1437     case 0x0019: /* VirtualUnlock */
1438         /* 
1439          * Input:   ECX: Current Process
1440          *
1441          *          EDX: Flat address of arguments on stack
1442          * 
1443          *   DWORD *retv     [out] TRUE if success, FALSE if failure
1444          *   LPVOID base     [in]  Flat address of range to unlock
1445          *   DWORD  size     [in]  Size of range
1446          *
1447          * Output:  EAX: NtStatus
1448          */
1449     {
1450         DWORD *stack  = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
1451         DWORD *retv   = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1452         LPVOID base   = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
1453         DWORD  size   = stack[2];
1454         DWORD  result;
1455
1456         TRACE("VirtualUnlock(%lx, %lx, %lx)\n", 
1457                    (DWORD)retv, (DWORD)base, size);
1458
1459         result = VirtualUnlock(base, size);
1460
1461         if (result)
1462             *retv            = TRUE,
1463             context->Eax = STATUS_SUCCESS;
1464         else
1465             *retv            = FALSE,
1466             context->Eax = STATUS_NO_MEMORY;  /* FIXME */
1467     }
1468     break;
1469
1470
1471     case 0x001A: /* KGetSystemInfo */
1472         /*
1473          * Input:   None
1474          *
1475          * Output:  ECX:  Start of sparse memory arena
1476          *          EDX:  End of sparse memory arena
1477          */
1478
1479         TRACE("KGetSystemInfo()\n");
1480         
1481         /*
1482          * Note: Win32s reserves 0GB - 2GB for Win 3.1 and uses 2GB - 4GB as 
1483          *       sparse memory arena. We do it the other way around, since 
1484          *       we have to reserve 3GB - 4GB for Linux, and thus use
1485          *       0GB - 3GB as sparse memory arena.
1486          *
1487          *       FIXME: What about other OSes ?
1488          */
1489
1490         context->Ecx = W32S_WINE2APP(0x00000000, W32S_OFFSET);
1491         context->Edx = W32S_WINE2APP(0xbfffffff, W32S_OFFSET);
1492         break;
1493
1494
1495     case 0x001B: /* KGlobalMemStat */
1496         /*
1497          * Input:   ESI: Flat address of buffer to receive memory info
1498          *
1499          * Output:  None
1500          */
1501     {
1502         struct Win32sMemoryInfo
1503         {
1504             DWORD DIPhys_Count;       /* Total physical pages */
1505             DWORD DIFree_Count;       /* Free physical pages */
1506             DWORD DILin_Total_Count;  /* Total virtual pages (private arena) */
1507             DWORD DILin_Total_Free;   /* Free virtual pages (private arena) */
1508
1509             DWORD SparseTotal;        /* Total size of sparse arena (bytes ?) */
1510             DWORD SparseFree;         /* Free size of sparse arena (bytes ?) */
1511         };
1512
1513         struct Win32sMemoryInfo *info = 
1514                        (struct Win32sMemoryInfo *)W32S_APP2WINE(context->Esi, W32S_OFFSET);
1515
1516         FIXME("KGlobalMemStat(%lx)\n", (DWORD)info);
1517
1518         /* FIXME */
1519     }
1520     break;
1521
1522
1523     case 0x001C: /* Enable/Disable Exceptions */
1524         /*
1525          * Input:   ECX: 0 to disable, 1 to enable exception handling
1526          *
1527          * Output:  None
1528          */
1529
1530         TRACE("[001c] ECX=%lx\n", context->Ecx);
1531
1532         /* FIXME */
1533         break;
1534
1535
1536     case 0x001D: /* VirtualAlloc called from 16-bit code */
1537         /* 
1538          * Input:   EDX: Segmented address of arguments on stack
1539          * 
1540          *   LPVOID base     [in]  Flat address of region to reserve/commit
1541          *   DWORD  size     [in]  Size of region
1542          *   DWORD  type     [in]  Type of allocation
1543          *   DWORD  prot     [in]  Type of access protection
1544          *
1545          * Output:  EAX: NtStatus
1546          *          EDX: Flat base address of allocated region
1547          */
1548     {
1549         DWORD *stack  = PTR_SEG_OFF_TO_LIN(LOWORD(context->Edx), 
1550                                            HIWORD(context->Edx));
1551         LPVOID base   = (LPVOID)W32S_APP2WINE(stack[0], W32S_OFFSET);
1552         DWORD  size   = stack[1];
1553         DWORD  type   = stack[2];
1554         DWORD  prot   = stack[3];
1555         DWORD  result;
1556
1557         TRACE("VirtualAlloc16(%lx, %lx, %lx, %lx)\n", 
1558                    (DWORD)base, size, type, prot);
1559
1560         if (type & 0x80000000)
1561         {
1562             WARN("VirtualAlloc16: strange type %lx\n", type);
1563             type &= 0x7fffffff;
1564         }
1565
1566         result = (DWORD)VirtualAlloc(base, size, type, prot);
1567
1568         if (W32S_WINE2APP(result, W32S_OFFSET))
1569             context->Edx = W32S_WINE2APP(result, W32S_OFFSET),
1570             context->Eax = STATUS_SUCCESS;
1571         else
1572             context->Edx = 0,
1573             context->Eax = STATUS_NO_MEMORY;  /* FIXME */
1574         TRACE("VirtualAlloc16: returning base %lx\n", context->Edx);
1575     }
1576     break;
1577
1578
1579     case 0x001E: /* VirtualFree called from 16-bit code */
1580         /* 
1581          * Input:   EDX: Segmented address of arguments on stack
1582          * 
1583          *   LPVOID base     [in]  Flat address of region
1584          *   DWORD  size     [in]  Size of region
1585          *   DWORD  type     [in]  Type of operation
1586          *
1587          * Output:  EAX: NtStatus
1588          *          EDX: TRUE if success, FALSE if failure
1589          */
1590     {
1591         DWORD *stack  = PTR_SEG_OFF_TO_LIN(LOWORD(context->Edx), 
1592                                            HIWORD(context->Edx));
1593         LPVOID base   = (LPVOID)W32S_APP2WINE(stack[0], W32S_OFFSET);
1594         DWORD  size   = stack[1];
1595         DWORD  type   = stack[2];
1596         DWORD  result;
1597
1598         TRACE("VirtualFree16(%lx, %lx, %lx)\n", 
1599                    (DWORD)base, size, type);
1600
1601         result = VirtualFree(base, size, type);
1602
1603         if (result)
1604             context->Edx = TRUE,
1605             context->Eax = STATUS_SUCCESS;
1606         else
1607             context->Edx = FALSE,
1608             context->Eax = STATUS_NO_MEMORY;  /* FIXME */
1609     }
1610     break;
1611
1612
1613     case 0x001F: /* FWorkingSetSize */
1614         /*
1615          * Input:   EDX: 0 if Get, 1 if Set
1616          *
1617          *          ECX: Get: Buffer to receive Working Set Size
1618          *               Set: Buffer containing Working Set Size
1619          *
1620          * Output:  NtStatus
1621          */
1622     {
1623         DWORD *ptr = (DWORD *)W32S_APP2WINE(context->Ecx, W32S_OFFSET);
1624         BOOL set = context->Edx;
1625         
1626         TRACE("FWorkingSetSize(%lx, %lx)\n", (DWORD)ptr, (DWORD)set);
1627
1628         if (set)
1629             /* We do it differently ... */;
1630         else
1631             *ptr = 0x100;
1632
1633         context->Eax = STATUS_SUCCESS;
1634     }
1635     break;
1636
1637
1638     default:
1639         VXD_BARF( context, "W32S" );
1640     }
1641
1642 }
1643