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