Release 980118
[wine] / memory / virtual.c
1 /*
2  * Win32 virtual memory functions
3  *
4  * Copyright 1997 Alexandre Julliard
5  */
6
7 #include <assert.h>
8 #include <fcntl.h>
9 #include <stdio.h>
10 #include <unistd.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <sys/types.h>
14 #include <sys/mman.h>
15 #include "winbase.h"
16 #include "winerror.h"
17 #include "file.h"
18 #include "heap.h"
19 #include "process.h"
20 #include "xmalloc.h"
21 #include "stddebug.h"
22 #include "debug.h"
23
24 #ifndef MS_SYNC
25 #define MS_SYNC 0
26 #endif
27
28 /* File mapping */
29 typedef struct
30 {
31     K32OBJ        header;
32     DWORD         size_high;
33     DWORD         size_low;
34     FILE_OBJECT  *file;
35     BYTE          protect;
36 } FILE_MAPPING;
37
38 /* File view */
39 typedef struct _FV
40 {
41     struct _FV   *next;     /* Next view */
42     struct _FV   *prev;     /* Prev view */
43     UINT32        base;     /* Base address */
44     UINT32        size;     /* Size in bytes */
45     UINT32        flags;    /* Allocation flags */
46     UINT32        offset;   /* Offset from start of mapped file */
47     FILE_MAPPING *mapping;  /* File mapping */
48     BYTE          protect;  /* Protection for all pages at allocation time */
49     BYTE          prot[1];  /* Protection byte for each page */
50 } FILE_VIEW;
51
52 /* Per-page protection byte values */
53 #define VPROT_READ       0x01
54 #define VPROT_WRITE      0x02
55 #define VPROT_EXEC       0x04
56 #define VPROT_WRITECOPY  0x08
57 #define VPROT_GUARD      0x10
58 #define VPROT_NOCACHE    0x20
59 #define VPROT_COMMITTED  0x40
60
61 /* Per-view flags */
62 #define VFLAG_SYSTEM     0x01
63
64 /* Conversion from VPROT_* to Win32 flags */
65 static const BYTE VIRTUAL_Win32Flags[16] =
66 {
67     PAGE_NOACCESS,              /* 0 */
68     PAGE_READONLY,              /* READ */
69     PAGE_READWRITE,             /* WRITE */
70     PAGE_READWRITE,             /* READ | WRITE */
71     PAGE_EXECUTE,               /* EXEC */
72     PAGE_EXECUTE_READ,          /* READ | EXEC */
73     PAGE_EXECUTE_READWRITE,     /* WRITE | EXEC */
74     PAGE_EXECUTE_READWRITE,     /* READ | WRITE | EXEC */
75     PAGE_WRITECOPY,             /* WRITECOPY */
76     PAGE_WRITECOPY,             /* READ | WRITECOPY */
77     PAGE_WRITECOPY,             /* WRITE | WRITECOPY */
78     PAGE_WRITECOPY,             /* READ | WRITE | WRITECOPY */
79     PAGE_EXECUTE_WRITECOPY,     /* EXEC | WRITECOPY */
80     PAGE_EXECUTE_WRITECOPY,     /* READ | EXEC | WRITECOPY */
81     PAGE_EXECUTE_WRITECOPY,     /* WRITE | EXEC | WRITECOPY */
82     PAGE_EXECUTE_WRITECOPY      /* READ | WRITE | EXEC | WRITECOPY */
83 };
84
85
86 static FILE_VIEW *VIRTUAL_FirstView;
87
88 static UINT32 page_shift;
89 static UINT32 page_mask;
90 static UINT32 granularity_mask;  /* Allocation granularity (usually 64k) */
91
92 #define ROUND_ADDR(addr) \
93    ((UINT32)(addr) & ~page_mask)
94
95 #define ROUND_SIZE(addr,size) \
96    (((UINT32)(size) + ((UINT32)(addr) & page_mask) + page_mask) & ~page_mask)
97
98 static void VIRTUAL_DestroyMapping( K32OBJ *obj );
99
100 const K32OBJ_OPS MEM_MAPPED_FILE_Ops =
101 {
102     /* Object cannot be waited upon, so we don't need these (except destroy) */
103     NULL,                      /* signaled */
104     NULL,                      /* satisfied */
105     NULL,                      /* add_wait */
106     NULL,                      /* remove_wait */
107     VIRTUAL_DestroyMapping     /* destroy */
108 };
109
110 /***********************************************************************
111  *           VIRTUAL_GetProtStr
112  */
113 static const char *VIRTUAL_GetProtStr( BYTE prot )
114 {
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' : '-';
122     buffer[5] = 0;
123     return buffer;
124 }
125
126
127 /***********************************************************************
128  *           VIRTUAL_DumpView
129  */
130 static void VIRTUAL_DumpView( FILE_VIEW *view )
131 {
132     UINT32 i, count;
133     UINT32 addr = view->base;
134     BYTE prot = view->prot[0];
135
136     dprintf_virtual( stddeb, "View: %08x - %08x%s",
137              view->base, view->base + view->size - 1,
138              (view->flags & VFLAG_SYSTEM) ? " (system)" : "" );
139     if (view->mapping && view->mapping->file)
140         dprintf_virtual( stddeb, " %s @ %08x\n",
141                  view->mapping->file->unix_name, view->offset );
142     else
143         dprintf_virtual( stddeb, " (anonymous)\n");
144
145     for (count = i = 1; i < view->size >> page_shift; i++, count++)
146     {
147         if (view->prot[i] == prot) continue;
148         dprintf_virtual( stddeb, "      %08x - %08x %s\n",
149                  addr, addr + (count << page_shift) - 1,
150                  VIRTUAL_GetProtStr(prot) );
151         addr += (count << page_shift);
152         prot = view->prot[i];
153         count = 0;
154     }
155     if (count)
156         dprintf_virtual( stddeb, "      %08x - %08x %s\n",
157                  addr, addr + (count << page_shift) - 1,
158                  VIRTUAL_GetProtStr(prot) );
159 }
160
161
162 /***********************************************************************
163  *           VIRTUAL_Dump
164  */
165 void VIRTUAL_Dump(void)
166 {
167     FILE_VIEW *view = VIRTUAL_FirstView;
168     dprintf_virtual( stddeb, "\nDump of all virtual memory views:\n\n" );
169     while (view)
170     {
171         VIRTUAL_DumpView( view );
172         view = view->next;
173     }
174 }
175
176
177 /***********************************************************************
178  *           VIRTUAL_FindView
179  *
180  * Find the view containing a given address.
181  */
182 static FILE_VIEW *VIRTUAL_FindView( UINT32 addr )
183 {
184     FILE_VIEW *view = VIRTUAL_FirstView;
185     while (view)
186     {
187         if (view->base > addr) return NULL;
188         if (view->base + view->size > addr) return view;
189         view = view->next;
190     }
191     return NULL;
192 }
193
194
195 /***********************************************************************
196  *           VIRTUAL_CreateView
197  *
198  * Create a new view and add it in the linked list.
199  */
200 static FILE_VIEW *VIRTUAL_CreateView( UINT32 base, UINT32 size, UINT32 offset,
201                                       UINT32 flags, BYTE vprot,
202                                       FILE_MAPPING *mapping )
203 {
204     FILE_VIEW *view, *prev;
205
206     /* Create the view structure */
207
208     assert( !(base & page_mask) );
209     assert( !(size & page_mask) );
210     size >>= page_shift;
211     if (!(view = (FILE_VIEW *)malloc( sizeof(*view) + size - 1 ))) return NULL;
212     view->base    = base;
213     view->size    = size << page_shift;
214     view->flags   = flags;
215     view->offset  = offset;
216     view->mapping = mapping;
217     view->protect = vprot;
218     memset( view->prot, vprot, size );
219
220     /* Insert it in the linked list */
221
222     if (!VIRTUAL_FirstView || (VIRTUAL_FirstView->base > base))
223     {
224         view->next = VIRTUAL_FirstView;
225         view->prev = NULL;
226         if (view->next) view->next->prev = view;
227         VIRTUAL_FirstView = view;
228     }
229     else
230     {
231         prev = VIRTUAL_FirstView;
232         while (prev->next && (prev->next->base < base)) prev = prev->next;
233         view->next = prev->next;
234         view->prev = prev;
235         if (view->next) view->next->prev = view;
236         prev->next  = view;
237     }
238     if (debugging_virtual) VIRTUAL_DumpView( view );
239     return view;
240 }
241
242
243 /***********************************************************************
244  *           VIRTUAL_DeleteView
245  *
246  * Delete an view.
247  */
248 static void VIRTUAL_DeleteView( FILE_VIEW *view )
249 {
250     FILE_munmap( (void *)view->base, 0, view->size );
251     if (view->next) view->next->prev = view->prev;
252     if (view->prev) view->prev->next = view->next;
253     else VIRTUAL_FirstView = view->next;
254     if (view->mapping) K32OBJ_DecCount( &view->mapping->header );
255     free( view );
256 }
257
258
259 /***********************************************************************
260  *           VIRTUAL_GetUnixProt
261  *
262  * Convert page protections to protection for mmap/mprotect.
263  */
264 static int VIRTUAL_GetUnixProt( BYTE vprot )
265 {
266     int prot = 0;
267     if ((vprot & VPROT_COMMITTED) && !(vprot & VPROT_GUARD))
268     {
269         if (vprot & VPROT_READ) prot |= PROT_READ;
270         if (vprot & VPROT_WRITE) prot |= PROT_WRITE;
271         if (vprot & VPROT_EXEC) prot |= PROT_EXEC;
272     }
273     return prot;
274 }
275
276
277 /***********************************************************************
278  *           VIRTUAL_GetWin32Prot
279  *
280  * Convert page protections to Win32 flags.
281  */
282 static void VIRTUAL_GetWin32Prot( BYTE vprot, DWORD *protect, DWORD *state )
283 {
284     *protect = VIRTUAL_Win32Flags[vprot & 0x0f];
285     if (vprot & VPROT_GUARD) *protect |= PAGE_GUARD;
286     if (vprot & VPROT_NOCACHE) *protect |= PAGE_NOCACHE;
287
288     if (state) *state = (vprot & VPROT_COMMITTED) ? MEM_COMMIT : MEM_RESERVE;
289 }
290
291
292 /***********************************************************************
293  *           VIRTUAL_GetProt
294  *
295  * Build page protections from Win32 flags.
296  */
297 static BYTE VIRTUAL_GetProt( DWORD protect )
298 {
299     BYTE vprot;
300
301     switch(protect & 0xff)
302     {
303     case PAGE_READONLY:
304         vprot = VPROT_READ;
305         break;
306     case PAGE_READWRITE:
307         vprot = VPROT_READ | VPROT_WRITE;
308         break;
309     case PAGE_WRITECOPY:
310         vprot = VPROT_READ | VPROT_WRITE | VPROT_WRITECOPY;
311         break;
312     case PAGE_EXECUTE:
313         vprot = VPROT_EXEC;
314         break;
315     case PAGE_EXECUTE_READ:
316         vprot = VPROT_EXEC | VPROT_READ;
317         break;
318     case PAGE_EXECUTE_READWRITE:
319         vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITE | VPROT_WRITECOPY;
320         break;
321     case PAGE_EXECUTE_WRITECOPY:
322         vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITE;
323         break;
324     case PAGE_NOACCESS:
325     default:
326         vprot = 0;
327         break;
328     }
329     if (protect & PAGE_GUARD) vprot |= VPROT_GUARD;
330     if (protect & PAGE_NOCACHE) vprot |= VPROT_NOCACHE;
331     return vprot;
332 }
333
334
335 /***********************************************************************
336  *           VIRTUAL_SetProt
337  *
338  * Change the protection of a range of pages.
339  */
340 static BOOL32 VIRTUAL_SetProt( FILE_VIEW *view, UINT32 base,
341                                UINT32 size, BYTE vprot )
342 {
343     dprintf_virtual( stddeb, "VIRTUAL_SetProt: %08x-%08x %s\n",
344                      base, base + size - 1, VIRTUAL_GetProtStr( vprot ) );
345
346     if (mprotect( (void *)base, size, VIRTUAL_GetUnixProt(vprot) ))
347         return FALSE;  /* FIXME: last error */
348
349     memset( view->prot + ((base - view->base) >> page_shift),
350             vprot, size >> page_shift );
351     if (debugging_virtual) VIRTUAL_DumpView( view );
352     return TRUE;
353 }
354
355
356 /***********************************************************************
357  *             VIRTUAL_CheckFlags
358  *
359  * Check that all pages in a range have the given flags.
360  */
361 static BOOL32 VIRTUAL_CheckFlags( UINT32 base, UINT32 size, BYTE flags )
362 {
363     FILE_VIEW *view;
364     UINT32 page;
365
366     if (!size) return TRUE;
367     if (!(view = VIRTUAL_FindView( base ))) return FALSE;
368     if (view->base + view->size < base + size) return FALSE;
369     page = (base - view->base) >> page_shift;
370     size = ROUND_SIZE( base, size ) >> page_shift;
371     while (size--) if ((view->prot[page++] & flags) != flags) return FALSE;
372     return TRUE;
373 }
374
375
376 /***********************************************************************
377  *           VIRTUAL_Init
378  */
379 BOOL32 VIRTUAL_Init(void)
380 {
381     SYSTEM_INFO sysinfo;
382     GetSystemInfo( &sysinfo );
383
384     page_mask = sysinfo.dwPageSize - 1;
385     granularity_mask = sysinfo.dwAllocationGranularity - 1;
386     /* Make sure we have a power of 2 */
387     assert( !(sysinfo.dwPageSize & page_mask) );
388     assert( !(sysinfo.dwAllocationGranularity & granularity_mask) );
389     page_shift = 0;
390     while ((1 << page_shift) != sysinfo.dwPageSize) page_shift++;
391
392 #ifdef linux
393     {
394         /* Do not use stdio here since it may temporarily change the size
395          * of some segments (ie libc6 adds 0x1000 per open FILE)
396          */
397         int fd = open ("/proc/self/maps", O_RDONLY);
398         if (fd >= 0)
399         {
400             char buffer[80];
401
402             for (;;)
403             {
404                 int start, end, offset;
405                 char r, w, x, p;
406                 BYTE vprot = VPROT_COMMITTED;
407
408                 char * ptr = buffer;
409                 int count = sizeof(buffer);
410                 while (1 == read(fd, ptr, 1) && *ptr != '\n' && --count > 0)
411                     ptr++;
412
413                 if (*ptr != '\n') break;
414                 *ptr = '\0';
415
416                 sscanf( buffer, "%x-%x %c%c%c%c %x",
417                         &start, &end, &r, &w, &x, &p, &offset );
418                 if (r == 'r') vprot |= VPROT_READ;
419                 if (w == 'w') vprot |= VPROT_WRITE;
420                 if (x == 'x') vprot |= VPROT_EXEC;
421                 if (p == 'p') vprot |= VPROT_WRITECOPY;
422                 VIRTUAL_CreateView( start, end - start, 0,
423                                     VFLAG_SYSTEM, vprot, NULL );
424             }
425             close (fd);
426         }
427     }
428 #endif  /* linux */
429     return TRUE;
430 }
431
432
433 /***********************************************************************
434  *             VirtualAlloc   (KERNEL32.548)
435  */
436 LPVOID WINAPI VirtualAlloc( LPVOID addr, DWORD size, DWORD type, DWORD protect)
437 {
438     FILE_VIEW *view;
439     UINT32 base, ptr, view_size;
440     BYTE vprot;
441
442     dprintf_virtual( stddeb, "VirtualAlloc: %08x %08lx %lx %08lx\n",
443                      (UINT32)addr, size, type, protect );
444
445     /* Round parameters to a page boundary */
446
447     if (size > 0x7fc00000)  /* 2Gb - 4Mb */
448     {
449         SetLastError( ERROR_OUTOFMEMORY );
450         return NULL;
451     }
452     if (addr)
453     {
454         if (type & MEM_RESERVE) /* Round down to 64k boundary */
455             base = ((UINT32)addr + granularity_mask) & ~granularity_mask;
456         else
457             base = ROUND_ADDR( addr );
458         size = (((UINT32)addr + size + page_mask) & ~page_mask) - base;
459         if (base + size < base)  /* Disallow wrap-around */
460         {
461             SetLastError( ERROR_INVALID_PARAMETER );
462             return NULL;
463         }
464     }
465     else
466     {
467         base = 0;
468         size = (size + page_mask) & ~page_mask;
469     }
470
471     /* Compute the protection flags */
472
473     if (!(type & (MEM_COMMIT | MEM_RESERVE)) ||
474         (type & ~(MEM_COMMIT | MEM_RESERVE)))
475     {
476         SetLastError( ERROR_INVALID_PARAMETER );
477         return NULL;
478     }
479     if (type & MEM_COMMIT)
480         vprot = VIRTUAL_GetProt( protect ) | VPROT_COMMITTED;
481     else vprot = 0;
482
483     /* Reserve the memory */
484
485     if ((type & MEM_RESERVE) || !base)
486     {
487         view_size = size + (base ? 0 : granularity_mask + 1);
488         ptr = (UINT32)FILE_dommap( NULL, (LPVOID)base, 0, view_size, 0, 0,
489                                    VIRTUAL_GetUnixProt( vprot ), MAP_PRIVATE );
490         if (ptr == (UINT32)-1)
491         {
492             SetLastError( ERROR_OUTOFMEMORY );
493             return NULL;
494         }
495         if (!base)
496         {
497             /* Release the extra memory while keeping the range */
498             /* starting on a 64k boundary. */
499
500             if (ptr & granularity_mask)
501             {
502                 UINT32 extra = granularity_mask + 1 - (ptr & granularity_mask);
503                 FILE_munmap( (void *)ptr, 0, extra );
504                 ptr += extra;
505                 view_size -= extra;
506             }
507             if (view_size > size)
508                 FILE_munmap( (void *)(ptr + size), 0, view_size - size );
509         }
510         else if (ptr != base)
511         {
512             /* We couldn't get the address we wanted */
513             FILE_munmap( (void *)ptr, 0, view_size );
514             SetLastError( ERROR_INVALID_ADDRESS );
515             return NULL;
516         }
517         if (!(view = VIRTUAL_CreateView( ptr, size, 0, 0, vprot, NULL )))
518         {
519             FILE_munmap( (void *)ptr, 0, size );
520             SetLastError( ERROR_OUTOFMEMORY );
521             return NULL;
522         }
523         if (debugging_virtual) VIRTUAL_DumpView( view );
524         return (LPVOID)ptr;
525     }
526
527     /* Commit the pages */
528
529     if (!(view = VIRTUAL_FindView( base )) ||
530         (base + size > view->base + view->size))
531     {
532         SetLastError( ERROR_INVALID_PARAMETER );
533         return NULL;
534     }
535
536     if (!VIRTUAL_SetProt( view, base, size, vprot )) return NULL;
537     return (LPVOID)base;
538 }
539
540
541 /***********************************************************************
542  *             VirtualFree   (KERNEL32.550)
543  */
544 BOOL32 WINAPI VirtualFree( LPVOID addr, DWORD size, DWORD type )
545 {
546     FILE_VIEW *view;
547     UINT32 base;
548
549     dprintf_virtual( stddeb, "VirtualFree: %08x %08lx %lx\n",
550                      (UINT32)addr, size, type );
551
552     /* Fix the parameters */
553
554     size = ROUND_SIZE( addr, size );
555     base = ROUND_ADDR( addr );
556
557     if (!(view = VIRTUAL_FindView( base )) ||
558         (base + size > view->base + view->size))
559     {
560         SetLastError( ERROR_INVALID_PARAMETER );
561         return FALSE;
562     }
563
564     /* Compute the protection flags */
565
566     if ((type != MEM_DECOMMIT) && (type != MEM_RELEASE))
567     {
568         SetLastError( ERROR_INVALID_PARAMETER );
569         return FALSE;
570     }
571
572     /* Free the pages */
573
574     if (type == MEM_RELEASE)
575     {
576         if (size || (base != view->base))
577         {
578             SetLastError( ERROR_INVALID_PARAMETER );
579             return FALSE;
580         }
581         VIRTUAL_DeleteView( view );
582         return TRUE;
583     }
584
585     /* Decommit the pages */
586
587     return VIRTUAL_SetProt( view, base, size, 0 );
588 }
589
590
591 /***********************************************************************
592  *             VirtualLock   (KERNEL32.551)
593  */
594 BOOL32 WINAPI VirtualLock( LPVOID addr, DWORD size )
595 {
596     return TRUE;
597 }
598
599
600 /***********************************************************************
601  *             VirtualUnlock   (KERNEL32.556)
602  */
603 BOOL32 WINAPI VirtualUnlock( LPVOID addr, DWORD size )
604 {
605     return TRUE;
606 }
607
608
609 /***********************************************************************
610  *             VirtualProtect   (KERNEL32.552)
611  */
612 BOOL32 WINAPI VirtualProtect( LPVOID addr, DWORD size, DWORD new_prot,
613                               LPDWORD old_prot )
614 {
615     FILE_VIEW *view;
616     UINT32 base, i;
617     BYTE vprot, *p;
618
619     dprintf_virtual( stddeb, "VirtualProtect: %08x %08lx %08lx\n",
620                      (UINT32)addr, size, new_prot );
621
622     /* Fix the parameters */
623
624     size = ROUND_SIZE( addr, size );
625     base = ROUND_ADDR( addr );
626
627     if (!(view = VIRTUAL_FindView( base )) ||
628         (base + size > view->base + view->size))
629     {
630         SetLastError( ERROR_INVALID_PARAMETER );
631         return FALSE;
632     }
633
634     /* Make sure all the pages are committed */
635
636     p = view->prot + ((base - view->base) >> page_shift);
637     for (i = size >> page_shift; i; i--, p++)
638     {
639         if (!(*p & VPROT_COMMITTED))
640         {
641             SetLastError( ERROR_INVALID_PARAMETER );
642             return FALSE;
643         }
644     }
645
646     VIRTUAL_GetWin32Prot( view->prot[0], old_prot, NULL );
647     vprot = VIRTUAL_GetProt( new_prot ) | VPROT_COMMITTED;
648     return VIRTUAL_SetProt( view, base, size, vprot );
649 }
650
651
652 /***********************************************************************
653  *             VirtualProtectEx   (KERNEL32.553)
654  */
655 BOOL32 WINAPI VirtualProtectEx( HANDLE32 handle, LPVOID addr, DWORD size,
656                                 DWORD new_prot, LPDWORD old_prot )
657 {
658     BOOL32 ret = FALSE;
659
660     PDB32 *pdb = (PDB32 *)PROCESS_GetObjPtr( handle, K32OBJ_PROCESS );
661     if (pdb)
662     {
663         if (pdb == PROCESS_Current())
664             ret = VirtualProtect( addr, size, new_prot, old_prot );
665         else
666             fprintf(stderr,"Unsupported: VirtualProtectEx on other process\n");
667         K32OBJ_DecCount( &pdb->header );
668     }
669     return ret;
670 }
671
672
673 /***********************************************************************
674  *             VirtualQuery   (KERNEL32.554)
675  */
676 BOOL32 WINAPI VirtualQuery( LPCVOID addr, LPMEMORY_BASIC_INFORMATION info,
677                             DWORD len )
678 {
679     FILE_VIEW *view = VIRTUAL_FirstView;
680     UINT32 base = ROUND_ADDR( addr );
681     UINT32 alloc_base = 0;
682     UINT32 size = 0;
683
684     /* Find the view containing the address */
685
686     for (;;)
687     {
688         if (!view)
689         {
690             size = 0xffff0000 - alloc_base;
691             break;
692         }
693         if (view->base > base)
694         {
695             size = view->base - alloc_base;
696             view = NULL;
697             break;
698         }
699         if (view->base + view->size > base)
700         {
701             alloc_base = view->base;
702             size = view->size;
703             break;
704         }
705         alloc_base = view->base + view->size;
706         view = view->next;
707     }
708
709     /* Fill the info structure */
710
711     if (!view)
712     {
713         info->State             = MEM_FREE;
714         info->Protect           = 0;
715         info->AllocationProtect = 0;
716         info->Type              = 0;
717     }
718     else
719     {
720         BYTE vprot = view->prot[(base - alloc_base) >> page_shift];
721         VIRTUAL_GetWin32Prot( vprot, &info->Protect, &info->State );
722         for (size = base - alloc_base; size < view->size; size += page_mask+1)
723             if (view->prot[size >> page_shift] != vprot) break;
724         info->AllocationProtect = view->protect;
725         info->Type              = MEM_PRIVATE;  /* FIXME */
726     }
727
728     info->BaseAddress    = (LPVOID)base;
729     info->AllocationBase = (LPVOID)alloc_base;
730     info->RegionSize     = size - (base - alloc_base);
731     return TRUE;
732 }
733
734
735 /***********************************************************************
736  *             VirtualQueryEx   (KERNEL32.555)
737  */
738 BOOL32 WINAPI VirtualQueryEx( HANDLE32 handle, LPCVOID addr,
739                               LPMEMORY_BASIC_INFORMATION info, DWORD len )
740 {
741     BOOL32 ret = FALSE;
742
743     PDB32 *pdb = (PDB32 *)PROCESS_GetObjPtr( handle, K32OBJ_PROCESS );
744     if (pdb)
745     {
746         if (pdb == PROCESS_Current())
747             ret = VirtualQuery( addr, info, len );
748         else
749             fprintf(stderr,"Unsupported: VirtualQueryEx on other process\n");
750         K32OBJ_DecCount( &pdb->header );
751     }
752     return ret;
753 }
754
755
756 /***********************************************************************
757  *             IsBadReadPtr32   (KERNEL32.354)
758  */
759 BOOL32 WINAPI IsBadReadPtr32( LPCVOID ptr, UINT32 size )
760 {
761     return !VIRTUAL_CheckFlags( (UINT32)ptr, size,
762                                 VPROT_READ | VPROT_COMMITTED );
763 }
764
765
766 /***********************************************************************
767  *             IsBadWritePtr32   (KERNEL32.357)
768  */
769 BOOL32 WINAPI IsBadWritePtr32( LPVOID ptr, UINT32 size )
770 {
771     return !VIRTUAL_CheckFlags( (UINT32)ptr, size,
772                                 VPROT_WRITE | VPROT_COMMITTED );
773 }
774
775
776 /***********************************************************************
777  *             IsBadHugeReadPtr32   (KERNEL32.352)
778  */
779 BOOL32 WINAPI IsBadHugeReadPtr32( LPCVOID ptr, UINT32 size )
780 {
781     return IsBadReadPtr32( ptr, size );
782 }
783
784
785 /***********************************************************************
786  *             IsBadHugeWritePtr32   (KERNEL32.353)
787  */
788 BOOL32 WINAPI IsBadHugeWritePtr32( LPVOID ptr, UINT32 size )
789 {
790     return IsBadWritePtr32( ptr, size );
791 }
792
793
794 /***********************************************************************
795  *             IsBadCodePtr32   (KERNEL32.351)
796  */
797 BOOL32 WINAPI IsBadCodePtr32( FARPROC32 ptr )
798 {
799     return !VIRTUAL_CheckFlags( (UINT32)ptr, 1, VPROT_EXEC | VPROT_COMMITTED );
800 }
801
802
803 /***********************************************************************
804  *             IsBadStringPtr32A   (KERNEL32.355)
805  */
806 BOOL32 WINAPI IsBadStringPtr32A( LPCSTR str, UINT32 max )
807 {
808     FILE_VIEW *view;
809     UINT32 page, count;
810
811     if (!max) return FALSE;
812     if (!(view = VIRTUAL_FindView( (UINT32)str ))) return TRUE;
813     page  = ((UINT32)str - view->base) >> page_shift;
814     count = page_mask + 1 - ((UINT32)str & page_mask);
815
816     while (max)
817     {
818         if ((view->prot[page] & (VPROT_READ | VPROT_COMMITTED)) != 
819                                                 (VPROT_READ | VPROT_COMMITTED))
820             return TRUE;
821         if (count > max) count = max;
822         max -= count;
823         while (count--) if (!*str++) return FALSE;
824         if (++page >= view->size >> page_shift) return TRUE;
825         count = page_mask + 1;
826     }
827     return FALSE;
828 }
829
830
831 /***********************************************************************
832  *             IsBadStringPtr32W   (KERNEL32.356)
833  */
834 BOOL32 WINAPI IsBadStringPtr32W( LPCWSTR str, UINT32 max )
835 {
836     FILE_VIEW *view;
837     UINT32 page, count;
838
839     if (!max) return FALSE;
840     if (!(view = VIRTUAL_FindView( (UINT32)str ))) return TRUE;
841     page  = ((UINT32)str - view->base) >> page_shift;
842     count = (page_mask + 1 - ((UINT32)str & page_mask)) / sizeof(WCHAR);
843
844     while (max)
845     {
846         if ((view->prot[page] & (VPROT_READ | VPROT_COMMITTED)) != 
847                                                 (VPROT_READ | VPROT_COMMITTED))
848             return TRUE;
849         if (count > max) count = max;
850         max -= count;
851         while (count--) if (!*str++) return FALSE;
852         if (++page >= view->size >> page_shift) return TRUE;
853         count = (page_mask + 1) / sizeof(WCHAR);
854     }
855     return FALSE;
856 }
857
858
859 /***********************************************************************
860  *             CreateFileMapping32A   (KERNEL32.46)
861  */
862 HANDLE32 WINAPI CreateFileMapping32A(HFILE32 hFile, LPSECURITY_ATTRIBUTES attr,
863                                      DWORD protect, DWORD size_high,
864                                      DWORD size_low, LPCSTR name )
865 {
866     FILE_MAPPING *mapping = NULL;
867     HANDLE32 handle;
868     BYTE vprot;
869
870     /* First search for an object with the same name */
871
872     K32OBJ *obj = K32OBJ_FindName( name );
873     if (obj)
874     {
875         if (obj->type == K32OBJ_MEM_MAPPED_FILE)
876         {
877             SetLastError( ERROR_ALREADY_EXISTS );
878             handle = PROCESS_AllocHandle( obj, 0 );
879         }
880         else
881         {
882             SetLastError( ERROR_DUP_NAME );
883             handle = 0;
884         }
885         K32OBJ_DecCount( obj );
886         return handle;
887     }
888
889     /* Check parameters */
890
891     dprintf_virtual(stddeb,"CreateFileMapping32A(%x,%p,%08lx,%08lx%08lx,%s)\n",
892                     hFile, attr, protect, size_high, size_low, name );
893
894     vprot = VIRTUAL_GetProt( protect );
895     if (protect & SEC_RESERVE)
896     {
897         if (hFile != INVALID_HANDLE_VALUE32)
898         {
899             SetLastError( ERROR_INVALID_PARAMETER );
900             return 0;
901         }
902     }
903     else vprot |= VPROT_COMMITTED;
904     if (protect & SEC_NOCACHE) vprot |= VPROT_NOCACHE;
905
906     /* Compute the size and extend the file if necessary */
907
908     if (hFile == INVALID_HANDLE_VALUE32)
909     {
910         if (!size_high && !size_low)
911         {
912             SetLastError( ERROR_INVALID_PARAMETER );
913             return 0;
914         }
915         obj = NULL;
916     }
917     else  /* We have a file */
918     {
919         BY_HANDLE_FILE_INFORMATION info;
920         if (!(obj = PROCESS_GetObjPtr( hFile, K32OBJ_FILE ))) goto error;
921         /* FIXME: should check if the file permissions agree
922          *        with the required protection flags */
923         if (!GetFileInformationByHandle( hFile, &info )) goto error;
924         if (!size_high && !size_low)
925         {
926             size_high = info.nFileSizeHigh;
927             size_low  = info.nFileSizeLow;
928         }
929         else if ((size_high > info.nFileSizeHigh) ||
930                  ((size_high == info.nFileSizeHigh) &&
931                   (size_low > info.nFileSizeLow)))
932         {
933             /* We have to grow the file */
934             if (SetFilePointer( hFile, size_low, &size_high,
935                                 FILE_BEGIN ) == 0xffffffff) goto error;
936             if (!SetEndOfFile( hFile )) goto error;
937         }
938     }
939
940     /* Allocate the mapping object */
941
942     if (!(mapping = HeapAlloc( SystemHeap, 0, sizeof(*mapping) ))) goto error;
943     mapping->header.type     = K32OBJ_MEM_MAPPED_FILE;
944     mapping->header.refcount = 1;
945     mapping->protect         = vprot;
946     mapping->size_high       = size_high;
947     mapping->size_low        = ROUND_SIZE( 0, size_low );
948     mapping->file            = (FILE_OBJECT *)obj;
949
950     if (!K32OBJ_AddName( &mapping->header, name )) handle = 0;
951     else handle = PROCESS_AllocHandle( &mapping->header, 0 );
952     K32OBJ_DecCount( &mapping->header );
953     return handle;
954
955 error:
956     if (obj) K32OBJ_DecCount( obj );
957     if (mapping) HeapFree( SystemHeap, 0, mapping );
958     return 0;
959 }
960
961
962 /***********************************************************************
963  *             CreateFileMapping32W   (KERNEL32.47)
964  */
965 HANDLE32 WINAPI CreateFileMapping32W(HFILE32 hFile, LPSECURITY_ATTRIBUTES attr,
966                                      DWORD protect, DWORD size_high,
967                                      DWORD size_low, LPCWSTR name )
968 {
969     LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
970     HANDLE32 ret = CreateFileMapping32A( hFile, attr, protect,
971                                          size_high, size_low, nameA );
972     HeapFree( GetProcessHeap(), 0, nameA );
973     return ret;
974 }
975
976
977 /***********************************************************************
978  *             OpenFileMapping32A   (KERNEL32.397)
979  */
980 HANDLE32 WINAPI OpenFileMapping32A( DWORD access, BOOL32 inherit, LPCSTR name )
981 {
982     HANDLE32 handle = 0;
983     K32OBJ *obj;
984     SYSTEM_LOCK();
985     if ((obj = K32OBJ_FindNameType( name, K32OBJ_MEM_MAPPED_FILE )))
986     {
987         handle = PROCESS_AllocHandle( obj, 0 );
988         K32OBJ_DecCount( obj );
989     }
990     SYSTEM_UNLOCK();
991     return handle;
992 }
993
994
995 /***********************************************************************
996  *             OpenFileMapping32W   (KERNEL32.398)
997  */
998 HANDLE32 WINAPI OpenFileMapping32W( DWORD access, BOOL32 inherit, LPCWSTR name)
999 {
1000     LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
1001     HANDLE32 ret = OpenFileMapping32A( access, inherit, nameA );
1002     HeapFree( GetProcessHeap(), 0, nameA );
1003     return ret;
1004 }
1005
1006
1007 /***********************************************************************
1008  *           VIRTUAL_DestroyMapping
1009  *
1010  * Destroy a FILE_MAPPING object.
1011  */
1012 static void VIRTUAL_DestroyMapping( K32OBJ *ptr )
1013 {
1014     FILE_MAPPING *mapping = (FILE_MAPPING *)ptr;
1015     assert( ptr->type == K32OBJ_MEM_MAPPED_FILE );
1016
1017     if (mapping->file) K32OBJ_DecCount( &mapping->file->header );
1018     ptr->type = K32OBJ_UNKNOWN;
1019     HeapFree( SystemHeap, 0, mapping );
1020 }
1021
1022
1023 /***********************************************************************
1024  *             MapViewOfFile   (KERNEL32.385)
1025  */
1026 LPVOID WINAPI MapViewOfFile( HANDLE32 mapping, DWORD access, DWORD offset_high,
1027                              DWORD offset_low, DWORD count )
1028 {
1029     return MapViewOfFileEx( mapping, access, offset_high,
1030                             offset_low, count, NULL );
1031 }
1032
1033
1034 /***********************************************************************
1035  *             MapViewOfFileEx   (KERNEL32.386)
1036  */
1037 LPVOID WINAPI MapViewOfFileEx(HANDLE32 handle, DWORD access, DWORD offset_high,
1038                               DWORD offset_low, DWORD count, LPVOID addr )
1039 {
1040     FILE_MAPPING *mapping;
1041     FILE_VIEW *view;
1042     UINT32 ptr = (UINT32)-1, size = 0;
1043     int flags = MAP_PRIVATE;
1044
1045     /* Check parameters */
1046
1047     if ((offset_low & granularity_mask) ||
1048         (addr && ((UINT32)addr & granularity_mask)))
1049     {
1050         SetLastError( ERROR_INVALID_PARAMETER );
1051         return NULL;
1052     }
1053
1054     if (!(mapping = (FILE_MAPPING *)PROCESS_GetObjPtr( handle,
1055                                                      K32OBJ_MEM_MAPPED_FILE )))
1056         return NULL;
1057
1058     if (mapping->size_high || offset_high)
1059         fprintf( stderr, "MapViewOfFileEx: offsets larger than 4Gb not supported\n");
1060
1061     if ((offset_low >= mapping->size_low) ||
1062         (count > mapping->size_low - offset_low))
1063     {
1064         SetLastError( ERROR_INVALID_PARAMETER );
1065         goto error;
1066     }
1067     if (count) size = ROUND_SIZE( offset_low, count );
1068     else size = mapping->size_low - offset_low;
1069
1070     switch(access)
1071     {
1072     case FILE_MAP_ALL_ACCESS:
1073     case FILE_MAP_WRITE:
1074     case FILE_MAP_WRITE | FILE_MAP_READ:
1075         if (!(mapping->protect & VPROT_WRITE))
1076         {
1077             SetLastError( ERROR_INVALID_PARAMETER );
1078             goto error;
1079         }
1080         flags = MAP_SHARED;
1081         /* fall through */
1082     case FILE_MAP_READ:
1083     case FILE_MAP_COPY:
1084     case FILE_MAP_COPY | FILE_MAP_READ:
1085         if (mapping->protect & VPROT_READ) break;
1086         /* fall through */
1087     default:
1088         SetLastError( ERROR_INVALID_PARAMETER );
1089         goto error;
1090     }
1091
1092     /* Map the file */
1093
1094     dprintf_virtual( stddeb, "MapViewOfFile: handle=%x size=%x offset=%lx\n",
1095                      handle, size, offset_low );
1096
1097     ptr = (UINT32)FILE_dommap( mapping->file, addr, 0, size, 0, offset_low,
1098                                VIRTUAL_GetUnixProt( mapping->protect ),
1099                                flags );
1100     if (ptr == (UINT32)-1)
1101     {
1102         SetLastError( ERROR_OUTOFMEMORY );
1103         goto error;
1104     }
1105
1106     if (!(view = VIRTUAL_CreateView( ptr, size, offset_low, 0,
1107                                      mapping->protect, mapping )))
1108     {
1109         SetLastError( ERROR_OUTOFMEMORY );
1110         goto error;
1111     }
1112     return (LPVOID)ptr;
1113
1114 error:
1115     if (ptr != (UINT32)-1) FILE_munmap( (void *)ptr, 0, size );
1116     K32OBJ_DecCount( &mapping->header );
1117     return NULL;
1118 }
1119
1120
1121 /***********************************************************************
1122  *             FlushViewOfFile   (KERNEL32.262)
1123  */
1124 BOOL32 WINAPI FlushViewOfFile( LPCVOID base, DWORD cbFlush )
1125 {
1126     FILE_VIEW *view;
1127     UINT32 addr = ROUND_ADDR( base );
1128
1129     dprintf_virtual( stddeb, "FlushViewOfFile at %p for %ld bytes\n",
1130                      base, cbFlush );
1131
1132     if (!(view = VIRTUAL_FindView( addr )))
1133     {
1134         SetLastError( ERROR_INVALID_PARAMETER );
1135         return FALSE;
1136     }
1137     if (!cbFlush) cbFlush = view->size;
1138     if (!msync( (void *)addr, cbFlush, MS_SYNC )) return TRUE;
1139     SetLastError( ERROR_INVALID_PARAMETER );
1140     return FALSE;
1141
1142 }
1143 /***********************************************************************
1144  *             UnmapViewOfFile   (KERNEL32.540)
1145  */
1146 BOOL32 WINAPI UnmapViewOfFile( LPVOID addr )
1147 {
1148     FILE_VIEW *view;
1149     UINT32 base = ROUND_ADDR( addr );
1150     if (!(view = VIRTUAL_FindView( base )) || (base != view->base))
1151     {
1152         SetLastError( ERROR_INVALID_PARAMETER );
1153         return FALSE;
1154     }
1155     VIRTUAL_DeleteView( view );
1156     return TRUE;
1157 }