Alexandre Julliard : ntdll: Allocate the per-page protection byte separately from the view.
Alexandre Julliard
julliard at winehq.org
Tue Sep 5 15:18:50 CDT 2017
Module: wine
Branch: master
Commit: 3ecf069e45c12cf3cd79319a633acecba9a00553
URL: http://source.winehq.org/git/wine.git/?a=commit;h=3ecf069e45c12cf3cd79319a633acecba9a00553
Author: Alexandre Julliard <julliard at winehq.org>
Date: Tue Sep 5 16:17:39 2017 +0200
ntdll: Allocate the per-page protection byte separately from the view.
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/ntdll/virtual.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 84 insertions(+), 11 deletions(-)
diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
index ea4834f..379c8a1 100644
--- a/dlls/ntdll/virtual.c
+++ b/dlls/ntdll/virtual.c
@@ -73,7 +73,6 @@ struct file_view
HANDLE mapping; /* Handle to the file mapping */
unsigned int map_protect; /* Mapping protection */
unsigned int protect; /* Protection for all pages at allocation time */
- BYTE prot[1]; /* Protection byte for each page */
};
@@ -146,6 +145,15 @@ static const BOOL is_win64 = (sizeof(void *) > sizeof(int));
#define VIRTUAL_HEAP_SIZE (sizeof(void*)*1024*1024)
+#ifdef _WIN64 /* on 64-bit the page protection bytes use a 2-level table */
+static const size_t pages_vprot_shift = 20;
+static const size_t pages_vprot_mask = (1 << 20) - 1;
+static size_t pages_vprot_size;
+static BYTE **pages_vprot;
+#else /* on 32-bit we use a simple array with one byte per page */
+static BYTE *pages_vprot;
+#endif
+
static HANDLE virtual_heap;
static void *preload_reserve_start;
static void *preload_reserve_end;
@@ -160,7 +168,13 @@ static BOOL force_exec_prot; /* whether to force PROT_EXEC on all PROT_READ mma
*/
static BYTE get_page_vprot( struct file_view *view, const void *addr )
{
- return view->prot[((const char *)addr - (const char *)view->base) >> page_shift];
+ size_t idx = (size_t)addr >> page_shift;
+
+#ifdef _WIN64
+ return pages_vprot[idx >> pages_vprot_shift][idx & pages_vprot_mask];
+#else
+ return pages_vprot[idx];
+#endif
}
@@ -171,8 +185,20 @@ static BYTE get_page_vprot( struct file_view *view, const void *addr )
*/
static void set_page_vprot( struct file_view *view, const void *addr, size_t size, BYTE vprot )
{
- BYTE *ptr = view->prot + (((const char *)addr - (const char *)view->base) >> page_shift);
- memset( ptr, vprot, ROUND_SIZE( addr, size ) >> page_shift );
+ size_t idx = (size_t)addr >> page_shift;
+ size_t end = ((size_t)addr + size + page_mask) >> page_shift;
+
+#ifdef _WIN64
+ while (idx >> pages_vprot_shift != end >> pages_vprot_shift)
+ {
+ size_t dir_size = pages_vprot_mask + 1 - (idx & pages_vprot_mask);
+ memset( pages_vprot[idx >> pages_vprot_shift] + (idx & pages_vprot_mask), vprot, dir_size );
+ idx += dir_size;
+ }
+ memset( pages_vprot[idx >> pages_vprot_shift] + (idx & pages_vprot_mask), vprot, end - idx );
+#else
+ memset( pages_vprot + idx, vprot, end - idx );
+#endif
}
@@ -184,10 +210,44 @@ static void set_page_vprot( struct file_view *view, const void *addr, size_t siz
static void set_page_vprot_bits( struct file_view *view, const void *addr, size_t size,
BYTE set, BYTE clear )
{
- BYTE *ptr = view->prot + (((const char *)addr - (const char *)view->base) >> page_shift);
+ size_t idx = (size_t)addr >> page_shift;
+ size_t end = ((size_t)addr + size + page_mask) >> page_shift;
+
+#ifdef _WIN64
+ for ( ; idx < end; idx++)
+ {
+ BYTE *ptr = pages_vprot[idx >> pages_vprot_shift] + (idx & pages_vprot_mask);
+ *ptr = (*ptr & ~clear) | set;
+ }
+#else
+ for ( ; idx < end; idx++) pages_vprot[idx] = (pages_vprot[idx] & ~clear) | set;
+#endif
+}
+
+
+/***********************************************************************
+ * alloc_pages_vprot
+ *
+ * Allocate the page protection bytes for a given range.
+ */
+static BOOL alloc_pages_vprot( const void *addr, size_t size )
+{
+#ifdef _WIN64
+ size_t idx = (size_t)addr >> page_shift;
+ size_t end = ((size_t)addr + size + page_mask) >> page_shift;
size_t i;
+ void *ptr;
- for (i = 0; i < ROUND_SIZE( addr, size ) >> page_shift; i++) ptr[i] = (ptr[i] & ~clear) | set;
+ assert( end <= pages_vprot_size << pages_vprot_shift );
+ for (i = idx >> pages_vprot_shift; i < (end + pages_vprot_mask) >> pages_vprot_shift; i++)
+ {
+ if (pages_vprot[i]) continue;
+ if ((ptr = wine_anon_mmap( NULL, pages_vprot_mask + 1, PROT_READ | PROT_WRITE, 0 )) == (void *)-1)
+ return FALSE;
+ pages_vprot[i] = ptr;
+ }
+#endif
+ return TRUE;
}
@@ -555,9 +615,11 @@ static NTSTATUS create_view( struct file_view **view_ret, void *base, size_t siz
assert( !((UINT_PTR)base & page_mask) );
assert( !(size & page_mask) );
+ if (!alloc_pages_vprot( base, size )) return STATUS_NO_MEMORY;
+
/* Create the view structure */
- if (!(view = RtlAllocateHeap( virtual_heap, 0, sizeof(*view) + (size >> page_shift) - 1 )))
+ if (!(view = RtlAllocateHeap( virtual_heap, 0, sizeof(*view) )))
{
FIXME( "out of memory in virtual heap for %p-%p\n", base, (char *)base + size );
return STATUS_NO_MEMORY;
@@ -1440,8 +1502,13 @@ void virtual_init(void)
assert( !(page_size & page_mask) );
page_shift = 0;
while ((1 << page_shift) != page_size) page_shift++;
- user_space_limit = working_set_limit = address_space_limit = (void *)~page_mask;
-#endif /* page_mask */
+#ifdef _WIN64
+ address_space_limit = (void *)(((1UL << 47) - 1) & ~page_mask);
+#else
+ address_space_limit = (void *)~page_mask;
+#endif
+ user_space_limit = working_set_limit = address_space_limit;
+#endif
if ((preload = getenv("WINEPRELOADRESERVE")))
{
unsigned long start, end;
@@ -1452,12 +1519,18 @@ void virtual_init(void)
}
}
- /* try to find space in a reserved area for the virtual heap */
- alloc_heap.size = VIRTUAL_HEAP_SIZE;
+ /* try to find space in a reserved area for the virtual heap and pages protection table */
+#ifdef _WIN64
+ pages_vprot_size = ((size_t)address_space_limit >> page_shift >> pages_vprot_shift) + 1;
+ alloc_heap.size = VIRTUAL_HEAP_SIZE + pages_vprot_size * sizeof(*pages_vprot);
+#else
+ alloc_heap.size = VIRTUAL_HEAP_SIZE + (1U << (32 - page_shift));
+#endif
if (!wine_mmap_enum_reserved_areas( alloc_virtual_heap, &alloc_heap, 1 ))
alloc_heap.base = wine_anon_mmap( NULL, alloc_heap.size, PROT_READ|PROT_WRITE, 0 );
assert( alloc_heap.base != (void *)-1 );
+ pages_vprot = (void *)((char *)alloc_heap.base + VIRTUAL_HEAP_SIZE);
virtual_heap = RtlCreateHeap( HEAP_NO_SERIALIZE, alloc_heap.base, VIRTUAL_HEAP_SIZE,
VIRTUAL_HEAP_SIZE, NULL, NULL );
create_view( &heap_view, alloc_heap.base, alloc_heap.size, VPROT_COMMITTED|VPROT_READ|VPROT_WRITE );
More information about the wine-cvs
mailing list