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