diff options
author | Peter Maydell | 2018-03-15 18:58:28 +0100 |
---|---|---|
committer | Peter Maydell | 2018-03-15 18:58:28 +0100 |
commit | 55901900ec69d6fd6f332003d8ab81b2f8a38529 (patch) | |
tree | 521ebc5c3532447b8669b7b673274ee2c0c9d425 /linux-user/elfload.c | |
parent | Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream-sev' into sta... (diff) | |
parent | linux-user: init_guest_space: Add a comment about search strategy (diff) | |
download | qemu-55901900ec69d6fd6f332003d8ab81b2f8a38529.tar.gz qemu-55901900ec69d6fd6f332003d8ab81b2f8a38529.tar.xz qemu-55901900ec69d6fd6f332003d8ab81b2f8a38529.zip |
Merge remote-tracking branch 'remotes/vivier2/tags/linux-user-for-2.12-pull-request' into staging
# gpg: Signature made Tue 13 Mar 2018 17:33:03 GMT
# gpg: using RSA key F30C38BD3F2FBE3C
# gpg: Good signature from "Laurent Vivier <lvivier@redhat.com>"
# gpg: aka "Laurent Vivier <laurent@vivier.eu>"
# gpg: aka "Laurent Vivier (Red Hat) <lvivier@redhat.com>"
# Primary key fingerprint: CD2F 75DD C8E3 A4DC 2E4F 5173 F30C 38BD 3F2F BE3C
* remotes/vivier2/tags/linux-user-for-2.12-pull-request:
linux-user: init_guest_space: Add a comment about search strategy
linux-user: init_guest_space: Don't try to align if we'll reject it
linux-user: init_guest_space: Clean up control flow a bit
linux-user: init_guest_commpage: Add a comment about size check
linux-user: init_guest_space: Clarify page alignment logic
linux-user: init_guest_space: Correctly handle guest_start in commpage initialization
linux-user: init_guest_space: Clean up if we can't initialize the commpage
linux-user: Rename validate_guest_space => init_guest_commpage
linux-user: Use #if to only call validate_guest_space for 32-bit ARM target
qemu-binfmt-conf.sh: add qemu-xtensa
linux-user: drop unused target_msync function
linux-user: fix target_mprotect/target_munmap error return values
linux-user: fix assertion in shmdt
linux-user: fix mmap/munmap/mprotect/mremap/shmat
linux-user: Support f_flags in statfs when available.
linux-user: allows to use "--systemd ALL" with qemu-binfmt-conf.sh
linux-user: Remove the unused "not implemented" signal handling stubs
linux-user: Drop unicore32 code
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'linux-user/elfload.c')
-rw-r--r-- | linux-user/elfload.c | 168 |
1 files changed, 65 insertions, 103 deletions
diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 5fc130cc20..9d10a5f592 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -354,7 +354,6 @@ enum { /* The commpage only exists for 32 bit kernels */ -#define TARGET_HAS_VALIDATE_GUEST_SPACE /* Return 1 if the proposed guest space is suitable for the guest. * Return 0 if the proposed guest space isn't suitable, but another * address space should be tried. @@ -363,8 +362,8 @@ enum { * The guest code may leave a page mapped and populate it if the * address is suitable. */ -static int validate_guest_space(unsigned long guest_base, - unsigned long guest_size) +static int init_guest_commpage(unsigned long guest_base, + unsigned long guest_size) { unsigned long real_start, test_page_addr; @@ -375,6 +374,11 @@ static int validate_guest_space(unsigned long guest_base, /* If the commpage lies within the already allocated guest space, * then there is no way we can allocate it. + * + * You may be thinking that that this check is redundant because + * we already validated the guest size against MAX_RESERVED_VA; + * but if qemu_host_page_mask is unusually large, then + * test_page_addr may be lower. */ if (test_page_addr >= guest_base && test_page_addr < (guest_base + guest_size)) { @@ -563,78 +567,6 @@ static uint32_t get_elf_hwcap(void) #endif /* not TARGET_AARCH64 */ #endif /* TARGET_ARM */ -#ifdef TARGET_UNICORE32 - -#define ELF_START_MMAP 0x80000000 - -#define ELF_CLASS ELFCLASS32 -#define ELF_DATA ELFDATA2LSB -#define ELF_ARCH EM_UNICORE32 - -static inline void init_thread(struct target_pt_regs *regs, - struct image_info *infop) -{ - abi_long stack = infop->start_stack; - memset(regs, 0, sizeof(*regs)); - regs->UC32_REG_asr = 0x10; - regs->UC32_REG_pc = infop->entry & 0xfffffffe; - regs->UC32_REG_sp = infop->start_stack; - /* FIXME - what to for failure of get_user()? */ - get_user_ual(regs->UC32_REG_02, stack + 8); /* envp */ - get_user_ual(regs->UC32_REG_01, stack + 4); /* envp */ - /* XXX: it seems that r0 is zeroed after ! */ - regs->UC32_REG_00 = 0; -} - -#define ELF_NREG 34 -typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG]; - -static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUUniCore32State *env) -{ - (*regs)[0] = env->regs[0]; - (*regs)[1] = env->regs[1]; - (*regs)[2] = env->regs[2]; - (*regs)[3] = env->regs[3]; - (*regs)[4] = env->regs[4]; - (*regs)[5] = env->regs[5]; - (*regs)[6] = env->regs[6]; - (*regs)[7] = env->regs[7]; - (*regs)[8] = env->regs[8]; - (*regs)[9] = env->regs[9]; - (*regs)[10] = env->regs[10]; - (*regs)[11] = env->regs[11]; - (*regs)[12] = env->regs[12]; - (*regs)[13] = env->regs[13]; - (*regs)[14] = env->regs[14]; - (*regs)[15] = env->regs[15]; - (*regs)[16] = env->regs[16]; - (*regs)[17] = env->regs[17]; - (*regs)[18] = env->regs[18]; - (*regs)[19] = env->regs[19]; - (*regs)[20] = env->regs[20]; - (*regs)[21] = env->regs[21]; - (*regs)[22] = env->regs[22]; - (*regs)[23] = env->regs[23]; - (*regs)[24] = env->regs[24]; - (*regs)[25] = env->regs[25]; - (*regs)[26] = env->regs[26]; - (*regs)[27] = env->regs[27]; - (*regs)[28] = env->regs[28]; - (*regs)[29] = env->regs[29]; - (*regs)[30] = env->regs[30]; - (*regs)[31] = env->regs[31]; - - (*regs)[32] = cpu_asr_read((CPUUniCore32State *)env); - (*regs)[33] = env->regs[0]; /* XXX */ -} - -#define USE_ELF_CORE_DUMP -#define ELF_EXEC_PAGESIZE 4096 - -#define ELF_HWCAP (UC32_HWCAP_CMOV | UC32_HWCAP_UCF64) - -#endif - #ifdef TARGET_SPARC #ifdef TARGET_SPARC64 @@ -1869,21 +1801,12 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, return sp; } -#ifndef TARGET_HAS_VALIDATE_GUEST_SPACE -/* If the guest doesn't have a validation function just agree */ -static int validate_guest_space(unsigned long guest_base, - unsigned long guest_size) -{ - return 1; -} -#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; + unsigned long current_start, aligned_start; int flags; assert(host_start || host_size); @@ -1891,11 +1814,12 @@ unsigned long init_guest_space(unsigned long host_start, /* If just a starting address is given, then just verify that * address. */ if (host_start && !host_size) { - if (validate_guest_space(host_start, host_size) == 1) { - return host_start; - } else { +#if defined(TARGET_ARM) && !defined(TARGET_AARCH64) + if (init_guest_commpage(host_start, host_size) != 1) { return (unsigned long)-1; } +#endif + return host_start; } /* Setup the initial flags and start address. */ @@ -1908,7 +1832,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 @@ -1920,30 +1845,63 @@ unsigned long init_guest_space(unsigned long host_start, return (unsigned long)-1; } + /* Check to see if the address is valid. */ + if (host_start && real_start != current_start) { + goto try_again; + } + /* 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) { - int valid = validate_guest_space(real_start - guest_start, - real_size); - if (valid == 1) { - break; - } else if (valid == -1) { - return (unsigned long)-1; - } - /* valid == 0, so try again. */ +#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(aligned_start - guest_start, + aligned_size + guest_start); + if (valid == -1) { + munmap((void *)real_start, real_size); + return (unsigned long)-1; + } else if (valid == 0) { + goto try_again; } +#endif + + /* If nothing has said `return -1` or `goto try_again` yet, + * then the address we have is good. + */ + break; + try_again: /* 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 @@ -1952,8 +1910,12 @@ unsigned long init_guest_space(unsigned long host_start, * happen often. Probably means we got unlucky and host * address space randomization put a shared library somewhere * inconvenient. + * + * This is probably a good strategy if host_start, but is + * probably a bad strategy if not, which means we got here + * because of trouble with ARM commpage setup. */ - 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 @@ -1965,7 +1927,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, |