Commit dce10401 authored by Meador Inge's avatar Meador Inge Committed by Peter Maydell
Browse files

linux-user: Factor out guest space probing into a function

parent cd8e407d
Loading
Loading
Loading
Loading
+77 −33
Original line number Diff line number Diff line
@@ -1426,6 +1426,73 @@ bool guest_validate_base(unsigned long guest_base)
}
#endif

unsigned long init_guest_space(unsigned long host_start,
                               unsigned long host_size,
                               unsigned long guest_start,
                               bool fixed)
{
    unsigned long current_start, real_start;
    int flags;

    assert(host_start || host_size);

    /* If just a starting address is given, then just verify that
     * address.  */
    if (host_start && !host_size) {
        if (guest_validate_base(host_start)) {
            return host_start;
        } else {
            return (unsigned long)-1;
        }
    }

    /* Setup the initial flags and start address.  */
    current_start = host_start & qemu_host_page_mask;
    flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE;
    if (fixed) {
        flags |= MAP_FIXED;
    }

    /* Otherwise, a non-zero size region of memory needs to be mapped
     * and validated.  */
    while (1) {
        /* Do not use mmap_find_vma here because that is limited to the
         * guest address space.  We are going to make the
         * guest address space fit whatever we're given.
         */
        real_start = (unsigned long)
            mmap((void *)current_start, host_size, PROT_NONE, flags, -1, 0);
        if (real_start == (unsigned long)-1) {
            return (unsigned long)-1;
        }

        if ((real_start == current_start)
            && guest_validate_base(real_start - guest_start)) {
            break;
        }

        /* That address didn't work.  Unmap and try a different one.
         * The address the host picked because is typically right at
         * the top of the host address space and leaves the guest with
         * no usable address space.  Resort to a linear search.  We
         * already compensated for mmap_min_addr, so this should not
         * happen often.  Probably means we got unlucky and host
         * address space randomization put a shared library somewhere
         * inconvenient.
         */
        munmap((void *)real_start, host_size);
        current_start += qemu_host_page_size;
        if (host_start == current_start) {
            /* Theoretically possible if host doesn't have any suitably
             * aligned areas.  Normally the first mmap will fail.
             */
            return (unsigned long)-1;
        }
    }

    return real_start;
}

static void probe_guest_base(const char *image_name,
                             abi_ulong loaddr, abi_ulong hiaddr)
{
@@ -1452,46 +1519,23 @@ static void probe_guest_base(const char *image_name,
            }
        }
        host_size = hiaddr - loaddr;
        while (1) {
            /* Do not use mmap_find_vma here because that is limited to the
               guest address space.  We are going to make the
               guest address space fit whatever we're given.  */
            real_start = (unsigned long)
                mmap((void *)host_start, host_size, PROT_NONE,
                     MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, -1, 0);

        /* Setup the initial guest memory space with ranges gleaned from
         * the ELF image that is being loaded.
         */
        real_start = init_guest_space(host_start, host_size, loaddr, false);
        if (real_start == (unsigned long)-1) {
                goto exit_perror;
            }
            guest_base = real_start - loaddr;
            if ((real_start == host_start) &&
                guest_validate_base(guest_base)) {
                break;
            }
            /* That address didn't work.  Unmap and try a different one.
               The address the host picked because is typically right at
               the top of the host address space and leaves the guest with
               no usable address space.  Resort to a linear search.  We
               already compensated for mmap_min_addr, so this should not
               happen often.  Probably means we got unlucky and host
               address space randomization put a shared library somewhere
               inconvenient.  */
            munmap((void *)real_start, host_size);
            host_start += qemu_host_page_size;
            if (host_start == loaddr) {
                /* Theoretically possible if host doesn't have any suitably
                   aligned areas.  Normally the first mmap will fail.  */
            errmsg = "Unable to find space for application";
            goto exit_errmsg;
        }
        }
        guest_base = real_start - loaddr;

        qemu_log("Relocating guest address space from 0x"
                 TARGET_ABI_FMT_lx " to 0x%lx\n",
                 loaddr, real_start);
    }
    return;

exit_perror:
    errmsg = strerror(errno);
exit_errmsg:
    fprintf(stderr, "%s: %s\n", image_name, errmsg);
    exit(-1);
+13 −0
Original line number Diff line number Diff line
@@ -210,6 +210,19 @@ void fork_end(int child);
 */
bool guest_validate_base(unsigned long guest_base);

/* Creates the initial guest address space in the host memory space using
 * the given host start address hint and size.  The guest_start parameter
 * specifies the start address of the guest space.  guest_base will be the
 * difference between the host start address computed by this function and
 * guest_start.  If fixed is specified, then the mapped address space must
 * start at host_start.  The real start address of the mapped memory space is
 * returned or -1 if there was an error.
 */
unsigned long init_guest_space(unsigned long host_start,
                               unsigned long host_size,
                               unsigned long guest_start,
                               bool fixed);

#include "qemu-log.h"

/* strace.c */