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