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