af062818b47340eef15700d2f0211576ba3506eevboxsync/*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Wine memory mappings support
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * Copyright 2000, 2004 Alexandre Julliard
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * This library is free software; you can redistribute it and/or
af062818b47340eef15700d2f0211576ba3506eevboxsync * modify it under the terms of the GNU Lesser General Public
af062818b47340eef15700d2f0211576ba3506eevboxsync * License as published by the Free Software Foundation; either
af062818b47340eef15700d2f0211576ba3506eevboxsync * version 2.1 of the License, or (at your option) any later version.
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * This library is distributed in the hope that it will be useful,
af062818b47340eef15700d2f0211576ba3506eevboxsync * but WITHOUT ANY WARRANTY; without even the implied warranty of
af062818b47340eef15700d2f0211576ba3506eevboxsync * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
af062818b47340eef15700d2f0211576ba3506eevboxsync * Lesser General Public License for more details.
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * You should have received a copy of the GNU Lesser General Public
af062818b47340eef15700d2f0211576ba3506eevboxsync * License along with this library; if not, write to the Free Software
af062818b47340eef15700d2f0211576ba3506eevboxsync * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsync/*
4b9d6701570cb98fd36e209314239d104ec584d3vboxsync * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
4b9d6701570cb98fd36e209314239d104ec584d3vboxsync * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsync * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsync * a choice of LGPL license versions is made available with the language indicating
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsync * that LGPLv2 or any later version may be used, or where a choice of which version
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsync * of the LGPL is applied is otherwise unspecified.
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsync */
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync#include "config.h"
af062818b47340eef15700d2f0211576ba3506eevboxsync#include "wine/port.h"
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync#include <assert.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync#include <ctype.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync#include <fcntl.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync#include <stdlib.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync#include <stdio.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync#include <string.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync#include <sys/types.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync#ifdef HAVE_SYS_MMAN_H
af062818b47340eef15700d2f0211576ba3506eevboxsync#include <sys/mman.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync#endif
af062818b47340eef15700d2f0211576ba3506eevboxsync#ifdef HAVE_UNISTD_H
af062818b47340eef15700d2f0211576ba3506eevboxsync# include <unistd.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync#endif
af062818b47340eef15700d2f0211576ba3506eevboxsync#ifdef HAVE_STDINT_H
af062818b47340eef15700d2f0211576ba3506eevboxsync# include <stdint.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync#endif
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync#include "wine/library.h"
af062818b47340eef15700d2f0211576ba3506eevboxsync#include "wine/list.h"
af062818b47340eef15700d2f0211576ba3506eevboxsync
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync#ifdef HAVE_MMAP
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsyncstruct reserved_area
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync struct list entry;
af062818b47340eef15700d2f0211576ba3506eevboxsync void *base;
af062818b47340eef15700d2f0211576ba3506eevboxsync size_t size;
af062818b47340eef15700d2f0211576ba3506eevboxsync};
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic struct list reserved_areas = LIST_INIT(reserved_areas);
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic const unsigned int granularity_mask = 0xffff; /* reserved areas have 64k granularity */
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync#ifndef MAP_NORESERVE
af062818b47340eef15700d2f0211576ba3506eevboxsync#define MAP_NORESERVE 0
af062818b47340eef15700d2f0211576ba3506eevboxsync#endif
af062818b47340eef15700d2f0211576ba3506eevboxsync#ifndef MAP_PRIVATE
af062818b47340eef15700d2f0211576ba3506eevboxsync#define MAP_PRIVATE 0
af062818b47340eef15700d2f0211576ba3506eevboxsync#endif
af062818b47340eef15700d2f0211576ba3506eevboxsync#ifndef MAP_ANON
af062818b47340eef15700d2f0211576ba3506eevboxsync#define MAP_ANON 0
af062818b47340eef15700d2f0211576ba3506eevboxsync#endif
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic inline int get_fdzero(void)
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync static int fd = -1;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync if (MAP_ANON == 0 && fd == -1)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync if ((fd = open( "/dev/zero", O_RDONLY )) == -1)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync perror( "/dev/zero: open" );
af062818b47340eef15700d2f0211576ba3506eevboxsync exit(1);
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync return fd;
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync#if (defined(__svr4__) || defined(__NetBSD__)) && !defined(MAP_TRYFIXED)
af062818b47340eef15700d2f0211576ba3506eevboxsync/***********************************************************************
af062818b47340eef15700d2f0211576ba3506eevboxsync * try_mmap_fixed
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * The purpose of this routine is to emulate the behaviour of
af062818b47340eef15700d2f0211576ba3506eevboxsync * the Linux mmap() routine if a non-NULL address is passed,
af062818b47340eef15700d2f0211576ba3506eevboxsync * but the MAP_FIXED flag is not set. Linux in this case tries
af062818b47340eef15700d2f0211576ba3506eevboxsync * to place the mapping at the specified address, *unless* the
af062818b47340eef15700d2f0211576ba3506eevboxsync * range is already in use. Solaris, however, completely ignores
af062818b47340eef15700d2f0211576ba3506eevboxsync * the address argument in this case.
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * As Wine code occasionally relies on the Linux behaviour, e.g. to
af062818b47340eef15700d2f0211576ba3506eevboxsync * be able to map non-relocatable PE executables to their proper
af062818b47340eef15700d2f0211576ba3506eevboxsync * start addresses, or to map the DOS memory to 0, this routine
af062818b47340eef15700d2f0211576ba3506eevboxsync * emulates the Linux behaviour by checking whether the desired
af062818b47340eef15700d2f0211576ba3506eevboxsync * address range is still available, and placing the mapping there
af062818b47340eef15700d2f0211576ba3506eevboxsync * using MAP_FIXED if so.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic int try_mmap_fixed (void *addr, size_t len, int prot, int flags,
af062818b47340eef15700d2f0211576ba3506eevboxsync int fildes, off_t off)
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync char * volatile result = NULL;
af062818b47340eef15700d2f0211576ba3506eevboxsync int pagesize = getpagesize();
af062818b47340eef15700d2f0211576ba3506eevboxsync pid_t pid;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /* We only try to map to a fixed address if
af062818b47340eef15700d2f0211576ba3506eevboxsync addr is non-NULL and properly aligned,
af062818b47340eef15700d2f0211576ba3506eevboxsync and MAP_FIXED isn't already specified. */
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync if ( !addr )
af062818b47340eef15700d2f0211576ba3506eevboxsync return 0;
af062818b47340eef15700d2f0211576ba3506eevboxsync if ( (uintptr_t)addr & (pagesize-1) )
af062818b47340eef15700d2f0211576ba3506eevboxsync return 0;
af062818b47340eef15700d2f0211576ba3506eevboxsync if ( flags & MAP_FIXED )
af062818b47340eef15700d2f0211576ba3506eevboxsync return 0;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /* We use vfork() to freeze all threads of the
af062818b47340eef15700d2f0211576ba3506eevboxsync current process. This allows us to check without
af062818b47340eef15700d2f0211576ba3506eevboxsync race condition whether the desired memory range is
af062818b47340eef15700d2f0211576ba3506eevboxsync already in use. Note that because vfork() shares
af062818b47340eef15700d2f0211576ba3506eevboxsync the address spaces between parent and child, we
af062818b47340eef15700d2f0211576ba3506eevboxsync can actually perform the mapping in the child. */
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync if ( (pid = vfork()) == -1 )
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync perror("try_mmap_fixed: vfork");
af062818b47340eef15700d2f0211576ba3506eevboxsync exit(1);
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync if ( pid == 0 )
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync int i;
af062818b47340eef15700d2f0211576ba3506eevboxsync char vec;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /* We call mincore() for every page in the desired range.
af062818b47340eef15700d2f0211576ba3506eevboxsync If any of these calls succeeds, the page is already
af062818b47340eef15700d2f0211576ba3506eevboxsync mapped and we must fail. */
af062818b47340eef15700d2f0211576ba3506eevboxsync for ( i = 0; i < len; i += pagesize )
af062818b47340eef15700d2f0211576ba3506eevboxsync if ( mincore( (caddr_t)addr + i, pagesize, &vec ) != -1 )
af062818b47340eef15700d2f0211576ba3506eevboxsync _exit(1);
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /* Perform the mapping with MAP_FIXED set. This is safe
af062818b47340eef15700d2f0211576ba3506eevboxsync now, as none of the pages is currently in use. */
af062818b47340eef15700d2f0211576ba3506eevboxsync result = mmap( addr, len, prot, flags | MAP_FIXED, fildes, off );
af062818b47340eef15700d2f0211576ba3506eevboxsync if ( result == addr )
af062818b47340eef15700d2f0211576ba3506eevboxsync _exit(0);
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync if ( result != (void *) -1 ) /* This should never happen ... */
af062818b47340eef15700d2f0211576ba3506eevboxsync munmap( result, len );
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync _exit(1);
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /* vfork() lets the parent continue only after the child
af062818b47340eef15700d2f0211576ba3506eevboxsync has exited. Furthermore, Wine sets SIGCHLD to SIG_IGN,
af062818b47340eef15700d2f0211576ba3506eevboxsync so we don't need to wait for the child. */
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync return result == addr;
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync#elif defined(__APPLE__)
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync#include <mach/mach_init.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync#include <mach/vm_map.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync/*
af062818b47340eef15700d2f0211576ba3506eevboxsync * On Darwin, we can use the Mach call vm_allocate to allocate
af062818b47340eef15700d2f0211576ba3506eevboxsync * anonymous memory at the specified address, and then use mmap with
af062818b47340eef15700d2f0211576ba3506eevboxsync * MAP_FIXED to replace the mapping.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic int try_mmap_fixed (void *addr, size_t len, int prot, int flags,
af062818b47340eef15700d2f0211576ba3506eevboxsync int fildes, off_t off)
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync vm_address_t result = (vm_address_t)addr;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync if (!vm_allocate(mach_task_self(),&result,len,0))
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync if (mmap( (void *)result, len, prot, flags | MAP_FIXED, fildes, off ) != MAP_FAILED)
af062818b47340eef15700d2f0211576ba3506eevboxsync return 1;
af062818b47340eef15700d2f0211576ba3506eevboxsync vm_deallocate(mach_task_self(),result,len);
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync return 0;
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync#endif /* (__svr4__ || __NetBSD__) && !MAP_TRYFIXED */
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync/***********************************************************************
af062818b47340eef15700d2f0211576ba3506eevboxsync * wine_anon_mmap
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * Portable wrapper for anonymous mmaps
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsyncvoid *wine_anon_mmap( void *start, size_t size, int prot, int flags )
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync#ifdef MAP_SHARED
af062818b47340eef15700d2f0211576ba3506eevboxsync flags &= ~MAP_SHARED;
af062818b47340eef15700d2f0211576ba3506eevboxsync#endif
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /* Linux EINVAL's on us if we don't pass MAP_PRIVATE to an anon mmap */
af062818b47340eef15700d2f0211576ba3506eevboxsync flags |= MAP_PRIVATE | MAP_ANON;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync if (!(flags & MAP_FIXED))
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
af062818b47340eef15700d2f0211576ba3506eevboxsync /* Even FreeBSD 5.3 does not properly support NULL here. */
af062818b47340eef15700d2f0211576ba3506eevboxsync if( start == NULL ) start = (void *)0x110000;
af062818b47340eef15700d2f0211576ba3506eevboxsync#endif
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync#ifdef MAP_TRYFIXED
af062818b47340eef15700d2f0211576ba3506eevboxsync /* If available, this will attempt a fixed mapping in-kernel */
af062818b47340eef15700d2f0211576ba3506eevboxsync flags |= MAP_TRYFIXED;
af062818b47340eef15700d2f0211576ba3506eevboxsync#elif defined(__svr4__) || defined(__NetBSD__) || defined(__APPLE__)
af062818b47340eef15700d2f0211576ba3506eevboxsync if ( try_mmap_fixed( start, size, prot, flags, get_fdzero(), 0 ) )
af062818b47340eef15700d2f0211576ba3506eevboxsync return start;
af062818b47340eef15700d2f0211576ba3506eevboxsync#endif
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync return mmap( start, size, prot, flags, get_fdzero(), 0 );
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync/***********************************************************************
af062818b47340eef15700d2f0211576ba3506eevboxsync * mmap_reserve
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * mmap wrapper used for reservations, only maps the specified address
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic inline int mmap_reserve( void *addr, size_t size )
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync void *ptr;
af062818b47340eef15700d2f0211576ba3506eevboxsync int flags = MAP_PRIVATE | MAP_ANON | MAP_NORESERVE;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync#ifdef MAP_TRYFIXED
af062818b47340eef15700d2f0211576ba3506eevboxsync flags |= MAP_TRYFIXED;
af062818b47340eef15700d2f0211576ba3506eevboxsync#elif defined(__APPLE__)
af062818b47340eef15700d2f0211576ba3506eevboxsync return try_mmap_fixed( addr, size, PROT_NONE, flags, get_fdzero(), 0 );
af062818b47340eef15700d2f0211576ba3506eevboxsync#endif
af062818b47340eef15700d2f0211576ba3506eevboxsync ptr = mmap( addr, size, PROT_NONE, flags, get_fdzero(), 0 );
af062818b47340eef15700d2f0211576ba3506eevboxsync if (ptr != addr && ptr != (void *)-1) munmap( ptr, size );
af062818b47340eef15700d2f0211576ba3506eevboxsync return (ptr == addr);
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync/***********************************************************************
af062818b47340eef15700d2f0211576ba3506eevboxsync * reserve_area
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * Reserve as much memory as possible in the given area.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync#ifdef __i386__
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic void reserve_area( void *addr, void *end )
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync size_t size = (char *)end - (char *)addr;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync#if (defined(__svr4__) || defined(__NetBSD__)) && !defined(MAP_TRYFIXED)
af062818b47340eef15700d2f0211576ba3506eevboxsync /* try_mmap_fixed is inefficient when using vfork, so we need a different algorithm here */
af062818b47340eef15700d2f0211576ba3506eevboxsync /* we assume no other thread is running at this point */
af062818b47340eef15700d2f0211576ba3506eevboxsync size_t i, pagesize = getpagesize();
af062818b47340eef15700d2f0211576ba3506eevboxsync char vec;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync while (size)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync for (i = 0; i < size; i += pagesize)
af062818b47340eef15700d2f0211576ba3506eevboxsync if (mincore( (caddr_t)addr + i, pagesize, &vec ) != -1) break;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync i &= ~granularity_mask;
af062818b47340eef15700d2f0211576ba3506eevboxsync if (i && mmap( addr, i, PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
af062818b47340eef15700d2f0211576ba3506eevboxsync get_fdzero(), 0 ) != (void *)-1)
af062818b47340eef15700d2f0211576ba3506eevboxsync wine_mmap_add_reserved_area( addr, i );
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync i += granularity_mask + 1;
af062818b47340eef15700d2f0211576ba3506eevboxsync if ((char *)addr + i < (char *)addr) break; /* overflow */
af062818b47340eef15700d2f0211576ba3506eevboxsync addr = (char *)addr + i;
af062818b47340eef15700d2f0211576ba3506eevboxsync if (addr >= end) break;
af062818b47340eef15700d2f0211576ba3506eevboxsync size = (char *)end - (char *)addr;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync#else
af062818b47340eef15700d2f0211576ba3506eevboxsync if (!size) return;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync if (mmap_reserve( addr, size ))
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync wine_mmap_add_reserved_area( addr, size );
af062818b47340eef15700d2f0211576ba3506eevboxsync return;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync if (size > granularity_mask + 1)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync size_t new_size = (size / 2) & ~granularity_mask;
af062818b47340eef15700d2f0211576ba3506eevboxsync reserve_area( addr, (char *)addr + new_size );
af062818b47340eef15700d2f0211576ba3506eevboxsync reserve_area( (char *)addr + new_size, end );
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync#endif
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync/***********************************************************************
af062818b47340eef15700d2f0211576ba3506eevboxsync * reserve_malloc_space
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * Solaris malloc is not smart enough to obtain space through mmap(), so try to make
af062818b47340eef15700d2f0211576ba3506eevboxsync * sure that there is some available sbrk() space before we reserve other things.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic void reserve_malloc_space( size_t size )
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync#ifdef __sun
af062818b47340eef15700d2f0211576ba3506eevboxsync size_t i, count = size / 1024;
af062818b47340eef15700d2f0211576ba3506eevboxsync void **ptrs = malloc( count * sizeof(ptrs[0]) );
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync if (!ptrs) return;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync for (i = 0; i < count; i++) if (!(ptrs[i] = malloc( 1024 ))) break;
af062818b47340eef15700d2f0211576ba3506eevboxsync if (i--) /* free everything except the last one */
af062818b47340eef15700d2f0211576ba3506eevboxsync while (i) free( ptrs[--i] );
af062818b47340eef15700d2f0211576ba3506eevboxsync free( ptrs );
af062818b47340eef15700d2f0211576ba3506eevboxsync#endif
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync#endif /* __i386__ */
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync/***********************************************************************
af062818b47340eef15700d2f0211576ba3506eevboxsync * reserve_dos_area
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * Reserve the DOS area (0x00000000-0x00110000).
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic void reserve_dos_area(void)
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync const size_t page_size = getpagesize();
af062818b47340eef15700d2f0211576ba3506eevboxsync const size_t dos_area_size = 0x110000;
af062818b47340eef15700d2f0211576ba3506eevboxsync void *ptr;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /* first page has to be handled specially */
af062818b47340eef15700d2f0211576ba3506eevboxsync ptr = wine_anon_mmap( (void *)page_size, dos_area_size - page_size, PROT_NONE, MAP_NORESERVE );
af062818b47340eef15700d2f0211576ba3506eevboxsync if (ptr != (void *)page_size)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync if (ptr != (void *)-1) munmap( ptr, dos_area_size - page_size );
af062818b47340eef15700d2f0211576ba3506eevboxsync return;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync /* now add first page with MAP_FIXED */
af062818b47340eef15700d2f0211576ba3506eevboxsync wine_anon_mmap( NULL, page_size, PROT_NONE, MAP_NORESERVE|MAP_FIXED );
af062818b47340eef15700d2f0211576ba3506eevboxsync wine_mmap_add_reserved_area( NULL, dos_area_size );
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync/***********************************************************************
af062818b47340eef15700d2f0211576ba3506eevboxsync * mmap_init
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsyncvoid mmap_init(void)
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync struct reserved_area *area;
af062818b47340eef15700d2f0211576ba3506eevboxsync struct list *ptr;
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync#ifdef __i386__
af062818b47340eef15700d2f0211576ba3506eevboxsync char stack;
af062818b47340eef15700d2f0211576ba3506eevboxsync char * const stack_ptr = &stack;
af062818b47340eef15700d2f0211576ba3506eevboxsync char *user_space_limit = (char *)0x7ffe0000;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync reserve_malloc_space( 8 * 1024 * 1024 );
af062818b47340eef15700d2f0211576ba3506eevboxsync
5112e32d7072e280613921c982a6672f2c859cf3vboxsync if (!list_head( &reserved_areas ))
5112e32d7072e280613921c982a6672f2c859cf3vboxsync {
5112e32d7072e280613921c982a6672f2c859cf3vboxsync /* if we don't have a preloader, try to reserve some space below 2Gb */
5112e32d7072e280613921c982a6672f2c859cf3vboxsync reserve_area( (void *)0x00110000, (void *)0x40000000 );
5112e32d7072e280613921c982a6672f2c859cf3vboxsync }
5112e32d7072e280613921c982a6672f2c859cf3vboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /* check for a reserved area starting at the user space limit */
af062818b47340eef15700d2f0211576ba3506eevboxsync /* to avoid wasting time trying to allocate it again */
af062818b47340eef15700d2f0211576ba3506eevboxsync LIST_FOR_EACH( ptr, &reserved_areas )
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync area = LIST_ENTRY( ptr, struct reserved_area, entry );
af062818b47340eef15700d2f0211576ba3506eevboxsync if ((char *)area->base > user_space_limit) break;
af062818b47340eef15700d2f0211576ba3506eevboxsync if ((char *)area->base + area->size > user_space_limit)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync user_space_limit = (char *)area->base + area->size;
af062818b47340eef15700d2f0211576ba3506eevboxsync break;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync if (stack_ptr >= user_space_limit)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync char *end = 0;
af062818b47340eef15700d2f0211576ba3506eevboxsync char *base = stack_ptr - ((unsigned int)stack_ptr & granularity_mask) - (granularity_mask + 1);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (base > user_space_limit) reserve_area( user_space_limit, base );
af062818b47340eef15700d2f0211576ba3506eevboxsync base = stack_ptr - ((unsigned int)stack_ptr & granularity_mask) + (granularity_mask + 1);
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync#if defined(linux) || defined(__FreeBSD__)
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync /* Heuristic: assume the stack is near the end of the address */
af062818b47340eef15700d2f0211576ba3506eevboxsync /* space, this avoids a lot of futile allocation attempts */
af062818b47340eef15700d2f0211576ba3506eevboxsync end = (char *)(((unsigned long)base + 0x0fffffff) & 0xf0000000);
af062818b47340eef15700d2f0211576ba3506eevboxsync#endif
af062818b47340eef15700d2f0211576ba3506eevboxsync reserve_area( base, end );
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync else reserve_area( user_space_limit, 0 );
af062818b47340eef15700d2f0211576ba3506eevboxsync#endif /* __i386__ */
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /* reserve the DOS area if not already done */
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync ptr = list_head( &reserved_areas );
af062818b47340eef15700d2f0211576ba3506eevboxsync if (ptr)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync area = LIST_ENTRY( ptr, struct reserved_area, entry );
af062818b47340eef15700d2f0211576ba3506eevboxsync if (!area->base) return; /* already reserved */
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync reserve_dos_area();
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync/***********************************************************************
af062818b47340eef15700d2f0211576ba3506eevboxsync * wine_mmap_add_reserved_area
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * Add an address range to the list of reserved areas.
af062818b47340eef15700d2f0211576ba3506eevboxsync * Caller must have made sure the range is not used by anything else.
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * Note: the reserved areas functions are not reentrant, caller is
af062818b47340eef15700d2f0211576ba3506eevboxsync * responsible for proper locking.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsyncvoid wine_mmap_add_reserved_area( void *addr, size_t size )
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync struct reserved_area *area;
af062818b47340eef15700d2f0211576ba3506eevboxsync struct list *ptr;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync if (!((char *)addr + size)) size--; /* avoid wrap-around */
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync LIST_FOR_EACH( ptr, &reserved_areas )
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync area = LIST_ENTRY( ptr, struct reserved_area, entry );
af062818b47340eef15700d2f0211576ba3506eevboxsync if (area->base > addr)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync /* try to merge with the next one */
af062818b47340eef15700d2f0211576ba3506eevboxsync if ((char *)addr + size == (char *)area->base)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync area->base = addr;
af062818b47340eef15700d2f0211576ba3506eevboxsync area->size += size;
af062818b47340eef15700d2f0211576ba3506eevboxsync return;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync break;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync else if ((char *)area->base + area->size == (char *)addr)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync /* merge with the previous one */
af062818b47340eef15700d2f0211576ba3506eevboxsync area->size += size;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /* try to merge with the next one too */
af062818b47340eef15700d2f0211576ba3506eevboxsync if ((ptr = list_next( &reserved_areas, ptr )))
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync struct reserved_area *next = LIST_ENTRY( ptr, struct reserved_area, entry );
af062818b47340eef15700d2f0211576ba3506eevboxsync if ((char *)addr + size == (char *)next->base)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync area->size += next->size;
af062818b47340eef15700d2f0211576ba3506eevboxsync list_remove( &next->entry );
af062818b47340eef15700d2f0211576ba3506eevboxsync free( next );
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync return;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync if ((area = malloc( sizeof(*area) )))
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync area->base = addr;
af062818b47340eef15700d2f0211576ba3506eevboxsync area->size = size;
af062818b47340eef15700d2f0211576ba3506eevboxsync list_add_before( ptr, &area->entry );
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync/***********************************************************************
af062818b47340eef15700d2f0211576ba3506eevboxsync * wine_mmap_remove_reserved_area
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * Remove an address range from the list of reserved areas.
af062818b47340eef15700d2f0211576ba3506eevboxsync * If 'unmap' is non-zero the range is unmapped too.
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * Note: the reserved areas functions are not reentrant, caller is
af062818b47340eef15700d2f0211576ba3506eevboxsync * responsible for proper locking.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsyncvoid wine_mmap_remove_reserved_area( void *addr, size_t size, int unmap )
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync struct reserved_area *area;
af062818b47340eef15700d2f0211576ba3506eevboxsync struct list *ptr;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync if (!((char *)addr + size)) size--; /* avoid wrap-around */
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync ptr = list_head( &reserved_areas );
af062818b47340eef15700d2f0211576ba3506eevboxsync /* find the first area covering address */
af062818b47340eef15700d2f0211576ba3506eevboxsync while (ptr)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync area = LIST_ENTRY( ptr, struct reserved_area, entry );
af062818b47340eef15700d2f0211576ba3506eevboxsync if ((char *)area->base >= (char *)addr + size) break; /* outside the range */
af062818b47340eef15700d2f0211576ba3506eevboxsync if ((char *)area->base + area->size > (char *)addr) /* overlaps range */
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync if (area->base >= addr)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync if ((char *)area->base + area->size > (char *)addr + size)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync /* range overlaps beginning of area only -> shrink area */
af062818b47340eef15700d2f0211576ba3506eevboxsync if (unmap) munmap( area->base, (char *)addr + size - (char *)area->base );
af062818b47340eef15700d2f0211576ba3506eevboxsync area->size -= (char *)addr + size - (char *)area->base;
af062818b47340eef15700d2f0211576ba3506eevboxsync area->base = (char *)addr + size;
af062818b47340eef15700d2f0211576ba3506eevboxsync break;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync else
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync /* range contains the whole area -> remove area completely */
af062818b47340eef15700d2f0211576ba3506eevboxsync ptr = list_next( &reserved_areas, ptr );
af062818b47340eef15700d2f0211576ba3506eevboxsync if (unmap) munmap( area->base, area->size );
af062818b47340eef15700d2f0211576ba3506eevboxsync list_remove( &area->entry );
af062818b47340eef15700d2f0211576ba3506eevboxsync free( area );
af062818b47340eef15700d2f0211576ba3506eevboxsync continue;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync else
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync if ((char *)area->base + area->size > (char *)addr + size)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync /* range is in the middle of area -> split area in two */
af062818b47340eef15700d2f0211576ba3506eevboxsync struct reserved_area *new_area = malloc( sizeof(*new_area) );
af062818b47340eef15700d2f0211576ba3506eevboxsync if (new_area)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync new_area->base = (char *)addr + size;
af062818b47340eef15700d2f0211576ba3506eevboxsync new_area->size = (char *)area->base + area->size - (char *)new_area->base;
af062818b47340eef15700d2f0211576ba3506eevboxsync list_add_after( ptr, &new_area->entry );
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync else size = (char *)area->base + area->size - (char *)addr;
af062818b47340eef15700d2f0211576ba3506eevboxsync area->size = (char *)addr - (char *)area->base;
af062818b47340eef15700d2f0211576ba3506eevboxsync if (unmap) munmap( addr, size );
af062818b47340eef15700d2f0211576ba3506eevboxsync break;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync else
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync /* range overlaps end of area only -> shrink area */
af062818b47340eef15700d2f0211576ba3506eevboxsync if (unmap) munmap( addr, (char *)area->base + area->size - (char *)addr );
af062818b47340eef15700d2f0211576ba3506eevboxsync area->size = (char *)addr - (char *)area->base;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync ptr = list_next( &reserved_areas, ptr );
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync/***********************************************************************
af062818b47340eef15700d2f0211576ba3506eevboxsync * wine_mmap_is_in_reserved_area
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * Check if the specified range is included in a reserved area.
af062818b47340eef15700d2f0211576ba3506eevboxsync * Returns 1 if range is fully included, 0 if range is not included
af062818b47340eef15700d2f0211576ba3506eevboxsync * at all, and -1 if it is only partially included.
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * Note: the reserved areas functions are not reentrant, caller is
af062818b47340eef15700d2f0211576ba3506eevboxsync * responsible for proper locking.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsyncint wine_mmap_is_in_reserved_area( void *addr, size_t size )
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync struct reserved_area *area;
af062818b47340eef15700d2f0211576ba3506eevboxsync struct list *ptr;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync LIST_FOR_EACH( ptr, &reserved_areas )
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync area = LIST_ENTRY( ptr, struct reserved_area, entry );
af062818b47340eef15700d2f0211576ba3506eevboxsync if (area->base > addr) break;
af062818b47340eef15700d2f0211576ba3506eevboxsync if ((char *)area->base + area->size <= (char *)addr) continue;
af062818b47340eef15700d2f0211576ba3506eevboxsync /* area must contain block completely */
af062818b47340eef15700d2f0211576ba3506eevboxsync if ((char *)area->base + area->size < (char *)addr + size) return -1;
af062818b47340eef15700d2f0211576ba3506eevboxsync return 1;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync return 0;
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync/***********************************************************************
af062818b47340eef15700d2f0211576ba3506eevboxsync * wine_mmap_enum_reserved_areas
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * Enumerate the list of reserved areas, sorted by addresses.
af062818b47340eef15700d2f0211576ba3506eevboxsync * If enum_func returns a non-zero value, enumeration is stopped and the value is returned.
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * Note: the reserved areas functions are not reentrant, caller is
af062818b47340eef15700d2f0211576ba3506eevboxsync * responsible for proper locking.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsyncint wine_mmap_enum_reserved_areas( int (*enum_func)(void *base, size_t size, void *arg), void *arg,
af062818b47340eef15700d2f0211576ba3506eevboxsync int top_down )
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync int ret = 0;
af062818b47340eef15700d2f0211576ba3506eevboxsync struct list *ptr;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync if (top_down)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync for (ptr = reserved_areas.prev; ptr != &reserved_areas; ptr = ptr->prev)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync struct reserved_area *area = LIST_ENTRY( ptr, struct reserved_area, entry );
af062818b47340eef15700d2f0211576ba3506eevboxsync if ((ret = enum_func( area->base, area->size, arg ))) break;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync else
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync for (ptr = reserved_areas.next; ptr != &reserved_areas; ptr = ptr->next)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync struct reserved_area *area = LIST_ENTRY( ptr, struct reserved_area, entry );
af062818b47340eef15700d2f0211576ba3506eevboxsync if ((ret = enum_func( area->base, area->size, arg ))) break;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync return ret;
af062818b47340eef15700d2f0211576ba3506eevboxsync}
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync#else /* HAVE_MMAP */
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsyncvoid mmap_init(void)
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync{
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync}
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync#endif