Added support for managing reserved memory areas in libwine and ntdll.
Try to reserve everything above 0x80000000 on startup.

diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
index 09d5b6d..f61fa5c 100644
--- a/dlls/ntdll/virtual.c
+++ b/dlls/ntdll/virtual.c
@@ -57,6 +57,10 @@
 #define MS_SYNC 0
 #endif
 
+#ifndef MAP_NORESERVE
+#define MAP_NORESERVE 0
+#endif
+
 /* File view */
 typedef struct file_view
 {
@@ -112,16 +116,15 @@
 # define page_mask  0xfff
 # define page_shift 12
 # define page_size  0x1000
-/* Note: ADDRESS_SPACE_LIMIT is a Windows limit, you cannot change it.
- * If you are on Solaris you need to find a way to avoid having the system
- * allocate things above 0xc000000. Don't touch that define.
- */
-# define ADDRESS_SPACE_LIMIT  ((void *)0xc0000000)  /* top of the user address space */
+/* Note: these are Windows limits, you cannot change them. */
+# define ADDRESS_SPACE_LIMIT  ((void *)0xc0000000)  /* top of the total available address space */
+# define USER_SPACE_LIMIT     ((void *)0x80000000)  /* top of the user address space */
 #else
 static UINT page_shift;
 static UINT page_mask;
 static UINT page_size;
 # define ADDRESS_SPACE_LIMIT  0   /* no limit needed on other platforms */
+# define USER_SPACE_LIMIT     0   /* no limit needed on other platforms */
 #endif  /* __i386__ */
 #define granularity_mask 0xffff  /* Allocation granularity (usually 64k) */
 
@@ -219,24 +222,88 @@
     {
         struct file_view *view = LIST_ENTRY( ptr, struct file_view, entry );
         if (view->base > addr) break;
-        if ((char*)view->base + view->size > (char*)addr) return view;
+        if ((char *)view->base + view->size > (const char *)addr) return view;
     }
     return NULL;
 }
 
 
 /***********************************************************************
- *           VIRTUAL_DeleteView
+ *           find_view_range
+ *
+ * Find the first view overlapping at least part of the specified range.
+ * The csVirtual section must be held by caller.
+ */
+static struct file_view *find_view_range( const void *addr, size_t size )
+{
+    struct list *ptr;
+
+    LIST_FOR_EACH( ptr, &views_list )
+    {
+        struct file_view *view = LIST_ENTRY( ptr, struct file_view, entry );
+        if ((char *)view->base >= (const char *)addr + size) break;
+        if ((char *)view->base + view->size > (const char *)addr) return view;
+    }
+    return NULL;
+}
+
+
+/***********************************************************************
+ *           add_reserved_area
+ *
+ * Add a reserved area to the list maintained by libwine.
+ * The csVirtual section must be held by caller.
+ */
+static void add_reserved_area( void *addr, size_t size )
+{
+    TRACE( "adding %p-%p\n", addr, (char *)addr + size );
+
+    if (addr < USER_SPACE_LIMIT)
+    {
+        /* unmap the part of the area that is below the limit */
+        assert( (char *)addr + size > (char *)USER_SPACE_LIMIT );
+        munmap( addr, (char *)USER_SPACE_LIMIT - (char *)addr );
+        size -= (char *)USER_SPACE_LIMIT - (char *)addr;
+        addr = USER_SPACE_LIMIT;
+    }
+    wine_mmap_add_reserved_area( addr, size );
+}
+
+
+/***********************************************************************
+ *           is_beyond_limit
+ *
+ * Check if an address range goes beyond a given limit.
+ */
+static inline int is_beyond_limit( void *addr, size_t size, void *limit )
+{
+    return (limit && (addr >= limit || (char *)addr + size > (char *)limit));
+}
+
+
+/***********************************************************************
+ *           unmap_area
+ *
+ * Unmap an area, or simply replace it by an empty mapping if it is
+ * in a reserved area. The csVirtual section must be held by caller.
+ */
+static inline void unmap_area( void *addr, size_t size )
+{
+    if (wine_mmap_is_in_reserved_area( addr, size ))
+        wine_anon_mmap( addr, size, PROT_NONE, MAP_NORESERVE | MAP_FIXED );
+    else
+        munmap( addr, size );
+}
+
+
+/***********************************************************************
+ *           delete_view
  *
  * Deletes a view. The csVirtual section must be held by caller.
- *
- * RETURNS
- *	None
  */
-static void VIRTUAL_DeleteView( struct file_view *view ) /* [in] View */
+static void delete_view( struct file_view *view ) /* [in] View */
 {
-    if (!(view->flags & VFLAG_SYSTEM))
-        munmap( (void *)view->base, view->size );
+    if (!(view->flags & VFLAG_SYSTEM)) unmap_area( view->base, view->size );
     list_remove( &view->entry );
     if (view->mapping) NtClose( view->mapping );
     free( view );
@@ -290,7 +357,7 @@
                    prev->base, (char *)prev->base + prev->size,
                    base, (char *)base + view->size );
             assert( prev->flags & VFLAG_SYSTEM );
-            VIRTUAL_DeleteView( prev );
+            delete_view( prev );
         }
     }
     if ((ptr = list_next( &views_list, &view->entry )) != NULL)
@@ -302,7 +369,7 @@
                    next->base, (char *)next->base + next->size,
                    base, (char *)base + view->size );
             assert( next->flags & VFLAG_SYSTEM );
-            VIRTUAL_DeleteView( next );
+            delete_view( next );
         }
     }
 
@@ -450,26 +517,52 @@
 
     if (base)
     {
-        if ((ptr = wine_anon_mmap( base, size, VIRTUAL_GetUnixProt(vprot), 0 )) == (void *)-1)
+        if (is_beyond_limit( base, size, ADDRESS_SPACE_LIMIT ))
+            return STATUS_WORKING_SET_LIMIT_RANGE;
+
+        switch (wine_mmap_is_in_reserved_area( base, size ))
         {
-            if (errno == ENOMEM) return STATUS_NO_MEMORY;
-            return STATUS_INVALID_PARAMETER;
-        }
-        if (ptr != base)
-        {
-            /* We couldn't get the address we wanted */
-            munmap( ptr, size );
+        case -1: /* partially in a reserved area */
             return STATUS_CONFLICTING_ADDRESSES;
+
+        case 0:  /* not in a reserved area, do a normal allocation */
+            if ((ptr = wine_anon_mmap( base, size, VIRTUAL_GetUnixProt(vprot), 0 )) == (void *)-1)
+            {
+                if (errno == ENOMEM) return STATUS_NO_MEMORY;
+                return STATUS_INVALID_PARAMETER;
+            }
+            if (ptr != base)
+            {
+                /* We couldn't get the address we wanted */
+                if (is_beyond_limit( ptr, size, USER_SPACE_LIMIT )) add_reserved_area( ptr, size );
+                else munmap( ptr, size );
+                return STATUS_CONFLICTING_ADDRESSES;
+            }
+            break;
+
+        default:
+        case 1:  /* in a reserved area, make sure the address is available */
+            if (find_view_range( base, size )) return STATUS_CONFLICTING_ADDRESSES;
+            /* replace the reserved area by our mapping */
+            if ((ptr = wine_anon_mmap( base, size, VIRTUAL_GetUnixProt(vprot), MAP_FIXED )) != base)
+                return STATUS_INVALID_PARAMETER;
+            break;
         }
     }
     else
     {
         size_t view_size = size + granularity_mask + 1;
 
-        if ((ptr = wine_anon_mmap( NULL, view_size, VIRTUAL_GetUnixProt(vprot), 0 )) == (void *)-1)
+        for (;;)
         {
-            if (errno == ENOMEM) return STATUS_NO_MEMORY;
-            return STATUS_INVALID_PARAMETER;
+            if ((ptr = wine_anon_mmap( NULL, view_size, VIRTUAL_GetUnixProt(vprot), 0 )) == (void *)-1)
+            {
+                if (errno == ENOMEM) return STATUS_NO_MEMORY;
+                return STATUS_INVALID_PARAMETER;
+            }
+            /* if we got something beyond the user limit, unmap it and retry */
+            if (is_beyond_limit( ptr, view_size, USER_SPACE_LIMIT )) add_reserved_area( ptr, view_size );
+            else break;
         }
 
         /* Release the extra memory while keeping the range
@@ -486,7 +579,7 @@
     }
 
     status = create_view( view_ret, ptr, size, vprot );
-    if (status != STATUS_SUCCESS) munmap( ptr, size );
+    if (status != STATUS_SUCCESS) unmap_area( ptr, size );
     return status;
 }
 
@@ -885,7 +978,7 @@
     return STATUS_SUCCESS;
 
  error:
-    if (view) VIRTUAL_DeleteView( view );
+    if (view) delete_view( view );
     RtlLeaveCriticalSection( &csVirtual );
     return status;
 }
@@ -1040,7 +1133,7 @@
         /* disallow low 64k, wrap-around and kernel space */
         if (((char *)base <= (char *)granularity_mask) ||
             ((char *)base + size < (char *)base) ||
-            (ADDRESS_SPACE_LIMIT && ((char *)base + size > (char *)ADDRESS_SPACE_LIMIT)))
+            is_beyond_limit( base, size, ADDRESS_SPACE_LIMIT ))
             return STATUS_INVALID_PARAMETER;
     }
     else
@@ -1148,7 +1241,7 @@
         *addr_ptr = view->base;
         *size_ptr = view->size;
         view->flags |= VFLAG_SYSTEM;
-        VIRTUAL_DeleteView( view );
+        delete_view( view );
     }
     else if (type == MEM_RELEASE)
     {
@@ -1157,7 +1250,7 @@
         if (size || (base != view->base)) status = STATUS_INVALID_PARAMETER;
         else
         {
-            VIRTUAL_DeleteView( view );
+            delete_view( view );
             *addr_ptr = base;
             *size_ptr = size;
         }
@@ -1264,7 +1357,7 @@
 
     if (info_class != MemoryBasicInformation) return STATUS_INVALID_INFO_CLASS;
     if (ADDRESS_SPACE_LIMIT && addr >= ADDRESS_SPACE_LIMIT)
-        return STATUS_WORKING_SET_LIMIT_RANGE;  /* FIXME */
+        return STATUS_WORKING_SET_LIMIT_RANGE;
 
     if (!is_current_process( process ))
     {
@@ -1282,7 +1375,18 @@
     {
         if (!ptr)
         {
-            size = (char *)ADDRESS_SPACE_LIMIT - alloc_base;
+            /* make the address space end at the user limit, except if
+             * the last view was mapped beyond that */
+            if (alloc_base < (char *)USER_SPACE_LIMIT)
+            {
+                if (USER_SPACE_LIMIT && base >= (char *)USER_SPACE_LIMIT)
+                {
+                    RtlLeaveCriticalSection( &csVirtual );
+                    return STATUS_WORKING_SET_LIMIT_RANGE;
+                }
+                size = (char *)USER_SPACE_LIMIT - alloc_base;
+            }
+            else size = (char *)ADDRESS_SPACE_LIMIT - alloc_base;
             view = NULL;
             break;
         }
@@ -1585,7 +1689,7 @@
     {
         ERR( "map_file_into_view %p %x %lx%08lx failed\n",
              view->base, size, offset->u.HighPart, offset->u.LowPart );
-        VIRTUAL_DeleteView( view );
+        delete_view( view );
     }
 
     RtlLeaveCriticalSection( &csVirtual );
@@ -1614,7 +1718,7 @@
     RtlEnterCriticalSection( &csVirtual );
     if ((view = VIRTUAL_FindView( base )) && (base == view->base))
     {
-        VIRTUAL_DeleteView( view );
+        delete_view( view );
         status = STATUS_SUCCESS;
     }
     RtlLeaveCriticalSection( &csVirtual );