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