#if defined(CONFIG_USE_NPTL)
static pthread_mutex_t mmap_mutex = PTHREAD_MUTEX_INITIALIZER;
-static int __thread mmap_lock_count;
+static __thread int mmap_lock_count;
void mmap_lock(void)
{
void *qemu_vmalloc(size_t size)
{
void *p;
- unsigned long addr;
+
mmap_lock();
/* Use map and mark the pages as used. */
p = mmap(NULL, size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- addr = (unsigned long)p;
- if (addr == (target_ulong) addr) {
- /* Allocated region overlaps guest address space.
- This may recurse. */
+ if (h2g_valid(p)) {
+ /* Allocated region overlaps guest address space. This may recurse. */
+ abi_ulong addr = h2g(p);
page_set_flags(addr & TARGET_PAGE_MASK, TARGET_PAGE_ALIGN(addr + size),
PAGE_RESERVED);
}
possible while it is a shared mapping */
if ((flags & MAP_TYPE) == MAP_SHARED &&
(prot & PROT_WRITE))
- return -EINVAL;
+ return -1;
/* adjust protection to be able to read */
if (!(prot1 & PROT_WRITE))
mprotect(host_start, qemu_host_page_size, prot1 | PROT_WRITE);
/* read the corresponding file data */
- pread(fd, g2h(start), end - start, offset);
+ if (pread(fd, g2h(start), end - start, offset) == -1)
+ return -1;
/* put final protection */
if (prot_new != (prot1 | PROT_WRITE))
return 0;
}
-#if defined(__CYGWIN__)
+#if HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 64
+# define TASK_UNMAPPED_BASE (1ul << 38)
+#elif defined(__CYGWIN__)
/* Cygwin doesn't have a whole lot of address space. */
-static abi_ulong mmap_next_start = 0x18000000;
+# define TASK_UNMAPPED_BASE 0x18000000
#else
-static abi_ulong mmap_next_start = 0x40000000;
+# define TASK_UNMAPPED_BASE 0x40000000
#endif
+static abi_ulong mmap_next_start = TASK_UNMAPPED_BASE;
unsigned long last_brk;
*/
abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
{
- void *ptr;
+ void *ptr, *prev;
abi_ulong addr;
-
- size = HOST_PAGE_ALIGN(size);
- start &= qemu_host_page_mask;
+ int wrapped, repeat;
/* If 'start' == 0, then a default start address is used. */
- if (start == 0)
+ if (start == 0) {
start = mmap_next_start;
+ } else {
+ start &= qemu_host_page_mask;
+ }
+
+ size = HOST_PAGE_ALIGN(size);
addr = start;
+ wrapped = repeat = 0;
+ prev = 0;
- for(;;) {
+ for (;; prev = ptr) {
/*
* Reserve needed memory area to avoid a race.
* It should be discarded using:
* - mremap() with MREMAP_FIXED flag
* - shmat() with SHM_REMAP flag
*/
- ptr = mmap((void *)(unsigned long)addr, size, PROT_NONE,
+ ptr = mmap(g2h(addr), size, PROT_NONE,
MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0);
/* ENOMEM, if host address space has no memory */
- if (ptr == MAP_FAILED)
+ if (ptr == MAP_FAILED) {
return (abi_ulong)-1;
+ }
- /* If address fits target address space we've found what we need */
- if ((unsigned long)ptr + size - 1 <= (abi_ulong)-1)
- break;
+ /* Count the number of sequential returns of the same address.
+ This is used to modify the search algorithm below. */
+ repeat = (ptr == prev ? repeat + 1 : 0);
+
+ if (h2g_valid(ptr + size - 1)) {
+ addr = h2g(ptr);
- /* Unmap and try again with new page */
+ if ((addr & ~TARGET_PAGE_MASK) == 0) {
+ /* Success. */
+ if (start == mmap_next_start && addr >= TASK_UNMAPPED_BASE) {
+ mmap_next_start = addr + size;
+ }
+ return addr;
+ }
+
+ /* The address is not properly aligned for the target. */
+ switch (repeat) {
+ case 0:
+ /* Assume the result that the kernel gave us is the
+ first with enough free space, so start again at the
+ next higher target page. */
+ addr = TARGET_PAGE_ALIGN(addr);
+ break;
+ case 1:
+ /* Sometimes the kernel decides to perform the allocation
+ at the top end of memory instead. */
+ addr &= TARGET_PAGE_MASK;
+ break;
+ case 2:
+ /* Start over at low memory. */
+ addr = 0;
+ break;
+ default:
+ /* Fail. This unaligned block must the last. */
+ addr = -1;
+ break;
+ }
+ } else {
+ /* Since the result the kernel gave didn't fit, start
+ again at low memory. If any repetition, fail. */
+ addr = (repeat ? -1 : 0);
+ }
+
+ /* Unmap and try again. */
munmap(ptr, size);
- addr += qemu_host_page_size;
- /* ENOMEM if we check whole of target address space */
- if (addr == start)
+ /* ENOMEM if we checked the whole of the target address space. */
+ if (addr == -1ul) {
return (abi_ulong)-1;
+ } else if (addr == 0) {
+ if (wrapped) {
+ return (abi_ulong)-1;
+ }
+ wrapped = 1;
+ /* Don't actually use 0 when wrapping, instead indicate
+ that we'd truely like an allocation in low memory. */
+ addr = (mmap_min_addr > TARGET_PAGE_SIZE
+ ? TARGET_PAGE_ALIGN(mmap_min_addr)
+ : TARGET_PAGE_SIZE);
+ } else if (wrapped && addr >= start) {
+ return (abi_ulong)-1;
+ }
}
-
- /* Update default start address */
- if (start == mmap_next_start)
- mmap_next_start = (unsigned long)ptr + size;
-
- return h2g(ptr);
}
/* NOTE: all the constants are the HOST ones */
-1, 0);
if (retaddr == -1)
goto fail;
- pread(fd, g2h(start), len, offset);
+ if (pread(fd, g2h(start), len, offset) == -1)
+ goto fail;
if (!(prot & PROT_WRITE)) {
ret = target_mprotect(start, len, prot);
if (ret != 0) {