|
@@ -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);
|
|
|
- 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;
|
|
|
- }
|
|
|
+
|
|
|
+ /* 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) {
|
|
|
+ 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);
|