diff options
author | Peter Maydell | 2017-01-24 10:52:42 +0100 |
---|---|---|
committer | Peter Maydell | 2017-01-24 10:52:42 +0100 |
commit | 48cef39bf39846ce4aaf79d4a2ae620373b3e181 (patch) | |
tree | 5056fc7d5e943cdcd552a7121446fb087e0f9948 /linux-user/elfload.c | |
parent | Merge remote-tracking branch 'remotes/berrange/tags/pull-qio-2017-01-23-2' in... (diff) | |
parent | target-hppa: Implement floating-point insns (diff) | |
download | qemu-48cef39bf39846ce4aaf79d4a2ae620373b3e181.tar.gz qemu-48cef39bf39846ce4aaf79d4a2ae620373b3e181.tar.xz qemu-48cef39bf39846ce4aaf79d4a2ae620373b3e181.zip |
Merge remote-tracking branch 'remotes/rth/tags/pull-hppa-20170123' into staging
hppa-linux target support
# gpg: Signature made Mon 23 Jan 2017 17:54:09 GMT
# gpg: using RSA key 0xAD1270CC4DD0279B
# gpg: Good signature from "Richard Henderson <rth7680@gmail.com>"
# gpg: aka "Richard Henderson <rth@redhat.com>"
# gpg: aka "Richard Henderson <rth@twiddle.net>"
# Primary key fingerprint: 9CB1 8DDA F8E8 49AD 2AFC 16A4 AD12 70CC 4DD0 279B
* remotes/rth/tags/pull-hppa-20170123: (25 commits)
target-hppa: Implement floating-point insns
target-hppa: Implement system and memory-management insns
target-hppa: Implement loads and stores
target-hppa: Implement shifts and deposits
target-hppa: Implement linux-user gateway page
target-hppa: Implement branches
target-hppa: Implement basic arithmetic
target-hppa: Add nullification framework
target-hppa: Add framework and enable compilation
target-hppa: Add softfloat specializations
linux-user: Add HPPA startup and main loop
linux-user: Add HPPA signal handling
linux-user: Add HPPA target_signal.h and target_cpu.h
linux-user: Add HPPA target_structs.h
linux-user: Add HPPA definitions to syscall_defs.h
linux-user: Add HPPA target_syscall.h
linux-user: Add HPPA termbits.h
linux-user: Add HPPA syscall numbers
linux-user: Add HPPA socket.h definitions
linux-user: Add some hppa ioctls
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'linux-user/elfload.c')
-rw-r--r-- | linux-user/elfload.c | 259 |
1 files changed, 194 insertions, 65 deletions
diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 547053c27a..51794bbb45 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1215,6 +1215,30 @@ static inline void init_thread(struct target_pt_regs *regs, #endif /* TARGET_TILEGX */ +#ifdef TARGET_HPPA + +#define ELF_START_MMAP 0x80000000 +#define ELF_CLASS ELFCLASS32 +#define ELF_ARCH EM_PARISC +#define ELF_PLATFORM "PARISC" +#define STACK_GROWS_DOWN 0 +#define STACK_ALIGNMENT 64 + +static inline void init_thread(struct target_pt_regs *regs, + struct image_info *infop) +{ + regs->iaoq[0] = infop->entry; + regs->iaoq[1] = infop->entry + 4; + regs->gr[23] = 0; + regs->gr[24] = infop->arg_start; + regs->gr[25] = (infop->arg_end - infop->arg_start) / sizeof(abi_ulong); + /* The top-of-stack contains a linkage buffer. */ + regs->gr[30] = infop->start_stack + 64; + regs->gr[31] = infop->entry; +} + +#endif /* TARGET_HPPA */ + #ifndef ELF_PLATFORM #define ELF_PLATFORM (NULL) #endif @@ -1231,6 +1255,14 @@ static inline void init_thread(struct target_pt_regs *regs, #define ELF_HWCAP 0 #endif +#ifndef STACK_GROWS_DOWN +#define STACK_GROWS_DOWN 1 +#endif + +#ifndef STACK_ALIGNMENT +#define STACK_ALIGNMENT 16 +#endif + #ifdef TARGET_ABI32 #undef ELF_CLASS #define ELF_CLASS ELFCLASS32 @@ -1374,45 +1406,78 @@ static abi_ulong copy_elf_strings(int argc, char **argv, char *scratch, abi_ulong p, abi_ulong stack_limit) { char *tmp; - int len, offset; + int len, i; abi_ulong top = p; if (!p) { return 0; /* bullet-proofing */ } - offset = ((p - 1) % TARGET_PAGE_SIZE) + 1; + if (STACK_GROWS_DOWN) { + int offset = ((p - 1) % TARGET_PAGE_SIZE) + 1; + for (i = argc - 1; i >= 0; --i) { + tmp = argv[i]; + if (!tmp) { + fprintf(stderr, "VFS: argc is wrong"); + exit(-1); + } + len = strlen(tmp) + 1; + tmp += len; - while (argc-- > 0) { - tmp = argv[argc]; - if (!tmp) { - fprintf(stderr, "VFS: argc is wrong"); - exit(-1); + if (len > (p - stack_limit)) { + return 0; + } + while (len) { + int bytes_to_copy = (len > offset) ? offset : len; + tmp -= bytes_to_copy; + p -= bytes_to_copy; + offset -= bytes_to_copy; + len -= bytes_to_copy; + + memcpy_fromfs(scratch + offset, tmp, bytes_to_copy); + + if (offset == 0) { + memcpy_to_target(p, scratch, top - p); + top = p; + offset = TARGET_PAGE_SIZE; + } + } } - len = strlen(tmp) + 1; - tmp += len; - - if (len > (p - stack_limit)) { - return 0; + if (p != top) { + memcpy_to_target(p, scratch + offset, top - p); } - while (len) { - int bytes_to_copy = (len > offset) ? offset : len; - tmp -= bytes_to_copy; - p -= bytes_to_copy; - offset -= bytes_to_copy; - len -= bytes_to_copy; - - memcpy_fromfs(scratch + offset, tmp, bytes_to_copy); - - if (offset == 0) { - memcpy_to_target(p, scratch, top - p); - top = p; - offset = TARGET_PAGE_SIZE; + } else { + int remaining = TARGET_PAGE_SIZE - (p % TARGET_PAGE_SIZE); + for (i = 0; i < argc; ++i) { + tmp = argv[i]; + if (!tmp) { + fprintf(stderr, "VFS: argc is wrong"); + exit(-1); + } + len = strlen(tmp) + 1; + if (len > (stack_limit - p)) { + return 0; + } + while (len) { + int bytes_to_copy = (len > remaining) ? remaining : len; + + memcpy_fromfs(scratch + (p - top), tmp, bytes_to_copy); + + tmp += bytes_to_copy; + remaining -= bytes_to_copy; + p += bytes_to_copy; + len -= bytes_to_copy; + + if (remaining == 0) { + memcpy_to_target(top, scratch, p - top); + top = p; + remaining = TARGET_PAGE_SIZE; + } } } - } - if (offset) { - memcpy_to_target(p, scratch + offset, top - p); + if (p != top) { + memcpy_to_target(top, scratch, p - top); + } } return p; @@ -1447,11 +1512,15 @@ static abi_ulong setup_arg_pages(struct linux_binprm *bprm, } /* We reserve one extra page at the top of the stack as guard. */ - target_mprotect(error, guard, PROT_NONE); - - info->stack_limit = error + guard; - - return info->stack_limit + size - sizeof(void *); + if (STACK_GROWS_DOWN) { + target_mprotect(error, guard, PROT_NONE); + info->stack_limit = error + guard; + return info->stack_limit + size - sizeof(void *); + } else { + target_mprotect(error + size, guard, PROT_NONE); + info->stack_limit = error + size; + return error; + } } /* Map and zero the bss. We need to explicitly zero any fractional pages @@ -1529,7 +1598,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, struct image_info *interp_info) { abi_ulong sp; - abi_ulong sp_auxv; + abi_ulong u_argc, u_argv, u_envp, u_auxv; int size; int i; abi_ulong u_rand_bytes; @@ -1558,10 +1627,25 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, k_platform = ELF_PLATFORM; if (k_platform) { size_t len = strlen(k_platform) + 1; - sp -= (len + n - 1) & ~(n - 1); - u_platform = sp; - /* FIXME - check return value of memcpy_to_target() for failure */ - memcpy_to_target(sp, k_platform, len); + if (STACK_GROWS_DOWN) { + sp -= (len + n - 1) & ~(n - 1); + u_platform = sp; + /* FIXME - check return value of memcpy_to_target() for failure */ + memcpy_to_target(sp, k_platform, len); + } else { + memcpy_to_target(sp, k_platform, len); + u_platform = sp; + sp += len + 1; + } + } + + /* Provide 16 byte alignment for the PRNG, and basic alignment for + * the argv and envp pointers. + */ + if (STACK_GROWS_DOWN) { + sp = QEMU_ALIGN_DOWN(sp, 16); + } else { + sp = QEMU_ALIGN_UP(sp, 16); } /* @@ -1571,15 +1655,17 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, for (i = 0; i < 16; i++) { k_rand_bytes[i] = rand(); } - sp -= 16; - u_rand_bytes = sp; - /* FIXME - check return value of memcpy_to_target() for failure */ - memcpy_to_target(sp, k_rand_bytes, 16); + if (STACK_GROWS_DOWN) { + sp -= 16; + u_rand_bytes = sp; + /* FIXME - check return value of memcpy_to_target() for failure */ + memcpy_to_target(sp, k_rand_bytes, 16); + } else { + memcpy_to_target(sp, k_rand_bytes, 16); + u_rand_bytes = sp; + sp += 16; + } - /* - * Force 16 byte _final_ alignment here for generality. - */ - sp = sp &~ (abi_ulong)15; size = (DLINFO_ITEMS + 1) * 2; if (k_platform) size += 2; @@ -1592,20 +1678,31 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, size += envc + argc + 2; size += 1; /* argc itself */ size *= n; - if (size & 15) - sp -= 16 - (size & 15); + + /* Allocate space and finalize stack alignment for entry now. */ + if (STACK_GROWS_DOWN) { + u_argc = QEMU_ALIGN_DOWN(sp - size, STACK_ALIGNMENT); + sp = u_argc; + } else { + u_argc = sp; + sp = QEMU_ALIGN_UP(sp + size, STACK_ALIGNMENT); + } + + u_argv = u_argc + n; + u_envp = u_argv + (argc + 1) * n; + u_auxv = u_envp + (envc + 1) * n; + info->saved_auxv = u_auxv; + info->arg_start = u_argv; + info->arg_end = u_argv + argc * n; /* This is correct because Linux defines * elf_addr_t as Elf32_Off / Elf64_Off */ #define NEW_AUX_ENT(id, val) do { \ - sp -= n; put_user_ual(val, sp); \ - sp -= n; put_user_ual(id, sp); \ + put_user_ual(id, u_auxv); u_auxv += n; \ + put_user_ual(val, u_auxv); u_auxv += n; \ } while(0) - sp_auxv = sp; - NEW_AUX_ENT (AT_NULL, 0); - /* There must be exactly DLINFO_ITEMS entries here. */ NEW_AUX_ENT(AT_PHDR, (abi_ulong)(info->load_addr + exec->e_phoff)); NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr))); @@ -1626,8 +1723,9 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, NEW_AUX_ENT(AT_HWCAP2, (abi_ulong) ELF_HWCAP2); #endif - if (k_platform) + if (u_platform) { NEW_AUX_ENT(AT_PLATFORM, u_platform); + } #ifdef ARCH_DLINFO /* * ARCH_DLINFO must come last so platform specific code can enforce @@ -1635,14 +1733,29 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, */ ARCH_DLINFO; #endif + NEW_AUX_ENT (AT_NULL, 0); #undef NEW_AUX_ENT - info->saved_auxv = sp; - info->auxv_len = sp_auxv - sp; + info->auxv_len = u_argv - info->saved_auxv; + + put_user_ual(argc, u_argc); + + p = info->arg_strings; + for (i = 0; i < argc; ++i) { + put_user_ual(p, u_argv); + u_argv += n; + p += target_strlen(p) + 1; + } + put_user_ual(0, u_argv); + + p = info->env_strings; + for (i = 0; i < envc; ++i) { + put_user_ual(p, u_envp); + u_envp += n; + p += target_strlen(p) + 1; + } + put_user_ual(0, u_envp); - sp = loader_build_argptr(envc, argc, sp, p, 0); - /* Check the right amount of stack was allocated for auxvec, envp & argv. */ - assert(sp_auxv - sp == size); return sp; } @@ -2213,12 +2326,28 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info) bprm->p = setup_arg_pages(bprm, info); scratch = g_new0(char, TARGET_PAGE_SIZE); - bprm->p = copy_elf_strings(1, &bprm->filename, scratch, - bprm->p, info->stack_limit); - bprm->p = copy_elf_strings(bprm->envc, bprm->envp, scratch, - bprm->p, info->stack_limit); - bprm->p = copy_elf_strings(bprm->argc, bprm->argv, scratch, - bprm->p, info->stack_limit); + if (STACK_GROWS_DOWN) { + bprm->p = copy_elf_strings(1, &bprm->filename, scratch, + bprm->p, info->stack_limit); + info->file_string = bprm->p; + bprm->p = copy_elf_strings(bprm->envc, bprm->envp, scratch, + bprm->p, info->stack_limit); + info->env_strings = bprm->p; + bprm->p = copy_elf_strings(bprm->argc, bprm->argv, scratch, + bprm->p, info->stack_limit); + info->arg_strings = bprm->p; + } else { + info->arg_strings = bprm->p; + bprm->p = copy_elf_strings(bprm->argc, bprm->argv, scratch, + bprm->p, info->stack_limit); + info->env_strings = bprm->p; + bprm->p = copy_elf_strings(bprm->envc, bprm->envp, scratch, + bprm->p, info->stack_limit); + info->file_string = bprm->p; + bprm->p = copy_elf_strings(1, &bprm->filename, scratch, + bprm->p, info->stack_limit); + } + g_free(scratch); if (!bprm->p) { |