blob: 69c791e19b91db5624e0378cb8e3118776dfa81d [file] [log] [blame]
Alexandre Julliardaf0bae51995-10-03 17:06:08 +00001/*
2 * VxD emulation
3 *
4 * Copyright 1995 Anand Kumria
5 */
6
Alexandre Julliard642d3131998-07-12 19:29:36 +00007#include <fcntl.h>
8#include <memory.h>
Jeremy Whited3e22d92000-02-10 19:03:02 +00009#include <sys/types.h>
10#include <unistd.h>
Alexandre Julliard642d3131998-07-12 19:29:36 +000011#include "winbase.h"
Jeremy Whited3e22d92000-02-10 19:03:02 +000012#include "windef.h"
13#include "wingdi.h"
Marcus Meissner219cfd81999-02-24 13:05:13 +000014#include "winuser.h"
15#include "wine/winbase16.h"
16#include "wine/winuser16.h"
Alexandre Julliardaf0bae51995-10-03 17:06:08 +000017#include "msdos.h"
18#include "miscemu.h"
Alexandre Julliard642d3131998-07-12 19:29:36 +000019#include "selectors.h"
Marcus Meissner317af321999-02-17 13:51:06 +000020#include "neexe.h"
Alexandre Julliard642d3131998-07-12 19:29:36 +000021#include "task.h"
22#include "process.h"
23#include "file.h"
Alexandre Julliard61fece01999-06-26 19:09:08 +000024#include "debugtools.h"
Alexandre Julliardaf0bae51995-10-03 17:06:08 +000025
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000026DEFAULT_DEBUG_CHANNEL(vxd)
27
Alexandre Julliardaf0bae51995-10-03 17:06:08 +000028
Alexandre Julliard139a4b11996-11-02 14:24:07 +000029#define VXD_BARF(context,name) \
Alexandre Julliard61fece01999-06-26 19:09:08 +000030 DPRINTF( "vxd %s: unknown/not implemented parameters:\n" \
Alexandre Julliard139a4b11996-11-02 14:24:07 +000031 "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), \
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +000035 DI_reg(context), (WORD)context->SegDs, (WORD)context->SegEs )
Alexandre Julliard139a4b11996-11-02 14:24:07 +000036
Alexandre Julliard670cdc41997-08-24 16:00:30 +000037
38static WORD VXD_WinVersion(void)
39{
Alexandre Julliard3db94ef1997-09-28 17:43:24 +000040 WORD version = LOWORD(GetVersion16());
Alexandre Julliard670cdc41997-08-24 16:00:30 +000041 return (version >> 8) | (version << 8);
42}
43
Alexandre Julliardaf0bae51995-10-03 17:06:08 +000044/***********************************************************************
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000045 * VXD_VMM
46 */
Ulrich Weigandff9c44f1999-06-27 15:28:51 +000047void WINAPI VXD_VMM ( CONTEXT86 *context )
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000048{
49 unsigned service = AX_reg(context);
50
Alexandre Julliard908464d2000-11-01 03:11:12 +000051 TRACE("[%04x] VMM\n", (UINT16)service);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000052
53 switch(service)
54 {
55 case 0x0000: /* version */
56 AX_reg(context) = VXD_WinVersion();
57 RESET_CFLAG(context);
58 break;
59
Ulrich Weigandff1c5691998-10-14 18:01:08 +000060 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
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000066 default:
67 VXD_BARF( context, "VMM" );
68 }
69}
70
71/***********************************************************************
Alexandre Julliardaf0bae51995-10-03 17:06:08 +000072 * VXD_PageFile
73 */
Alexandre Julliard617955d1999-06-26 18:40:24 +000074void WINAPI VXD_PageFile( CONTEXT86 *context )
Alexandre Julliardaf0bae51995-10-03 17:06:08 +000075{
Alexandre Julliard670cdc41997-08-24 16:00:30 +000076 unsigned service = AX_reg(context);
77
Alexandre Julliardaf0bae51995-10-03 17:06:08 +000078 /* taken from Ralf Brown's Interrupt List */
79
Alexandre Julliard61fece01999-06-26 19:09:08 +000080 TRACE("[%04x] PageFile\n", (UINT16)service );
Alexandre Julliardaf0bae51995-10-03 17:06:08 +000081
Alexandre Julliard670cdc41997-08-24 16:00:30 +000082 switch(service)
Alexandre Julliardaf0bae51995-10-03 17:06:08 +000083 {
84 case 0x00: /* get version, is this windows version? */
Alexandre Julliard61fece01999-06-26 19:09:08 +000085 TRACE("returning version\n");
Alexandre Julliard670cdc41997-08-24 16:00:30 +000086 AX_reg(context) = VXD_WinVersion();
Alexandre Julliardca22b331996-07-12 19:02:39 +000087 RESET_CFLAG(context);
Alexandre Julliardaf0bae51995-10-03 17:06:08 +000088 break;
89
90 case 0x01: /* get swap file info */
Alexandre Julliard61fece01999-06-26 19:09:08 +000091 TRACE("VxD PageFile: returning swap file info\n");
Alexandre Julliardca22b331996-07-12 19:02:39 +000092 AX_reg(context) = 0x00; /* paging disabled */
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +000093 context->Ecx = 0; /* maximum size of paging file */
Alexandre Julliardaf0bae51995-10-03 17:06:08 +000094 /* FIXME: do I touch DS:SI or DS:DI? */
Alexandre Julliardca22b331996-07-12 19:02:39 +000095 RESET_CFLAG(context);
Alexandre Julliardaf0bae51995-10-03 17:06:08 +000096 break;
97
98 case 0x02: /* delete permanent swap on exit */
Alexandre Julliard61fece01999-06-26 19:09:08 +000099 TRACE("VxD PageFile: supposed to delete swap\n");
Alexandre Julliardca22b331996-07-12 19:02:39 +0000100 RESET_CFLAG(context);
Alexandre Julliardaf0bae51995-10-03 17:06:08 +0000101 break;
102
103 case 0x03: /* current temporary swap file size */
Alexandre Julliard61fece01999-06-26 19:09:08 +0000104 TRACE("VxD PageFile: what is current temp. swap size\n");
Alexandre Julliardca22b331996-07-12 19:02:39 +0000105 RESET_CFLAG(context);
Alexandre Julliardaf0bae51995-10-03 17:06:08 +0000106 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:
Alexandre Julliard139a4b11996-11-02 14:24:07 +0000112 VXD_BARF( context, "pagefile" );
Alexandre Julliardaf0bae51995-10-03 17:06:08 +0000113 break;
114 }
115}
116
Ulrich Weigand0b597bc1998-10-11 19:01:33 +0000117/***********************************************************************
118 * VXD_Reboot
119 */
Ulrich Weigandff9c44f1999-06-27 15:28:51 +0000120void WINAPI VXD_Reboot ( CONTEXT86 *context )
Ulrich Weigand0b597bc1998-10-11 19:01:33 +0000121{
122 unsigned service = AX_reg(context);
123
Alexandre Julliard908464d2000-11-01 03:11:12 +0000124 TRACE("[%04x] Reboot\n", (UINT16)service);
Ulrich Weigand0b597bc1998-10-11 19:01:33 +0000125
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 */
Ulrich Weigandff9c44f1999-06-27 15:28:51 +0000141void WINAPI VXD_VDD ( CONTEXT86 *context )
Ulrich Weigand0b597bc1998-10-11 19:01:33 +0000142{
143 unsigned service = AX_reg(context);
144
Alexandre Julliard908464d2000-11-01 03:11:12 +0000145 TRACE("[%04x] VDD\n", (UINT16)service);
Ulrich Weigand0b597bc1998-10-11 19:01:33 +0000146
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}
Alexandre Julliardaf0bae51995-10-03 17:06:08 +0000158
159/***********************************************************************
Ulrich Weigandab635b21998-11-14 18:33:34 +0000160 * VXD_VMD
161 */
Ulrich Weigandff9c44f1999-06-27 15:28:51 +0000162void WINAPI VXD_VMD ( CONTEXT86 *context )
Ulrich Weigandab635b21998-11-14 18:33:34 +0000163{
164 unsigned service = AX_reg(context);
165
Alexandre Julliard908464d2000-11-01 03:11:12 +0000166 TRACE("[%04x] VMD\n", (UINT16)service);
Ulrich Weigandab635b21998-11-14 18:33:34 +0000167
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/***********************************************************************
James Abbatiello5f150ba2000-08-28 19:29:26 +0000181 * VXD_VXDLoader
182 */
183void 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",
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000200 context->SegDs, DX_reg(context),
201 debugstr_a(PTR_SEG_OFF_TO_LIN(context->SegDs, DX_reg(context))));
James Abbatiello5f150ba2000-08-28 19:29:26 +0000202 AX_reg(context) = 0x0000;
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000203 context->SegEs = 0x0000;
James Abbatiello5f150ba2000-08-28 19:29:26 +0000204 DI_reg(context) = 0x0000;
205 RESET_CFLAG(context);
206 break;
207
208 case 0x0002: /* unload device */
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000209 FIXME("unload device (%08lx)\n", context->Ebx);
James Abbatiello5f150ba2000-08-28 19:29:26 +0000210 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/***********************************************************************
Alexandre Julliardaf0bae51995-10-03 17:06:08 +0000223 * VXD_Shell
224 */
Alexandre Julliard617955d1999-06-26 18:40:24 +0000225void WINAPI VXD_Shell( CONTEXT86 *context )
Alexandre Julliardaf0bae51995-10-03 17:06:08 +0000226{
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000227 unsigned service = DX_reg(context);
Alexandre Julliardaf0bae51995-10-03 17:06:08 +0000228
Alexandre Julliard61fece01999-06-26 19:09:08 +0000229 TRACE("[%04x] Shell\n", (UINT16)service);
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000230
231 switch (service) /* Ralf Brown says EDX, but I use DX instead */
Alexandre Julliardaf0bae51995-10-03 17:06:08 +0000232 {
233 case 0x0000:
Alexandre Julliard61fece01999-06-26 19:09:08 +0000234 TRACE("returning version\n");
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000235 AX_reg(context) = VXD_WinVersion();
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000236 context->Ebx = 1; /* system VM Handle */
Alexandre Julliardaf0bae51995-10-03 17:06:08 +0000237 break;
238
239 case 0x0001:
240 case 0x0002:
241 case 0x0003:
Juergen Schmiedf08b8191999-05-22 10:33:50 +0000242 /* 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 */
Alexandre Julliardaf0bae51995-10-03 17:06:08 +0000249 case 0x0004:
Juergen Schmiedf08b8191999-05-22 10:33:50 +0000250 /* 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 */
Alexandre Julliardaf0bae51995-10-03 17:06:08 +0000259 case 0x0005:
Alexandre Julliard139a4b11996-11-02 14:24:07 +0000260 VXD_BARF( context, "shell" );
Alexandre Julliardaf0bae51995-10-03 17:06:08 +0000261 break;
262
263 case 0x0006: /* SHELL_Get_VM_State */
Alexandre Julliard61fece01999-06-26 19:09:08 +0000264 TRACE("VxD Shell: returning VM state\n");
Alexandre Julliardaf0bae51995-10-03 17:06:08 +0000265 /* 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 */
Alexandre Julliardca22b331996-07-12 19:02:39 +0000270 /* RESET_CFLAG(context); */
Alexandre Julliardaf0bae51995-10-03 17:06:08 +0000271 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:
Ulrich Weigandab635b21998-11-14 18:33:34 +0000289 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 */
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000303 TRACE("VxD Shell: ignoring shell callback (%ld sec.)\n", context->Ebx);
Ulrich Weigandab635b21998-11-14 18:33:34 +0000304 SET_CFLAG(context);
305 break;
306
307 case 0x0107: /* get version of any VxD */
Alexandre Julliardaf0bae51995-10-03 17:06:08 +0000308 default:
Ulrich Weigandab635b21998-11-14 18:33:34 +0000309 VXD_BARF( context, "SHELL" );
Alexandre Julliardaf0bae51995-10-03 17:06:08 +0000310 break;
311 }
312}
313
314
315/***********************************************************************
316 * VXD_Comm
317 */
Alexandre Julliard617955d1999-06-26 18:40:24 +0000318void WINAPI VXD_Comm( CONTEXT86 *context )
Alexandre Julliardaf0bae51995-10-03 17:06:08 +0000319{
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000320 unsigned service = AX_reg(context);
Alexandre Julliardaf0bae51995-10-03 17:06:08 +0000321
Alexandre Julliard61fece01999-06-26 19:09:08 +0000322 TRACE("[%04x] Comm\n", (UINT16)service);
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000323
324 switch (service)
Alexandre Julliardaf0bae51995-10-03 17:06:08 +0000325 {
326 case 0x0000: /* get version */
Alexandre Julliard61fece01999-06-26 19:09:08 +0000327 TRACE("returning version\n");
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000328 AX_reg(context) = VXD_WinVersion();
Alexandre Julliardca22b331996-07-12 19:02:39 +0000329 RESET_CFLAG(context);
Alexandre Julliardaf0bae51995-10-03 17:06:08 +0000330 break;
331
332 case 0x0001: /* set port global */
333 case 0x0002: /* get focus */
334 case 0x0003: /* virtualise port */
335 default:
Alexandre Julliard139a4b11996-11-02 14:24:07 +0000336 VXD_BARF( context, "comm" );
Alexandre Julliardaf0bae51995-10-03 17:06:08 +0000337 }
338}
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000339
340/***********************************************************************
341 * VXD_Timer
342 */
Ulrich Weigandff9c44f1999-06-27 15:28:51 +0000343void WINAPI VXD_Timer( CONTEXT86 *context )
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000344{
345 unsigned service = AX_reg(context);
346
Alexandre Julliard61fece01999-06-26 19:09:08 +0000347 TRACE("[%04x] Virtual Timer\n", (UINT16)service);
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000348
349 switch(service)
350 {
351 case 0x0000: /* version */
352 AX_reg(context) = VXD_WinVersion();
353 RESET_CFLAG(context);
354 break;
355
356 case 0x0100: /* clock tick time, in 840nsecs */
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000357 context->Eax = GetTickCount();
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000358
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000359 context->Edx = context->Eax >> 22;
360 context->Eax <<= 10; /* not very precise */
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000361 break;
362
363 case 0x0101: /* current Windows time, msecs */
364 case 0x0102: /* current VM time, msecs */
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000365 context->Eax = GetTickCount();
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000366 break;
367
368 default:
369 VXD_BARF( context, "VTD" );
370 }
371}
372
Alexandre Julliard642d3131998-07-12 19:29:36 +0000373/***********************************************************************
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000374 * VXD_TimerAPI
375 */
Ulrich Weigand1cd07941998-12-10 11:01:09 +0000376static DWORD System_Time = 0;
377static WORD System_Time_Selector = 0;
378static void System_Time_Tick( WORD timer ) { System_Time += 55; }
Ulrich Weigandff9c44f1999-06-27 15:28:51 +0000379void WINAPI VXD_TimerAPI ( CONTEXT86 *context )
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000380{
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000381 unsigned service = AX_reg(context);
382
Alexandre Julliard908464d2000-11-01 03:11:12 +0000383 TRACE("[%04x] TimerAPI\n", (UINT16)service);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000384
385 switch(service)
386 {
387 case 0x0000: /* version */
388 AX_reg(context) = VXD_WinVersion();
389 RESET_CFLAG(context);
390 break;
391
392 case 0x0009: /* get system time selector */
Ulrich Weigand1cd07941998-12-10 11:01:09 +0000393 if ( !System_Time_Selector )
394 {
Alexandre Julliard914406f2000-11-14 01:54:49 +0000395 System_Time_Selector = SELECTOR_AllocBlock( &System_Time, sizeof(DWORD), WINE_LDT_FLAGS_DATA );
Ulrich Weigand1cd07941998-12-10 11:01:09 +0000396 CreateSystemTimer( 55, System_Time_Tick );
397 }
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000398
Ulrich Weigand1cd07941998-12-10 11:01:09 +0000399 AX_reg(context) = System_Time_Selector;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000400 RESET_CFLAG(context);
401 break;
402
403 default:
404 VXD_BARF( context, "VTDAPI" );
405 }
406}
407
408/***********************************************************************
409 * VXD_ConfigMG
410 */
Ulrich Weigandff9c44f1999-06-27 15:28:51 +0000411void WINAPI VXD_ConfigMG ( CONTEXT86 *context )
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000412{
413 unsigned service = AX_reg(context);
414
Alexandre Julliard908464d2000-11-01 03:11:12 +0000415 TRACE("[%04x] ConfigMG\n", (UINT16)service);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000416
417 switch(service)
418 {
419 case 0x0000: /* version */
420 AX_reg(context) = VXD_WinVersion();
421 RESET_CFLAG(context);
422 break;
423
424 default:
425 VXD_BARF( context, "CONFIGMG" );
426 }
427}
428
429/***********************************************************************
Ulrich Weigandab635b21998-11-14 18:33:34 +0000430 * VXD_Enable
431 */
Ulrich Weigandff9c44f1999-06-27 15:28:51 +0000432void WINAPI VXD_Enable ( CONTEXT86 *context )
Ulrich Weigandab635b21998-11-14 18:33:34 +0000433{
434 unsigned service = AX_reg(context);
435
Alexandre Julliard908464d2000-11-01 03:11:12 +0000436 TRACE("[%04x] Enable\n", (UINT16)service);
Ulrich Weigandab635b21998-11-14 18:33:34 +0000437
438 switch(service)
439 {
440 case 0x0000: /* version */
441 AX_reg(context) = VXD_WinVersion();
442 RESET_CFLAG(context);
443 break;
444
445 default:
446 VXD_BARF( context, "ENABLE" );
447 }
448}
449
450/***********************************************************************
451 * VXD_APM
452 */
Ulrich Weigandff9c44f1999-06-27 15:28:51 +0000453void WINAPI VXD_APM ( CONTEXT86 *context )
Ulrich Weigandab635b21998-11-14 18:33:34 +0000454{
455 unsigned service = AX_reg(context);
456
Alexandre Julliard908464d2000-11-01 03:11:12 +0000457 TRACE("[%04x] APM\n", (UINT16)service);
Ulrich Weigandab635b21998-11-14 18:33:34 +0000458
459 switch(service)
460 {
461 case 0x0000: /* version */
462 AX_reg(context) = VXD_WinVersion();
463 RESET_CFLAG(context);
464 break;
465
466 default:
467 VXD_BARF( context, "APM" );
468 }
469}
470
471/***********************************************************************
Alexandre Julliard642d3131998-07-12 19:29:36 +0000472 * VXD_Win32s
473 *
474 * This is an implementation of the services of the Win32s VxD.
475 * Since official documentation of these does not seem to be available,
476 * certain arguments of some of the services remain unclear.
477 *
478 * FIXME: The following services are currently unimplemented:
479 * Exception handling (0x01, 0x1C)
480 * Debugger support (0x0C, 0x14, 0x17)
481 * Low-level memory access (0x02, 0x03, 0x0A, 0x0B)
482 * Memory Statistics (0x1B)
483 *
484 *
485 * We have a specific problem running Win32s on Linux (and probably also
486 * the other x86 unixes), since Win32s tries to allocate its main 'flat
487 * code/data segment' selectors with a base of 0xffff0000 (and limit 4GB).
488 * The rationale for this seems to be that they want one the one hand to
489 * be able to leave the Win 3.1 memory (starting with the main DOS memory)
490 * at linear address 0, but want at other hand to have offset 0 of the
491 * flat data/code segment point to an unmapped page (to catch NULL pointer
492 * accesses). Hence they allocate the flat segments with a base of 0xffff0000
493 * so that the Win 3.1 memory area at linear address zero shows up in the
494 * flat segments at offset 0x10000 (since linear addresses wrap around at
495 * 4GB). To compensate for that discrepancy between flat segment offsets
496 * and plain linear addresses, all flat pointers passed between the 32-bit
497 * and the 16-bit parts of Win32s are shifted by 0x10000 in the appropriate
498 * direction by the glue code (mainly) in W32SKRNL and WIN32S16.
499 *
500 * The problem for us is now that Linux does not allow a LDT selector with
501 * base 0xffff0000 to be created, since it would 'see' a part of the kernel
502 * address space. To address this problem we introduce *another* offset:
503 * We add 0x10000 to every linear address we get as an argument from Win32s.
504 * This means especially that the flat code/data selectors get actually
505 * allocated with base 0x0, so that flat offsets and (real) linear addresses
506 * do again agree! In fact, every call e.g. of a Win32s VxD service now
507 * has all pointer arguments (which are offsets in the flat data segement)
508 * first reduced by 0x10000 by the W32SKRNL glue code, and then again
509 * increased by 0x10000 by *our* code.
510 *
511 * Note that to keep everything consistent, this offset has to be applied by
512 * every Wine function that operates on 'linear addresses' passed to it by
513 * Win32s. Fortunately, since Win32s does not directly call any Wine 32-bit
514 * API routines, this affects only two locations: this VxD and the DPMI
515 * handler. (NOTE: Should any Win32s application pass a linear address to
516 * any routine apart from those, e.g. some other VxD handler, that code
517 * would have to take the offset into account as well!)
518 *
519 * The application of the offset is triggered by marking the current process
520 * as a Win32s process by setting the PDB32_WIN32S_PROC flag in the process
521 * database. This is done the first time any application calls the GetVersion()
522 * service of the Win32s VxD. (Note that the flag is never removed.)
523 *
524 */
525
Ulrich Weigandff9c44f1999-06-27 15:28:51 +0000526void WINAPI VXD_Win32s( CONTEXT86 *context )
Alexandre Julliard642d3131998-07-12 19:29:36 +0000527{
Alexandre Julliard642d3131998-07-12 19:29:36 +0000528 switch (AX_reg(context))
529 {
530 case 0x0000: /* Get Version */
531 /*
532 * Input: None
533 *
534 * Output: EAX: LoWord: Win32s Version (1.30)
535 * HiWord: VxD Version (200)
536 *
537 * EBX: Build (172)
538 *
539 * ECX: ??? (1)
540 *
541 * EDX: Debugging Flags
542 *
543 * EDI: Error Flag
544 * 0 if OK,
545 * 1 if VMCPD VxD not found
546 */
547
Alexandre Julliard61fece01999-06-26 19:09:08 +0000548 TRACE("GetVersion()\n");
Alexandre Julliard642d3131998-07-12 19:29:36 +0000549
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000550 context->Eax = VXD_WinVersion() | (200 << 16);
551 context->Ebx = 0;
552 context->Ecx = 0;
553 context->Edx = 0;
554 context->Edi = 0;
Alexandre Julliard642d3131998-07-12 19:29:36 +0000555
556 /*
557 * If this is the first time we are called for this process,
558 * hack the memory image of WIN32S16 so that it doesn't try
559 * to access the GDT directly ...
560 *
561 * The first code segment of WIN32S16 (version 1.30) contains
562 * an unexported function somewhere between the exported functions
563 * SetFS and StackLinearToSegmented that tries to find a selector
564 * in the LDT that maps to the memory image of the LDT itself.
565 * If it succeeds, it stores this selector into a global variable
566 * which will be used to speed up execution by using this selector
567 * to modify the LDT directly instead of using the DPMI calls.
568 *
569 * To perform this search of the LDT, this function uses the
570 * sgdt and sldt instructions to find the linear address of
571 * the (GDT and then) LDT. While those instructions themselves
572 * execute without problem, the linear address that sgdt returns
573 * points (at least under Linux) to the kernel address space, so
574 * that any subsequent access leads to a segfault.
575 *
576 * Fortunately, WIN32S16 still contains as a fallback option the
577 * mechanism of using DPMI calls to modify LDT selectors instead
578 * of direct writes to the LDT. Thus we can circumvent the problem
579 * by simply replacing the first byte of the offending function
580 * with an 'retf' instruction. This means that the global variable
581 * supposed to contain the LDT alias selector will remain zero,
582 * and hence WIN32S16 will fall back to using DPMI calls.
583 *
584 * The heuristic we employ to _find_ that function is as follows:
585 * We search between the addresses of the exported symbols SetFS
586 * and StackLinearToSegmented for the byte sequence '0F 01 04'
587 * (this is the opcode of 'sgdt [si]'). We then search backwards
588 * from this address for the last occurrance of 'CB' (retf) that marks
589 * the end of the preceeding function. The following byte (which
590 * should now be the first byte of the function we are looking for)
591 * will be replaced by 'CB' (retf).
592 *
593 * This heuristic works for the retail as well as the debug version
594 * of Win32s version 1.30. For versions earlier than that this
595 * hack should not be necessary at all, since the whole mechanism
596 * ('PERF130') was introduced only in 1.30 to improve the overall
597 * performance of Win32s.
598 */
599
600 if (!(PROCESS_Current()->flags & PDB32_WIN32S_PROC))
601 {
602 HMODULE16 hModule = GetModuleHandle16("win32s16");
603 SEGPTR func1 = (SEGPTR)WIN32_GetProcAddress16(hModule, "SetFS");
604 SEGPTR func2 = (SEGPTR)WIN32_GetProcAddress16(hModule,
605 "StackLinearToSegmented");
606
607 if ( hModule && func1 && func2
608 && SELECTOROF(func1) == SELECTOROF(func2))
609 {
610 BYTE *start = PTR_SEG_TO_LIN(func1);
611 BYTE *end = PTR_SEG_TO_LIN(func2);
612 BYTE *p, *retv = NULL;
613 int found = 0;
614
615 for (p = start; p < end; p++)
616 if (*p == 0xCB) found = 0, retv = p;
617 else if (*p == 0x0F) found = 1;
618 else if (*p == 0x01 && found == 1) found = 2;
619 else if (*p == 0x04 && found == 2) { found = 3; break; }
620 else found = 0;
621
622 if (found == 3 && retv)
623 {
Alexandre Julliard61fece01999-06-26 19:09:08 +0000624 TRACE("PERF130 hack: "
Alexandre Julliard642d3131998-07-12 19:29:36 +0000625 "Replacing byte %02X at offset %04X:%04X\n",
626 *(retv+1), SELECTOROF(func1),
627 OFFSETOF(func1) + retv+1-start);
628
629 *(retv+1) = (BYTE)0xCB;
630 }
631 }
632 }
633
634 /*
635 * Mark process as Win32s, so that subsequent DPMI calls
Andreas Mohra00b49f1998-12-07 10:48:09 +0000636 * will perform the W32S_APP2WINE/W32S_WINE2APP address shift.
Alexandre Julliard642d3131998-07-12 19:29:36 +0000637 */
638
639 PROCESS_Current()->flags |= PDB32_WIN32S_PROC;
640 break;
641
642
643 case 0x0001: /* Install Exception Handling */
644 /*
645 * Input: EBX: Flat address of W32SKRNL Exception Data
646 *
647 * ECX: LoWord: Flat Code Selector
648 * HiWord: Flat Data Selector
649 *
650 * EDX: Flat address of W32SKRNL Exception Handler
651 * (this is equal to W32S_BackTo32 + 0x40)
652 *
653 * ESI: SEGPTR KERNEL.HASGPHANDLER
654 *
655 * EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10)
656 *
657 * Output: EAX: 0 if OK
658 */
659
Alexandre Julliard61fece01999-06-26 19:09:08 +0000660 TRACE("[0001] EBX=%lx ECX=%lx EDX=%lx ESI=%lx EDI=%lx\n",
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000661 context->Ebx, context->Ecx, context->Edx,
662 context->Esi, context->Edi);
Alexandre Julliard642d3131998-07-12 19:29:36 +0000663
664 /* FIXME */
665
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000666 context->Eax = 0;
Alexandre Julliard642d3131998-07-12 19:29:36 +0000667 break;
668
669
670 case 0x0002: /* Set Page Access Flags */
671 /*
672 * Input: EBX: New access flags
673 * Bit 2: User Page if set, Supervisor Page if clear
674 * Bit 1: Read-Write if set, Read-Only if clear
675 *
676 * ECX: Size of memory area to change
677 *
678 * EDX: Flat start address of memory area
679 *
680 * Output: EAX: Size of area changed
681 */
682
Alexandre Julliard61fece01999-06-26 19:09:08 +0000683 TRACE("[0002] EBX=%lx ECX=%lx EDX=%lx\n",
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000684 context->Ebx, context->Ecx, context->Edx);
Alexandre Julliard642d3131998-07-12 19:29:36 +0000685
686 /* FIXME */
687
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000688 context->Eax = context->Ecx;
Alexandre Julliard642d3131998-07-12 19:29:36 +0000689 break;
690
691
692 case 0x0003: /* Get Page Access Flags */
693 /*
694 * Input: EDX: Flat address of page to query
695 *
696 * Output: EAX: Page access flags
697 * Bit 2: User Page if set, Supervisor Page if clear
698 * Bit 1: Read-Write if set, Read-Only if clear
699 */
700
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000701 TRACE("[0003] EDX=%lx\n", context->Edx);
Alexandre Julliard642d3131998-07-12 19:29:36 +0000702
703 /* FIXME */
704
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000705 context->Eax = 6;
Alexandre Julliard642d3131998-07-12 19:29:36 +0000706 break;
707
708
709 case 0x0004: /* Map Module */
710 /*
711 * Input: ECX: IMTE (offset in Module Table) of new module
712 *
713 * EDX: Flat address of Win32s Module Table
714 *
715 * Output: EAX: 0 if OK
716 */
717
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000718 if (!context->Edx || CX_reg(context) == 0xFFFF)
Alexandre Julliard642d3131998-07-12 19:29:36 +0000719 {
Alexandre Julliard61fece01999-06-26 19:09:08 +0000720 TRACE("MapModule: Initialization call\n");
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000721 context->Eax = 0;
Alexandre Julliard642d3131998-07-12 19:29:36 +0000722 }
723 else
724 {
725 /*
726 * Structure of a Win32s Module Table Entry:
727 */
728 struct Win32sModule
729 {
730 DWORD flags;
731 DWORD flatBaseAddr;
732 LPCSTR moduleName;
733 LPCSTR pathName;
734 LPCSTR unknown;
735 LPBYTE baseAddr;
736 DWORD hModule;
737 DWORD relocDelta;
738 };
739
740 /*
741 * Note: This function should set up a demand-paged memory image
742 * of the given module. Since mmap does not allow file offsets
743 * not aligned at 1024 bytes, we simply load the image fully
744 * into memory.
745 */
746
747 struct Win32sModule *moduleTable =
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000748 (struct Win32sModule *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
749 struct Win32sModule *module = moduleTable + context->Ecx;
Alexandre Julliard642d3131998-07-12 19:29:36 +0000750
751 IMAGE_NT_HEADERS *nt_header = PE_HEADER(module->baseAddr);
752 IMAGE_SECTION_HEADER *pe_seg = PE_SECTIONS(module->baseAddr);
753
Alexandre Julliarda3960291999-02-26 11:11:13 +0000754 HFILE image = _lopen(module->pathName, OF_READ);
Alexandre Julliard908464d2000-11-01 03:11:12 +0000755 BOOL error = (image == HFILE_ERROR);
Alexandre Julliarda3960291999-02-26 11:11:13 +0000756 UINT i;
Alexandre Julliard642d3131998-07-12 19:29:36 +0000757
Alexandre Julliard61fece01999-06-26 19:09:08 +0000758 TRACE("MapModule: Loading %s\n", module->pathName);
Alexandre Julliard642d3131998-07-12 19:29:36 +0000759
760 for (i = 0;
761 !error && i < nt_header->FileHeader.NumberOfSections;
762 i++, pe_seg++)
763 if(!(pe_seg->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA))
764 {
765 DWORD off = pe_seg->PointerToRawData;
766 DWORD len = pe_seg->SizeOfRawData;
767 LPBYTE addr = module->baseAddr + pe_seg->VirtualAddress;
768
Alexandre Julliard61fece01999-06-26 19:09:08 +0000769 TRACE("MapModule: "
Alexandre Julliard642d3131998-07-12 19:29:36 +0000770 "Section %d at %08lx from %08lx len %08lx\n",
771 i, (DWORD)addr, off, len);
772
Alexandre Julliarda3960291999-02-26 11:11:13 +0000773 if ( _llseek(image, off, SEEK_SET) != off
774 || _lread(image, addr, len) != len)
Alexandre Julliard642d3131998-07-12 19:29:36 +0000775 error = TRUE;
776 }
777
Alexandre Julliarda3960291999-02-26 11:11:13 +0000778 _lclose(image);
Alexandre Julliard642d3131998-07-12 19:29:36 +0000779
780 if (error)
Alexandre Julliard61fece01999-06-26 19:09:08 +0000781 ERR("MapModule: Unable to load %s\n", module->pathName);
Alexandre Julliard642d3131998-07-12 19:29:36 +0000782
783 else if (module->relocDelta != 0)
784 {
785 IMAGE_DATA_DIRECTORY *dir = nt_header->OptionalHeader.DataDirectory
786 + IMAGE_DIRECTORY_ENTRY_BASERELOC;
787 IMAGE_BASE_RELOCATION *r = (IMAGE_BASE_RELOCATION *)
788 (dir->Size? module->baseAddr + dir->VirtualAddress : 0);
789
Alexandre Julliard61fece01999-06-26 19:09:08 +0000790 TRACE("MapModule: Reloc delta %08lx\n", module->relocDelta);
Alexandre Julliard642d3131998-07-12 19:29:36 +0000791
792 while (r && r->VirtualAddress)
793 {
794 LPBYTE page = module->baseAddr + r->VirtualAddress;
795 int count = (r->SizeOfBlock - 8) / 2;
796
Alexandre Julliard61fece01999-06-26 19:09:08 +0000797 TRACE("MapModule: %d relocations for page %08lx\n",
Alexandre Julliard642d3131998-07-12 19:29:36 +0000798 count, (DWORD)page);
799
800 for(i = 0; i < count; i++)
801 {
802 int offset = r->TypeOffset[i] & 0xFFF;
803 int type = r->TypeOffset[i] >> 12;
804 switch(type)
805 {
806 case IMAGE_REL_BASED_ABSOLUTE:
807 break;
808 case IMAGE_REL_BASED_HIGH:
809 *(WORD *)(page+offset) += HIWORD(module->relocDelta);
810 break;
811 case IMAGE_REL_BASED_LOW:
812 *(WORD *)(page+offset) += LOWORD(module->relocDelta);
813 break;
814 case IMAGE_REL_BASED_HIGHLOW:
815 *(DWORD*)(page+offset) += module->relocDelta;
816 break;
817 default:
Alexandre Julliard61fece01999-06-26 19:09:08 +0000818 WARN("MapModule: Unsupported fixup type\n");
Alexandre Julliard642d3131998-07-12 19:29:36 +0000819 break;
820 }
821 }
822
823 r = (IMAGE_BASE_RELOCATION *)((LPBYTE)r + r->SizeOfBlock);
824 }
825 }
826
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000827 context->Eax = 0;
Alexandre Julliard642d3131998-07-12 19:29:36 +0000828 RESET_CFLAG(context);
829 }
830 break;
831
832
833 case 0x0005: /* UnMap Module */
834 /*
835 * Input: EDX: Flat address of module image
836 *
837 * Output: EAX: 1 if OK
838 */
839
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000840 TRACE("UnMapModule: %lx\n", (DWORD)W32S_APP2WINE(context->Edx, W32S_OFFSET));
Alexandre Julliard642d3131998-07-12 19:29:36 +0000841
842 /* As we didn't map anything, there's nothing to unmap ... */
843
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000844 context->Eax = 1;
Alexandre Julliard642d3131998-07-12 19:29:36 +0000845 break;
846
847
848 case 0x0006: /* VirtualAlloc */
849 /*
850 * Input: ECX: Current Process
851 *
852 * EDX: Flat address of arguments on stack
853 *
854 * DWORD *retv [out] Flat base address of allocated region
855 * LPVOID base [in] Flat address of region to reserve/commit
856 * DWORD size [in] Size of region
857 * DWORD type [in] Type of allocation
858 * DWORD prot [in] Type of access protection
859 *
860 * Output: EAX: NtStatus
861 */
862 {
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000863 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
Andreas Mohra00b49f1998-12-07 10:48:09 +0000864 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
865 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
Alexandre Julliard642d3131998-07-12 19:29:36 +0000866 DWORD size = stack[2];
867 DWORD type = stack[3];
868 DWORD prot = stack[4];
869 DWORD result;
870
Alexandre Julliard61fece01999-06-26 19:09:08 +0000871 TRACE("VirtualAlloc(%lx, %lx, %lx, %lx, %lx)\n",
Alexandre Julliard642d3131998-07-12 19:29:36 +0000872 (DWORD)retv, (DWORD)base, size, type, prot);
873
874 if (type & 0x80000000)
875 {
Alexandre Julliard61fece01999-06-26 19:09:08 +0000876 WARN("VirtualAlloc: strange type %lx\n", type);
Alexandre Julliard642d3131998-07-12 19:29:36 +0000877 type &= 0x7fffffff;
878 }
879
880 if (!base && (type & MEM_COMMIT) && prot == PAGE_READONLY)
881 {
Alexandre Julliard61fece01999-06-26 19:09:08 +0000882 WARN("VirtualAlloc: NLS hack, allowing write access!\n");
Alexandre Julliard642d3131998-07-12 19:29:36 +0000883 prot = PAGE_READWRITE;
884 }
885
886 result = (DWORD)VirtualAlloc(base, size, type, prot);
887
Andreas Mohra00b49f1998-12-07 10:48:09 +0000888 if (W32S_WINE2APP(result, W32S_OFFSET))
889 *retv = W32S_WINE2APP(result, W32S_OFFSET),
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000890 context->Eax = STATUS_SUCCESS;
Alexandre Julliard642d3131998-07-12 19:29:36 +0000891 else
892 *retv = 0,
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000893 context->Eax = STATUS_NO_MEMORY; /* FIXME */
Alexandre Julliard642d3131998-07-12 19:29:36 +0000894 }
895 break;
896
897
898 case 0x0007: /* VirtualFree */
899 /*
900 * Input: ECX: Current Process
901 *
902 * EDX: Flat address of arguments on stack
903 *
904 * DWORD *retv [out] TRUE if success, FALSE if failure
905 * LPVOID base [in] Flat address of region
906 * DWORD size [in] Size of region
907 * DWORD type [in] Type of operation
908 *
909 * Output: EAX: NtStatus
910 */
911 {
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000912 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
Andreas Mohra00b49f1998-12-07 10:48:09 +0000913 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
914 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
Alexandre Julliard642d3131998-07-12 19:29:36 +0000915 DWORD size = stack[2];
916 DWORD type = stack[3];
917 DWORD result;
918
Alexandre Julliard61fece01999-06-26 19:09:08 +0000919 TRACE("VirtualFree(%lx, %lx, %lx, %lx)\n",
Alexandre Julliard642d3131998-07-12 19:29:36 +0000920 (DWORD)retv, (DWORD)base, size, type);
921
922 result = VirtualFree(base, size, type);
923
924 if (result)
925 *retv = TRUE,
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000926 context->Eax = STATUS_SUCCESS;
Alexandre Julliard642d3131998-07-12 19:29:36 +0000927 else
928 *retv = FALSE,
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000929 context->Eax = STATUS_NO_MEMORY; /* FIXME */
Alexandre Julliard642d3131998-07-12 19:29:36 +0000930 }
931 break;
932
933
934 case 0x0008: /* VirtualProtect */
935 /*
936 * Input: ECX: Current Process
937 *
938 * EDX: Flat address of arguments on stack
939 *
940 * DWORD *retv [out] TRUE if success, FALSE if failure
941 * LPVOID base [in] Flat address of region
942 * DWORD size [in] Size of region
943 * DWORD new_prot [in] Desired access protection
944 * DWORD *old_prot [out] Previous access protection
945 *
946 * Output: EAX: NtStatus
947 */
948 {
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000949 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
Andreas Mohra00b49f1998-12-07 10:48:09 +0000950 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
951 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
Alexandre Julliard642d3131998-07-12 19:29:36 +0000952 DWORD size = stack[2];
953 DWORD new_prot = stack[3];
Andreas Mohra00b49f1998-12-07 10:48:09 +0000954 DWORD *old_prot = (DWORD *)W32S_APP2WINE(stack[4], W32S_OFFSET);
Alexandre Julliard642d3131998-07-12 19:29:36 +0000955 DWORD result;
956
Alexandre Julliard61fece01999-06-26 19:09:08 +0000957 TRACE("VirtualProtect(%lx, %lx, %lx, %lx, %lx)\n",
Alexandre Julliard642d3131998-07-12 19:29:36 +0000958 (DWORD)retv, (DWORD)base, size, new_prot, (DWORD)old_prot);
959
960 result = VirtualProtect(base, size, new_prot, old_prot);
961
962 if (result)
963 *retv = TRUE,
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000964 context->Eax = STATUS_SUCCESS;
Alexandre Julliard642d3131998-07-12 19:29:36 +0000965 else
966 *retv = FALSE,
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000967 context->Eax = STATUS_NO_MEMORY; /* FIXME */
Alexandre Julliard642d3131998-07-12 19:29:36 +0000968 }
969 break;
970
971
972 case 0x0009: /* VirtualQuery */
973 /*
974 * Input: ECX: Current Process
975 *
976 * EDX: Flat address of arguments on stack
977 *
978 * DWORD *retv [out] Nr. bytes returned
979 * LPVOID base [in] Flat address of region
980 * LPMEMORY_BASIC_INFORMATION info [out] Info buffer
981 * DWORD len [in] Size of buffer
982 *
983 * Output: EAX: NtStatus
984 */
985 {
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000986 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
Andreas Mohra00b49f1998-12-07 10:48:09 +0000987 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
988 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
Alexandre Julliard642d3131998-07-12 19:29:36 +0000989 LPMEMORY_BASIC_INFORMATION info =
Andreas Mohra00b49f1998-12-07 10:48:09 +0000990 (LPMEMORY_BASIC_INFORMATION)W32S_APP2WINE(stack[2], W32S_OFFSET);
Alexandre Julliard642d3131998-07-12 19:29:36 +0000991 DWORD len = stack[3];
992 DWORD result;
993
Alexandre Julliard61fece01999-06-26 19:09:08 +0000994 TRACE("VirtualQuery(%lx, %lx, %lx, %lx)\n",
Alexandre Julliard642d3131998-07-12 19:29:36 +0000995 (DWORD)retv, (DWORD)base, (DWORD)info, len);
996
997 result = VirtualQuery(base, info, len);
998
999 *retv = result;
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001000 context->Eax = STATUS_SUCCESS;
Alexandre Julliard642d3131998-07-12 19:29:36 +00001001 }
1002 break;
1003
1004
1005 case 0x000A: /* SetVirtMemProcess */
1006 /*
1007 * Input: ECX: Process Handle
1008 *
1009 * EDX: Flat address of region
1010 *
1011 * Output: EAX: NtStatus
1012 */
1013
Alexandre Julliard61fece01999-06-26 19:09:08 +00001014 TRACE("[000a] ECX=%lx EDX=%lx\n",
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001015 context->Ecx, context->Edx);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001016
1017 /* FIXME */
1018
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001019 context->Eax = STATUS_SUCCESS;
Alexandre Julliard642d3131998-07-12 19:29:36 +00001020 break;
1021
1022
1023 case 0x000B: /* ??? some kind of cleanup */
1024 /*
1025 * Input: ECX: Process Handle
1026 *
1027 * Output: EAX: NtStatus
1028 */
1029
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001030 TRACE("[000b] ECX=%lx\n", context->Ecx);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001031
1032 /* FIXME */
1033
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001034 context->Eax = STATUS_SUCCESS;
Alexandre Julliard642d3131998-07-12 19:29:36 +00001035 break;
1036
1037
1038 case 0x000C: /* Set Debug Flags */
1039 /*
1040 * Input: EDX: Debug Flags
1041 *
1042 * Output: EDX: Previous Debug Flags
1043 */
1044
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001045 FIXME("[000c] EDX=%lx\n", context->Edx);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001046
1047 /* FIXME */
1048
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001049 context->Edx = 0;
Alexandre Julliard642d3131998-07-12 19:29:36 +00001050 break;
1051
1052
1053 case 0x000D: /* NtCreateSection */
1054 /*
1055 * Input: EDX: Flat address of arguments on stack
1056 *
1057 * HANDLE32 *retv [out] Handle of Section created
1058 * DWORD flags1 [in] (?? unknown ??)
1059 * DWORD atom [in] Name of Section to create
1060 * LARGE_INTEGER *size [in] Size of Section
1061 * DWORD protect [in] Access protection
1062 * DWORD flags2 [in] (?? unknown ??)
1063 * HFILE32 hFile [in] Handle of file to map
1064 * DWORD psp [in] (Win32s: PSP that hFile belongs to)
1065 *
1066 * Output: EAX: NtStatus
1067 */
1068 {
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001069 DWORD *stack = (DWORD *) W32S_APP2WINE(context->Edx, W32S_OFFSET);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001070 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0], W32S_OFFSET);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001071 DWORD flags1 = stack[1];
1072 DWORD atom = stack[2];
Andreas Mohra00b49f1998-12-07 10:48:09 +00001073 LARGE_INTEGER *size = (LARGE_INTEGER *)W32S_APP2WINE(stack[3], W32S_OFFSET);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001074 DWORD protect = stack[4];
1075 DWORD flags2 = stack[5];
Alexandre Julliarda3960291999-02-26 11:11:13 +00001076 HFILE hFile = FILE_GetHandle(stack[6]);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001077 DWORD psp = stack[7];
1078
Alexandre Julliarda3960291999-02-26 11:11:13 +00001079 HANDLE result = INVALID_HANDLE_VALUE;
Alexandre Julliard642d3131998-07-12 19:29:36 +00001080 char name[128];
1081
Alexandre Julliard61fece01999-06-26 19:09:08 +00001082 TRACE("NtCreateSection(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
Alexandre Julliard642d3131998-07-12 19:29:36 +00001083 (DWORD)retv, flags1, atom, (DWORD)size, protect, flags2,
1084 (DWORD)hFile, psp);
1085
Alexandre Julliarda3960291999-02-26 11:11:13 +00001086 if (!atom || GlobalGetAtomNameA(atom, name, sizeof(name)))
Alexandre Julliard642d3131998-07-12 19:29:36 +00001087 {
Alexandre Julliard61fece01999-06-26 19:09:08 +00001088 TRACE("NtCreateSection: name=%s\n", atom? name : NULL);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001089
Alexandre Julliarda3960291999-02-26 11:11:13 +00001090 result = CreateFileMappingA(hFile, NULL, protect,
Patrik Stridvall311e4561999-09-19 14:20:33 +00001091 size? size->s.HighPart : 0,
1092 size? size->s.LowPart : 0,
Alexandre Julliard642d3131998-07-12 19:29:36 +00001093 atom? name : NULL);
1094 }
1095
Alexandre Julliarda3960291999-02-26 11:11:13 +00001096 if (result == INVALID_HANDLE_VALUE)
Alexandre Julliard61fece01999-06-26 19:09:08 +00001097 WARN("NtCreateSection: failed!\n");
Alexandre Julliard642d3131998-07-12 19:29:36 +00001098 else
Alexandre Julliard61fece01999-06-26 19:09:08 +00001099 TRACE("NtCreateSection: returned %lx\n", (DWORD)result);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001100
Alexandre Julliarda3960291999-02-26 11:11:13 +00001101 if (result != INVALID_HANDLE_VALUE)
Alexandre Julliard642d3131998-07-12 19:29:36 +00001102 *retv = result,
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001103 context->Eax = STATUS_SUCCESS;
Alexandre Julliard642d3131998-07-12 19:29:36 +00001104 else
1105 *retv = result,
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001106 context->Eax = STATUS_NO_MEMORY; /* FIXME */
Alexandre Julliard642d3131998-07-12 19:29:36 +00001107 }
1108 break;
1109
1110
1111 case 0x000E: /* NtOpenSection */
1112 /*
1113 * Input: EDX: Flat address of arguments on stack
1114 *
1115 * HANDLE32 *retv [out] Handle of Section opened
1116 * DWORD protect [in] Access protection
1117 * DWORD atom [in] Name of Section to create
1118 *
1119 * Output: EAX: NtStatus
1120 */
1121 {
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001122 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001123 HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0], W32S_OFFSET);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001124 DWORD protect = stack[1];
1125 DWORD atom = stack[2];
1126
Alexandre Julliarda3960291999-02-26 11:11:13 +00001127 HANDLE result = INVALID_HANDLE_VALUE;
Alexandre Julliard642d3131998-07-12 19:29:36 +00001128 char name[128];
1129
Alexandre Julliard61fece01999-06-26 19:09:08 +00001130 TRACE("NtOpenSection(%lx, %lx, %lx)\n",
Alexandre Julliard642d3131998-07-12 19:29:36 +00001131 (DWORD)retv, protect, atom);
1132
Alexandre Julliarda3960291999-02-26 11:11:13 +00001133 if (atom && GlobalGetAtomNameA(atom, name, sizeof(name)))
Alexandre Julliard642d3131998-07-12 19:29:36 +00001134 {
Alexandre Julliard61fece01999-06-26 19:09:08 +00001135 TRACE("NtOpenSection: name=%s\n", name);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001136
Alexandre Julliarda3960291999-02-26 11:11:13 +00001137 result = OpenFileMappingA(protect, FALSE, name);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001138 }
1139
Alexandre Julliarda3960291999-02-26 11:11:13 +00001140 if (result == INVALID_HANDLE_VALUE)
Alexandre Julliard61fece01999-06-26 19:09:08 +00001141 WARN("NtOpenSection: failed!\n");
Alexandre Julliard642d3131998-07-12 19:29:36 +00001142 else
Alexandre Julliard61fece01999-06-26 19:09:08 +00001143 TRACE("NtOpenSection: returned %lx\n", (DWORD)result);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001144
Alexandre Julliarda3960291999-02-26 11:11:13 +00001145 if (result != INVALID_HANDLE_VALUE)
Alexandre Julliard642d3131998-07-12 19:29:36 +00001146 *retv = result,
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001147 context->Eax = STATUS_SUCCESS;
Alexandre Julliard642d3131998-07-12 19:29:36 +00001148 else
1149 *retv = result,
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001150 context->Eax = STATUS_NO_MEMORY; /* FIXME */
Alexandre Julliard642d3131998-07-12 19:29:36 +00001151 }
1152 break;
1153
1154
1155 case 0x000F: /* NtCloseSection */
1156 /*
1157 * Input: EDX: Flat address of arguments on stack
1158 *
1159 * HANDLE32 handle [in] Handle of Section to close
1160 * DWORD *id [out] Unique ID (?? unclear ??)
1161 *
1162 * Output: EAX: NtStatus
1163 */
1164 {
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001165 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001166 HANDLE handle = stack[0];
Andreas Mohra00b49f1998-12-07 10:48:09 +00001167 DWORD *id = (DWORD *)W32S_APP2WINE(stack[1], W32S_OFFSET);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001168
Alexandre Julliard61fece01999-06-26 19:09:08 +00001169 TRACE("NtCloseSection(%lx, %lx)\n", (DWORD)handle, (DWORD)id);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001170
1171 CloseHandle(handle);
1172 if (id) *id = 0; /* FIXME */
1173
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001174 context->Eax = STATUS_SUCCESS;
Alexandre Julliard642d3131998-07-12 19:29:36 +00001175 }
1176 break;
1177
1178
1179 case 0x0010: /* NtDupSection */
1180 /*
1181 * Input: EDX: Flat address of arguments on stack
1182 *
1183 * HANDLE32 handle [in] Handle of Section to duplicate
1184 *
1185 * Output: EAX: NtStatus
1186 */
1187 {
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001188 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001189 HANDLE handle = stack[0];
1190 HANDLE new_handle;
Alexandre Julliard642d3131998-07-12 19:29:36 +00001191
Alexandre Julliard61fece01999-06-26 19:09:08 +00001192 TRACE("NtDupSection(%lx)\n", (DWORD)handle);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001193
Alexandre Julliard62a8b431999-01-19 17:48:23 +00001194 DuplicateHandle( GetCurrentProcess(), handle,
1195 GetCurrentProcess(), &new_handle,
1196 0, FALSE, DUPLICATE_SAME_ACCESS );
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001197 context->Eax = STATUS_SUCCESS;
Alexandre Julliard642d3131998-07-12 19:29:36 +00001198 }
1199 break;
1200
1201
1202 case 0x0011: /* NtMapViewOfSection */
1203 /*
1204 * Input: EDX: Flat address of arguments on stack
1205 *
1206 * HANDLE32 SectionHandle [in] Section to be mapped
1207 * DWORD ProcessHandle [in] Process to be mapped into
1208 * DWORD * BaseAddress [in/out] Address to be mapped at
1209 * DWORD ZeroBits [in] (?? unclear ??)
1210 * DWORD CommitSize [in] (?? unclear ??)
1211 * LARGE_INTEGER *SectionOffset [in] Offset within section
1212 * DWORD * ViewSize [in] Size of view
1213 * DWORD InheritDisposition [in] (?? unclear ??)
1214 * DWORD AllocationType [in] (?? unclear ??)
1215 * DWORD Protect [in] Access protection
1216 *
1217 * Output: EAX: NtStatus
1218 */
1219 {
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001220 DWORD * stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001221 HANDLE SectionHandle = stack[0];
Alexandre Julliard642d3131998-07-12 19:29:36 +00001222 DWORD ProcessHandle = stack[1]; /* ignored */
Andreas Mohra00b49f1998-12-07 10:48:09 +00001223 DWORD * BaseAddress = (DWORD *)W32S_APP2WINE(stack[2], W32S_OFFSET);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001224 DWORD ZeroBits = stack[3];
1225 DWORD CommitSize = stack[4];
Andreas Mohra00b49f1998-12-07 10:48:09 +00001226 LARGE_INTEGER *SectionOffset = (LARGE_INTEGER *)W32S_APP2WINE(stack[5], W32S_OFFSET);
1227 DWORD * ViewSize = (DWORD *)W32S_APP2WINE(stack[6], W32S_OFFSET);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001228 DWORD InheritDisposition = stack[7];
1229 DWORD AllocationType = stack[8];
1230 DWORD Protect = stack[9];
1231
Andreas Mohra00b49f1998-12-07 10:48:09 +00001232 LPBYTE address = (LPBYTE)(BaseAddress?
1233 W32S_APP2WINE(*BaseAddress, W32S_OFFSET) : 0);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001234 DWORD access = 0, result;
1235
1236 switch (Protect & ~(PAGE_GUARD|PAGE_NOCACHE))
1237 {
1238 case PAGE_READONLY: access = FILE_MAP_READ; break;
1239 case PAGE_READWRITE: access = FILE_MAP_WRITE; break;
1240 case PAGE_WRITECOPY: access = FILE_MAP_COPY; break;
1241
1242 case PAGE_EXECUTE_READ: access = FILE_MAP_READ; break;
1243 case PAGE_EXECUTE_READWRITE: access = FILE_MAP_WRITE; break;
1244 case PAGE_EXECUTE_WRITECOPY: access = FILE_MAP_COPY; break;
1245 }
1246
Alexandre Julliard61fece01999-06-26 19:09:08 +00001247 TRACE("NtMapViewOfSection"
Alexandre Julliard642d3131998-07-12 19:29:36 +00001248 "(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n",
1249 (DWORD)SectionHandle, ProcessHandle, (DWORD)BaseAddress,
1250 ZeroBits, CommitSize, (DWORD)SectionOffset, (DWORD)ViewSize,
1251 InheritDisposition, AllocationType, Protect);
Alexandre Julliard61fece01999-06-26 19:09:08 +00001252 TRACE("NtMapViewOfSection: "
Alexandre Julliard642d3131998-07-12 19:29:36 +00001253 "base=%lx, offset=%lx, size=%lx, access=%lx\n",
Patrik Stridvall311e4561999-09-19 14:20:33 +00001254 (DWORD)address, SectionOffset? SectionOffset->s.LowPart : 0,
Alexandre Julliard642d3131998-07-12 19:29:36 +00001255 ViewSize? *ViewSize : 0, access);
1256
1257 result = (DWORD)MapViewOfFileEx(SectionHandle, access,
Patrik Stridvall311e4561999-09-19 14:20:33 +00001258 SectionOffset? SectionOffset->s.HighPart : 0,
1259 SectionOffset? SectionOffset->s.LowPart : 0,
Alexandre Julliard642d3131998-07-12 19:29:36 +00001260 ViewSize? *ViewSize : 0, address);
1261
Alexandre Julliard61fece01999-06-26 19:09:08 +00001262 TRACE("NtMapViewOfSection: result=%lx\n", result);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001263
Andreas Mohra00b49f1998-12-07 10:48:09 +00001264 if (W32S_WINE2APP(result, W32S_OFFSET))
Alexandre Julliard642d3131998-07-12 19:29:36 +00001265 {
Andreas Mohra00b49f1998-12-07 10:48:09 +00001266 if (BaseAddress) *BaseAddress = W32S_WINE2APP(result, W32S_OFFSET);
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001267 context->Eax = STATUS_SUCCESS;
Alexandre Julliard642d3131998-07-12 19:29:36 +00001268 }
1269 else
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001270 context->Eax = STATUS_NO_MEMORY; /* FIXME */
Alexandre Julliard642d3131998-07-12 19:29:36 +00001271 }
1272 break;
1273
1274
1275 case 0x0012: /* NtUnmapViewOfSection */
1276 /*
1277 * Input: EDX: Flat address of arguments on stack
1278 *
1279 * DWORD ProcessHandle [in] Process (defining address space)
1280 * LPBYTE BaseAddress [in] Base address of view to be unmapped
1281 *
1282 * Output: EAX: NtStatus
1283 */
1284 {
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001285 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001286 DWORD ProcessHandle = stack[0]; /* ignored */
Andreas Mohra00b49f1998-12-07 10:48:09 +00001287 LPBYTE BaseAddress = (LPBYTE)W32S_APP2WINE(stack[1], W32S_OFFSET);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001288
Alexandre Julliard61fece01999-06-26 19:09:08 +00001289 TRACE("NtUnmapViewOfSection(%lx, %lx)\n",
Alexandre Julliard642d3131998-07-12 19:29:36 +00001290 ProcessHandle, (DWORD)BaseAddress);
1291
1292 UnmapViewOfFile(BaseAddress);
1293
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001294 context->Eax = STATUS_SUCCESS;
Alexandre Julliard642d3131998-07-12 19:29:36 +00001295 }
1296 break;
1297
1298
1299 case 0x0013: /* NtFlushVirtualMemory */
1300 /*
1301 * Input: EDX: Flat address of arguments on stack
1302 *
1303 * DWORD ProcessHandle [in] Process (defining address space)
1304 * LPBYTE *BaseAddress [in?] Base address of range to be flushed
1305 * DWORD *ViewSize [in?] Number of bytes to be flushed
1306 * DWORD *unknown [???] (?? unknown ??)
1307 *
1308 * Output: EAX: NtStatus
1309 */
1310 {
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001311 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001312 DWORD ProcessHandle = stack[0]; /* ignored */
Andreas Mohra00b49f1998-12-07 10:48:09 +00001313 DWORD *BaseAddress = (DWORD *)W32S_APP2WINE(stack[1], W32S_OFFSET);
1314 DWORD *ViewSize = (DWORD *)W32S_APP2WINE(stack[2], W32S_OFFSET);
1315 DWORD *unknown = (DWORD *)W32S_APP2WINE(stack[3], W32S_OFFSET);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001316
Andreas Mohra00b49f1998-12-07 10:48:09 +00001317 LPBYTE address = (LPBYTE)(BaseAddress? W32S_APP2WINE(*BaseAddress, W32S_OFFSET) : 0);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001318 DWORD size = ViewSize? *ViewSize : 0;
1319
Alexandre Julliard61fece01999-06-26 19:09:08 +00001320 TRACE("NtFlushVirtualMemory(%lx, %lx, %lx, %lx)\n",
Alexandre Julliard642d3131998-07-12 19:29:36 +00001321 ProcessHandle, (DWORD)BaseAddress, (DWORD)ViewSize,
1322 (DWORD)unknown);
Alexandre Julliard61fece01999-06-26 19:09:08 +00001323 TRACE("NtFlushVirtualMemory: base=%lx, size=%lx\n",
Alexandre Julliard642d3131998-07-12 19:29:36 +00001324 (DWORD)address, size);
1325
1326 FlushViewOfFile(address, size);
1327
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001328 context->Eax = STATUS_SUCCESS;
Alexandre Julliard642d3131998-07-12 19:29:36 +00001329 }
1330 break;
1331
1332
1333 case 0x0014: /* Get/Set Debug Registers */
1334 /*
1335 * Input: ECX: 0 if Get, 1 if Set
1336 *
1337 * EDX: Get: Flat address of buffer to receive values of
1338 * debug registers DR0 .. DR7
1339 * Set: Flat address of buffer containing values of
1340 * debug registers DR0 .. DR7 to be set
1341 * Output: None
1342 */
1343
Alexandre Julliard61fece01999-06-26 19:09:08 +00001344 FIXME("[0014] ECX=%lx EDX=%lx\n",
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001345 context->Ecx, context->Edx);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001346
1347 /* FIXME */
1348 break;
1349
1350
1351 case 0x0015: /* Set Coprocessor Emulation Flag */
1352 /*
1353 * Input: EDX: 0 to deactivate, 1 to activate coprocessor emulation
1354 *
1355 * Output: None
1356 */
1357
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001358 TRACE("[0015] EDX=%lx\n", context->Edx);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001359
1360 /* We don't care, as we always have a coprocessor anyway */
1361 break;
1362
1363
1364 case 0x0016: /* Init Win32S VxD PSP */
1365 /*
1366 * If called to query required PSP size:
1367 *
1368 * Input: EBX: 0
1369 * Output: EDX: Required size of Win32s VxD PSP
1370 *
1371 * If called to initialize allocated PSP:
1372 *
1373 * Input: EBX: LoWord: Selector of Win32s VxD PSP
1374 * HiWord: Paragraph of Win32s VxD PSP (DOSMEM)
1375 * Output: None
1376 */
1377
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001378 if (context->Ebx == 0)
1379 context->Edx = 0x80;
Alexandre Julliard642d3131998-07-12 19:29:36 +00001380 else
1381 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001382 PDB16 *psp = PTR_SEG_OFF_TO_LIN(BX_reg(context), 0);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001383 psp->nbFiles = 32;
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001384 psp->fileHandlesPtr = MAKELONG(HIWORD(context->Ebx), 0x5c);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001385 memset((LPBYTE)psp + 0x5c, '\xFF', 32);
1386 }
1387 break;
1388
1389
1390 case 0x0017: /* Set Break Point */
1391 /*
1392 * Input: EBX: Offset of Break Point
1393 * CX: Selector of Break Point
1394 *
1395 * Output: None
1396 */
1397
Alexandre Julliard61fece01999-06-26 19:09:08 +00001398 FIXME("[0017] EBX=%lx CX=%x\n",
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001399 context->Ebx, CX_reg(context));
Alexandre Julliard642d3131998-07-12 19:29:36 +00001400
1401 /* FIXME */
1402 break;
1403
1404
1405 case 0x0018: /* VirtualLock */
1406 /*
1407 * Input: ECX: Current Process
1408 *
1409 * EDX: Flat address of arguments on stack
1410 *
1411 * DWORD *retv [out] TRUE if success, FALSE if failure
1412 * LPVOID base [in] Flat address of range to lock
1413 * DWORD size [in] Size of range
1414 *
1415 * Output: EAX: NtStatus
1416 */
1417 {
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001418 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
Andreas Mohra00b49f1998-12-07 10:48:09 +00001419 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1420 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001421 DWORD size = stack[2];
1422 DWORD result;
1423
Alexandre Julliard61fece01999-06-26 19:09:08 +00001424 TRACE("VirtualLock(%lx, %lx, %lx)\n",
Alexandre Julliard642d3131998-07-12 19:29:36 +00001425 (DWORD)retv, (DWORD)base, size);
1426
1427 result = VirtualLock(base, size);
1428
1429 if (result)
1430 *retv = TRUE,
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001431 context->Eax = STATUS_SUCCESS;
Alexandre Julliard642d3131998-07-12 19:29:36 +00001432 else
1433 *retv = FALSE,
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001434 context->Eax = STATUS_NO_MEMORY; /* FIXME */
Alexandre Julliard642d3131998-07-12 19:29:36 +00001435 }
1436 break;
1437
1438
1439 case 0x0019: /* VirtualUnlock */
1440 /*
1441 * Input: ECX: Current Process
1442 *
1443 * EDX: Flat address of arguments on stack
1444 *
1445 * DWORD *retv [out] TRUE if success, FALSE if failure
1446 * LPVOID base [in] Flat address of range to unlock
1447 * DWORD size [in] Size of range
1448 *
1449 * Output: EAX: NtStatus
1450 */
1451 {
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001452 DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx, W32S_OFFSET);
Andreas Mohra00b49f1998-12-07 10:48:09 +00001453 DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0], W32S_OFFSET);
1454 LPVOID base = (LPVOID) W32S_APP2WINE(stack[1], W32S_OFFSET);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001455 DWORD size = stack[2];
1456 DWORD result;
1457
Alexandre Julliard61fece01999-06-26 19:09:08 +00001458 TRACE("VirtualUnlock(%lx, %lx, %lx)\n",
Alexandre Julliard642d3131998-07-12 19:29:36 +00001459 (DWORD)retv, (DWORD)base, size);
1460
1461 result = VirtualUnlock(base, size);
1462
1463 if (result)
1464 *retv = TRUE,
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001465 context->Eax = STATUS_SUCCESS;
Alexandre Julliard642d3131998-07-12 19:29:36 +00001466 else
1467 *retv = FALSE,
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001468 context->Eax = STATUS_NO_MEMORY; /* FIXME */
Alexandre Julliard642d3131998-07-12 19:29:36 +00001469 }
1470 break;
1471
1472
1473 case 0x001A: /* KGetSystemInfo */
1474 /*
1475 * Input: None
1476 *
1477 * Output: ECX: Start of sparse memory arena
1478 * EDX: End of sparse memory arena
1479 */
1480
Alexandre Julliard61fece01999-06-26 19:09:08 +00001481 TRACE("KGetSystemInfo()\n");
Alexandre Julliard642d3131998-07-12 19:29:36 +00001482
1483 /*
1484 * Note: Win32s reserves 0GB - 2GB for Win 3.1 and uses 2GB - 4GB as
1485 * sparse memory arena. We do it the other way around, since
1486 * we have to reserve 3GB - 4GB for Linux, and thus use
1487 * 0GB - 3GB as sparse memory arena.
1488 *
1489 * FIXME: What about other OSes ?
1490 */
1491
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001492 context->Ecx = W32S_WINE2APP(0x00000000, W32S_OFFSET);
1493 context->Edx = W32S_WINE2APP(0xbfffffff, W32S_OFFSET);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001494 break;
1495
1496
1497 case 0x001B: /* KGlobalMemStat */
1498 /*
1499 * Input: ESI: Flat address of buffer to receive memory info
1500 *
1501 * Output: None
1502 */
1503 {
1504 struct Win32sMemoryInfo
1505 {
1506 DWORD DIPhys_Count; /* Total physical pages */
1507 DWORD DIFree_Count; /* Free physical pages */
1508 DWORD DILin_Total_Count; /* Total virtual pages (private arena) */
1509 DWORD DILin_Total_Free; /* Free virtual pages (private arena) */
1510
1511 DWORD SparseTotal; /* Total size of sparse arena (bytes ?) */
1512 DWORD SparseFree; /* Free size of sparse arena (bytes ?) */
1513 };
1514
1515 struct Win32sMemoryInfo *info =
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001516 (struct Win32sMemoryInfo *)W32S_APP2WINE(context->Esi, W32S_OFFSET);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001517
Alexandre Julliard61fece01999-06-26 19:09:08 +00001518 FIXME("KGlobalMemStat(%lx)\n", (DWORD)info);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001519
1520 /* FIXME */
1521 }
1522 break;
1523
1524
1525 case 0x001C: /* Enable/Disable Exceptions */
1526 /*
1527 * Input: ECX: 0 to disable, 1 to enable exception handling
1528 *
1529 * Output: None
1530 */
1531
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001532 TRACE("[001c] ECX=%lx\n", context->Ecx);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001533
1534 /* FIXME */
1535 break;
1536
1537
1538 case 0x001D: /* VirtualAlloc called from 16-bit code */
1539 /*
1540 * Input: EDX: Segmented address of arguments on stack
1541 *
1542 * LPVOID base [in] Flat address of region to reserve/commit
1543 * DWORD size [in] Size of region
1544 * DWORD type [in] Type of allocation
1545 * DWORD prot [in] Type of access protection
1546 *
1547 * Output: EAX: NtStatus
1548 * EDX: Flat base address of allocated region
1549 */
1550 {
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001551 DWORD *stack = PTR_SEG_OFF_TO_LIN(LOWORD(context->Edx),
1552 HIWORD(context->Edx));
Andreas Mohra00b49f1998-12-07 10:48:09 +00001553 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0], W32S_OFFSET);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001554 DWORD size = stack[1];
1555 DWORD type = stack[2];
1556 DWORD prot = stack[3];
1557 DWORD result;
1558
Alexandre Julliard61fece01999-06-26 19:09:08 +00001559 TRACE("VirtualAlloc16(%lx, %lx, %lx, %lx)\n",
Alexandre Julliard642d3131998-07-12 19:29:36 +00001560 (DWORD)base, size, type, prot);
1561
1562 if (type & 0x80000000)
1563 {
Alexandre Julliard61fece01999-06-26 19:09:08 +00001564 WARN("VirtualAlloc16: strange type %lx\n", type);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001565 type &= 0x7fffffff;
1566 }
1567
1568 result = (DWORD)VirtualAlloc(base, size, type, prot);
1569
Andreas Mohra00b49f1998-12-07 10:48:09 +00001570 if (W32S_WINE2APP(result, W32S_OFFSET))
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001571 context->Edx = W32S_WINE2APP(result, W32S_OFFSET),
1572 context->Eax = STATUS_SUCCESS;
Alexandre Julliard642d3131998-07-12 19:29:36 +00001573 else
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001574 context->Edx = 0,
1575 context->Eax = STATUS_NO_MEMORY; /* FIXME */
1576 TRACE("VirtualAlloc16: returning base %lx\n", context->Edx);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001577 }
1578 break;
1579
1580
1581 case 0x001E: /* VirtualFree called from 16-bit code */
1582 /*
1583 * Input: EDX: Segmented address of arguments on stack
1584 *
1585 * LPVOID base [in] Flat address of region
1586 * DWORD size [in] Size of region
1587 * DWORD type [in] Type of operation
1588 *
1589 * Output: EAX: NtStatus
1590 * EDX: TRUE if success, FALSE if failure
1591 */
1592 {
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001593 DWORD *stack = PTR_SEG_OFF_TO_LIN(LOWORD(context->Edx),
1594 HIWORD(context->Edx));
Andreas Mohra00b49f1998-12-07 10:48:09 +00001595 LPVOID base = (LPVOID)W32S_APP2WINE(stack[0], W32S_OFFSET);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001596 DWORD size = stack[1];
1597 DWORD type = stack[2];
1598 DWORD result;
1599
Alexandre Julliard61fece01999-06-26 19:09:08 +00001600 TRACE("VirtualFree16(%lx, %lx, %lx)\n",
Alexandre Julliard642d3131998-07-12 19:29:36 +00001601 (DWORD)base, size, type);
1602
1603 result = VirtualFree(base, size, type);
1604
1605 if (result)
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001606 context->Edx = TRUE,
1607 context->Eax = STATUS_SUCCESS;
Alexandre Julliard642d3131998-07-12 19:29:36 +00001608 else
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001609 context->Edx = FALSE,
1610 context->Eax = STATUS_NO_MEMORY; /* FIXME */
Alexandre Julliard642d3131998-07-12 19:29:36 +00001611 }
1612 break;
1613
1614
1615 case 0x001F: /* FWorkingSetSize */
1616 /*
1617 * Input: EDX: 0 if Get, 1 if Set
1618 *
1619 * ECX: Get: Buffer to receive Working Set Size
1620 * Set: Buffer containing Working Set Size
1621 *
1622 * Output: NtStatus
1623 */
1624 {
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001625 DWORD *ptr = (DWORD *)W32S_APP2WINE(context->Ecx, W32S_OFFSET);
1626 BOOL set = context->Edx;
Alexandre Julliard642d3131998-07-12 19:29:36 +00001627
Alexandre Julliard61fece01999-06-26 19:09:08 +00001628 TRACE("FWorkingSetSize(%lx, %lx)\n", (DWORD)ptr, (DWORD)set);
Alexandre Julliard642d3131998-07-12 19:29:36 +00001629
1630 if (set)
1631 /* We do it differently ... */;
1632 else
1633 *ptr = 0x100;
1634
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +00001635 context->Eax = STATUS_SUCCESS;
Alexandre Julliard642d3131998-07-12 19:29:36 +00001636 }
1637 break;
1638
1639
1640 default:
1641 VXD_BARF( context, "W32S" );
1642 }
1643
Alexandre Julliard642d3131998-07-12 19:29:36 +00001644}
1645