ws2_32/tests: Add SO_ERROR [set|get]sockopt tests.
[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 static const DWORD page_size = 0x1000;  /* we only care about x86 */
123
124 /* Pop a DWORD from the 32-bit stack */
125 static inline DWORD stack32_pop( CONTEXT *context )
126 {
127     DWORD ret = *(DWORD *)context->Esp;
128     context->Esp += sizeof(DWORD);
129     return ret;
130 }
131
132
133 /***********************************************************************
134  *           VxDCall   (VMM.VXD.@)
135  */
136 DWORD WINAPI VMM_VxDCall( DWORD service, CONTEXT *context )
137 {
138     static int warned;
139
140     switch ( LOWORD(service) )
141     {
142     case 0x0000: /* PageReserve */
143     {
144         LPVOID address;
145         LPVOID ret;
146         ULONG page   = stack32_pop( context );
147         ULONG npages = stack32_pop( context );
148         ULONG flags  = stack32_pop( context );
149
150         TRACE("PageReserve: page: %08x, npages: %08x, flags: %08x partial stub!\n",
151               page, npages, flags );
152
153         if ( page == PR_SYSTEM ) {
154           ERR("Can't reserve ring 1 memory\n");
155           return -1;
156         }
157         /* FIXME: This has to be handled separately for the separate
158            address-spaces we now have */
159         if ( page == PR_PRIVATE || page == PR_SHARED ) page = 0;
160         /* FIXME: Handle flags in some way */
161         address = (LPVOID )(page * page_size);
162         ret = VirtualAlloc ( address, npages * page_size, MEM_RESERVE, 0 );
163         TRACE("PageReserve: returning: %p\n", ret );
164         if ( ret == NULL )
165           return -1;
166         else
167           return (DWORD )ret;
168     }
169
170     case 0x0001: /* PageCommit */
171     {
172         LPVOID address;
173         LPVOID ret;
174         DWORD virt_perm;
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 * page_size);
194         ret = VirtualAlloc ( address, npages * page_size, 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         ULONG page = stack32_pop( context );
205         ULONG npages = stack32_pop( context );
206         ULONG flags = stack32_pop( context );
207
208         TRACE("PageDecommit: page: %08x, npages: %08x, flags: %08x partial stub\n",
209               page, npages, flags );
210         address = (LPVOID )( page * page_size );
211         ret = VirtualFree ( address, npages * page_size, MEM_DECOMMIT );
212         TRACE("PageDecommit: Returning: %s\n", ret ? "TRUE" : "FALSE" );
213         return ret;
214     }
215
216     case 0x000d: /* PageModifyPermissions */
217     {
218         DWORD pg_old_perm;
219         DWORD pg_new_perm;
220         DWORD virt_old_perm;
221         DWORD virt_new_perm;
222         MEMORY_BASIC_INFORMATION mbi;
223         LPVOID address;
224         ULONG page = stack32_pop ( context );
225         ULONG npages = stack32_pop ( context );
226         ULONG permand = stack32_pop ( context );
227         ULONG permor = stack32_pop ( context );
228
229         TRACE("PageModifyPermissions %08x %08x %08x %08x partial stub\n",
230               page, npages, permand, permor );
231         address = (LPVOID )( page * page_size );
232
233         VirtualQuery ( address, &mbi, sizeof ( MEMORY_BASIC_INFORMATION ));
234         virt_old_perm = mbi.Protect;
235
236         switch ( virt_old_perm & mbi.Protect ) {
237         case PAGE_READONLY:
238         case PAGE_EXECUTE:
239         case PAGE_EXECUTE_READ:
240           pg_old_perm = PC_USER;
241           break;
242         case PAGE_READWRITE:
243         case PAGE_WRITECOPY:
244         case PAGE_EXECUTE_READWRITE:
245         case PAGE_EXECUTE_WRITECOPY:
246           pg_old_perm = PC_USER | PC_WRITABLE;
247           break;
248         case PAGE_NOACCESS:
249         default:
250           pg_old_perm = 0;
251           break;
252         }
253         pg_new_perm = pg_old_perm;
254         pg_new_perm &= permand & ~PC_STATIC;
255         pg_new_perm |= permor  & ~PC_STATIC;
256
257         virt_new_perm = ( virt_old_perm )  & ~0xff;
258         if ( pg_new_perm & PC_USER )
259         {
260           if ( pg_new_perm & PC_WRITABLE )
261             virt_new_perm |= PAGE_EXECUTE_READWRITE;
262           else
263             virt_new_perm |= PAGE_EXECUTE_READ;
264         }
265
266         if ( ! VirtualProtect ( address, npages * page_size, virt_new_perm, &virt_old_perm ) ) {
267           ERR("Can't change page permissions for %p\n", address );
268           return 0xffffffff;
269         }
270         TRACE("Returning: %08x\n", pg_old_perm );
271         return pg_old_perm;
272     }
273
274     case 0x000a: /* PageFree */
275     {
276         BOOL ret;
277         LPVOID hmem = (LPVOID) stack32_pop( context );
278         DWORD flags = stack32_pop( context );
279
280         TRACE("PageFree: hmem: %p, flags: %08x partial stub\n",
281               hmem, flags );
282
283         ret = VirtualFree ( hmem, 0, MEM_RELEASE );
284         TRACE("Returning: %d\n", ret );
285         return ret;
286     }
287
288     case 0x0011:  /* RegOpenKey */
289         stack32_pop( context ); /* kkey */
290         stack32_pop( context ); /* lpszSubKey */
291         stack32_pop( context ); /* retkey */
292         /* return RegOpenKeyExA( hkey, lpszSubKey, 0, KEY_ALL_ACCESS, retkey ); */
293         if (!warned)
294         {
295             ERR( "Using the native Win95 advapi32.dll is no longer supported.\n" );
296             ERR( "Please configure advapi32 to builtin.\n" );
297             warned++;
298         }
299         return ERROR_CALL_NOT_IMPLEMENTED;
300
301     case 0x0012:  /* RegCreateKey */
302         stack32_pop( context ); /* hkey */
303         stack32_pop( context ); /* lpszSubKey */
304         stack32_pop( context ); /* retkey */
305         /* return RegCreateKeyA( hkey, lpszSubKey, retkey ); */
306         if (!warned)
307         {
308             ERR( "Using the native Win95 advapi32.dll is no longer supported.\n" );
309             ERR( "Please configure advapi32 to builtin.\n" );
310             warned++;
311         }
312         return ERROR_CALL_NOT_IMPLEMENTED;
313
314     case 0x0013:  /* RegCloseKey */
315         stack32_pop( context ); /* hkey */
316         /* return RegCloseKey( hkey ); */
317         return ERROR_CALL_NOT_IMPLEMENTED;
318
319     case 0x0014:  /* RegDeleteKey */
320         stack32_pop( context ); /* hkey */
321         stack32_pop( context ); /* lpszSubKey */
322         /* return RegDeleteKeyA( hkey, lpszSubKey ); */
323         return ERROR_CALL_NOT_IMPLEMENTED;
324
325     case 0x0015:  /* RegSetValue */
326         stack32_pop( context ); /* hkey */
327         stack32_pop( context ); /* lpszSubKey */
328         stack32_pop( context ); /* dwType */
329         stack32_pop( context ); /* lpszData */
330         stack32_pop( context ); /* cbData */
331         /* return RegSetValueA( hkey, lpszSubKey, dwType, lpszData, cbData ); */
332         return ERROR_CALL_NOT_IMPLEMENTED;
333
334     case 0x0016:  /* RegDeleteValue */
335         stack32_pop( context ); /* hkey */
336         stack32_pop( context ); /* lpszValue */
337         /* return RegDeleteValueA( hkey, lpszValue ); */
338         return ERROR_CALL_NOT_IMPLEMENTED;
339
340     case 0x0017:  /* RegQueryValue */
341         stack32_pop( context ); /* hkey */
342         stack32_pop( context ); /* lpszSubKey */
343         stack32_pop( context ); /* lpszData */
344         stack32_pop( context ); /* lpcbData */
345         /* return RegQueryValueA( hkey, lpszSubKey, lpszData, lpcbData ); */
346         return ERROR_CALL_NOT_IMPLEMENTED;
347
348     case 0x0018:  /* RegEnumKey */
349         stack32_pop( context ); /* hkey */
350         stack32_pop( context ); /* iSubkey */
351         stack32_pop( context ); /* lpszName */
352         stack32_pop( context ); /* lpcchName */
353         /* return RegEnumKeyA( hkey, iSubkey, lpszName, lpcchName ); */
354         return ERROR_CALL_NOT_IMPLEMENTED;
355
356     case 0x0019:  /* RegEnumValue */
357         stack32_pop( context ); /* hkey */
358         stack32_pop( context ); /* iValue */
359         stack32_pop( context ); /* lpszValue */
360         stack32_pop( context ); /* lpcchValue */
361         stack32_pop( context ); /* lpReserved */
362         stack32_pop( context ); /* lpdwType */
363         stack32_pop( context ); /* lpbData */
364         stack32_pop( context ); /* lpcbData */
365         /* return RegEnumValueA( hkey, iValue, lpszValue, lpcchValue, lpReserved, lpdwType, lpbData, lpcbData ); */
366         return ERROR_CALL_NOT_IMPLEMENTED;
367
368     case 0x001A:  /* RegQueryValueEx */
369         stack32_pop( context ); /* hkey */
370         stack32_pop( context ); /* lpszValue */
371         stack32_pop( context ); /* lpReserved */
372         stack32_pop( context ); /* lpdwType */
373         stack32_pop( context ); /* lpbData */
374         stack32_pop( context ); /* lpcbData */
375         /* return RegQueryValueExA( hkey, lpszValue, lpReserved, lpdwType, lpbData, lpcbData ); */
376         return ERROR_CALL_NOT_IMPLEMENTED;
377
378     case 0x001B:  /* RegSetValueEx */
379         stack32_pop( context ); /* hkey */
380         stack32_pop( context ); /* lpszValue */
381         stack32_pop( context ); /* dwReserved */
382         stack32_pop( context ); /* dwType */
383         stack32_pop( context ); /* lpbData */
384         stack32_pop( context ); /* cbData */
385         /* return RegSetValueExA( hkey, lpszValue, dwReserved, dwType, lpbData, cbData ); */
386         return ERROR_CALL_NOT_IMPLEMENTED;
387
388     case 0x001C:  /* RegFlushKey */
389         stack32_pop( context ); /* hkey */
390         /* return RegFlushKey( hkey ); */
391         return ERROR_CALL_NOT_IMPLEMENTED;
392
393     case 0x001D:  /* RegQueryInfoKey */
394         /* NOTE: This VxDCall takes only a subset of the parameters that the
395                  corresponding Win32 API call does. The implementation in Win95
396                  ADVAPI32 sets all output parameters not mentioned here to zero. */
397         stack32_pop( context ); /* hkey */
398         stack32_pop( context ); /* lpcSubKeys */
399         stack32_pop( context ); /* lpcchMaxSubKey */
400         stack32_pop( context ); /* lpcValues */
401         stack32_pop( context ); /* lpcchMaxValueName */
402         stack32_pop( context ); /* lpcchMaxValueData */
403         /* return RegQueryInfoKeyA( hkey, lpcSubKeys, lpcchMaxSubKey, lpcValues, lpcchMaxValueName, lpcchMaxValueData ); */
404         return ERROR_CALL_NOT_IMPLEMENTED;
405
406     case 0x001e: /* GetDemandPageInfo */
407     {
408          DWORD dinfo = stack32_pop( context );
409          DWORD flags = stack32_pop( context );
410
411          /* GetDemandPageInfo is supposed to fill out the struct at
412           * "dinfo" with various low-level memory management information.
413           * Apps are certainly not supposed to call this, although it's
414           * demoed and documented by Pietrek on pages 441-443 of "Windows
415           * 95 System Programming Secrets" if any program needs a real
416           * implementation of this.
417           */
418
419          FIXME("GetDemandPageInfo(%08x %08x): stub!\n", dinfo, flags);
420
421          return 0;
422     }
423
424     case 0x0021:  /* RegLoadKey */
425     {
426         HKEY    hkey       = (HKEY)  stack32_pop( context );
427         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
428         LPCSTR  lpszFile   = (LPCSTR)stack32_pop( context );
429         FIXME("RegLoadKey(%p,%s,%s): stub\n",hkey, debugstr_a(lpszSubKey), debugstr_a(lpszFile));
430         return ERROR_CALL_NOT_IMPLEMENTED;
431     }
432
433     case 0x0022:  /* RegUnLoadKey */
434     {
435         HKEY    hkey       = (HKEY)  stack32_pop( context );
436         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
437         FIXME("RegUnLoadKey(%p,%s): stub\n",hkey, debugstr_a(lpszSubKey));
438         return ERROR_CALL_NOT_IMPLEMENTED;
439     }
440
441     case 0x0023:  /* RegSaveKey */
442     {
443         HKEY    hkey       = (HKEY)  stack32_pop( context );
444         LPCSTR  lpszFile   = (LPCSTR)stack32_pop( context );
445         LPSECURITY_ATTRIBUTES sa = (LPSECURITY_ATTRIBUTES)stack32_pop( context );
446         FIXME("RegSaveKey(%p,%s,%p): stub\n",hkey, debugstr_a(lpszFile),sa);
447         return ERROR_CALL_NOT_IMPLEMENTED;
448     }
449
450 #if 0 /* Functions are not yet implemented in misc/registry.c */
451     case 0x0024:  /* RegRemapPreDefKey */
452     case 0x0026:  /* RegQueryMultipleValues */
453 #endif
454
455     case 0x0027:  /* RegReplaceKey */
456     {
457         HKEY    hkey       = (HKEY)  stack32_pop( context );
458         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
459         LPCSTR  lpszNewFile= (LPCSTR)stack32_pop( context );
460         LPCSTR  lpszOldFile= (LPCSTR)stack32_pop( context );
461         FIXME("RegReplaceKey(%p,%s,%s,%s): stub\n", hkey, debugstr_a(lpszSubKey),
462               debugstr_a(lpszNewFile),debugstr_a(lpszOldFile));
463         return ERROR_CALL_NOT_IMPLEMENTED;
464     }
465
466     default:
467         if (LOWORD(service) < N_VMM_SERVICE)
468             FIXME( "Unimplemented service %s (%08x)\n",
469                    VMM_Service_Name[LOWORD(service)], service);
470         else
471             FIXME( "Unknown service %08x\n", service);
472         return 0xffffffff;  /* FIXME */
473     }
474 }