From 11d3672788b48548811810bdc0f3f7969662572d Mon Sep 17 00:00:00 2001 From: Alex Bennée Date: Thu, 13 Jan 2022 16:55:50 +0000 Subject: linux-user: expand reserved brk space for 64bit guests A recent change to fix commpage allocation issues on 32bit hosts revealed another intermittent issue on s390x. The root cause was the headroom we give for the brk space wasn't enough causing the guest to attempt to map something on top of QEMUs own pages. We do not currently do anything to protect from this (see #555). By inspection the brk mmap moves around and top of the address range has been measured as far as 19Mb away from the top of the binary. As we chose a smallish number to keep 32bit on 32 bit feasible we only increase the gap for 64 bit guests. This does mean that 64-on-32 static binaries are more likely to fail to find a hole in the address space but that is hopefully a fairly rare situation. Signed-off-by: Alex Bennée Reviewed-by: Thomas Huth Message-Id: <20220113165550.4184455-1-alex.bennee@linaro.org> --- linux-user/elfload.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'linux-user') diff --git a/linux-user/elfload.c b/linux-user/elfload.c index d3274edfdb..fc23a6dcf6 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -2783,11 +2783,17 @@ static void load_elf_image(const char *image_name, int image_fd, * and the stack, lest they be placed immediately after * the data segment and block allocation from the brk. * - * 16MB is chosen as "large enough" without being so large - * as to allow the result to not fit with a 32-bit guest on - * a 32-bit host. + * 16MB is chosen as "large enough" without being so large as + * to allow the result to not fit with a 32-bit guest on a + * 32-bit host. However some 64 bit guests (e.g. s390x) + * attempt to place their heap further ahead and currently + * nothing stops them smashing into QEMUs address space. */ +#if TARGET_LONG_BITS == 64 + info->reserve_brk = 32 * MiB; +#else info->reserve_brk = 16 * MiB; +#endif hiaddr += info->reserve_brk; if (ehdr->e_type == ET_EXEC) { -- cgit v1.2.3-55-g7522 From e7588237ce8f8115b5ad9a3ecdd46f60d95a461a Mon Sep 17 00:00:00 2001 From: Alex Bennée Date: Wed, 5 Jan 2022 13:50:00 +0000 Subject: linux-user/elfload: add extra logging for hole finding The various approaches to finding memory holes are quite complicated to follow especially at a distance. Improve the logging so we can see exactly what method found the space for the guest memory. Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Warner Losh Message-Id: <20220105135009.1584676-26-alex.bennee@linaro.org> --- linux-user/elfload.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'linux-user') diff --git a/linux-user/elfload.c b/linux-user/elfload.c index fc23a6dcf6..30dbb005c2 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -2267,6 +2267,9 @@ static void pgb_have_guest_base(const char *image_name, abi_ulong guest_loaddr, if (test != addr) { pgb_fail_in_use(image_name); } + qemu_log_mask(CPU_LOG_PAGE, + "%s: base @ %p for " TARGET_ABI_FMT_ld " bytes\n", + __func__, addr, guest_hiaddr - guest_loaddr); } /** @@ -2309,6 +2312,9 @@ static uintptr_t pgd_find_hole_fallback(uintptr_t guest_size, uintptr_t brk, if (mmap_start != MAP_FAILED) { munmap(mmap_start, guest_size); if (mmap_start == (void *) align_start) { + qemu_log_mask(CPU_LOG_PAGE, + "%s: base @ %p for %" PRIdPTR" bytes\n", + __func__, mmap_start + offset, guest_size); return (uintptr_t) mmap_start + offset; } } @@ -2388,6 +2394,12 @@ static uintptr_t pgb_find_hole(uintptr_t guest_loaddr, uintptr_t guest_size, } free_self_maps(maps); + if (ret != -1) { + qemu_log_mask(CPU_LOG_PAGE, "%s: base @ %" PRIxPTR + " for %" PRIuPTR " bytes\n", + __func__, ret, guest_size); + } + return ret; } @@ -2439,6 +2451,9 @@ static void pgb_static(const char *image_name, abi_ulong orig_loaddr, } guest_base = addr; + + qemu_log_mask(CPU_LOG_PAGE, "%s: base @ %"PRIxPTR" for %" PRIuPTR" bytes\n", + __func__, addr, hiaddr - loaddr); } static void pgb_dynamic(const char *image_name, long align) @@ -2495,6 +2510,9 @@ static void pgb_reserved_va(const char *image_name, abi_ulong guest_loaddr, "using -R option)", reserved_va, test, strerror(errno)); exit(EXIT_FAILURE); } + + qemu_log_mask(CPU_LOG_PAGE, "%s: base @ %p for %lu bytes\n", + __func__, addr, reserved_va); } void probe_guest_base(const char *image_name, abi_ulong guest_loaddr, -- cgit v1.2.3-55-g7522 From 190674f3719d7a26387715952312f6397cddfaaf Mon Sep 17 00:00:00 2001 From: Alex Bennée Date: Wed, 5 Jan 2022 13:50:01 +0000 Subject: linux-user: don't adjust base of found hole The pgb_find_hole function goes to the trouble of taking account of both mmap_min_addr and any offset we've applied to decide the starting address of a potential hole. This is especially important for emulating 32bit ARM in a 32bit build as we have applied the offset to ensure there will be space to map the ARM_COMMPAGE bellow the main guest map (using wrapped arithmetic). Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Resolves: https://gitlab.com/qemu-project/qemu/-/issues/690 Message-Id: <20220105135009.1584676-27-alex.bennee@linaro.org> --- linux-user/elfload.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'linux-user') diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 30dbb005c2..99829faf89 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -2339,8 +2339,7 @@ static uintptr_t pgb_find_hole(uintptr_t guest_loaddr, uintptr_t guest_size, brk = (uintptr_t)sbrk(0); if (!maps) { - ret = pgd_find_hole_fallback(guest_size, brk, align, offset); - return ret == -1 ? -1 : ret - guest_loaddr; + return pgd_find_hole_fallback(guest_size, brk, align, offset); } /* The first hole is before the first map entry. */ @@ -2380,7 +2379,7 @@ static uintptr_t pgb_find_hole(uintptr_t guest_loaddr, uintptr_t guest_size, /* Record the lowest successful match. */ if (ret < 0) { - ret = align_start - guest_loaddr; + ret = align_start; } /* If this hole contains the identity map, select it. */ if (align_start <= guest_loaddr && -- cgit v1.2.3-55-g7522