kernel: Moved main stack initialization to process.c.
[wine] / dlls / kernel / virtual.c
1 /*
2  * Win32 virtual memory functions
3  *
4  * Copyright 1997 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <fcntl.h>
25 #include <stdarg.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/types.h>
29 #ifdef HAVE_UNISTD_H
30 # include <unistd.h>
31 #endif
32
33 #define NONAMELESSUNION
34 #define NONAMELESSSTRUCT
35 #include "ntstatus.h"
36 #define WIN32_NO_STATUS
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winnls.h"
40 #include "winternl.h"
41 #include "winerror.h"
42 #include "wine/exception.h"
43 #include "excpt.h"
44 #include "wine/debug.h"
45
46 #include "kernel_private.h"
47
48 WINE_DEFAULT_DEBUG_CHANNEL(virtual);
49 WINE_DECLARE_DEBUG_CHANNEL(seh);
50
51 static unsigned int page_size;
52
53 /* filter for page-fault exceptions */
54 static WINE_EXCEPTION_FILTER(page_fault)
55 {
56     if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
57         return EXCEPTION_EXECUTE_HANDLER;
58     return EXCEPTION_CONTINUE_SEARCH;
59 }
60
61
62 /***********************************************************************
63  *             VirtualAlloc   (KERNEL32.@)
64  * Reserves or commits a region of pages in virtual address space
65  *
66  * RETURNS
67  *      Base address of allocated region of pages
68  *      NULL: Failure
69  */
70 LPVOID WINAPI VirtualAlloc(
71               LPVOID addr,  /* [in] Address of region to reserve or commit */
72               SIZE_T size,  /* [in] Size of region */
73               DWORD type,   /* [in] Type of allocation */
74               DWORD protect)/* [in] Type of access protection */
75 {
76     return VirtualAllocEx( GetCurrentProcess(), addr, size, type, protect );
77 }
78
79
80 /***********************************************************************
81  *             VirtualAllocEx   (KERNEL32.@)
82  *
83  * Seems to be just as VirtualAlloc, but with process handle.
84  *
85  * RETURNS
86  *      Base address of allocated region of pages
87  *      NULL: Failure
88  */
89 LPVOID WINAPI VirtualAllocEx(
90               HANDLE hProcess, /* [in] Handle of process to do mem operation */
91               LPVOID addr,     /* [in] Address of region to reserve or commit */
92               SIZE_T size,     /* [in] Size of region */
93               DWORD type,      /* [in] Type of allocation */
94               DWORD protect )  /* [in] Type of access protection */
95 {
96     LPVOID ret = addr;
97     NTSTATUS status;
98
99     if ((status = NtAllocateVirtualMemory( hProcess, &ret, 0, &size, type, protect )))
100     {
101         SetLastError( RtlNtStatusToDosError(status) );
102         ret = NULL;
103     }
104     return ret;
105 }
106
107
108 /***********************************************************************
109  *             VirtualFree   (KERNEL32.@)
110  * Release or decommits a region of pages in virtual address space.
111  *
112  * RETURNS
113  *      TRUE: Success
114  *      FALSE: Failure
115  */
116 BOOL WINAPI VirtualFree(
117               LPVOID addr, /* [in] Address of region of committed pages */
118               SIZE_T size, /* [in] Size of region */
119               DWORD type   /* [in] Type of operation */
120 ) {
121     return VirtualFreeEx( GetCurrentProcess(), addr, size, type );
122 }
123
124
125 /***********************************************************************
126  *             VirtualFreeEx   (KERNEL32.@)
127  * Release or decommits a region of pages in virtual address space.
128  *
129  * RETURNS
130  *      TRUE: Success
131  *      FALSE: Failure
132  */
133 BOOL WINAPI VirtualFreeEx( HANDLE process, LPVOID addr, SIZE_T size, DWORD type )
134 {
135     NTSTATUS status = NtFreeVirtualMemory( process, &addr, &size, type );
136     if (status) SetLastError( RtlNtStatusToDosError(status) );
137     return !status;
138 }
139
140
141 /***********************************************************************
142  *             VirtualLock   (KERNEL32.@)
143  * Locks the specified region of virtual address space
144  *
145  * NOTE
146  *      Always returns TRUE
147  *
148  * RETURNS
149  *      TRUE: Success
150  *      FALSE: Failure
151  */
152 BOOL WINAPI VirtualLock( LPVOID addr, /* [in] Address of first byte of range to lock */
153                          SIZE_T size ) /* [in] Number of bytes in range to lock */
154 {
155     NTSTATUS status = NtLockVirtualMemory( GetCurrentProcess(), &addr, &size, 1 );
156     if (status) SetLastError( RtlNtStatusToDosError(status) );
157     return !status;
158 }
159
160
161 /***********************************************************************
162  *             VirtualUnlock   (KERNEL32.@)
163  * Unlocks a range of pages in the virtual address space
164  *
165  * NOTE
166  *      Always returns TRUE
167  *
168  * RETURNS
169  *      TRUE: Success
170  *      FALSE: Failure
171  */
172 BOOL WINAPI VirtualUnlock( LPVOID addr, /* [in] Address of first byte of range */
173                            SIZE_T size ) /* [in] Number of bytes in range */
174 {
175     NTSTATUS status = NtUnlockVirtualMemory( GetCurrentProcess(), &addr, &size, 1 );
176     if (status) SetLastError( RtlNtStatusToDosError(status) );
177     return !status;
178 }
179
180
181 /***********************************************************************
182  *             VirtualProtect   (KERNEL32.@)
183  * Changes the access protection on a region of committed pages
184  *
185  * RETURNS
186  *      TRUE: Success
187  *      FALSE: Failure
188  */
189 BOOL WINAPI VirtualProtect(
190               LPVOID addr,     /* [in] Address of region of committed pages */
191               SIZE_T size,     /* [in] Size of region */
192               DWORD new_prot,  /* [in] Desired access protection */
193               LPDWORD old_prot /* [out] Address of variable to get old protection */
194 ) {
195     return VirtualProtectEx( GetCurrentProcess(), addr, size, new_prot, old_prot );
196 }
197
198
199 /***********************************************************************
200  *             VirtualProtectEx   (KERNEL32.@)
201  * Changes the access protection on a region of committed pages in the
202  * virtual address space of a specified process
203  *
204  * RETURNS
205  *      TRUE: Success
206  *      FALSE: Failure
207  */
208 BOOL WINAPI VirtualProtectEx(
209               HANDLE process,  /* [in]  Handle of process */
210               LPVOID addr,     /* [in]  Address of region of committed pages */
211               SIZE_T size,     /* [in]  Size of region */
212               DWORD new_prot,  /* [in]  Desired access protection */
213               LPDWORD old_prot /* [out] Address of variable to get old protection */ )
214 {
215     NTSTATUS status = NtProtectVirtualMemory( process, &addr, &size, new_prot, old_prot );
216     if (status) SetLastError( RtlNtStatusToDosError(status) );
217     return !status;
218 }
219
220
221 /***********************************************************************
222  *             VirtualQuery   (KERNEL32.@)
223  * Provides info about a range of pages in virtual address space
224  *
225  * RETURNS
226  *      Number of bytes returned in information buffer
227  *      or 0 if addr is >= 0xc0000000 (kernel space).
228  */
229 SIZE_T WINAPI VirtualQuery(
230              LPCVOID addr,                    /* [in]  Address of region */
231              PMEMORY_BASIC_INFORMATION info,  /* [out] Address of info buffer */
232              SIZE_T len                       /* [in]  Size of buffer */
233 ) {
234     return VirtualQueryEx( GetCurrentProcess(), addr, info, len );
235 }
236
237
238 /***********************************************************************
239  *             VirtualQueryEx   (KERNEL32.@)
240  * Provides info about a range of pages in virtual address space of a
241  * specified process
242  *
243  * RETURNS
244  *      Number of bytes returned in information buffer
245  */
246 SIZE_T WINAPI VirtualQueryEx(
247              HANDLE process,                  /* [in] Handle of process */
248              LPCVOID addr,                    /* [in] Address of region */
249              PMEMORY_BASIC_INFORMATION info,  /* [out] Address of info buffer */
250              SIZE_T len                       /* [in] Size of buffer */ )
251 {
252     SIZE_T ret;
253     NTSTATUS status;
254
255     if ((status = NtQueryVirtualMemory( process, addr, MemoryBasicInformation, info, len, &ret )))
256     {
257         SetLastError( RtlNtStatusToDosError(status) );
258         ret = 0;
259     }
260     return ret;
261 }
262
263
264 /***********************************************************************
265  *             CreateFileMappingA   (KERNEL32.@)
266  * Creates a named or unnamed file-mapping object for the specified file
267  *
268  * RETURNS
269  *      Handle: Success
270  *      0: Mapping object does not exist
271  *      NULL: Failure
272  */
273 HANDLE WINAPI CreateFileMappingA(
274                 HANDLE hFile,   /* [in] Handle of file to map */
275                 SECURITY_ATTRIBUTES *sa, /* [in] Optional security attributes*/
276                 DWORD protect,   /* [in] Protection for mapping object */
277                 DWORD size_high, /* [in] High-order 32 bits of object size */
278                 DWORD size_low,  /* [in] Low-order 32 bits of object size */
279                 LPCSTR name      /* [in] Name of file-mapping object */ )
280 {
281     WCHAR buffer[MAX_PATH];
282
283     if (!name) return CreateFileMappingW( hFile, sa, protect, size_high, size_low, NULL );
284
285     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
286     {
287         SetLastError( ERROR_FILENAME_EXCED_RANGE );
288         return 0;
289     }
290     return CreateFileMappingW( hFile, sa, protect, size_high, size_low, buffer );
291 }
292
293
294 /***********************************************************************
295  *             CreateFileMappingW   (KERNEL32.@)
296  * See CreateFileMappingA.
297  */
298 HANDLE WINAPI CreateFileMappingW( HANDLE hFile, LPSECURITY_ATTRIBUTES sa,
299                                   DWORD protect, DWORD size_high,
300                                   DWORD size_low, LPCWSTR name )
301 {
302     static const int sec_flags = SEC_FILE | SEC_IMAGE | SEC_RESERVE | SEC_COMMIT | SEC_NOCACHE;
303
304     HANDLE ret;
305     OBJECT_ATTRIBUTES attr;
306     UNICODE_STRING nameW;
307     NTSTATUS status;
308     DWORD access, sec_type;
309     LARGE_INTEGER size;
310
311     attr.Length                   = sizeof(attr);
312     attr.RootDirectory            = 0;
313     attr.ObjectName               = NULL;
314     attr.Attributes               = OBJ_CASE_INSENSITIVE | OBJ_OPENIF |
315                                     ((sa && sa->bInheritHandle) ? OBJ_INHERIT : 0);
316     attr.SecurityDescriptor       = sa ? sa->lpSecurityDescriptor : NULL;
317     attr.SecurityQualityOfService = NULL;
318
319     if (name)
320     {
321         RtlInitUnicodeString( &nameW, name );
322         attr.ObjectName = &nameW;
323         attr.RootDirectory = get_BaseNamedObjects_handle();
324     }
325
326     sec_type = protect & sec_flags;
327     protect &= ~sec_flags;
328     if (!sec_type) sec_type = SEC_COMMIT;
329
330     switch(protect)
331     {
332     case 0:
333         protect = PAGE_READONLY;  /* Win9x compatibility */
334         /* fall through */
335     case PAGE_READONLY:
336     case PAGE_WRITECOPY:
337         access = STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ;
338         break;
339     case PAGE_READWRITE:
340         access = STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ | SECTION_MAP_WRITE;
341         break;
342     default:
343         SetLastError( ERROR_INVALID_PARAMETER );
344         return 0;
345     }
346
347     if (hFile == INVALID_HANDLE_VALUE)
348     {
349         hFile = 0;
350         if (!size_low && !size_high)
351         {
352             SetLastError( ERROR_INVALID_PARAMETER );
353             return 0;
354         }
355     }
356
357     size.u.LowPart  = size_low;
358     size.u.HighPart = size_high;
359
360     status = NtCreateSection( &ret, access, &attr, &size, protect, sec_type, hFile );
361     if (status == STATUS_OBJECT_NAME_EXISTS)
362         SetLastError( ERROR_ALREADY_EXISTS );
363     else
364         SetLastError( RtlNtStatusToDosError(status) );
365     return ret;
366 }
367
368
369 /***********************************************************************
370  *             OpenFileMappingA   (KERNEL32.@)
371  * Opens a named file-mapping object.
372  *
373  * RETURNS
374  *      Handle: Success
375  *      NULL: Failure
376  */
377 HANDLE WINAPI OpenFileMappingA(
378                 DWORD access,   /* [in] Access mode */
379                 BOOL inherit, /* [in] Inherit flag */
380                 LPCSTR name )   /* [in] Name of file-mapping object */
381 {
382     WCHAR buffer[MAX_PATH];
383
384     if (!name) return OpenFileMappingW( access, inherit, NULL );
385
386     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
387     {
388         SetLastError( ERROR_FILENAME_EXCED_RANGE );
389         return 0;
390     }
391     return OpenFileMappingW( access, inherit, buffer );
392 }
393
394
395 /***********************************************************************
396  *             OpenFileMappingW   (KERNEL32.@)
397  * See OpenFileMappingA.
398  */
399 HANDLE WINAPI OpenFileMappingW( DWORD access, BOOL inherit, LPCWSTR name)
400 {
401     OBJECT_ATTRIBUTES attr;
402     UNICODE_STRING nameW;
403     HANDLE ret;
404     NTSTATUS status;
405
406     if (!name)
407     {
408         SetLastError( ERROR_INVALID_PARAMETER );
409         return 0;
410     }
411     attr.Length = sizeof(attr);
412     attr.RootDirectory = get_BaseNamedObjects_handle();
413     attr.ObjectName = &nameW;
414     attr.Attributes = OBJ_CASE_INSENSITIVE | (inherit ? OBJ_INHERIT : 0);
415     attr.SecurityDescriptor = NULL;
416     attr.SecurityQualityOfService = NULL;
417     RtlInitUnicodeString( &nameW, name );
418
419     if (access == FILE_MAP_COPY) access = FILE_MAP_READ;
420
421     if ((status = NtOpenSection( &ret, access, &attr )))
422     {
423         SetLastError( RtlNtStatusToDosError(status) );
424         ret = 0;
425     }
426     return ret;
427 }
428
429
430 /***********************************************************************
431  *             MapViewOfFile   (KERNEL32.@)
432  * Maps a view of a file into the address space
433  *
434  * RETURNS
435  *      Starting address of mapped view
436  *      NULL: Failure
437  */
438 LPVOID WINAPI MapViewOfFile(
439               HANDLE mapping,  /* [in] File-mapping object to map */
440               DWORD access,      /* [in] Access mode */
441               DWORD offset_high, /* [in] High-order 32 bits of file offset */
442               DWORD offset_low,  /* [in] Low-order 32 bits of file offset */
443               SIZE_T count       /* [in] Number of bytes to map */
444 ) {
445     return MapViewOfFileEx( mapping, access, offset_high,
446                             offset_low, count, NULL );
447 }
448
449
450 /***********************************************************************
451  *             MapViewOfFileEx   (KERNEL32.@)
452  * Maps a view of a file into the address space
453  *
454  * RETURNS
455  *      Starting address of mapped view
456  *      NULL: Failure
457  */
458 LPVOID WINAPI MapViewOfFileEx(
459               HANDLE handle,   /* [in] File-mapping object to map */
460               DWORD access,      /* [in] Access mode */
461               DWORD offset_high, /* [in] High-order 32 bits of file offset */
462               DWORD offset_low,  /* [in] Low-order 32 bits of file offset */
463               SIZE_T count,      /* [in] Number of bytes to map */
464               LPVOID addr        /* [in] Suggested starting address for mapped view */
465 ) {
466     NTSTATUS status;
467     LARGE_INTEGER offset;
468     ULONG protect;
469
470     offset.u.LowPart  = offset_low;
471     offset.u.HighPart = offset_high;
472
473     if (access & FILE_MAP_WRITE) protect = PAGE_READWRITE;
474     else if (access & FILE_MAP_READ) protect = PAGE_READONLY;
475     else if (access & FILE_MAP_COPY) protect = PAGE_WRITECOPY;
476     else protect = PAGE_NOACCESS;
477
478     if ((status = NtMapViewOfSection( handle, GetCurrentProcess(), &addr, 0, 0, &offset,
479                                       &count, ViewShare, 0, protect )))
480     {
481         SetLastError( RtlNtStatusToDosError(status) );
482         addr = NULL;
483     }
484     return addr;
485 }
486
487
488 /***********************************************************************
489  *             UnmapViewOfFile   (KERNEL32.@)
490  * Unmaps a mapped view of a file.
491  *
492  * NOTES
493  *      Should addr be an LPCVOID?
494  *
495  * RETURNS
496  *      TRUE: Success
497  *      FALSE: Failure
498  */
499 BOOL WINAPI UnmapViewOfFile( LPVOID addr ) /* [in] Address where mapped view begins */
500 {
501     NTSTATUS status = NtUnmapViewOfSection( GetCurrentProcess(), addr );
502     if (status) SetLastError( RtlNtStatusToDosError(status) );
503     return !status;
504 }
505
506
507 /***********************************************************************
508  *             FlushViewOfFile   (KERNEL32.@)
509  * Writes to the disk a byte range within a mapped view of a file
510  *
511  * RETURNS
512  *      TRUE: Success
513  *      FALSE: Failure
514  */
515 BOOL WINAPI FlushViewOfFile( LPCVOID base,  /* [in] Start address of byte range to flush */
516                              SIZE_T size )   /* [in] Number of bytes in range */
517 {
518     NTSTATUS status = NtFlushVirtualMemory( GetCurrentProcess(), &base, &size, 0 );
519     if (status)
520     {
521         if (status == STATUS_NOT_MAPPED_DATA) status = STATUS_SUCCESS;
522         else SetLastError( RtlNtStatusToDosError(status) );
523     }
524     return !status;
525 }
526
527
528 /***********************************************************************
529  *             IsBadReadPtr   (KERNEL32.@)
530  *
531  * Check for read access on a memory block.
532  *
533  * RETURNS
534  *      FALSE: Process has read access to entire block
535  *      TRUE: Otherwise
536  */
537 BOOL WINAPI IsBadReadPtr(
538               LPCVOID ptr, /* [in] Address of memory block */
539               UINT size )  /* [in] Size of block */
540 {
541     if (!size) return FALSE;  /* handle 0 size case w/o reference */
542     if (!ptr) return TRUE;
543     
544     if (!page_size) page_size = getpagesize();
545     __TRY
546     {
547         volatile const char *p = ptr;
548         char dummy;
549         UINT count = size;
550
551         while (count > page_size)
552         {
553             dummy = *p;
554             p += page_size;
555             count -= page_size;
556         }
557         dummy = p[0];
558         dummy = p[count - 1];
559     }
560     __EXCEPT(page_fault)
561     {
562         TRACE_(seh)("%p caused page fault during read\n", ptr);
563         return TRUE;
564     }
565     __ENDTRY
566     return FALSE;
567 }
568
569
570 /***********************************************************************
571  *             IsBadWritePtr   (KERNEL32.@)
572  *
573  * Check for write access on a memory block.
574  *
575  * RETURNS
576  *      FALSE: Process has write access to entire block
577  *      TRUE: Otherwise
578  */
579 BOOL WINAPI IsBadWritePtr(
580               LPVOID ptr, /* [in] Address of memory block */
581               UINT size ) /* [in] Size of block in bytes */
582 {
583     if (!size) return FALSE;  /* handle 0 size case w/o reference */
584     if (!ptr) return TRUE;
585     
586     if (!page_size) page_size = getpagesize();
587     __TRY
588     {
589         volatile char *p = ptr;
590         UINT count = size;
591
592         while (count > page_size)
593         {
594             *p |= 0;
595             p += page_size;
596             count -= page_size;
597         }
598         p[0] |= 0;
599         p[count - 1] |= 0;
600     }
601     __EXCEPT(page_fault)
602     {
603         TRACE_(seh)("%p caused page fault during write\n", ptr);
604         return TRUE;
605     }
606     __ENDTRY
607     return FALSE;
608 }
609
610
611 /***********************************************************************
612  *             IsBadHugeReadPtr   (KERNEL32.@)
613  *
614  * Check for read access on a memory block.
615  *
616  * RETURNS
617  *      FALSE: Process has read access to entire block
618  *      TRUE: Otherwise
619  */
620 BOOL WINAPI IsBadHugeReadPtr(
621               LPCVOID ptr, /* [in] Address of memory block */
622               UINT size  /* [in] Size of block */
623 ) {
624     return IsBadReadPtr( ptr, size );
625 }
626
627
628 /***********************************************************************
629  *             IsBadHugeWritePtr   (KERNEL32.@)
630  *
631  * Check for write access on a memory block.
632  *
633  * RETURNS
634  *      FALSE: Process has write access to entire block
635  *      TRUE: Otherwise
636  */
637 BOOL WINAPI IsBadHugeWritePtr(
638               LPVOID ptr, /* [in] Address of memory block */
639               UINT size /* [in] Size of block */
640 ) {
641     return IsBadWritePtr( ptr, size );
642 }
643
644
645 /***********************************************************************
646  *             IsBadCodePtr   (KERNEL32.@)
647  *
648  * Check for read access on a memory address.
649  *
650  * RETURNS
651  *      FALSE: Process has read access to specified memory
652  *      TRUE: Otherwise
653  */
654 BOOL WINAPI IsBadCodePtr( FARPROC ptr ) /* [in] Address of function */
655 {
656     return IsBadReadPtr( ptr, 1 );
657 }
658
659
660 /***********************************************************************
661  *             IsBadStringPtrA   (KERNEL32.@)
662  *
663  * Check for read access on a range of memory pointed to by a string pointer.
664  *
665  * RETURNS
666  *      FALSE: Read access to all bytes in string
667  *      TRUE: Else
668  */
669 BOOL WINAPI IsBadStringPtrA(
670               LPCSTR str, /* [in] Address of string */
671               UINT max )  /* [in] Maximum size of string */
672 {
673     if (!str) return TRUE;
674     
675     __TRY
676     {
677         volatile const char *p = str;
678         while (p != str + max) if (!*p++) break;
679     }
680     __EXCEPT(page_fault)
681     {
682         TRACE_(seh)("%p caused page fault during read\n", str);
683         return TRUE;
684     }
685     __ENDTRY
686     return FALSE;
687 }
688
689
690 /***********************************************************************
691  *             IsBadStringPtrW   (KERNEL32.@)
692  * See IsBadStringPtrA.
693  */
694 BOOL WINAPI IsBadStringPtrW( LPCWSTR str, UINT max )
695 {
696     if (!str) return TRUE;
697     
698     __TRY
699     {
700         volatile const WCHAR *p = str;
701         while (p != str + max) if (!*p++) break;
702     }
703     __EXCEPT(page_fault)
704     {
705         TRACE_(seh)("%p caused page fault during read\n", str);
706         return TRUE;
707     }
708     __ENDTRY
709     return FALSE;
710 }