libport: Replacement for poll().
[wine] / dlls / vmm.vxd / vmm.c
1 /*
2  * VMM VxD implementation
3  *
4  * Copyright 1998 Marcus Meissner
5  * Copyright 1998 Ulrich Weigand
6  * Copyright 1998 Patrik Stridvall
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include <stdarg.h>
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winternl.h"
31 #include "wine/debug.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(vxd);
34
35 /*
36  * VMM VxDCall service names are (mostly) taken from Stan Mitchell's
37  * "Inside the Windows 95 File System"
38  */
39
40 #define N_VMM_SERVICE 41
41
42 static const char * const VMM_Service_Name[N_VMM_SERVICE] =
43 {
44     "PageReserve",            /* 0x0000 */
45     "PageCommit",             /* 0x0001 */
46     "PageDecommit",           /* 0x0002 */
47     "PagerRegister",          /* 0x0003 */
48     "PagerQuery",             /* 0x0004 */
49     "HeapAllocate",           /* 0x0005 */
50     "ContextCreate",          /* 0x0006 */
51     "ContextDestroy",         /* 0x0007 */
52     "PageAttach",             /* 0x0008 */
53     "PageFlush",              /* 0x0009 */
54     "PageFree",               /* 0x000A */
55     "ContextSwitch",          /* 0x000B */
56     "HeapReAllocate",         /* 0x000C */
57     "PageModifyPermissions",  /* 0x000D */
58     "PageQuery",              /* 0x000E */
59     "GetCurrentContext",      /* 0x000F */
60     "HeapFree",               /* 0x0010 */
61     "RegOpenKey",             /* 0x0011 */
62     "RegCreateKey",           /* 0x0012 */
63     "RegCloseKey",            /* 0x0013 */
64     "RegDeleteKey",           /* 0x0014 */
65     "RegSetValue",            /* 0x0015 */
66     "RegDeleteValue",         /* 0x0016 */
67     "RegQueryValue",          /* 0x0017 */
68     "RegEnumKey",             /* 0x0018 */
69     "RegEnumValue",           /* 0x0019 */
70     "RegQueryValueEx",        /* 0x001A */
71     "RegSetValueEx",          /* 0x001B */
72     "RegFlushKey",            /* 0x001C */
73     "RegQueryInfoKey",        /* 0x001D */
74     "GetDemandPageInfo",      /* 0x001E */
75     "BlockOnID",              /* 0x001F */
76     "SignalID",               /* 0x0020 */
77     "RegLoadKey",             /* 0x0021 */
78     "RegUnLoadKey",           /* 0x0022 */
79     "RegSaveKey",             /* 0x0023 */
80     "RegRemapPreDefKey",      /* 0x0024 */
81     "PageChangePager",        /* 0x0025 */
82     "RegQueryMultipleValues", /* 0x0026 */
83     "RegReplaceKey",          /* 0x0027 */
84     "<KERNEL32.101>"          /* 0x0028 -- What does this do??? */
85 };
86
87 /* PageReserve arena values */
88 #define PR_PRIVATE    0x80000400 /* anywhere in private arena */
89 #define PR_SHARED     0x80060000 /* anywhere in shared arena */
90 #define PR_SYSTEM     0x80080000 /* anywhere in system arena */
91
92 /* PageReserve flags */
93 #define PR_FIXED      0x00000008 /* don't move during PageReAllocate */
94 #define PR_4MEG       0x00000001 /* allocate on 4mb boundary */
95 #define PR_STATIC     0x00000010 /* see PageReserve documentation */
96
97 /* PageCommit default pager handle values */
98 #define PD_ZEROINIT   0x00000001 /* swappable zero-initialized pages */
99 #define PD_NOINIT     0x00000002 /* swappable uninitialized pages */
100 #define PD_FIXEDZERO  0x00000003 /* fixed zero-initialized pages */
101 #define PD_FIXED      0x00000004 /* fixed uninitialized pages */
102
103 /* PageCommit flags */
104 #define PC_FIXED      0x00000008 /* pages are permanently locked */
105 #define PC_LOCKED     0x00000080 /* pages are made present and locked */
106 #define PC_LOCKEDIFDP 0x00000100 /* pages are locked if swap via DOS */
107 #define PC_WRITABLE   0x00020000 /* make the pages writable */
108 #define PC_USER       0x00040000 /* make the pages ring 3 accessible */
109 #define PC_INCR       0x40000000 /* increment "pagerdata" each page */
110 #define PC_PRESENT    0x80000000 /* make pages initially present */
111 #define PC_STATIC     0x20000000 /* allow commit in PR_STATIC object */
112 #define PC_DIRTY      0x08000000 /* make pages initially dirty */
113 #define PC_CACHEDIS   0x00100000 /* Allocate uncached pages - new for WDM */
114 #define PC_CACHEWT    0x00080000 /* Allocate write through cache pages - new for WDM */
115 #define PC_PAGEFLUSH  0x00008000 /* Touch device mapped pages on alloc - new for WDM */
116
117 /* PageCommitContig additional flags */
118 #define PCC_ZEROINIT  0x00000001 /* zero-initialize new pages */
119 #define PCC_NOLIN     0x10000000 /* don't map to any linear address */
120
121
122 /* Pop a DWORD from the 32-bit stack */
123 static inline DWORD stack32_pop( CONTEXT86 *context )
124 {
125     DWORD ret = *(DWORD *)context->Esp;
126     context->Esp += sizeof(DWORD);
127     return ret;
128 }
129
130
131 /***********************************************************************
132  *           VxDCall   (VMM.VXD.@)
133  */
134 DWORD WINAPI VMM_VxDCall( DWORD service, CONTEXT86 *context )
135 {
136     static int warned;
137
138     switch ( LOWORD(service) )
139     {
140     case 0x0000: /* PageReserve */
141     {
142         LPVOID address;
143         LPVOID ret;
144         DWORD psize = getpagesize();
145         ULONG page   = stack32_pop( context );
146         ULONG npages = stack32_pop( context );
147         ULONG flags  = stack32_pop( context );
148
149         TRACE("PageReserve: page: %08x, npages: %08x, flags: %08x partial stub!\n",
150               page, npages, flags );
151
152         if ( page == PR_SYSTEM ) {
153           ERR("Can't reserve ring 1 memory\n");
154           return -1;
155         }
156         /* FIXME: This has to be handled separately for the separate
157            address-spaces we now have */
158         if ( page == PR_PRIVATE || page == PR_SHARED ) page = 0;
159         /* FIXME: Handle flags in some way */
160         address = (LPVOID )(page * psize);
161         ret = VirtualAlloc ( address, ( npages * psize ), MEM_RESERVE, 0 );
162         TRACE("PageReserve: returning: %p\n", ret );
163         if ( ret == NULL )
164           return -1;
165         else
166           return (DWORD )ret;
167     }
168
169     case 0x0001: /* PageCommit */
170     {
171         LPVOID address;
172         LPVOID ret;
173         DWORD virt_perm;
174         DWORD psize = getpagesize();
175         ULONG page   = stack32_pop( context );
176         ULONG npages = stack32_pop( context );
177         ULONG hpd  = stack32_pop( context );
178         ULONG pagerdata   = stack32_pop( context );
179         ULONG flags  = stack32_pop( context );
180
181         TRACE("PageCommit: page: %08x, npages: %08x, hpd: %08x pagerdata: "
182               "%08x, flags: %08x partial stub\n",
183               page, npages, hpd, pagerdata, flags );
184
185         if ( flags & PC_USER )
186           if ( flags & PC_WRITABLE )
187             virt_perm = PAGE_EXECUTE_READWRITE;
188           else
189             virt_perm = PAGE_EXECUTE_READ;
190         else
191           virt_perm = PAGE_NOACCESS;
192
193         address = (LPVOID )(page * psize);
194         ret = VirtualAlloc ( address, ( npages * psize ), MEM_COMMIT, virt_perm );
195         TRACE("PageCommit: Returning: %p\n", ret );
196         return (DWORD )ret;
197
198     }
199
200     case 0x0002: /* PageDecommit */
201     {
202         LPVOID address;
203         BOOL ret;
204         DWORD psize = getpagesize();
205         ULONG page = stack32_pop( context );
206         ULONG npages = stack32_pop( context );
207         ULONG flags = stack32_pop( context );
208
209         TRACE("PageDecommit: page: %08x, npages: %08x, flags: %08x partial stub\n",
210               page, npages, flags );
211         address = (LPVOID )( page * psize );
212         ret = VirtualFree ( address, ( npages * psize ), MEM_DECOMMIT );
213         TRACE("PageDecommit: Returning: %s\n", ret ? "TRUE" : "FALSE" );
214         return ret;
215     }
216
217     case 0x000d: /* PageModifyPermissions */
218     {
219         DWORD pg_old_perm;
220         DWORD pg_new_perm;
221         DWORD virt_old_perm;
222         DWORD virt_new_perm;
223         MEMORY_BASIC_INFORMATION mbi;
224         LPVOID address;
225         DWORD psize = getpagesize();
226         ULONG page = stack32_pop ( context );
227         ULONG npages = stack32_pop ( context );
228         ULONG permand = stack32_pop ( context );
229         ULONG permor = stack32_pop ( context );
230
231         TRACE("PageModifyPermissions %08x %08x %08x %08x partial stub\n",
232               page, npages, permand, permor );
233         address = (LPVOID )( page * psize );
234
235         VirtualQuery ( address, &mbi, sizeof ( MEMORY_BASIC_INFORMATION ));
236         virt_old_perm = mbi.Protect;
237
238         switch ( virt_old_perm & mbi.Protect ) {
239         case PAGE_READONLY:
240         case PAGE_EXECUTE:
241         case PAGE_EXECUTE_READ:
242           pg_old_perm = PC_USER;
243           break;
244         case PAGE_READWRITE:
245         case PAGE_WRITECOPY:
246         case PAGE_EXECUTE_READWRITE:
247         case PAGE_EXECUTE_WRITECOPY:
248           pg_old_perm = PC_USER | PC_WRITABLE;
249           break;
250         case PAGE_NOACCESS:
251         default:
252           pg_old_perm = 0;
253           break;
254         }
255         pg_new_perm = pg_old_perm;
256         pg_new_perm &= permand & ~PC_STATIC;
257         pg_new_perm |= permor  & ~PC_STATIC;
258
259         virt_new_perm = ( virt_old_perm )  & ~0xff;
260         if ( pg_new_perm & PC_USER )
261         {
262           if ( pg_new_perm & PC_WRITABLE )
263             virt_new_perm |= PAGE_EXECUTE_READWRITE;
264           else
265             virt_new_perm |= PAGE_EXECUTE_READ;
266         }
267
268         if ( ! VirtualProtect ( address, ( npages * psize ), virt_new_perm, &virt_old_perm ) ) {
269           ERR("Can't change page permissions for %p\n", address );
270           return 0xffffffff;
271         }
272         TRACE("Returning: %08x\n", pg_old_perm );
273         return pg_old_perm;
274     }
275
276     case 0x000a: /* PageFree */
277     {
278         BOOL ret;
279         LPVOID hmem = (LPVOID) stack32_pop( context );
280         DWORD flags = stack32_pop( context );
281
282         TRACE("PageFree: hmem: %p, flags: %08x partial stub\n",
283               hmem, flags );
284
285         ret = VirtualFree ( hmem, 0, MEM_RELEASE );
286         TRACE("Returning: %d\n", ret );
287         return ret;
288     }
289
290     case 0x0011:  /* RegOpenKey */
291         stack32_pop( context ); /* kkey */
292         stack32_pop( context ); /* lpszSubKey */
293         stack32_pop( context ); /* retkey */
294         /* return RegOpenKeyExA( hkey, lpszSubKey, 0, KEY_ALL_ACCESS, retkey ); */
295         if (!warned)
296         {
297             ERR( "Using the native Win95 advapi32.dll is no longer supported.\n" );
298             ERR( "Please configure advapi32 to builtin.\n" );
299             warned++;
300         }
301         return ERROR_CALL_NOT_IMPLEMENTED;
302
303     case 0x0012:  /* RegCreateKey */
304         stack32_pop( context ); /* hkey */
305         stack32_pop( context ); /* lpszSubKey */
306         stack32_pop( context ); /* retkey */
307         /* return RegCreateKeyA( hkey, lpszSubKey, retkey ); */
308         if (!warned)
309         {
310             ERR( "Using the native Win95 advapi32.dll is no longer supported.\n" );
311             ERR( "Please configure advapi32 to builtin.\n" );
312             warned++;
313         }
314         return ERROR_CALL_NOT_IMPLEMENTED;
315
316     case 0x0013:  /* RegCloseKey */
317         stack32_pop( context ); /* hkey */
318         /* return RegCloseKey( hkey ); */
319         return ERROR_CALL_NOT_IMPLEMENTED;
320
321     case 0x0014:  /* RegDeleteKey */
322         stack32_pop( context ); /* hkey */
323         stack32_pop( context ); /* lpszSubKey */
324         /* return RegDeleteKeyA( hkey, lpszSubKey ); */
325         return ERROR_CALL_NOT_IMPLEMENTED;
326
327     case 0x0015:  /* RegSetValue */
328         stack32_pop( context ); /* hkey */
329         stack32_pop( context ); /* lpszSubKey */
330         stack32_pop( context ); /* dwType */
331         stack32_pop( context ); /* lpszData */
332         stack32_pop( context ); /* cbData */
333         /* return RegSetValueA( hkey, lpszSubKey, dwType, lpszData, cbData ); */
334         return ERROR_CALL_NOT_IMPLEMENTED;
335
336     case 0x0016:  /* RegDeleteValue */
337         stack32_pop( context ); /* hkey */
338         stack32_pop( context ); /* lpszValue */
339         /* return RegDeleteValueA( hkey, lpszValue ); */
340         return ERROR_CALL_NOT_IMPLEMENTED;
341
342     case 0x0017:  /* RegQueryValue */
343         stack32_pop( context ); /* hkey */
344         stack32_pop( context ); /* lpszSubKey */
345         stack32_pop( context ); /* lpszData */
346         stack32_pop( context ); /* lpcbData */
347         /* return RegQueryValueA( hkey, lpszSubKey, lpszData, lpcbData ); */
348         return ERROR_CALL_NOT_IMPLEMENTED;
349
350     case 0x0018:  /* RegEnumKey */
351         stack32_pop( context ); /* hkey */
352         stack32_pop( context ); /* iSubkey */
353         stack32_pop( context ); /* lpszName */
354         stack32_pop( context ); /* lpcchName */
355         /* return RegEnumKeyA( hkey, iSubkey, lpszName, lpcchName ); */
356         return ERROR_CALL_NOT_IMPLEMENTED;
357
358     case 0x0019:  /* RegEnumValue */
359         stack32_pop( context ); /* hkey */
360         stack32_pop( context ); /* iValue */
361         stack32_pop( context ); /* lpszValue */
362         stack32_pop( context ); /* lpcchValue */
363         stack32_pop( context ); /* lpReserved */
364         stack32_pop( context ); /* lpdwType */
365         stack32_pop( context ); /* lpbData */
366         stack32_pop( context ); /* lpcbData */
367         /* return RegEnumValueA( hkey, iValue, lpszValue, lpcchValue, lpReserved, lpdwType, lpbData, lpcbData ); */
368         return ERROR_CALL_NOT_IMPLEMENTED;
369
370     case 0x001A:  /* RegQueryValueEx */
371         stack32_pop( context ); /* hkey */
372         stack32_pop( context ); /* lpszValue */
373         stack32_pop( context ); /* lpReserved */
374         stack32_pop( context ); /* lpdwType */
375         stack32_pop( context ); /* lpbData */
376         stack32_pop( context ); /* lpcbData */
377         /* return RegQueryValueExA( hkey, lpszValue, lpReserved, lpdwType, lpbData, lpcbData ); */
378         return ERROR_CALL_NOT_IMPLEMENTED;
379
380     case 0x001B:  /* RegSetValueEx */
381         stack32_pop( context ); /* hkey */
382         stack32_pop( context ); /* lpszValue */
383         stack32_pop( context ); /* dwReserved */
384         stack32_pop( context ); /* dwType */
385         stack32_pop( context ); /* lpbData */
386         stack32_pop( context ); /* cbData */
387         /* return RegSetValueExA( hkey, lpszValue, dwReserved, dwType, lpbData, cbData ); */
388         return ERROR_CALL_NOT_IMPLEMENTED;
389
390     case 0x001C:  /* RegFlushKey */
391         stack32_pop( context ); /* hkey */
392         /* return RegFlushKey( hkey ); */
393         return ERROR_CALL_NOT_IMPLEMENTED;
394
395     case 0x001D:  /* RegQueryInfoKey */
396         /* NOTE: This VxDCall takes only a subset of the parameters that the
397                  corresponding Win32 API call does. The implementation in Win95
398                  ADVAPI32 sets all output parameters not mentioned here to zero. */
399         stack32_pop( context ); /* hkey */
400         stack32_pop( context ); /* lpcSubKeys */
401         stack32_pop( context ); /* lpcchMaxSubKey */
402         stack32_pop( context ); /* lpcValues */
403         stack32_pop( context ); /* lpcchMaxValueName */
404         stack32_pop( context ); /* lpcchMaxValueData */
405         /* return RegQueryInfoKeyA( hkey, lpcSubKeys, lpcchMaxSubKey, lpcValues, lpcchMaxValueName, lpcchMaxValueData ); */
406         return ERROR_CALL_NOT_IMPLEMENTED;
407
408     case 0x001e: /* GetDemandPageInfo */
409     {
410          DWORD dinfo = stack32_pop( context );
411          DWORD flags = stack32_pop( context );
412
413          /* GetDemandPageInfo is supposed to fill out the struct at
414           * "dinfo" with various low-level memory management information.
415           * Apps are certainly not supposed to call this, although it's
416           * demoed and documented by Pietrek on pages 441-443 of "Windows
417           * 95 System Programming Secrets" if any program needs a real
418           * implementation of this.
419           */
420
421          FIXME("GetDemandPageInfo(%08x %08x): stub!\n", dinfo, flags);
422
423          return 0;
424     }
425
426     case 0x0021:  /* RegLoadKey */
427     {
428         HKEY    hkey       = (HKEY)  stack32_pop( context );
429         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
430         LPCSTR  lpszFile   = (LPCSTR)stack32_pop( context );
431         FIXME("RegLoadKey(%p,%s,%s): stub\n",hkey, debugstr_a(lpszSubKey), debugstr_a(lpszFile));
432         return ERROR_CALL_NOT_IMPLEMENTED;
433     }
434
435     case 0x0022:  /* RegUnLoadKey */
436     {
437         HKEY    hkey       = (HKEY)  stack32_pop( context );
438         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
439         FIXME("RegUnLoadKey(%p,%s): stub\n",hkey, debugstr_a(lpszSubKey));
440         return ERROR_CALL_NOT_IMPLEMENTED;
441     }
442
443     case 0x0023:  /* RegSaveKey */
444     {
445         HKEY    hkey       = (HKEY)  stack32_pop( context );
446         LPCSTR  lpszFile   = (LPCSTR)stack32_pop( context );
447         LPSECURITY_ATTRIBUTES sa = (LPSECURITY_ATTRIBUTES)stack32_pop( context );
448         FIXME("RegSaveKey(%p,%s,%p): stub\n",hkey, debugstr_a(lpszFile),sa);
449         return ERROR_CALL_NOT_IMPLEMENTED;
450     }
451
452 #if 0 /* Functions are not yet implemented in misc/registry.c */
453     case 0x0024:  /* RegRemapPreDefKey */
454     case 0x0026:  /* RegQueryMultipleValues */
455 #endif
456
457     case 0x0027:  /* RegReplaceKey */
458     {
459         HKEY    hkey       = (HKEY)  stack32_pop( context );
460         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
461         LPCSTR  lpszNewFile= (LPCSTR)stack32_pop( context );
462         LPCSTR  lpszOldFile= (LPCSTR)stack32_pop( context );
463         FIXME("RegReplaceKey(%p,%s,%s,%s): stub\n", hkey, debugstr_a(lpszSubKey),
464               debugstr_a(lpszNewFile),debugstr_a(lpszOldFile));
465         return ERROR_CALL_NOT_IMPLEMENTED;
466     }
467
468     default:
469         if (LOWORD(service) < N_VMM_SERVICE)
470             FIXME( "Unimplemented service %s (%08x)\n",
471                    VMM_Service_Name[LOWORD(service)], service);
472         else
473             FIXME( "Unknown service %08x\n", service);
474         return 0xffffffff;  /* FIXME */
475     }
476 }