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