2 * Win32 virtual memory functions
4 * Copyright 1997 Alexandre Julliard
11 #ifdef HAVE_SYS_ERRNO_H
12 #include <sys/errno.h>
19 #include <sys/types.h>
20 #ifdef HAVE_SYS_MMAN_H
24 #include "wine/exception.h"
25 #include "wine/unicode.h"
31 #include "debugtools.h"
33 DEFAULT_DEBUG_CHANNEL(virtual);
34 DECLARE_DEBUG_CHANNEL(module
);
43 struct _FV
*next
; /* Next view */
44 struct _FV
*prev
; /* Prev view */
45 UINT base
; /* Base address */
46 UINT size
; /* Size in bytes */
47 UINT flags
; /* Allocation flags */
48 HANDLE mapping
; /* Handle to the file mapping */
49 HANDLERPROC handlerProc
; /* Fault handler */
50 LPVOID handlerArg
; /* Fault handler argument */
51 BYTE protect
; /* Protection for all pages at allocation time */
52 BYTE prot
[1]; /* Protection byte for each page */
56 #define VFLAG_SYSTEM 0x01
58 /* Conversion from VPROT_* to Win32 flags */
59 static const BYTE VIRTUAL_Win32Flags
[16] =
61 PAGE_NOACCESS
, /* 0 */
62 PAGE_READONLY
, /* READ */
63 PAGE_READWRITE
, /* WRITE */
64 PAGE_READWRITE
, /* READ | WRITE */
65 PAGE_EXECUTE
, /* EXEC */
66 PAGE_EXECUTE_READ
, /* READ | EXEC */
67 PAGE_EXECUTE_READWRITE
, /* WRITE | EXEC */
68 PAGE_EXECUTE_READWRITE
, /* READ | WRITE | EXEC */
69 PAGE_WRITECOPY
, /* WRITECOPY */
70 PAGE_WRITECOPY
, /* READ | WRITECOPY */
71 PAGE_WRITECOPY
, /* WRITE | WRITECOPY */
72 PAGE_WRITECOPY
, /* READ | WRITE | WRITECOPY */
73 PAGE_EXECUTE_WRITECOPY
, /* EXEC | WRITECOPY */
74 PAGE_EXECUTE_WRITECOPY
, /* READ | EXEC | WRITECOPY */
75 PAGE_EXECUTE_WRITECOPY
, /* WRITE | EXEC | WRITECOPY */
76 PAGE_EXECUTE_WRITECOPY
/* READ | WRITE | EXEC | WRITECOPY */
80 static FILE_VIEW
*VIRTUAL_FirstView
;
83 /* These are always the same on an i386, and it will be faster this way */
84 # define page_mask 0xfff
85 # define page_shift 12
87 static UINT page_shift
;
88 static UINT page_mask
;
90 #define granularity_mask 0xffff /* Allocation granularity (usually 64k) */
92 #define ROUND_ADDR(addr) \
93 ((UINT)(addr) & ~page_mask)
95 #define ROUND_SIZE(addr,size) \
96 (((UINT)(size) + ((UINT)(addr) & page_mask) + page_mask) & ~page_mask)
98 #define VIRTUAL_DEBUG_DUMP_VIEW(view) \
99 if (!TRACE_ON(virtual)); else VIRTUAL_DumpView(view)
102 /* filter for page-fault exceptions */
103 static WINE_EXCEPTION_FILTER(page_fault
)
105 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION
)
106 return EXCEPTION_EXECUTE_HANDLER
;
107 return EXCEPTION_CONTINUE_SEARCH
;
110 /***********************************************************************
113 static const char *VIRTUAL_GetProtStr( BYTE prot
)
115 static char buffer
[6];
116 buffer
[0] = (prot
& VPROT_COMMITTED
) ? 'c' : '-';
117 buffer
[1] = (prot
& VPROT_GUARD
) ? 'g' : '-';
118 buffer
[2] = (prot
& VPROT_READ
) ? 'r' : '-';
119 buffer
[3] = (prot
& VPROT_WRITE
) ?
120 ((prot
& VPROT_WRITECOPY
) ? 'w' : 'W') : '-';
121 buffer
[4] = (prot
& VPROT_EXEC
) ? 'x' : '-';
127 /***********************************************************************
130 static void VIRTUAL_DumpView( FILE_VIEW
*view
)
133 UINT addr
= view
->base
;
134 BYTE prot
= view
->prot
[0];
136 DPRINTF( "View: %08x - %08x%s",
137 view
->base
, view
->base
+ view
->size
- 1,
138 (view
->flags
& VFLAG_SYSTEM
) ? " (system)" : "" );
140 DPRINTF( " %d\n", view
->mapping
);
142 DPRINTF( " (anonymous)\n");
144 for (count
= i
= 1; i
< view
->size
>> page_shift
; i
++, count
++)
146 if (view
->prot
[i
] == prot
) continue;
147 DPRINTF( " %08x - %08x %s\n",
148 addr
, addr
+ (count
<< page_shift
) - 1,
149 VIRTUAL_GetProtStr(prot
) );
150 addr
+= (count
<< page_shift
);
151 prot
= view
->prot
[i
];
155 DPRINTF( " %08x - %08x %s\n",
156 addr
, addr
+ (count
<< page_shift
) - 1,
157 VIRTUAL_GetProtStr(prot
) );
161 /***********************************************************************
164 void VIRTUAL_Dump(void)
166 FILE_VIEW
*view
= VIRTUAL_FirstView
;
167 DPRINTF( "\nDump of all virtual memory views:\n\n" );
170 VIRTUAL_DumpView( view
);
176 /***********************************************************************
179 * Find the view containing a given address.
185 static FILE_VIEW
*VIRTUAL_FindView(
186 UINT addr
/* [in] Address */
188 FILE_VIEW
*view
= VIRTUAL_FirstView
;
191 if (view
->base
> addr
) return NULL
;
192 if (view
->base
+ view
->size
> addr
) return view
;
199 /***********************************************************************
202 * Create a new view and add it in the linked list.
204 static FILE_VIEW
*VIRTUAL_CreateView( UINT base
, UINT size
, UINT flags
,
205 BYTE vprot
, HANDLE mapping
)
207 FILE_VIEW
*view
, *prev
;
209 /* Create the view structure */
211 assert( !(base
& page_mask
) );
212 assert( !(size
& page_mask
) );
214 if (!(view
= (FILE_VIEW
*)malloc( sizeof(*view
) + size
- 1 ))) return NULL
;
216 view
->size
= size
<< page_shift
;
218 view
->mapping
= mapping
;
219 view
->protect
= vprot
;
220 view
->handlerProc
= NULL
;
221 memset( view
->prot
, vprot
, size
);
223 /* Duplicate the mapping handle */
225 if ((view
->mapping
!= -1) &&
226 !DuplicateHandle( GetCurrentProcess(), view
->mapping
,
227 GetCurrentProcess(), &view
->mapping
,
228 0, FALSE
, DUPLICATE_SAME_ACCESS
))
234 /* Insert it in the linked list */
236 if (!VIRTUAL_FirstView
|| (VIRTUAL_FirstView
->base
> base
))
238 view
->next
= VIRTUAL_FirstView
;
240 if (view
->next
) view
->next
->prev
= view
;
241 VIRTUAL_FirstView
= view
;
245 prev
= VIRTUAL_FirstView
;
246 while (prev
->next
&& (prev
->next
->base
< base
)) prev
= prev
->next
;
247 view
->next
= prev
->next
;
249 if (view
->next
) view
->next
->prev
= view
;
252 VIRTUAL_DEBUG_DUMP_VIEW( view
);
257 /***********************************************************************
264 static void VIRTUAL_DeleteView(
265 FILE_VIEW
*view
/* [in] View */
267 if (!(view
->flags
& VFLAG_SYSTEM
))
268 FILE_munmap( (void *)view
->base
, 0, view
->size
);
269 if (view
->next
) view
->next
->prev
= view
->prev
;
270 if (view
->prev
) view
->prev
->next
= view
->next
;
271 else VIRTUAL_FirstView
= view
->next
;
272 if (view
->mapping
) CloseHandle( view
->mapping
);
277 /***********************************************************************
278 * VIRTUAL_GetUnixProt
280 * Convert page protections to protection for mmap/mprotect.
282 static int VIRTUAL_GetUnixProt( BYTE vprot
)
285 if ((vprot
& VPROT_COMMITTED
) && !(vprot
& VPROT_GUARD
))
287 if (vprot
& VPROT_READ
) prot
|= PROT_READ
;
288 if (vprot
& VPROT_WRITE
) prot
|= PROT_WRITE
;
289 if (vprot
& VPROT_WRITECOPY
) prot
|= PROT_WRITE
;
290 if (vprot
& VPROT_EXEC
) prot
|= PROT_EXEC
;
296 /***********************************************************************
297 * VIRTUAL_GetWin32Prot
299 * Convert page protections to Win32 flags.
304 static void VIRTUAL_GetWin32Prot(
305 BYTE vprot
, /* [in] Page protection flags */
306 DWORD
*protect
, /* [out] Location to store Win32 protection flags */
307 DWORD
*state
/* [out] Location to store mem state flag */
310 *protect
= VIRTUAL_Win32Flags
[vprot
& 0x0f];
311 /* if (vprot & VPROT_GUARD) *protect |= PAGE_GUARD;*/
312 if (vprot
& VPROT_NOCACHE
) *protect
|= PAGE_NOCACHE
;
314 if (vprot
& VPROT_GUARD
) *protect
= PAGE_NOACCESS
;
317 if (state
) *state
= (vprot
& VPROT_COMMITTED
) ? MEM_COMMIT
: MEM_RESERVE
;
321 /***********************************************************************
324 * Build page protections from Win32 flags.
327 * Value of page protection flags
329 static BYTE
VIRTUAL_GetProt(
330 DWORD protect
/* [in] Win32 protection flags */
334 switch(protect
& 0xff)
340 vprot
= VPROT_READ
| VPROT_WRITE
;
343 vprot
= VPROT_READ
| VPROT_WRITE
| VPROT_WRITECOPY
;
348 case PAGE_EXECUTE_READ
:
349 vprot
= VPROT_EXEC
| VPROT_READ
;
351 case PAGE_EXECUTE_READWRITE
:
352 vprot
= VPROT_EXEC
| VPROT_READ
| VPROT_WRITE
;
354 case PAGE_EXECUTE_WRITECOPY
:
355 vprot
= VPROT_EXEC
| VPROT_READ
| VPROT_WRITE
| VPROT_WRITECOPY
;
362 if (protect
& PAGE_GUARD
) vprot
|= VPROT_GUARD
;
363 if (protect
& PAGE_NOCACHE
) vprot
|= VPROT_NOCACHE
;
368 /***********************************************************************
371 * Change the protection of a range of pages.
377 static BOOL
VIRTUAL_SetProt(
378 FILE_VIEW
*view
, /* [in] Pointer to view */
379 UINT base
, /* [in] Starting address */
380 UINT size
, /* [in] Size in bytes */
381 BYTE vprot
/* [in] Protections to use */
383 TRACE("%08x-%08x %s\n",
384 base
, base
+ size
- 1, VIRTUAL_GetProtStr( vprot
) );
386 if (mprotect( (void *)base
, size
, VIRTUAL_GetUnixProt(vprot
) ))
387 return FALSE
; /* FIXME: last error */
389 memset( view
->prot
+ ((base
- view
->base
) >> page_shift
),
390 vprot
, size
>> page_shift
);
391 VIRTUAL_DEBUG_DUMP_VIEW( view
);
396 /***********************************************************************
399 * Map an executable (PE format) image into memory.
401 static LPVOID
map_image( HANDLE hmapping
, int fd
, char *base
, DWORD total_size
,
402 DWORD header_size
, HANDLE shared_file
, DWORD shared_size
)
404 IMAGE_DOS_HEADER
*dos
;
405 IMAGE_NT_HEADERS
*nt
;
406 IMAGE_SECTION_HEADER
*sec
;
408 DWORD err
= GetLastError();
409 FILE_VIEW
*view
= NULL
;
413 SetLastError( ERROR_BAD_EXE_FORMAT
); /* generic error */
415 /* zero-map the whole range */
417 if ((ptr
= FILE_dommap( -1, base
, 0, total_size
, 0, 0, PROT_READ
|PROT_WRITE
|PROT_EXEC
,
418 MAP_PRIVATE
)) == (char *)-1)
420 ptr
= FILE_dommap( -1, NULL
, 0, total_size
, 0, 0,
421 PROT_READ
|PROT_WRITE
|PROT_EXEC
, MAP_PRIVATE
);
422 if (ptr
== (char *)-1)
424 ERR_(module
)("Not enough memory for module (%ld bytes)\n", total_size
);
428 TRACE_(module
)( "mapped PE file at %p-%p\n", ptr
, ptr
+ total_size
);
430 if (!(view
= VIRTUAL_CreateView( (UINT
)ptr
, total_size
, 0,
431 VPROT_COMMITTED
|VPROT_READ
|VPROT_WRITE
|VPROT_WRITECOPY
,
434 FILE_munmap( ptr
, 0, total_size
);
435 SetLastError( ERROR_OUTOFMEMORY
);
441 if (FILE_dommap( fd
, ptr
, 0, header_size
, 0, 0,
442 PROT_READ
| PROT_WRITE
, MAP_PRIVATE
| MAP_FIXED
) == (char *)-1) goto error
;
443 dos
= (IMAGE_DOS_HEADER
*)ptr
;
444 nt
= (IMAGE_NT_HEADERS
*)(ptr
+ dos
->e_lfanew
);
445 if ((char *)(nt
+ 1) > ptr
+ header_size
) goto error
;
447 sec
= (IMAGE_SECTION_HEADER
*)((char*)&nt
->OptionalHeader
+nt
->FileHeader
.SizeOfOptionalHeader
);
448 if ((char *)(sec
+ nt
->FileHeader
.NumberOfSections
) > ptr
+ header_size
) goto error
;
450 /* check the architecture */
452 if (nt
->FileHeader
.Machine
!= IMAGE_FILE_MACHINE_I386
)
454 MESSAGE("Trying to load PE image for unsupported architecture (");
455 switch (nt
->FileHeader
.Machine
)
457 case IMAGE_FILE_MACHINE_UNKNOWN
: MESSAGE("Unknown"); break;
458 case IMAGE_FILE_MACHINE_I860
: MESSAGE("I860"); break;
459 case IMAGE_FILE_MACHINE_R3000
: MESSAGE("R3000"); break;
460 case IMAGE_FILE_MACHINE_R4000
: MESSAGE("R4000"); break;
461 case IMAGE_FILE_MACHINE_R10000
: MESSAGE("R10000"); break;
462 case IMAGE_FILE_MACHINE_ALPHA
: MESSAGE("Alpha"); break;
463 case IMAGE_FILE_MACHINE_POWERPC
: MESSAGE("PowerPC"); break;
464 default: MESSAGE("Unknown-%04x", nt
->FileHeader
.Machine
); break;
470 /* retrieve the shared sections file */
474 if ((shared_fd
= FILE_GetUnixHandle( shared_file
, GENERIC_READ
)) == -1) goto error
;
475 CloseHandle( shared_file
); /* we no longer need it */
476 shared_file
= INVALID_HANDLE_VALUE
;
479 /* map all the sections */
481 for (i
= pos
= 0; i
< nt
->FileHeader
.NumberOfSections
; i
++, sec
++)
485 /* a few sanity checks */
486 size
= sec
->VirtualAddress
+ ROUND_SIZE( sec
->VirtualAddress
, sec
->Misc
.VirtualSize
);
487 if (sec
->VirtualAddress
> total_size
|| size
> total_size
|| size
< sec
->VirtualAddress
)
489 ERR_(module
)( "Section %.8s too large (%lx+%lx/%lx)\n",
490 sec
->Name
, sec
->VirtualAddress
, sec
->Misc
.VirtualSize
, total_size
);
494 if ((sec
->Characteristics
& IMAGE_SCN_MEM_SHARED
) &&
495 (sec
->Characteristics
& IMAGE_SCN_MEM_WRITE
))
497 size
= ROUND_SIZE( 0, sec
->Misc
.VirtualSize
);
498 TRACE_(module
)( "mapping shared section %.8s at %p off %lx (%x) size %lx (%lx) flags %lx\n",
499 sec
->Name
, (char *)ptr
+ sec
->VirtualAddress
,
500 sec
->PointerToRawData
, pos
, sec
->SizeOfRawData
,
501 size
, sec
->Characteristics
);
502 if (FILE_dommap( shared_fd
, (char *)ptr
+ sec
->VirtualAddress
, 0, size
,
503 0, pos
, PROT_READ
|PROT_WRITE
|PROT_EXEC
,
504 MAP_SHARED
|MAP_FIXED
) == (void *)-1)
506 ERR_(module
)( "Could not map shared section %.8s\n", sec
->Name
);
513 if (sec
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
) continue;
514 if (!sec
->PointerToRawData
|| !sec
->SizeOfRawData
) continue;
516 TRACE_(module
)( "mapping section %.8s at %p off %lx size %lx flags %lx\n",
517 sec
->Name
, (char *)ptr
+ sec
->VirtualAddress
,
518 sec
->PointerToRawData
, sec
->SizeOfRawData
,
519 sec
->Characteristics
);
521 /* Note: if the section is not aligned properly FILE_dommap will magically
522 * fall back to read(), so we don't need to check anything here.
524 if (FILE_dommap( fd
, (char *)ptr
+ sec
->VirtualAddress
, 0, sec
->SizeOfRawData
,
525 0, sec
->PointerToRawData
, PROT_READ
|PROT_WRITE
|PROT_EXEC
,
526 MAP_PRIVATE
| MAP_FIXED
) == (void *)-1)
528 ERR_(module
)( "Could not map section %.8s, file probably truncated\n", sec
->Name
);
532 if ((sec
->SizeOfRawData
< sec
->Misc
.VirtualSize
) && (sec
->SizeOfRawData
& page_mask
))
534 DWORD end
= ROUND_SIZE( 0, sec
->SizeOfRawData
);
535 if (end
> sec
->Misc
.VirtualSize
) end
= sec
->Misc
.VirtualSize
;
536 TRACE_(module
)("clearing %p - %p\n",
537 (char *)ptr
+ sec
->VirtualAddress
+ sec
->SizeOfRawData
,
538 (char *)ptr
+ sec
->VirtualAddress
+ end
);
539 memset( (char *)ptr
+ sec
->VirtualAddress
+ sec
->SizeOfRawData
, 0,
540 end
- sec
->SizeOfRawData
);
544 SetLastError( err
); /* restore last error */
546 if (shared_fd
!= -1) close( shared_fd
);
550 if (view
) VIRTUAL_DeleteView( view
);
552 if (shared_fd
!= -1) close( shared_fd
);
553 if (shared_file
!= INVALID_HANDLE_VALUE
) CloseHandle( shared_file
);
558 /***********************************************************************
562 DECL_GLOBAL_CONSTRUCTOR(VIRTUAL_Init
)
566 # ifdef HAVE_GETPAGESIZE
567 page_size
= getpagesize();
570 page_size
= sysconf(_SC_PAGESIZE
);
572 # error Cannot get the page size on this platform
575 page_mask
= page_size
- 1;
576 /* Make sure we have a power of 2 */
577 assert( !(page_size
& page_mask
) );
579 while ((1 << page_shift
) != page_size
) page_shift
++;
581 #endif /* page_mask */
584 /***********************************************************************
585 * VIRTUAL_GetPageSize
587 DWORD
VIRTUAL_GetPageSize(void)
589 return 1 << page_shift
;
593 /***********************************************************************
594 * VIRTUAL_GetGranularity
596 DWORD
VIRTUAL_GetGranularity(void)
598 return granularity_mask
+ 1;
602 /***********************************************************************
603 * VIRTUAL_SetFaultHandler
605 BOOL
VIRTUAL_SetFaultHandler( LPCVOID addr
, HANDLERPROC proc
, LPVOID arg
)
609 if (!(view
= VIRTUAL_FindView((UINT
)addr
))) return FALSE
;
610 view
->handlerProc
= proc
;
611 view
->handlerArg
= arg
;
615 /***********************************************************************
616 * VIRTUAL_HandleFault
618 DWORD
VIRTUAL_HandleFault( LPCVOID addr
)
620 FILE_VIEW
*view
= VIRTUAL_FindView((UINT
)addr
);
621 DWORD ret
= EXCEPTION_ACCESS_VIOLATION
;
625 if (view
->handlerProc
)
627 if (view
->handlerProc(view
->handlerArg
, addr
)) ret
= 0; /* handled */
631 BYTE vprot
= view
->prot
[((UINT
)addr
- view
->base
) >> page_shift
];
632 UINT page
= (UINT
)addr
& ~page_mask
;
633 char *stack
= (char *)NtCurrentTeb()->stack_base
+ SIGNAL_STACK_SIZE
+ page_mask
+ 1;
634 if (vprot
& VPROT_GUARD
)
636 VIRTUAL_SetProt( view
, page
, page_mask
+ 1, vprot
& ~VPROT_GUARD
);
637 ret
= STATUS_GUARD_PAGE_VIOLATION
;
639 /* is it inside the stack guard pages? */
640 if (((char *)addr
>= stack
) && ((char *)addr
< stack
+ 2*(page_mask
+1)))
641 ret
= STATUS_STACK_OVERFLOW
;
648 /***********************************************************************
649 * VirtualAlloc (KERNEL32.548)
650 * Reserves or commits a region of pages in virtual address space
653 * Base address of allocated region of pages
656 LPVOID WINAPI
VirtualAlloc(
657 LPVOID addr
, /* [in] Address of region to reserve or commit */
658 DWORD size
, /* [in] Size of region */
659 DWORD type
, /* [in] Type of allocation */
660 DWORD protect
/* [in] Type of access protection */
663 UINT base
, ptr
, view_size
;
666 TRACE("%08x %08lx %lx %08lx\n",
667 (UINT
)addr
, size
, type
, protect
);
669 /* Round parameters to a page boundary */
671 if (size
> 0x7fc00000) /* 2Gb - 4Mb */
673 SetLastError( ERROR_OUTOFMEMORY
);
678 if (type
& MEM_RESERVE
) /* Round down to 64k boundary */
679 base
= (UINT
)addr
& ~granularity_mask
;
681 base
= ROUND_ADDR( addr
);
682 size
= (((UINT
)addr
+ size
+ page_mask
) & ~page_mask
) - base
;
683 if ((base
<= granularity_mask
) || (base
+ size
< base
))
685 /* disallow low 64k and wrap-around */
686 SetLastError( ERROR_INVALID_PARAMETER
);
693 size
= (size
+ page_mask
) & ~page_mask
;
696 if (type
& MEM_TOP_DOWN
) {
697 /* FIXME: MEM_TOP_DOWN allocates the largest possible address.
698 * Is there _ANY_ way to do it with UNIX mmap()?
700 WARN("MEM_TOP_DOWN ignored\n");
701 type
&= ~MEM_TOP_DOWN
;
703 /* Compute the protection flags */
705 if (!(type
& (MEM_COMMIT
| MEM_RESERVE
| MEM_SYSTEM
)) ||
706 (type
& ~(MEM_COMMIT
| MEM_RESERVE
| MEM_SYSTEM
)))
708 SetLastError( ERROR_INVALID_PARAMETER
);
711 if (type
& (MEM_COMMIT
| MEM_SYSTEM
))
712 vprot
= VIRTUAL_GetProt( protect
) | VPROT_COMMITTED
;
715 /* Reserve the memory */
717 if ((type
& MEM_RESERVE
) || !base
)
719 view_size
= size
+ (base
? 0 : granularity_mask
+ 1);
720 if (type
& MEM_SYSTEM
)
723 ptr
= (UINT
)FILE_dommap( -1, (LPVOID
)base
, 0, view_size
, 0, 0,
724 VIRTUAL_GetUnixProt( vprot
), MAP_PRIVATE
);
727 SetLastError( ERROR_OUTOFMEMORY
);
732 /* Release the extra memory while keeping the range */
733 /* starting on a 64k boundary. */
735 if (ptr
& granularity_mask
)
737 UINT extra
= granularity_mask
+ 1 - (ptr
& granularity_mask
);
738 FILE_munmap( (void *)ptr
, 0, extra
);
742 if (view_size
> size
)
743 FILE_munmap( (void *)(ptr
+ size
), 0, view_size
- size
);
745 else if (ptr
!= base
)
747 /* We couldn't get the address we wanted */
748 FILE_munmap( (void *)ptr
, 0, view_size
);
749 SetLastError( ERROR_INVALID_ADDRESS
);
752 if (!(view
= VIRTUAL_CreateView( ptr
, size
, (type
& MEM_SYSTEM
) ?
753 VFLAG_SYSTEM
: 0, vprot
, -1 )))
755 FILE_munmap( (void *)ptr
, 0, size
);
756 SetLastError( ERROR_OUTOFMEMORY
);
759 VIRTUAL_DEBUG_DUMP_VIEW( view
);
763 /* Commit the pages */
765 if (!(view
= VIRTUAL_FindView( base
)) ||
766 (base
+ size
> view
->base
+ view
->size
))
768 SetLastError( ERROR_INVALID_ADDRESS
);
772 if (!VIRTUAL_SetProt( view
, base
, size
, vprot
)) return NULL
;
777 /***********************************************************************
778 * VirtualFree (KERNEL32.550)
779 * Release or decommits a region of pages in virtual address space.
785 BOOL WINAPI
VirtualFree(
786 LPVOID addr
, /* [in] Address of region of committed pages */
787 DWORD size
, /* [in] Size of region */
788 DWORD type
/* [in] Type of operation */
793 TRACE("%08x %08lx %lx\n",
794 (UINT
)addr
, size
, type
);
796 /* Fix the parameters */
798 size
= ROUND_SIZE( addr
, size
);
799 base
= ROUND_ADDR( addr
);
801 if (!(view
= VIRTUAL_FindView( base
)) ||
802 (base
+ size
> view
->base
+ view
->size
))
804 SetLastError( ERROR_INVALID_PARAMETER
);
808 /* Compute the protection flags */
810 if ((type
!= MEM_DECOMMIT
) && (type
!= MEM_RELEASE
))
812 SetLastError( ERROR_INVALID_PARAMETER
);
818 if (type
== MEM_RELEASE
)
820 if (size
|| (base
!= view
->base
))
822 SetLastError( ERROR_INVALID_PARAMETER
);
825 VIRTUAL_DeleteView( view
);
829 /* Decommit the pages by remapping zero-pages instead */
831 if (FILE_dommap( -1, (LPVOID
)base
, 0, size
, 0, 0,
832 VIRTUAL_GetUnixProt( 0 ), MAP_PRIVATE
|MAP_FIXED
)
834 ERR( "Could not remap pages, expect trouble\n" );
835 return VIRTUAL_SetProt( view
, base
, size
, 0 );
839 /***********************************************************************
840 * VirtualLock (KERNEL32.551)
841 * Locks the specified region of virtual address space
844 * Always returns TRUE
850 BOOL WINAPI
VirtualLock(
851 LPVOID addr
, /* [in] Address of first byte of range to lock */
852 DWORD size
/* [in] Number of bytes in range to lock */
858 /***********************************************************************
859 * VirtualUnlock (KERNEL32.556)
860 * Unlocks a range of pages in the virtual address space
863 * Always returns TRUE
869 BOOL WINAPI
VirtualUnlock(
870 LPVOID addr
, /* [in] Address of first byte of range */
871 DWORD size
/* [in] Number of bytes in range */
877 /***********************************************************************
878 * VirtualProtect (KERNEL32.552)
879 * Changes the access protection on a region of committed pages
885 BOOL WINAPI
VirtualProtect(
886 LPVOID addr
, /* [in] Address of region of committed pages */
887 DWORD size
, /* [in] Size of region */
888 DWORD new_prot
, /* [in] Desired access protection */
889 LPDWORD old_prot
/* [out] Address of variable to get old protection */
895 TRACE("%08x %08lx %08lx\n",
896 (UINT
)addr
, size
, new_prot
);
898 /* Fix the parameters */
900 size
= ROUND_SIZE( addr
, size
);
901 base
= ROUND_ADDR( addr
);
903 if (!(view
= VIRTUAL_FindView( base
)) ||
904 (base
+ size
> view
->base
+ view
->size
))
906 SetLastError( ERROR_INVALID_PARAMETER
);
910 /* Make sure all the pages are committed */
912 p
= view
->prot
+ ((base
- view
->base
) >> page_shift
);
913 for (i
= size
>> page_shift
; i
; i
--, p
++)
915 if (!(*p
& VPROT_COMMITTED
))
917 SetLastError( ERROR_INVALID_PARAMETER
);
922 VIRTUAL_GetWin32Prot( view
->prot
[0], old_prot
, NULL
);
923 vprot
= VIRTUAL_GetProt( new_prot
) | VPROT_COMMITTED
;
924 return VIRTUAL_SetProt( view
, base
, size
, vprot
);
928 /***********************************************************************
929 * VirtualProtectEx (KERNEL32.553)
930 * Changes the access protection on a region of committed pages in the
931 * virtual address space of a specified process
937 BOOL WINAPI
VirtualProtectEx(
938 HANDLE handle
, /* [in] Handle of process */
939 LPVOID addr
, /* [in] Address of region of committed pages */
940 DWORD size
, /* [in] Size of region */
941 DWORD new_prot
, /* [in] Desired access protection */
942 LPDWORD old_prot
/* [out] Address of variable to get old protection */ )
944 if (MapProcessHandle( handle
) == GetCurrentProcessId())
945 return VirtualProtect( addr
, size
, new_prot
, old_prot
);
946 ERR("Unsupported on other process\n");
951 /***********************************************************************
952 * VirtualQuery (KERNEL32.554)
953 * Provides info about a range of pages in virtual address space
956 * Number of bytes returned in information buffer
958 DWORD WINAPI
VirtualQuery(
959 LPCVOID addr
, /* [in] Address of region */
960 LPMEMORY_BASIC_INFORMATION info
, /* [out] Address of info buffer */
961 DWORD len
/* [in] Size of buffer */
963 FILE_VIEW
*view
= VIRTUAL_FirstView
;
964 UINT base
= ROUND_ADDR( addr
);
968 /* Find the view containing the address */
974 size
= 0xffff0000 - alloc_base
;
977 if (view
->base
> base
)
979 size
= view
->base
- alloc_base
;
983 if (view
->base
+ view
->size
> base
)
985 alloc_base
= view
->base
;
989 alloc_base
= view
->base
+ view
->size
;
993 /* Fill the info structure */
997 info
->State
= MEM_FREE
;
999 info
->AllocationProtect
= 0;
1004 BYTE vprot
= view
->prot
[(base
- alloc_base
) >> page_shift
];
1005 VIRTUAL_GetWin32Prot( vprot
, &info
->Protect
, &info
->State
);
1006 for (size
= base
- alloc_base
; size
< view
->size
; size
+= page_mask
+1)
1007 if (view
->prot
[size
>> page_shift
] != vprot
) break;
1008 info
->AllocationProtect
= view
->protect
;
1009 info
->Type
= MEM_PRIVATE
; /* FIXME */
1012 info
->BaseAddress
= (LPVOID
)base
;
1013 info
->AllocationBase
= (LPVOID
)alloc_base
;
1014 info
->RegionSize
= size
- (base
- alloc_base
);
1015 return sizeof(*info
);
1019 /***********************************************************************
1020 * VirtualQueryEx (KERNEL32.555)
1021 * Provides info about a range of pages in virtual address space of a
1025 * Number of bytes returned in information buffer
1027 DWORD WINAPI
VirtualQueryEx(
1028 HANDLE handle
, /* [in] Handle of process */
1029 LPCVOID addr
, /* [in] Address of region */
1030 LPMEMORY_BASIC_INFORMATION info
, /* [out] Address of info buffer */
1031 DWORD len
/* [in] Size of buffer */ )
1033 if (MapProcessHandle( handle
) == GetCurrentProcessId())
1034 return VirtualQuery( addr
, info
, len
);
1035 ERR("Unsupported on other process\n");
1040 /***********************************************************************
1041 * IsBadReadPtr (KERNEL32.354)
1044 * FALSE: Process has read access to entire block
1047 BOOL WINAPI
IsBadReadPtr(
1048 LPCVOID ptr
, /* Address of memory block */
1049 UINT size
) /* Size of block */
1053 volatile const char *p
= ptr
;
1054 volatile const char *end
= p
+ size
- 1;
1064 __EXCEPT(page_fault
) { return TRUE
; }
1070 /***********************************************************************
1071 * IsBadWritePtr (KERNEL32.357)
1074 * FALSE: Process has write access to entire block
1077 BOOL WINAPI
IsBadWritePtr(
1078 LPVOID ptr
, /* [in] Address of memory block */
1079 UINT size
) /* [in] Size of block in bytes */
1083 volatile char *p
= ptr
;
1084 volatile char *end
= p
+ size
- 1;
1093 __EXCEPT(page_fault
) { return TRUE
; }
1099 /***********************************************************************
1100 * IsBadHugeReadPtr (KERNEL32.352)
1102 * FALSE: Process has read access to entire block
1105 BOOL WINAPI
IsBadHugeReadPtr(
1106 LPCVOID ptr
, /* [in] Address of memory block */
1107 UINT size
/* [in] Size of block */
1109 return IsBadReadPtr( ptr
, size
);
1113 /***********************************************************************
1114 * IsBadHugeWritePtr (KERNEL32.353)
1116 * FALSE: Process has write access to entire block
1119 BOOL WINAPI
IsBadHugeWritePtr(
1120 LPVOID ptr
, /* [in] Address of memory block */
1121 UINT size
/* [in] Size of block */
1123 return IsBadWritePtr( ptr
, size
);
1127 /***********************************************************************
1128 * IsBadCodePtr (KERNEL32.351)
1131 * FALSE: Process has read access to specified memory
1134 BOOL WINAPI
IsBadCodePtr( FARPROC ptr
) /* [in] Address of function */
1136 return IsBadReadPtr( ptr
, 1 );
1140 /***********************************************************************
1141 * IsBadStringPtrA (KERNEL32.355)
1144 * FALSE: Read access to all bytes in string
1147 BOOL WINAPI
IsBadStringPtrA(
1148 LPCSTR str
, /* [in] Address of string */
1149 UINT max
) /* [in] Maximum size of string */
1153 volatile const char *p
= str
;
1154 while (p
< str
+ max
) if (!*p
++) break;
1156 __EXCEPT(page_fault
) { return TRUE
; }
1162 /***********************************************************************
1163 * IsBadStringPtrW (KERNEL32.356)
1164 * See IsBadStringPtrA
1166 BOOL WINAPI
IsBadStringPtrW( LPCWSTR str
, UINT max
)
1170 volatile const WCHAR
*p
= str
;
1171 while (p
< str
+ max
) if (!*p
++) break;
1173 __EXCEPT(page_fault
) { return TRUE
; }
1179 /***********************************************************************
1180 * CreateFileMappingA (KERNEL32.46)
1181 * Creates a named or unnamed file-mapping object for the specified file
1185 * 0: Mapping object does not exist
1188 HANDLE WINAPI
CreateFileMappingA(
1189 HFILE hFile
, /* [in] Handle of file to map */
1190 SECURITY_ATTRIBUTES
*sa
, /* [in] Optional security attributes*/
1191 DWORD protect
, /* [in] Protection for mapping object */
1192 DWORD size_high
, /* [in] High-order 32 bits of object size */
1193 DWORD size_low
, /* [in] Low-order 32 bits of object size */
1194 LPCSTR name
/* [in] Name of file-mapping object */ )
1198 DWORD len
= name
? MultiByteToWideChar( CP_ACP
, 0, name
, strlen(name
), NULL
, 0 ) : 0;
1200 /* Check parameters */
1202 TRACE("(%x,%p,%08lx,%08lx%08lx,%s)\n",
1203 hFile
, sa
, protect
, size_high
, size_low
, debugstr_a(name
) );
1207 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
1210 vprot
= VIRTUAL_GetProt( protect
);
1211 if (protect
& SEC_RESERVE
)
1213 if (hFile
!= INVALID_HANDLE_VALUE
)
1215 SetLastError( ERROR_INVALID_PARAMETER
);
1219 else vprot
|= VPROT_COMMITTED
;
1220 if (protect
& SEC_NOCACHE
) vprot
|= VPROT_NOCACHE
;
1221 if (protect
& SEC_IMAGE
) vprot
|= VPROT_IMAGE
;
1223 /* Create the server object */
1227 struct create_mapping_request
*req
= server_alloc_req( sizeof(*req
),
1228 len
* sizeof(WCHAR
) );
1229 req
->file_handle
= hFile
;
1230 req
->size_high
= size_high
;
1231 req
->size_low
= size_low
;
1232 req
->protect
= vprot
;
1233 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
1234 if (len
) MultiByteToWideChar( CP_ACP
, 0, name
, strlen(name
), server_data_ptr(req
), len
);
1236 server_call( REQ_CREATE_MAPPING
);
1240 if (ret
== -1) ret
= 0; /* must return 0 on failure, not -1 */
1245 /***********************************************************************
1246 * CreateFileMappingW (KERNEL32.47)
1247 * See CreateFileMappingA
1249 HANDLE WINAPI
CreateFileMappingW( HFILE hFile
, LPSECURITY_ATTRIBUTES sa
,
1250 DWORD protect
, DWORD size_high
,
1251 DWORD size_low
, LPCWSTR name
)
1255 DWORD len
= name
? strlenW(name
) : 0;
1257 /* Check parameters */
1259 TRACE("(%x,%p,%08lx,%08lx%08lx,%s)\n",
1260 hFile
, sa
, protect
, size_high
, size_low
, debugstr_w(name
) );
1264 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
1268 vprot
= VIRTUAL_GetProt( protect
);
1269 if (protect
& SEC_RESERVE
)
1271 if (hFile
!= INVALID_HANDLE_VALUE
)
1273 SetLastError( ERROR_INVALID_PARAMETER
);
1277 else vprot
|= VPROT_COMMITTED
;
1278 if (protect
& SEC_NOCACHE
) vprot
|= VPROT_NOCACHE
;
1279 if (protect
& SEC_IMAGE
) vprot
|= VPROT_IMAGE
;
1281 /* Create the server object */
1285 struct create_mapping_request
*req
= server_alloc_req( sizeof(*req
),
1286 len
* sizeof(WCHAR
) );
1287 req
->file_handle
= hFile
;
1288 req
->size_high
= size_high
;
1289 req
->size_low
= size_low
;
1290 req
->protect
= vprot
;
1291 req
->inherit
= (sa
&& (sa
->nLength
>=sizeof(*sa
)) && sa
->bInheritHandle
);
1292 memcpy( server_data_ptr(req
), name
, len
* sizeof(WCHAR
) );
1294 server_call( REQ_CREATE_MAPPING
);
1298 if (ret
== -1) ret
= 0; /* must return 0 on failure, not -1 */
1303 /***********************************************************************
1304 * OpenFileMappingA (KERNEL32.397)
1305 * Opens a named file-mapping object.
1311 HANDLE WINAPI
OpenFileMappingA(
1312 DWORD access
, /* [in] Access mode */
1313 BOOL inherit
, /* [in] Inherit flag */
1314 LPCSTR name
) /* [in] Name of file-mapping object */
1317 DWORD len
= name
? MultiByteToWideChar( CP_ACP
, 0, name
, strlen(name
), NULL
, 0 ) : 0;
1320 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
1325 struct open_mapping_request
*req
= server_alloc_req( sizeof(*req
), len
* sizeof(WCHAR
) );
1327 req
->access
= access
;
1328 req
->inherit
= inherit
;
1329 if (len
) MultiByteToWideChar( CP_ACP
, 0, name
, strlen(name
), server_data_ptr(req
), len
);
1330 server_call( REQ_OPEN_MAPPING
);
1334 if (ret
== -1) ret
= 0; /* must return 0 on failure, not -1 */
1339 /***********************************************************************
1340 * OpenFileMappingW (KERNEL32.398)
1341 * See OpenFileMappingA
1343 HANDLE WINAPI
OpenFileMappingW( DWORD access
, BOOL inherit
, LPCWSTR name
)
1346 DWORD len
= name
? strlenW(name
) : 0;
1349 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
1354 struct open_mapping_request
*req
= server_alloc_req( sizeof(*req
), len
* sizeof(WCHAR
) );
1356 req
->access
= access
;
1357 req
->inherit
= inherit
;
1358 memcpy( server_data_ptr(req
), name
, len
* sizeof(WCHAR
) );
1359 server_call( REQ_OPEN_MAPPING
);
1363 if (ret
== -1) ret
= 0; /* must return 0 on failure, not -1 */
1368 /***********************************************************************
1369 * MapViewOfFile (KERNEL32.385)
1370 * Maps a view of a file into the address space
1373 * Starting address of mapped view
1376 LPVOID WINAPI
MapViewOfFile(
1377 HANDLE mapping
, /* [in] File-mapping object to map */
1378 DWORD access
, /* [in] Access mode */
1379 DWORD offset_high
, /* [in] High-order 32 bits of file offset */
1380 DWORD offset_low
, /* [in] Low-order 32 bits of file offset */
1381 DWORD count
/* [in] Number of bytes to map */
1383 return MapViewOfFileEx( mapping
, access
, offset_high
,
1384 offset_low
, count
, NULL
);
1388 /***********************************************************************
1389 * MapViewOfFileEx (KERNEL32.386)
1390 * Maps a view of a file into the address space
1393 * Starting address of mapped view
1396 LPVOID WINAPI
MapViewOfFileEx(
1397 HANDLE handle
, /* [in] File-mapping object to map */
1398 DWORD access
, /* [in] Access mode */
1399 DWORD offset_high
, /* [in] High-order 32 bits of file offset */
1400 DWORD offset_low
, /* [in] Low-order 32 bits of file offset */
1401 DWORD count
, /* [in] Number of bytes to map */
1402 LPVOID addr
/* [in] Suggested starting address for mapped view */
1405 UINT ptr
= (UINT
)-1, size
= 0;
1406 int flags
= MAP_PRIVATE
;
1407 int unix_handle
= -1;
1409 struct get_mapping_info_request
*req
= get_req_buffer();
1411 /* Check parameters */
1413 if ((offset_low
& granularity_mask
) ||
1414 (addr
&& ((UINT
)addr
& granularity_mask
)))
1416 SetLastError( ERROR_INVALID_PARAMETER
);
1420 req
->handle
= handle
;
1421 if (server_call_fd( REQ_GET_MAPPING_INFO
, -1, &unix_handle
)) goto error
;
1422 prot
= req
->protect
;
1424 if (prot
& VPROT_IMAGE
)
1425 return map_image( handle
, unix_handle
, req
->base
, req
->size_low
, req
->header_size
,
1426 req
->shared_file
, req
->shared_size
);
1428 if (req
->size_high
|| offset_high
)
1429 ERR("Offsets larger than 4Gb not supported\n");
1431 if ((offset_low
>= req
->size_low
) ||
1432 (count
> req
->size_low
- offset_low
))
1434 SetLastError( ERROR_INVALID_PARAMETER
);
1437 if (count
) size
= ROUND_SIZE( offset_low
, count
);
1438 else size
= req
->size_low
- offset_low
;
1442 case FILE_MAP_ALL_ACCESS
:
1443 case FILE_MAP_WRITE
:
1444 case FILE_MAP_WRITE
| FILE_MAP_READ
:
1445 if (!(prot
& VPROT_WRITE
))
1447 SetLastError( ERROR_INVALID_PARAMETER
);
1454 case FILE_MAP_COPY
| FILE_MAP_READ
:
1455 if (prot
& VPROT_READ
) break;
1458 SetLastError( ERROR_INVALID_PARAMETER
);
1462 /* FIXME: If a mapping is created with SEC_RESERVE and a process,
1463 * which has a view of this mapping commits some pages, they will
1464 * appear commited in all other processes, which have the same
1465 * view created. Since we don`t support this yet, we create the
1466 * whole mapping commited.
1468 prot
|= VPROT_COMMITTED
;
1472 TRACE("handle=%x size=%x offset=%lx\n", handle
, size
, offset_low
);
1474 ptr
= (UINT
)FILE_dommap( unix_handle
, addr
, 0, size
, 0, offset_low
,
1475 VIRTUAL_GetUnixProt( prot
), flags
);
1476 if (ptr
== (UINT
)-1) {
1477 /* KB: Q125713, 25-SEP-1995, "Common File Mapping Problems and
1478 * Platform Differences":
1479 * Windows NT: ERROR_INVALID_PARAMETER
1480 * Windows 95: ERROR_INVALID_ADDRESS.
1481 * FIXME: So should we add a module dependend check here? -MM
1484 SetLastError( ERROR_OUTOFMEMORY
);
1486 SetLastError( ERROR_INVALID_PARAMETER
);
1490 if (!(view
= VIRTUAL_CreateView( ptr
, size
, 0, prot
, handle
)))
1492 SetLastError( ERROR_OUTOFMEMORY
);
1495 if (unix_handle
!= -1) close( unix_handle
);
1499 if (unix_handle
!= -1) close( unix_handle
);
1500 if (ptr
!= (UINT
)-1) FILE_munmap( (void *)ptr
, 0, size
);
1505 /***********************************************************************
1506 * FlushViewOfFile (KERNEL32.262)
1507 * Writes to the disk a byte range within a mapped view of a file
1513 BOOL WINAPI
FlushViewOfFile(
1514 LPCVOID base
, /* [in] Start address of byte range to flush */
1515 DWORD cbFlush
/* [in] Number of bytes in range */
1518 UINT addr
= ROUND_ADDR( base
);
1520 TRACE("FlushViewOfFile at %p for %ld bytes\n",
1523 if (!(view
= VIRTUAL_FindView( addr
)))
1525 SetLastError( ERROR_INVALID_PARAMETER
);
1528 if (!cbFlush
) cbFlush
= view
->size
;
1529 if (!msync( (void *)addr
, cbFlush
, MS_SYNC
)) return TRUE
;
1530 SetLastError( ERROR_INVALID_PARAMETER
);
1535 /***********************************************************************
1536 * UnmapViewOfFile (KERNEL32.540)
1537 * Unmaps a mapped view of a file.
1540 * Should addr be an LPCVOID?
1546 BOOL WINAPI
UnmapViewOfFile(
1547 LPVOID addr
/* [in] Address where mapped view begins */
1550 UINT base
= ROUND_ADDR( addr
);
1551 if (!(view
= VIRTUAL_FindView( base
)) || (base
!= view
->base
))
1553 SetLastError( ERROR_INVALID_PARAMETER
);
1556 VIRTUAL_DeleteView( view
);
1560 /***********************************************************************
1563 * Helper function to map a file to memory:
1565 * [RETURN] ptr - pointer to mapped file
1567 LPVOID
VIRTUAL_MapFileW( LPCWSTR name
)
1569 HANDLE hFile
, hMapping
;
1572 hFile
= CreateFileW( name
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
1573 OPEN_EXISTING
, FILE_FLAG_RANDOM_ACCESS
, 0);
1574 if (hFile
!= INVALID_HANDLE_VALUE
)
1576 hMapping
= CreateFileMappingA( hFile
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
1577 CloseHandle( hFile
);
1580 ptr
= MapViewOfFile( hMapping
, FILE_MAP_READ
, 0, 0, 0 );
1581 CloseHandle( hMapping
);