Fix some parameter types.
[wine] / dlls / ntdll / virtual.c
1 /*
2  * Win32 virtual memory functions
3  *
4  * Copyright 1997, 2002 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 <assert.h>
25 #include <errno.h>
26 #ifdef HAVE_SYS_ERRNO_H
27 #include <sys/errno.h>
28 #endif
29 #include <fcntl.h>
30 #ifdef HAVE_UNISTD_H
31 # include <unistd.h>
32 #endif
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <sys/types.h>
37 #ifdef HAVE_SYS_MMAN_H
38 #include <sys/mman.h>
39 #endif
40
41 #include "winternl.h"
42 #include "global.h"
43 #include "wine/library.h"
44 #include "wine/server.h"
45 #include "wine/debug.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(virtual);
48 WINE_DECLARE_DEBUG_CHANNEL(module);
49
50 #ifndef MS_SYNC
51 #define MS_SYNC 0
52 #endif
53
54 /* File view */
55 typedef struct _FV
56 {
57     struct _FV   *next;        /* Next view */
58     struct _FV   *prev;        /* Prev view */
59     void         *base;        /* Base address */
60     UINT          size;        /* Size in bytes */
61     UINT          flags;       /* Allocation flags */
62     HANDLE        mapping;     /* Handle to the file mapping */
63     HANDLERPROC   handlerProc; /* Fault handler */
64     LPVOID        handlerArg;  /* Fault handler argument */
65     BYTE          protect;     /* Protection for all pages at allocation time */
66     BYTE          prot[1];     /* Protection byte for each page */
67 } FILE_VIEW;
68
69 /* Per-view flags */
70 #define VFLAG_SYSTEM     0x01
71 #define VFLAG_VALLOC     0x02  /* allocated by VirtualAlloc */
72
73 /* Conversion from VPROT_* to Win32 flags */
74 static const BYTE VIRTUAL_Win32Flags[16] =
75 {
76     PAGE_NOACCESS,              /* 0 */
77     PAGE_READONLY,              /* READ */
78     PAGE_READWRITE,             /* WRITE */
79     PAGE_READWRITE,             /* READ | WRITE */
80     PAGE_EXECUTE,               /* EXEC */
81     PAGE_EXECUTE_READ,          /* READ | EXEC */
82     PAGE_EXECUTE_READWRITE,     /* WRITE | EXEC */
83     PAGE_EXECUTE_READWRITE,     /* READ | WRITE | EXEC */
84     PAGE_WRITECOPY,             /* WRITECOPY */
85     PAGE_WRITECOPY,             /* READ | WRITECOPY */
86     PAGE_WRITECOPY,             /* WRITE | WRITECOPY */
87     PAGE_WRITECOPY,             /* READ | WRITE | WRITECOPY */
88     PAGE_EXECUTE_WRITECOPY,     /* EXEC | WRITECOPY */
89     PAGE_EXECUTE_WRITECOPY,     /* READ | EXEC | WRITECOPY */
90     PAGE_EXECUTE_WRITECOPY,     /* WRITE | EXEC | WRITECOPY */
91     PAGE_EXECUTE_WRITECOPY      /* READ | WRITE | EXEC | WRITECOPY */
92 };
93
94
95 static FILE_VIEW *VIRTUAL_FirstView;
96 static CRITICAL_SECTION csVirtual = CRITICAL_SECTION_INIT("csVirtual");
97
98 #ifdef __i386__
99 /* These are always the same on an i386, and it will be faster this way */
100 # define page_mask  0xfff
101 # define page_shift 12
102 # define page_size  0x1000
103 # define ADDRESS_SPACE_LIMIT  ((void *)0xc0000000)  /* top of the user address space */
104 #else
105 static UINT page_shift;
106 static UINT page_mask;
107 static UINT page_size;
108 # define ADDRESS_SPACE_LIMIT  0   /* no limit needed on other platforms */
109 #endif  /* __i386__ */
110 #define granularity_mask 0xffff  /* Allocation granularity (usually 64k) */
111
112 #define ROUND_ADDR(addr,mask) \
113    ((void *)((UINT_PTR)(addr) & ~(mask)))
114
115 #define ROUND_SIZE(addr,size) \
116    (((UINT)(size) + ((UINT_PTR)(addr) & page_mask) + page_mask) & ~page_mask)
117
118 #define VIRTUAL_DEBUG_DUMP_VIEW(view) \
119    if (!TRACE_ON(virtual)); else VIRTUAL_DumpView(view)
120
121 static LPVOID VIRTUAL_mmap( int fd, LPVOID start, DWORD size, DWORD offset_low,
122                             DWORD offset_high, int prot, int flags, BOOL *removable );
123
124
125 /***********************************************************************
126  *           VIRTUAL_GetProtStr
127  */
128 static const char *VIRTUAL_GetProtStr( BYTE prot )
129 {
130     static char buffer[6];
131     buffer[0] = (prot & VPROT_COMMITTED) ? 'c' : '-';
132     buffer[1] = (prot & VPROT_GUARD) ? 'g' : '-';
133     buffer[2] = (prot & VPROT_READ) ? 'r' : '-';
134     buffer[3] = (prot & VPROT_WRITE) ?
135                     ((prot & VPROT_WRITECOPY) ? 'w' : 'W') : '-';
136     buffer[4] = (prot & VPROT_EXEC) ? 'x' : '-';
137     buffer[5] = 0;
138     return buffer;
139 }
140
141
142 /***********************************************************************
143  *           VIRTUAL_DumpView
144  */
145 static void VIRTUAL_DumpView( FILE_VIEW *view )
146 {
147     UINT i, count;
148     char *addr = view->base;
149     BYTE prot = view->prot[0];
150
151     DPRINTF( "View: %p - %p", addr, addr + view->size - 1 );
152     if (view->flags & VFLAG_SYSTEM)
153         DPRINTF( " (system)\n" );
154     else if (view->flags & VFLAG_VALLOC)
155         DPRINTF( " (valloc)\n" );
156     else if (view->mapping)
157         DPRINTF( " %p\n", view->mapping );
158     else
159         DPRINTF( " (anonymous)\n");
160
161     for (count = i = 1; i < view->size >> page_shift; i++, count++)
162     {
163         if (view->prot[i] == prot) continue;
164         DPRINTF( "      %p - %p %s\n",
165                  addr, addr + (count << page_shift) - 1, VIRTUAL_GetProtStr(prot) );
166         addr += (count << page_shift);
167         prot = view->prot[i];
168         count = 0;
169     }
170     if (count)
171         DPRINTF( "      %p - %p %s\n",
172                  addr, addr + (count << page_shift) - 1, VIRTUAL_GetProtStr(prot) );
173 }
174
175
176 /***********************************************************************
177  *           VIRTUAL_Dump
178  */
179 void VIRTUAL_Dump(void)
180 {
181     FILE_VIEW *view;
182     DPRINTF( "\nDump of all virtual memory views:\n\n" );
183     RtlEnterCriticalSection(&csVirtual);
184     view = VIRTUAL_FirstView;
185     while (view)
186     {
187         VIRTUAL_DumpView( view );
188         view = view->next;
189     }
190     RtlLeaveCriticalSection(&csVirtual);
191 }
192
193
194 /***********************************************************************
195  *           VIRTUAL_FindView
196  *
197  * Find the view containing a given address.
198  *
199  * RETURNS
200  *      View: Success
201  *      NULL: Failure
202  */
203 static FILE_VIEW *VIRTUAL_FindView( const void *addr ) /* [in] Address */
204 {
205     FILE_VIEW *view;
206
207     RtlEnterCriticalSection(&csVirtual);
208     view = VIRTUAL_FirstView;
209     while (view)
210     {
211         if (view->base > addr)
212         {
213             view = NULL;
214             break;
215         }
216         if ((char*)view->base + view->size > (char*)addr) break;
217         view = view->next;
218     }
219     RtlLeaveCriticalSection(&csVirtual);
220     return view;
221 }
222
223
224 /***********************************************************************
225  *           VIRTUAL_CreateView
226  *
227  * Create a new view and add it in the linked list.
228  */
229 static FILE_VIEW *VIRTUAL_CreateView( void *base, UINT size, UINT flags,
230                                       BYTE vprot, HANDLE mapping )
231 {
232     FILE_VIEW *view, *prev;
233
234     /* Create the view structure */
235
236     assert( !((unsigned int)base & page_mask) );
237     assert( !(size & page_mask) );
238     size >>= page_shift;
239     if (!(view = (FILE_VIEW *)malloc( sizeof(*view) + size - 1 ))) return NULL;
240     view->base    = base;
241     view->size    = size << page_shift;
242     view->flags   = flags;
243     view->mapping = mapping;
244     view->protect = vprot;
245     view->handlerProc = NULL;
246     memset( view->prot, vprot, size );
247
248     /* Duplicate the mapping handle */
249
250     if (view->mapping &&
251         NtDuplicateObject( GetCurrentProcess(), view->mapping,
252                            GetCurrentProcess(), &view->mapping,
253                            0, 0, DUPLICATE_SAME_ACCESS ))
254     {
255         free( view );
256         return NULL;
257     }
258
259     /* Insert it in the linked list */
260
261     RtlEnterCriticalSection(&csVirtual);
262     if (!VIRTUAL_FirstView || (VIRTUAL_FirstView->base > base))
263     {
264         view->next = VIRTUAL_FirstView;
265         view->prev = NULL;
266         if (view->next) view->next->prev = view;
267         VIRTUAL_FirstView = view;
268     }
269     else
270     {
271         prev = VIRTUAL_FirstView;
272         while (prev->next && (prev->next->base < base)) prev = prev->next;
273         view->next = prev->next;
274         view->prev = prev;
275         if (view->next) view->next->prev = view;
276         prev->next  = view;
277     }
278     RtlLeaveCriticalSection(&csVirtual);
279     VIRTUAL_DEBUG_DUMP_VIEW( view );
280     return view;
281 }
282
283
284 /***********************************************************************
285  *           VIRTUAL_DeleteView
286  * Deletes a view.
287  *
288  * RETURNS
289  *      None
290  */
291 static void VIRTUAL_DeleteView( FILE_VIEW *view ) /* [in] View */
292 {
293     if (!(view->flags & VFLAG_SYSTEM))
294         munmap( (void *)view->base, view->size );
295     RtlEnterCriticalSection(&csVirtual);
296     if (view->next) view->next->prev = view->prev;
297     if (view->prev) view->prev->next = view->next;
298     else VIRTUAL_FirstView = view->next;
299     RtlLeaveCriticalSection(&csVirtual);
300     if (view->mapping) NtClose( view->mapping );
301     free( view );
302 }
303
304
305 /***********************************************************************
306  *           VIRTUAL_GetUnixProt
307  *
308  * Convert page protections to protection for mmap/mprotect.
309  */
310 static int VIRTUAL_GetUnixProt( BYTE vprot )
311 {
312     int prot = 0;
313     if ((vprot & VPROT_COMMITTED) && !(vprot & VPROT_GUARD))
314     {
315         if (vprot & VPROT_READ) prot |= PROT_READ;
316         if (vprot & VPROT_WRITE) prot |= PROT_WRITE;
317         if (vprot & VPROT_WRITECOPY) prot |= PROT_WRITE;
318         if (vprot & VPROT_EXEC) prot |= PROT_EXEC;
319     }
320     return prot;
321 }
322
323
324 /***********************************************************************
325  *           VIRTUAL_GetWin32Prot
326  *
327  * Convert page protections to Win32 flags.
328  *
329  * RETURNS
330  *      None
331  */
332 static void VIRTUAL_GetWin32Prot(
333             BYTE vprot,     /* [in] Page protection flags */
334             DWORD *protect, /* [out] Location to store Win32 protection flags */
335             DWORD *state )  /* [out] Location to store mem state flag */
336 {
337     if (protect) {
338         *protect = VIRTUAL_Win32Flags[vprot & 0x0f];
339 /*      if (vprot & VPROT_GUARD) *protect |= PAGE_GUARD;*/
340         if (vprot & VPROT_NOCACHE) *protect |= PAGE_NOCACHE;
341
342         if (vprot & VPROT_GUARD) *protect = PAGE_NOACCESS;
343     }
344
345     if (state) *state = (vprot & VPROT_COMMITTED) ? MEM_COMMIT : MEM_RESERVE;
346 }
347
348
349 /***********************************************************************
350  *           VIRTUAL_GetProt
351  *
352  * Build page protections from Win32 flags.
353  *
354  * RETURNS
355  *      Value of page protection flags
356  */
357 static BYTE VIRTUAL_GetProt( DWORD protect )  /* [in] Win32 protection flags */
358 {
359     BYTE vprot;
360
361     switch(protect & 0xff)
362     {
363     case PAGE_READONLY:
364         vprot = VPROT_READ;
365         break;
366     case PAGE_READWRITE:
367         vprot = VPROT_READ | VPROT_WRITE;
368         break;
369     case PAGE_WRITECOPY:
370         /* MSDN CreateFileMapping() states that if PAGE_WRITECOPY is given,
371          * that the hFile must have been opened with GENERIC_READ and
372          * GENERIC_WRITE access.  This is WRONG as tests show that you
373          * only need GENERIC_READ access (at least for Win9x,
374          * FIXME: what about NT?).  Thus, we don't put VPROT_WRITE in
375          * PAGE_WRITECOPY and PAGE_EXECUTE_WRITECOPY.
376          */
377         vprot = VPROT_READ | VPROT_WRITECOPY;
378         break;
379     case PAGE_EXECUTE:
380         vprot = VPROT_EXEC;
381         break;
382     case PAGE_EXECUTE_READ:
383         vprot = VPROT_EXEC | VPROT_READ;
384         break;
385     case PAGE_EXECUTE_READWRITE:
386         vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITE;
387         break;
388     case PAGE_EXECUTE_WRITECOPY:
389         /* See comment for PAGE_WRITECOPY above */
390         vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITECOPY;
391         break;
392     case PAGE_NOACCESS:
393     default:
394         vprot = 0;
395         break;
396     }
397     if (protect & PAGE_GUARD) vprot |= VPROT_GUARD;
398     if (protect & PAGE_NOCACHE) vprot |= VPROT_NOCACHE;
399     return vprot;
400 }
401
402
403 /***********************************************************************
404  *           VIRTUAL_SetProt
405  *
406  * Change the protection of a range of pages.
407  *
408  * RETURNS
409  *      TRUE: Success
410  *      FALSE: Failure
411  */
412 static BOOL VIRTUAL_SetProt( FILE_VIEW *view, /* [in] Pointer to view */
413                              void *base,      /* [in] Starting address */
414                              UINT size,       /* [in] Size in bytes */
415                              BYTE vprot )     /* [in] Protections to use */
416 {
417     TRACE("%p-%p %s\n",
418           base, (char *)base + size - 1, VIRTUAL_GetProtStr( vprot ) );
419
420     if (mprotect( base, size, VIRTUAL_GetUnixProt(vprot) ))
421         return FALSE;  /* FIXME: last error */
422
423     memset( view->prot + (((char *)base - (char *)view->base) >> page_shift),
424             vprot, size >> page_shift );
425     VIRTUAL_DEBUG_DUMP_VIEW( view );
426     return TRUE;
427 }
428
429
430 /***********************************************************************
431  *           anon_mmap_aligned
432  *
433  * Create an anonymous mapping aligned to the allocation granularity.
434  */
435 static NTSTATUS anon_mmap_aligned( void **addr, unsigned int size, int prot, int flags )
436 {
437     void *ptr, *base = *addr;
438     unsigned int view_size = size + (base ? 0 : granularity_mask + 1);
439
440     if ((ptr = wine_anon_mmap( base, view_size, prot, flags )) == (void *)-1)
441     {
442         if (errno == ENOMEM) return STATUS_NO_MEMORY;
443         return STATUS_INVALID_PARAMETER;
444     }
445
446     if (!base)
447     {
448         /* Release the extra memory while keeping the range
449          * starting on the granularity boundary. */
450         if ((unsigned int)ptr & granularity_mask)
451         {
452             unsigned int extra = granularity_mask + 1 - ((unsigned int)ptr & granularity_mask);
453             munmap( ptr, extra );
454             ptr = (char *)ptr + extra;
455             view_size -= extra;
456         }
457         if (view_size > size)
458             munmap( (char *)ptr + size, view_size - size );
459     }
460     else if (ptr != base)
461     {
462         /* We couldn't get the address we wanted */
463         munmap( ptr, view_size );
464         return STATUS_CONFLICTING_ADDRESSES;
465     }
466     *addr = ptr;
467     return STATUS_SUCCESS;
468 }
469
470
471 /***********************************************************************
472  *           do_relocations
473  *
474  * Apply the relocations to a mapped PE image
475  */
476 static int do_relocations( char *base, const IMAGE_DATA_DIRECTORY *dir,
477                            int delta, DWORD total_size )
478 {
479     IMAGE_BASE_RELOCATION *rel;
480
481     TRACE_(module)( "relocating from %p-%p to %p-%p\n",
482                     base - delta, base - delta + total_size, base, base + total_size );
483
484     for (rel = (IMAGE_BASE_RELOCATION *)(base + dir->VirtualAddress);
485          ((char *)rel < base + dir->VirtualAddress + dir->Size) && rel->SizeOfBlock;
486          rel = (IMAGE_BASE_RELOCATION*)((char*)rel + rel->SizeOfBlock) )
487     {
488         char *page = base + rel->VirtualAddress;
489         WORD *TypeOffset = (WORD *)(rel + 1);
490         int i, count = (rel->SizeOfBlock - sizeof(*rel)) / sizeof(*TypeOffset);
491
492         if (!count) continue;
493
494         /* sanity checks */
495         if ((char *)rel + rel->SizeOfBlock > base + dir->VirtualAddress + dir->Size ||
496             page > base + total_size)
497         {
498             ERR_(module)("invalid relocation %p,%lx,%ld at %p,%lx,%lx\n",
499                          rel, rel->VirtualAddress, rel->SizeOfBlock,
500                          base, dir->VirtualAddress, dir->Size );
501             return 0;
502         }
503
504         TRACE_(module)("%ld relocations for page %lx\n", rel->SizeOfBlock, rel->VirtualAddress);
505
506         /* patching in reverse order */
507         for (i = 0 ; i < count; i++)
508         {
509             int offset = TypeOffset[i] & 0xFFF;
510             int type = TypeOffset[i] >> 12;
511             switch(type)
512             {
513             case IMAGE_REL_BASED_ABSOLUTE:
514                 break;
515             case IMAGE_REL_BASED_HIGH:
516                 *(short*)(page+offset) += HIWORD(delta);
517                 break;
518             case IMAGE_REL_BASED_LOW:
519                 *(short*)(page+offset) += LOWORD(delta);
520                 break;
521             case IMAGE_REL_BASED_HIGHLOW:
522                 *(int*)(page+offset) += delta;
523                 /* FIXME: if this is an exported address, fire up enhanced logic */
524                 break;
525             default:
526                 FIXME_(module)("Unknown/unsupported fixup type %d.\n", type);
527                 break;
528             }
529         }
530     }
531     return 1;
532 }
533
534
535 /***********************************************************************
536  *           map_image
537  *
538  * Map an executable (PE format) image into memory.
539  */
540 static NTSTATUS map_image( HANDLE hmapping, int fd, char *base, DWORD total_size,
541                            DWORD header_size, int shared_fd, DWORD shared_size,
542                            BOOL removable, PVOID *addr_ptr )
543 {
544     IMAGE_DOS_HEADER *dos;
545     IMAGE_NT_HEADERS *nt;
546     IMAGE_SECTION_HEADER *sec;
547     IMAGE_DATA_DIRECTORY *imports;
548     NTSTATUS status = STATUS_INVALID_IMAGE_FORMAT;  /* generic error (FIXME) */
549     int i, pos;
550     FILE_VIEW *view;
551     char *ptr;
552
553     /* zero-map the whole range */
554
555     if (base < (char *)0x110000 ||  /* make sure the DOS area remains free */
556         (ptr = wine_anon_mmap( base, total_size,
557                                PROT_READ | PROT_WRITE | PROT_EXEC, 0 )) == (char *)-1)
558     {
559         ptr = wine_anon_mmap( NULL, total_size,
560                             PROT_READ | PROT_WRITE | PROT_EXEC, 0 );
561         if (ptr == (char *)-1)
562         {
563             ERR_(module)("Not enough memory for module (%ld bytes)\n", total_size);
564             goto error;
565         }
566     }
567     TRACE_(module)( "mapped PE file at %p-%p\n", ptr, ptr + total_size );
568
569     /* map the header */
570
571     if (VIRTUAL_mmap( fd, ptr, header_size, 0, 0, PROT_READ,
572                       MAP_PRIVATE | MAP_FIXED, &removable ) == (char *)-1) goto error;
573     dos = (IMAGE_DOS_HEADER *)ptr;
574     nt = (IMAGE_NT_HEADERS *)(ptr + dos->e_lfanew);
575     if ((char *)(nt + 1) > ptr + header_size) goto error;
576
577     sec = (IMAGE_SECTION_HEADER*)((char*)&nt->OptionalHeader+nt->FileHeader.SizeOfOptionalHeader);
578     if ((char *)(sec + nt->FileHeader.NumberOfSections) > ptr + header_size) goto error;
579
580     imports = nt->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_IMPORT;
581     if (!imports->Size || !imports->VirtualAddress) imports = NULL;
582
583     /* check the architecture */
584
585     if (nt->FileHeader.Machine != IMAGE_FILE_MACHINE_I386)
586     {
587         MESSAGE("Trying to load PE image for unsupported architecture (");
588         switch (nt->FileHeader.Machine)
589         {
590         case IMAGE_FILE_MACHINE_UNKNOWN: MESSAGE("Unknown"); break;
591         case IMAGE_FILE_MACHINE_I860:    MESSAGE("I860"); break;
592         case IMAGE_FILE_MACHINE_R3000:   MESSAGE("R3000"); break;
593         case IMAGE_FILE_MACHINE_R4000:   MESSAGE("R4000"); break;
594         case IMAGE_FILE_MACHINE_R10000:  MESSAGE("R10000"); break;
595         case IMAGE_FILE_MACHINE_ALPHA:   MESSAGE("Alpha"); break;
596         case IMAGE_FILE_MACHINE_POWERPC: MESSAGE("PowerPC"); break;
597         default: MESSAGE("Unknown-%04x", nt->FileHeader.Machine); break;
598         }
599         MESSAGE(")\n");
600         goto error;
601     }
602
603     /* map all the sections */
604
605     for (i = pos = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)
606     {
607         DWORD size;
608
609         /* a few sanity checks */
610         size = sec->VirtualAddress + ROUND_SIZE( sec->VirtualAddress, sec->Misc.VirtualSize );
611         if (sec->VirtualAddress > total_size || size > total_size || size < sec->VirtualAddress)
612         {
613             ERR_(module)( "Section %.8s too large (%lx+%lx/%lx)\n",
614                           sec->Name, sec->VirtualAddress, sec->Misc.VirtualSize, total_size );
615             goto error;
616         }
617
618         if ((sec->Characteristics & IMAGE_SCN_MEM_SHARED) &&
619             (sec->Characteristics & IMAGE_SCN_MEM_WRITE))
620         {
621             size = ROUND_SIZE( 0, sec->Misc.VirtualSize );
622             TRACE_(module)( "mapping shared section %.8s at %p off %lx (%x) size %lx (%lx) flags %lx\n",
623                           sec->Name, ptr + sec->VirtualAddress,
624                           sec->PointerToRawData, pos, sec->SizeOfRawData,
625                           size, sec->Characteristics );
626             if (VIRTUAL_mmap( shared_fd, ptr + sec->VirtualAddress, size,
627                               pos, 0, PROT_READ|PROT_WRITE|PROT_EXEC,
628                               MAP_SHARED|MAP_FIXED, NULL ) == (void *)-1)
629             {
630                 ERR_(module)( "Could not map shared section %.8s\n", sec->Name );
631                 goto error;
632             }
633
634             /* check if the import directory falls inside this section */
635             if (imports && imports->VirtualAddress >= sec->VirtualAddress &&
636                 imports->VirtualAddress < sec->VirtualAddress + size)
637             {
638                 UINT_PTR base = imports->VirtualAddress & ~page_mask;
639                 UINT_PTR end = base + ROUND_SIZE( imports->VirtualAddress, imports->Size );
640                 if (end > sec->VirtualAddress + size) end = sec->VirtualAddress + size;
641                 if (end > base) VIRTUAL_mmap( shared_fd, ptr + base, end - base,
642                                               pos, 0, PROT_READ|PROT_WRITE|PROT_EXEC,
643                                               MAP_PRIVATE|MAP_FIXED, NULL );
644             }
645             pos += size;
646             continue;
647         }
648
649         TRACE_(module)( "mapping section %.8s at %p off %lx size %lx flags %lx\n",
650                         sec->Name, ptr + sec->VirtualAddress,
651                         sec->PointerToRawData, sec->SizeOfRawData,
652                         sec->Characteristics );
653
654         if (sec->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) continue;
655         if (!sec->PointerToRawData || !sec->SizeOfRawData) continue;
656
657         /* Note: if the section is not aligned properly VIRTUAL_mmap will magically
658          *       fall back to read(), so we don't need to check anything here.
659          */
660         if (VIRTUAL_mmap( fd, ptr + sec->VirtualAddress, sec->SizeOfRawData,
661                           sec->PointerToRawData, 0, PROT_READ|PROT_WRITE|PROT_EXEC,
662                           MAP_PRIVATE | MAP_FIXED, &removable ) == (void *)-1)
663         {
664             ERR_(module)( "Could not map section %.8s, file probably truncated\n", sec->Name );
665             goto error;
666         }
667
668         if ((sec->SizeOfRawData < sec->Misc.VirtualSize) && (sec->SizeOfRawData & page_mask))
669         {
670             DWORD end = ROUND_SIZE( 0, sec->SizeOfRawData );
671             if (end > sec->Misc.VirtualSize) end = sec->Misc.VirtualSize;
672             TRACE_(module)("clearing %p - %p\n",
673                            ptr + sec->VirtualAddress + sec->SizeOfRawData,
674                            ptr + sec->VirtualAddress + end );
675             memset( ptr + sec->VirtualAddress + sec->SizeOfRawData, 0,
676                     end - sec->SizeOfRawData );
677         }
678     }
679
680
681     /* perform base relocation, if necessary */
682
683     if (ptr != base)
684     {
685         const IMAGE_DATA_DIRECTORY *relocs;
686
687         relocs = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
688         if (!relocs->VirtualAddress || !relocs->Size)
689         {
690             if (nt->OptionalHeader.ImageBase == 0x400000)
691                 ERR("Standard load address for a Win32 program (0x00400000) not available - security-patched kernel ?\n");
692             else
693                 ERR( "FATAL: Need to relocate module from addr %lx, but there are no relocation records\n",
694                      nt->OptionalHeader.ImageBase );
695             goto error;
696         }
697
698         /* FIXME: If we need to relocate a system DLL (base > 2GB) we should
699          *        really make sure that the *new* base address is also > 2GB.
700          *        Some DLLs really check the MSB of the module handle :-/
701          */
702         if ((nt->OptionalHeader.ImageBase & 0x80000000) && !((DWORD)base & 0x80000000))
703             ERR( "Forced to relocate system DLL (base > 2GB). This is not good.\n" );
704
705         if (!do_relocations( ptr, relocs, ptr - base, total_size ))
706         {
707             goto error;
708         }
709     }
710
711     if (removable) hmapping = 0;  /* don't keep handle open on removable media */
712     if (!(view = VIRTUAL_CreateView( ptr, total_size, 0, VPROT_COMMITTED|VPROT_READ, hmapping )))
713     {
714         status = STATUS_NO_MEMORY;
715         goto error;
716     }
717
718     /* set the image protections */
719
720     sec = (IMAGE_SECTION_HEADER*)((char *)&nt->OptionalHeader+nt->FileHeader.SizeOfOptionalHeader);
721     for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)
722     {
723         DWORD size = ROUND_SIZE( sec->VirtualAddress, sec->Misc.VirtualSize );
724         BYTE vprot = VPROT_COMMITTED;
725         if (sec->Characteristics & IMAGE_SCN_MEM_READ)    vprot |= VPROT_READ;
726         if (sec->Characteristics & IMAGE_SCN_MEM_WRITE)   vprot |= VPROT_WRITE|VPROT_WRITECOPY;
727         if (sec->Characteristics & IMAGE_SCN_MEM_EXECUTE) vprot |= VPROT_EXEC;
728
729         /* make sure the import directory is writable */
730         if (imports && imports->VirtualAddress >= sec->VirtualAddress &&
731             imports->VirtualAddress < sec->VirtualAddress + size)
732             vprot |= VPROT_READ|VPROT_WRITE|VPROT_WRITECOPY;
733
734         VIRTUAL_SetProt( view, ptr + sec->VirtualAddress, size, vprot );
735     }
736
737     close( fd );
738     *addr_ptr = ptr;
739     return STATUS_SUCCESS;
740
741  error:
742     if (ptr != (char *)-1) munmap( ptr, total_size );
743     close( fd );
744     return status;
745 }
746
747
748 /***********************************************************************
749  *           is_current_process
750  *
751  * Check whether a process handle is for the current process.
752  */
753 static BOOL is_current_process( HANDLE handle )
754 {
755     BOOL ret = FALSE;
756
757     if (handle == GetCurrentProcess()) return TRUE;
758     SERVER_START_REQ( get_process_info )
759     {
760         req->handle = handle;
761         if (!wine_server_call( req ))
762             ret = ((DWORD)reply->pid == GetCurrentProcessId());
763     }
764     SERVER_END_REQ;
765     return ret;
766 }
767
768
769 /***********************************************************************
770  *           VIRTUAL_Init
771  */
772 #ifndef page_mask
773 DECL_GLOBAL_CONSTRUCTOR(VIRTUAL_Init)
774 {
775     page_size = getpagesize();
776     page_mask = page_size - 1;
777     /* Make sure we have a power of 2 */
778     assert( !(page_size & page_mask) );
779     page_shift = 0;
780     while ((1 << page_shift) != page_size) page_shift++;
781 }
782 #endif  /* page_mask */
783
784
785 /***********************************************************************
786  *           VIRTUAL_SetFaultHandler
787  */
788 BOOL VIRTUAL_SetFaultHandler( LPCVOID addr, HANDLERPROC proc, LPVOID arg )
789 {
790     FILE_VIEW *view;
791
792     if (!(view = VIRTUAL_FindView( addr ))) return FALSE;
793     view->handlerProc = proc;
794     view->handlerArg  = arg;
795     return TRUE;
796 }
797
798 /***********************************************************************
799  *           VIRTUAL_HandleFault
800  */
801 DWORD VIRTUAL_HandleFault( LPCVOID addr )
802 {
803     FILE_VIEW *view = VIRTUAL_FindView( addr );
804     DWORD ret = EXCEPTION_ACCESS_VIOLATION;
805
806     if (view)
807     {
808         if (view->handlerProc)
809         {
810             if (view->handlerProc(view->handlerArg, addr)) ret = 0;  /* handled */
811         }
812         else
813         {
814             BYTE vprot = view->prot[((char *)addr - (char *)view->base) >> page_shift];
815             void *page = (void *)((UINT_PTR)addr & ~page_mask);
816             char *stack = (char *)NtCurrentTeb()->stack_base + SIGNAL_STACK_SIZE + page_mask + 1;
817             if (vprot & VPROT_GUARD)
818             {
819                 VIRTUAL_SetProt( view, page, page_mask + 1, vprot & ~VPROT_GUARD );
820                 ret = STATUS_GUARD_PAGE_VIOLATION;
821             }
822             /* is it inside the stack guard pages? */
823             if (((char *)addr >= stack) && ((char *)addr < stack + 2*(page_mask+1)))
824                 ret = STATUS_STACK_OVERFLOW;
825         }
826     }
827     return ret;
828 }
829
830
831
832 /***********************************************************************
833  *           unaligned_mmap
834  *
835  * Linux kernels before 2.4.x can support non page-aligned offsets, as
836  * long as the offset is aligned to the filesystem block size. This is
837  * a big performance gain so we want to take advantage of it.
838  *
839  * However, when we use 64-bit file support this doesn't work because
840  * glibc rejects unaligned offsets. Also glibc 2.1.3 mmap64 is broken
841  * in that it rounds unaligned offsets down to a page boundary. For
842  * these reasons we do a direct system call here.
843  */
844 static void *unaligned_mmap( void *addr, size_t length, unsigned int prot,
845                              unsigned int flags, int fd, unsigned int offset_low,
846                              unsigned int offset_high )
847 {
848 #if defined(linux) && defined(__i386__) && defined(__GNUC__)
849     if (!offset_high && (offset_low & page_mask))
850     {
851         int ret;
852
853         struct
854         {
855             void        *addr;
856             unsigned int length;
857             unsigned int prot;
858             unsigned int flags;
859             unsigned int fd;
860             unsigned int offset;
861         } args;
862
863         args.addr   = addr;
864         args.length = length;
865         args.prot   = prot;
866         args.flags  = flags;
867         args.fd     = fd;
868         args.offset = offset_low;
869
870         __asm__ __volatile__("push %%ebx\n\t"
871                              "movl %2,%%ebx\n\t"
872                              "int $0x80\n\t"
873                              "popl %%ebx"
874                              : "=a" (ret)
875                              : "0" (90), /* SYS_mmap */
876                                "g" (&args) );
877         if (ret < 0 && ret > -4096)
878         {
879             errno = -ret;
880             ret = -1;
881         }
882         return (void *)ret;
883     }
884 #endif
885     return mmap( addr, length, prot, flags, fd, ((off_t)offset_high << 32) | offset_low );
886 }
887
888
889 /***********************************************************************
890  *           VIRTUAL_mmap
891  *
892  * Wrapper for mmap() that handles anonymous mappings portably,
893  * and falls back to read if mmap of a file fails.
894  */
895 static LPVOID VIRTUAL_mmap( int fd, LPVOID start, DWORD size,
896                             DWORD offset_low, DWORD offset_high,
897                             int prot, int flags, BOOL *removable )
898 {
899     int pos;
900     LPVOID ret;
901     off_t offset;
902     BOOL is_shared_write = FALSE;
903
904     if (fd == -1) return wine_anon_mmap( start, size, prot, flags );
905
906     if (prot & PROT_WRITE)
907     {
908 #ifdef MAP_SHARED
909         if (flags & MAP_SHARED) is_shared_write = TRUE;
910 #endif
911 #ifdef MAP_PRIVATE
912         if (!(flags & MAP_PRIVATE)) is_shared_write = TRUE;
913 #endif
914     }
915
916     if (removable && *removable)
917     {
918         /* if on removable media, try using read instead of mmap */
919         if (!is_shared_write) goto fake_mmap;
920         *removable = FALSE;
921     }
922
923     if ((ret = unaligned_mmap( start, size, prot, flags, fd,
924                                offset_low, offset_high )) != (LPVOID)-1) return ret;
925
926     /* mmap() failed; if this is because the file offset is not    */
927     /* page-aligned (EINVAL), or because the underlying filesystem */
928     /* does not support mmap() (ENOEXEC,ENODEV), we do it by hand. */
929
930     if ((errno != ENOEXEC) && (errno != EINVAL) && (errno != ENODEV)) return ret;
931     if (is_shared_write) return ret;  /* we cannot fake shared write mappings */
932
933  fake_mmap:
934     /* Reserve the memory with an anonymous mmap */
935     ret = wine_anon_mmap( start, size, PROT_READ | PROT_WRITE, flags );
936     if (ret == (LPVOID)-1) return ret;
937     /* Now read in the file */
938     offset = ((off_t)offset_high << 32) | offset_low;
939     if ((pos = lseek( fd, offset, SEEK_SET )) == -1)
940     {
941         munmap( ret, size );
942         return (LPVOID)-1;
943     }
944     read( fd, ret, size );
945     lseek( fd, pos, SEEK_SET );  /* Restore the file pointer */
946     mprotect( ret, size, prot );  /* Set the right protection */
947     return ret;
948 }
949
950
951 /***********************************************************************
952  *             NtAllocateVirtualMemory   (NTDLL.@)
953  *             ZwAllocateVirtualMemory   (NTDLL.@)
954  */
955 NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, PVOID addr,
956                                          ULONG *size_ptr, ULONG type, ULONG protect )
957 {
958     FILE_VIEW *view;
959     void *base;
960     BYTE vprot;
961     DWORD size = *size_ptr;
962
963     if (!is_current_process( process ))
964     {
965         ERR("Unsupported on other process\n");
966         return STATUS_ACCESS_DENIED;
967     }
968
969     TRACE("%p %08lx %lx %08lx\n", addr, size, type, protect );
970
971     /* Round parameters to a page boundary */
972
973     if (size > 0x7fc00000) return STATUS_WORKING_SET_LIMIT_RANGE; /* 2Gb - 4Mb */
974
975     if (addr)
976     {
977         if (type & MEM_RESERVE) /* Round down to 64k boundary */
978             base = ROUND_ADDR( addr, granularity_mask );
979         else
980             base = ROUND_ADDR( addr, page_mask );
981         size = (((UINT_PTR)addr + size + page_mask) & ~page_mask) - (UINT_PTR)base;
982
983         /* disallow low 64k, wrap-around and kernel space */
984         if (((char *)base <= (char *)granularity_mask) ||
985             ((char *)base + size < (char *)base) ||
986             (ADDRESS_SPACE_LIMIT && ((char *)base + size > (char *)ADDRESS_SPACE_LIMIT)))
987             return STATUS_INVALID_PARAMETER;
988     }
989     else
990     {
991         base = NULL;
992         size = (size + page_mask) & ~page_mask;
993     }
994
995     if (type & MEM_TOP_DOWN) {
996         /* FIXME: MEM_TOP_DOWN allocates the largest possible address.
997          *        Is there _ANY_ way to do it with UNIX mmap()?
998          */
999         WARN("MEM_TOP_DOWN ignored\n");
1000         type &= ~MEM_TOP_DOWN;
1001     }
1002
1003     /* Compute the alloc type flags */
1004
1005     if (!(type & (MEM_COMMIT | MEM_RESERVE | MEM_SYSTEM)) ||
1006         (type & ~(MEM_COMMIT | MEM_RESERVE | MEM_SYSTEM)))
1007     {
1008         ERR("called with wrong alloc type flags (%08lx) !\n", type);
1009         return STATUS_INVALID_PARAMETER;
1010     }
1011     if (type & (MEM_COMMIT | MEM_SYSTEM))
1012         vprot = VIRTUAL_GetProt( protect ) | VPROT_COMMITTED;
1013     else vprot = 0;
1014
1015     /* Reserve the memory */
1016
1017     if ((type & MEM_RESERVE) || !base)
1018     {
1019         if (type & MEM_SYSTEM)
1020         {
1021             if (!(view = VIRTUAL_CreateView( base, size, VFLAG_VALLOC | VFLAG_SYSTEM, vprot, 0 )))
1022                 return STATUS_NO_MEMORY;
1023         }
1024         else
1025         {
1026             NTSTATUS res = anon_mmap_aligned( &base, size, VIRTUAL_GetUnixProt( vprot ), 0 );
1027             if (res) return res;
1028
1029             if (!(view = VIRTUAL_CreateView( base, size, VFLAG_VALLOC, vprot, 0 )))
1030             {
1031                 munmap( base, size );
1032                 return STATUS_NO_MEMORY;
1033             }
1034         }
1035     }
1036     else
1037     {
1038         /* Commit the pages */
1039
1040         if (!(view = VIRTUAL_FindView( base )) ||
1041             ((char *)base + size > (char *)view->base + view->size)) return STATUS_NOT_MAPPED_VIEW;
1042
1043         if (!VIRTUAL_SetProt( view, base, size, vprot )) return STATUS_ACCESS_DENIED;
1044     }
1045
1046     *ret = base;
1047     *size_ptr = size;
1048     return STATUS_SUCCESS;
1049 }
1050
1051
1052 /***********************************************************************
1053  *             NtFreeVirtualMemory   (NTDLL.@)
1054  *             ZwFreeVirtualMemory   (NTDLL.@)
1055  */
1056 NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, ULONG *size_ptr, ULONG type )
1057 {
1058     FILE_VIEW *view;
1059     char *base;
1060     LPVOID addr = *addr_ptr;
1061     DWORD size = *size_ptr;
1062
1063     if (!is_current_process( process ))
1064     {
1065         ERR("Unsupported on other process\n");
1066         return STATUS_ACCESS_DENIED;
1067     }
1068
1069     TRACE("%p %08lx %lx\n", addr, size, type );
1070
1071     /* Fix the parameters */
1072
1073     size = ROUND_SIZE( addr, size );
1074     base = ROUND_ADDR( addr, page_mask );
1075
1076     if (!(view = VIRTUAL_FindView( base )) ||
1077         (base + size > (char *)view->base + view->size) ||
1078         !(view->flags & VFLAG_VALLOC))
1079         return STATUS_INVALID_PARAMETER;
1080
1081     /* Check the type */
1082
1083     if (type & MEM_SYSTEM)
1084     {
1085         view->flags |= VFLAG_SYSTEM;
1086         type &= ~MEM_SYSTEM;
1087     }
1088
1089     if ((type != MEM_DECOMMIT) && (type != MEM_RELEASE))
1090     {
1091         ERR("called with wrong free type flags (%08lx) !\n", type);
1092         return STATUS_INVALID_PARAMETER;
1093     }
1094
1095     /* Free the pages */
1096
1097     if (type == MEM_RELEASE)
1098     {
1099         if (size || (base != view->base)) return STATUS_INVALID_PARAMETER;
1100         VIRTUAL_DeleteView( view );
1101     }
1102     else
1103     {
1104         /* Decommit the pages by remapping zero-pages instead */
1105
1106         if (wine_anon_mmap( (LPVOID)base, size, VIRTUAL_GetUnixProt(0), MAP_FIXED ) != (LPVOID)base)
1107             ERR( "Could not remap pages, expect trouble\n" );
1108         if (!VIRTUAL_SetProt( view, base, size, 0 )) return STATUS_ACCESS_DENIED;  /* FIXME */
1109     }
1110
1111     *addr_ptr = base;
1112     *size_ptr = size;
1113     return STATUS_SUCCESS;
1114 }
1115
1116
1117 /***********************************************************************
1118  *             NtProtectVirtualMemory   (NTDLL.@)
1119  *             ZwProtectVirtualMemory   (NTDLL.@)
1120  */
1121 NTSTATUS WINAPI NtProtectVirtualMemory( HANDLE process, PVOID *addr_ptr, ULONG *size_ptr,
1122                                         ULONG new_prot, ULONG *old_prot )
1123 {
1124     FILE_VIEW *view;
1125     char *base;
1126     UINT i;
1127     BYTE vprot, *p;
1128     DWORD prot, size = *size_ptr;
1129     LPVOID addr = *addr_ptr;
1130
1131     if (!is_current_process( process ))
1132     {
1133         ERR("Unsupported on other process\n");
1134         return STATUS_ACCESS_DENIED;
1135     }
1136
1137     TRACE("%p %08lx %08lx\n", addr, size, new_prot );
1138
1139     /* Fix the parameters */
1140
1141     size = ROUND_SIZE( addr, size );
1142     base = ROUND_ADDR( addr, page_mask );
1143
1144     if (!(view = VIRTUAL_FindView( base )) ||
1145         (base + size > (char *)view->base + view->size))
1146         return STATUS_INVALID_PARAMETER;
1147
1148     /* Make sure all the pages are committed */
1149
1150     p = view->prot + ((base - (char *)view->base) >> page_shift);
1151     VIRTUAL_GetWin32Prot( *p, &prot, NULL );
1152     for (i = size >> page_shift; i; i--, p++)
1153     {
1154         if (!(*p & VPROT_COMMITTED)) return STATUS_INVALID_PARAMETER;
1155     }
1156
1157     if (old_prot) *old_prot = prot;
1158     vprot = VIRTUAL_GetProt( new_prot ) | VPROT_COMMITTED;
1159     if (!VIRTUAL_SetProt( view, base, size, vprot )) return STATUS_ACCESS_DENIED;
1160
1161     *addr_ptr = base;
1162     *size_ptr = size;
1163     return STATUS_SUCCESS;
1164 }
1165
1166
1167 /***********************************************************************
1168  *             NtQueryVirtualMemory   (NTDLL.@)
1169  *             ZwQueryVirtualMemory   (NTDLL.@)
1170  */
1171 NTSTATUS WINAPI NtQueryVirtualMemory( HANDLE process, LPCVOID addr,
1172                                       MEMORY_INFORMATION_CLASS info_class, PVOID buffer,
1173                                       ULONG len, ULONG *res_len )
1174 {
1175     FILE_VIEW *view;
1176     char *base, *alloc_base = 0;
1177     UINT size = 0;
1178     MEMORY_BASIC_INFORMATION *info = buffer;
1179
1180     if (info_class != MemoryBasicInformation) return STATUS_INVALID_INFO_CLASS;
1181     if (ADDRESS_SPACE_LIMIT && addr >= ADDRESS_SPACE_LIMIT)
1182         return STATUS_WORKING_SET_LIMIT_RANGE;  /* FIXME */
1183
1184     if (!is_current_process( process ))
1185     {
1186         ERR("Unsupported on other process\n");
1187         return STATUS_ACCESS_DENIED;
1188     }
1189
1190     base = ROUND_ADDR( addr, page_mask );
1191
1192     /* Find the view containing the address */
1193
1194     RtlEnterCriticalSection(&csVirtual);
1195     view = VIRTUAL_FirstView;
1196     for (;;)
1197     {
1198         if (!view)
1199         {
1200             size = (char *)ADDRESS_SPACE_LIMIT - alloc_base;
1201             break;
1202         }
1203         if ((char *)view->base > base)
1204         {
1205             size = (char *)view->base - alloc_base;
1206             view = NULL;
1207             break;
1208         }
1209         if ((char *)view->base + view->size > base)
1210         {
1211             alloc_base = view->base;
1212             size = view->size;
1213             break;
1214         }
1215         alloc_base = (char *)view->base + view->size;
1216         view = view->next;
1217     }
1218     RtlLeaveCriticalSection(&csVirtual);
1219
1220     /* Fill the info structure */
1221
1222     if (!view)
1223     {
1224         info->State             = MEM_FREE;
1225         info->Protect           = 0;
1226         info->AllocationProtect = 0;
1227         info->Type              = 0;
1228     }
1229     else
1230     {
1231         BYTE vprot = view->prot[(base - alloc_base) >> page_shift];
1232         VIRTUAL_GetWin32Prot( vprot, &info->Protect, &info->State );
1233         for (size = base - alloc_base; size < view->size; size += page_mask+1)
1234             if (view->prot[size >> page_shift] != vprot) break;
1235         info->AllocationProtect = view->protect;
1236         info->Type              = MEM_PRIVATE;  /* FIXME */
1237     }
1238
1239     info->BaseAddress    = (LPVOID)base;
1240     info->AllocationBase = (LPVOID)alloc_base;
1241     info->RegionSize     = size - (base - alloc_base);
1242     *res_len = sizeof(*info);
1243     return STATUS_SUCCESS;
1244 }
1245
1246
1247 /***********************************************************************
1248  *             NtLockVirtualMemory   (NTDLL.@)
1249  *             ZwLockVirtualMemory   (NTDLL.@)
1250  */
1251 NTSTATUS WINAPI NtLockVirtualMemory( HANDLE process, PVOID *addr, ULONG *size, ULONG unknown )
1252 {
1253     if (!is_current_process( process ))
1254     {
1255         ERR("Unsupported on other process\n");
1256         return STATUS_ACCESS_DENIED;
1257     }
1258     return STATUS_SUCCESS;
1259 }
1260
1261
1262 /***********************************************************************
1263  *             NtUnlockVirtualMemory   (NTDLL.@)
1264  *             ZwUnlockVirtualMemory   (NTDLL.@)
1265  */
1266 NTSTATUS WINAPI NtUnlockVirtualMemory( HANDLE process, PVOID *addr, ULONG *size, ULONG unknown )
1267 {
1268     if (!is_current_process( process ))
1269     {
1270         ERR("Unsupported on other process\n");
1271         return STATUS_ACCESS_DENIED;
1272     }
1273     return STATUS_SUCCESS;
1274 }
1275
1276
1277 /***********************************************************************
1278  *             NtCreateSection   (NTDLL.@)
1279  *             ZwCreateSection   (NTDLL.@)
1280  */
1281 NTSTATUS WINAPI NtCreateSection( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
1282                                  const LARGE_INTEGER *size, ULONG protect,
1283                                  ULONG sec_flags, HANDLE file )
1284 {
1285     NTSTATUS ret;
1286     BYTE vprot;
1287     DWORD len = attr->ObjectName ? attr->ObjectName->Length : 0;
1288
1289     /* Check parameters */
1290
1291     if (len > MAX_PATH*sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
1292
1293     vprot = VIRTUAL_GetProt( protect );
1294     if (sec_flags & SEC_RESERVE)
1295     {
1296         if (file) return STATUS_INVALID_PARAMETER;
1297     }
1298     else vprot |= VPROT_COMMITTED;
1299     if (sec_flags & SEC_NOCACHE) vprot |= VPROT_NOCACHE;
1300     if (sec_flags & SEC_IMAGE) vprot |= VPROT_IMAGE;
1301
1302     /* Create the server object */
1303
1304     SERVER_START_REQ( create_mapping )
1305     {
1306         req->file_handle = file;
1307         req->size_high   = size ? size->s.HighPart : 0;
1308         req->size_low    = size ? size->s.LowPart : 0;
1309         req->protect     = vprot;
1310         req->access      = access;
1311         req->inherit     = (attr->Attributes & OBJ_INHERIT) != 0;
1312         if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
1313         ret = wine_server_call( req );
1314         *handle = reply->handle;
1315     }
1316     SERVER_END_REQ;
1317     return ret;
1318 }
1319
1320
1321 /***********************************************************************
1322  *             NtOpenSection   (NTDLL.@)
1323  *             ZwOpenSection   (NTDLL.@)
1324  */
1325 NTSTATUS WINAPI NtOpenSection( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
1326 {
1327     NTSTATUS ret;
1328     DWORD len = attr->ObjectName->Length;
1329
1330     if (len > MAX_PATH*sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
1331
1332     SERVER_START_REQ( open_mapping )
1333     {
1334         req->access  = access;
1335         req->inherit = (attr->Attributes & OBJ_INHERIT) != 0;
1336         wine_server_add_data( req, attr->ObjectName->Buffer, len );
1337         if (!(ret = wine_server_call( req ))) *handle = reply->handle;
1338     }
1339     SERVER_END_REQ;
1340     return ret;
1341 }
1342
1343
1344 /***********************************************************************
1345  *             NtMapViewOfSection   (NTDLL.@)
1346  *             ZwMapViewOfSection   (NTDLL.@)
1347  */
1348 NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_ptr, ULONG zero_bits,
1349                                     ULONG commit_size, const LARGE_INTEGER *offset, ULONG *size_ptr,
1350                                     SECTION_INHERIT inherit, ULONG alloc_type, ULONG protect )
1351 {
1352     FILE_VIEW *view;
1353     NTSTATUS res;
1354     UINT size = 0;
1355     int flags = MAP_PRIVATE;
1356     int unix_handle = -1;
1357     int prot;
1358     void *base, *ptr = (void *)-1, *ret;
1359     DWORD size_low, size_high, header_size, shared_size;
1360     HANDLE shared_file;
1361     BOOL removable;
1362
1363     if (!is_current_process( process ))
1364     {
1365         ERR("Unsupported on other process\n");
1366         return STATUS_ACCESS_DENIED;
1367     }
1368
1369     TRACE("handle=%p addr=%p off=%lx%08lx size=%x access=%lx\n",
1370           handle, *addr_ptr, offset->s.HighPart, offset->s.LowPart, size, protect );
1371
1372     /* Check parameters */
1373
1374     if ((offset->s.LowPart & granularity_mask) ||
1375         (*addr_ptr && ((UINT_PTR)*addr_ptr & granularity_mask)))
1376         return STATUS_INVALID_PARAMETER;
1377
1378     SERVER_START_REQ( get_mapping_info )
1379     {
1380         req->handle = handle;
1381         res = wine_server_call( req );
1382         prot        = reply->protect;
1383         base        = reply->base;
1384         size_low    = reply->size_low;
1385         size_high   = reply->size_high;
1386         header_size = reply->header_size;
1387         shared_file = reply->shared_file;
1388         shared_size = reply->shared_size;
1389         removable   = (reply->drive_type == DRIVE_REMOVABLE ||
1390                        reply->drive_type == DRIVE_CDROM);
1391     }
1392     SERVER_END_REQ;
1393     if (res) goto error;
1394
1395     if ((res = wine_server_handle_to_fd( handle, 0, &unix_handle, NULL, NULL ))) goto error;
1396
1397     if (prot & VPROT_IMAGE)
1398     {
1399         int shared_fd = -1;
1400
1401         if (shared_file)
1402         {
1403             if ((res = wine_server_handle_to_fd( shared_file, GENERIC_READ, &shared_fd,
1404                                                  NULL, NULL ))) goto error;
1405             NtClose( shared_file );  /* we no longer need it */
1406         }
1407         res = map_image( handle, unix_handle, base, size_low, header_size,
1408                          shared_fd, shared_size, removable, addr_ptr );
1409         if (shared_fd != -1) close( shared_fd );
1410         if (!res) *size_ptr = size_low;
1411         return res;
1412     }
1413
1414
1415     if (size_high)
1416         ERR("Sizes larger than 4Gb not supported\n");
1417
1418     if ((offset->s.LowPart >= size_low) ||
1419         (*size_ptr > size_low - offset->s.LowPart))
1420     {
1421         res = STATUS_INVALID_PARAMETER;
1422         goto error;
1423     }
1424     if (*size_ptr) size = ROUND_SIZE( offset->s.LowPart, *size_ptr );
1425     else size = size_low - offset->s.LowPart;
1426
1427     switch(protect)
1428     {
1429     case PAGE_NOACCESS:
1430         break;
1431     case PAGE_READWRITE:
1432     case PAGE_EXECUTE_READWRITE:
1433         if (!(prot & VPROT_WRITE))
1434         {
1435             res = STATUS_INVALID_PARAMETER;
1436             goto error;
1437         }
1438         flags = MAP_SHARED;
1439         /* fall through */
1440     case PAGE_READONLY:
1441     case PAGE_WRITECOPY:
1442     case PAGE_EXECUTE:
1443     case PAGE_EXECUTE_READ:
1444     case PAGE_EXECUTE_WRITECOPY:
1445         if (prot & VPROT_READ) break;
1446         /* fall through */
1447     default:
1448         res = STATUS_INVALID_PARAMETER;
1449         goto error;
1450     }
1451
1452     /* FIXME: If a mapping is created with SEC_RESERVE and a process,
1453      * which has a view of this mapping commits some pages, they will
1454      * appear commited in all other processes, which have the same
1455      * view created. Since we don`t support this yet, we create the
1456      * whole mapping commited.
1457      */
1458     prot |= VPROT_COMMITTED;
1459
1460     /* Reserve a properly aligned area */
1461
1462     if ((res = anon_mmap_aligned( addr_ptr, size, PROT_NONE, 0 ))) goto error;
1463     ptr = *addr_ptr;
1464
1465     /* Map the file */
1466
1467     TRACE("handle=%p size=%x offset=%lx\n", handle, size, offset->s.LowPart );
1468
1469     ret = VIRTUAL_mmap( unix_handle, ptr, size, offset->s.LowPart, offset->s.HighPart,
1470                         VIRTUAL_GetUnixProt( prot ), flags | MAP_FIXED, &removable );
1471     if (ret != ptr)
1472     {
1473         ERR( "VIRTUAL_mmap %p %x %lx%08lx failed\n",
1474              ptr, size, offset->s.HighPart, offset->s.LowPart );
1475         res = STATUS_NO_MEMORY;  /* FIXME */
1476         goto error;
1477     }
1478     if (removable) handle = 0;  /* don't keep handle open on removable media */
1479
1480     if (!(view = VIRTUAL_CreateView( ptr, size, 0, prot, handle )))
1481     {
1482         res = STATUS_NO_MEMORY;
1483         goto error;
1484     }
1485     if (unix_handle != -1) close( unix_handle );
1486     *size_ptr = size;
1487     return STATUS_SUCCESS;
1488
1489 error:
1490     if (unix_handle != -1) close( unix_handle );
1491     if (ptr != (void *)-1) munmap( ptr, size );
1492     return res;
1493 }
1494
1495
1496 /***********************************************************************
1497  *             NtUnmapViewOfSection   (NTDLL.@)
1498  *             ZwUnmapViewOfSection   (NTDLL.@)
1499  */
1500 NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr )
1501 {
1502     FILE_VIEW *view;
1503     void *base = ROUND_ADDR( addr, page_mask );
1504
1505     if (!is_current_process( process ))
1506     {
1507         ERR("Unsupported on other process\n");
1508         return STATUS_ACCESS_DENIED;
1509     }
1510     if (!(view = VIRTUAL_FindView( base )) || (base != view->base)) return STATUS_INVALID_PARAMETER;
1511     VIRTUAL_DeleteView( view );
1512     return STATUS_SUCCESS;
1513 }
1514
1515
1516 /***********************************************************************
1517  *             NtFlushVirtualMemory   (NTDLL.@)
1518  *             ZwFlushVirtualMemory   (NTDLL.@)
1519  */
1520 NTSTATUS WINAPI NtFlushVirtualMemory( HANDLE process, LPCVOID *addr_ptr,
1521                                       ULONG *size_ptr, ULONG unknown )
1522 {
1523     FILE_VIEW *view;
1524     void *addr = ROUND_ADDR( *addr_ptr, page_mask );
1525
1526     if (!is_current_process( process ))
1527     {
1528         ERR("Unsupported on other process\n");
1529         return STATUS_ACCESS_DENIED;
1530     }
1531     if (!(view = VIRTUAL_FindView( addr ))) return STATUS_INVALID_PARAMETER;
1532     if (!*size_ptr) *size_ptr = view->size;
1533     *addr_ptr = addr;
1534     if (!msync( addr, *size_ptr, MS_SYNC )) return STATUS_SUCCESS;
1535     return STATUS_NOT_MAPPED_DATA;
1536 }