diff options
author | Luke Shumaker <lukeshu@parabola.nu> | 2017-12-28 13:08:08 -0500 |
---|---|---|
committer | Laurent Vivier <laurent@vivier.eu> | 2018-03-09 21:29:24 +0100 |
commit | 293f20600896d18c05880fb003f08d281b3156cb (patch) | |
tree | 629b6bfbf71614459b670e54d245ac740598f714 /linux-user/elfload.c | |
parent | e7ea02e62a37ea94a2ee6cc99e7c682ef0e61e9f (diff) |
linux-user: init_guest_space: Clarify page alignment logic
There are 3 parts to this change:
- Add a comment showing the relative sizes and positions of the blocks of
memory
- introduce and use new aligned_{start,size} instead of adjusting
real_{start_size}
- When we clean up (on failure), munmap(real_start, real_size) instead of
munmap(aligned_start, aligned_size). It *shouldn't* make any
difference, but I will admit that this does mean we are making the
syscall with different values, so this isn't quite a no-op patch.
Signed-off-by: Luke Shumaker <lukeshu@parabola.nu>
Message-Id: <20171228180814.9749-6-lukeshu@lukeshu.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
Diffstat (limited to 'linux-user/elfload.c')
-rw-r--r-- | linux-user/elfload.c | 43 |
1 files changed, 33 insertions, 10 deletions
diff --git a/linux-user/elfload.c b/linux-user/elfload.c index feecbd4163..653157876c 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1801,7 +1801,7 @@ unsigned long init_guest_space(unsigned long host_start, unsigned long guest_start, bool fixed) { - unsigned long current_start, real_start; + unsigned long current_start, aligned_start; int flags; assert(host_start || host_size); @@ -1827,7 +1827,8 @@ unsigned long init_guest_space(unsigned long host_start, /* Otherwise, a non-zero size region of memory needs to be mapped * and validated. */ while (1) { - unsigned long real_size = host_size; + unsigned long real_start, real_size, aligned_size; + aligned_size = real_size = host_size; /* Do not use mmap_find_vma here because that is limited to the * guest address space. We are going to make the @@ -1841,26 +1842,48 @@ unsigned long init_guest_space(unsigned long host_start, /* Ensure the address is properly aligned. */ if (real_start & ~qemu_host_page_mask) { + /* Ideally, we adjust like + * + * pages: [ ][ ][ ][ ][ ] + * old: [ real ] + * [ aligned ] + * new: [ real ] + * [ aligned ] + * + * But if there is something else mapped right after it, + * then obviously it won't have room to grow, and the + * kernel will put the new larger real someplace else with + * unknown alignment (if we made it to here, then + * fixed=false). Which is why we grow real by a full page + * size, instead of by part of one; so that even if we get + * moved, we can still guarantee alignment. But this does + * mean that there is a padding of < 1 page both before + * and after the aligned range; the "after" could could + * cause problems for ARM emulation where it could butt in + * to where we need to put the commpage. + */ munmap((void *)real_start, host_size); - real_size = host_size + qemu_host_page_size; + real_size = aligned_size + qemu_host_page_size; real_start = (unsigned long) mmap((void *)real_start, real_size, PROT_NONE, flags, -1, 0); if (real_start == (unsigned long)-1) { return (unsigned long)-1; } - real_start = HOST_PAGE_ALIGN(real_start); + aligned_start = HOST_PAGE_ALIGN(real_start); + } else { + aligned_start = real_start; } /* Check to see if the address is valid. */ - if (!host_start || real_start == current_start) { + if (!host_start || aligned_start == current_start) { #if defined(TARGET_ARM) && !defined(TARGET_AARCH64) /* On 32-bit ARM, we need to also be able to map the commpage. */ - int valid = init_guest_commpage(real_start - guest_start, - real_size + guest_start); + int valid = init_guest_commpage(aligned_start - guest_start, + aligned_size + guest_start); if (valid == 1) { break; } else if (valid == -1) { - munmap((void *)real_start, host_size); + munmap((void *)real_start, real_size); return (unsigned long)-1; } /* valid == 0, so try again. */ @@ -1879,7 +1902,7 @@ unsigned long init_guest_space(unsigned long host_start, * address space randomization put a shared library somewhere * inconvenient. */ - munmap((void *)real_start, host_size); + munmap((void *)real_start, real_size); current_start += qemu_host_page_size; if (host_start == current_start) { /* Theoretically possible if host doesn't have any suitably @@ -1891,7 +1914,7 @@ unsigned long init_guest_space(unsigned long host_start, qemu_log_mask(CPU_LOG_PAGE, "Reserved 0x%lx bytes of guest address space\n", host_size); - return real_start; + return aligned_start; } static void probe_guest_base(const char *image_name, |