Commit 33240c54 authored by Alexandre Julliard's avatar Alexandre Julliard

ntdll: Reimplement map_fixed_area() to avoid recursion and callbacks.

parent 4cdc2f75
......@@ -1463,42 +1463,6 @@ static void remove_reserved_area( void *addr, size_t size )
}
struct area_boundary
{
void *base;
size_t size;
void *boundary;
};
/***********************************************************************
* get_area_boundary_callback
*
* Get lowest boundary address between reserved area and non-reserved area
* in the specified region. If no boundaries are found, result is NULL.
* virtual_mutex must be held by caller.
*/
static int get_area_boundary_callback( void *start, SIZE_T size, void *arg )
{
struct area_boundary *area = arg;
void *end = (char *)start + size;
area->boundary = NULL;
if (area->base >= end) return 0;
if ((char *)start >= (char *)area->base + area->size) return 1;
if (area->base >= start)
{
if ((char *)area->base + area->size > (char *)end)
{
area->boundary = end;
return 1;
}
return 0;
}
area->boundary = start;
return 1;
}
/***********************************************************************
* unmap_area
*
......@@ -1918,52 +1882,48 @@ static int alloc_reserved_area_callback( void *start, SIZE_T size, void *arg )
/***********************************************************************
* map_fixed_area
*
* mmap the fixed memory area.
* Map a memory area at a fixed address.
* virtual_mutex must be held by caller.
*/
static NTSTATUS map_fixed_area( void *base, size_t size, unsigned int vprot )
{
void *ptr;
int unix_prot = get_unix_prot(vprot);
struct reserved_area *area;
NTSTATUS status;
char *start = base, *end = (char *)base + size;
switch (mmap_is_in_reserved_area( base, size ))
{
case -1: /* partially in a reserved area */
if (find_view_range( base, size )) return STATUS_CONFLICTING_ADDRESSES;
LIST_FOR_EACH_ENTRY( area, &reserved_areas, struct reserved_area, entry )
{
NTSTATUS status;
struct area_boundary area;
size_t lower_size;
area.base = base;
area.size = size;
mmap_enum_reserved_areas( get_area_boundary_callback, &area, 0 );
assert( area.boundary );
lower_size = (char *)area.boundary - (char *)base;
status = map_fixed_area( base, lower_size, vprot );
if (status == STATUS_SUCCESS)
char *area_start = area->base;
char *area_end = area_start + area->size;
if (area_start >= end) break;
if (area_end <= start) continue;
if (area_start > start)
{
status = map_fixed_area( area.boundary, size - lower_size, vprot);
if (status != STATUS_SUCCESS) unmap_area( base, lower_size );
if (anon_mmap_tryfixed( start, area_start - start, unix_prot, 0 ) == MAP_FAILED) goto failed;
start = area_start;
}
return status;
}
case 0: /* not in a reserved area, do a normal allocation */
if ((ptr = anon_mmap_tryfixed( base, size, get_unix_prot(vprot), 0 )) == MAP_FAILED)
if (area_end >= end)
{
if (errno == ENOMEM) return STATUS_NO_MEMORY;
if (errno == EEXIST) return STATUS_CONFLICTING_ADDRESSES;
return STATUS_INVALID_PARAMETER;
if (anon_mmap_fixed( start, end - start, unix_prot, 0 ) == MAP_FAILED) goto failed;
return STATUS_SUCCESS;
}
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 = anon_mmap_fixed( base, size, get_unix_prot(vprot), 0 )) != base)
return STATUS_INVALID_PARAMETER;
break;
if (anon_mmap_fixed( start, area_end - start, unix_prot, 0 ) == MAP_FAILED) goto failed;
start = area_end;
}
if (is_beyond_limit( ptr, size, working_set_limit )) working_set_limit = address_space_limit;
if (anon_mmap_tryfixed( start, end - start, unix_prot, 0 ) == MAP_FAILED) goto failed;
return STATUS_SUCCESS;
failed:
if (errno == ENOMEM) status = STATUS_NO_MEMORY;
else if (errno == EEXIST) status = STATUS_CONFLICTING_ADDRESSES;
else status = STATUS_INVALID_PARAMETER;
unmap_area( base, start - (char *)base );
return status;
}
/***********************************************************************
......@@ -1998,12 +1958,10 @@ static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size,
if (base)
{
if (is_beyond_limit( base, size, address_space_limit ))
return STATUS_WORKING_SET_LIMIT_RANGE;
if (limit && is_beyond_limit( base, size, (void *)limit ))
return STATUS_CONFLICTING_ADDRESSES;
status = map_fixed_area( base, size, vprot );
if (status != STATUS_SUCCESS) return status;
if (is_beyond_limit( base, size, address_space_limit )) return STATUS_WORKING_SET_LIMIT_RANGE;
if (limit && is_beyond_limit( base, size, (void *)limit )) return STATUS_CONFLICTING_ADDRESSES;
if ((status = map_fixed_area( base, size, vprot ))) return status;
if (is_beyond_limit( base, size, working_set_limit )) working_set_limit = address_space_limit;
ptr = base;
}
else
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment