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