diff options
Diffstat (limited to 'qemu/linux-user/elfload.c')
-rw-r--r-- | qemu/linux-user/elfload.c | 201 |
1 files changed, 98 insertions, 103 deletions
diff --git a/qemu/linux-user/elfload.c b/qemu/linux-user/elfload.c index 17883686f..e47caff7a 100644 --- a/qemu/linux-user/elfload.c +++ b/qemu/linux-user/elfload.c @@ -1,20 +1,13 @@ /* This is the Linux kernel elf-loading code, ported into user space */ -#include <sys/time.h> +#include "qemu/osdep.h" #include <sys/param.h> -#include <stdio.h> -#include <sys/types.h> -#include <fcntl.h> -#include <errno.h> -#include <unistd.h> #include <sys/mman.h> #include <sys/resource.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> #include "qemu.h" #include "disas/disas.h" +#include "qemu/path.h" #ifdef _ARCH_PPC64 #undef ARCH_DLINFO @@ -145,7 +138,6 @@ static uint32_t get_elf_hwcap(void) #ifdef TARGET_X86_64 #define ELF_START_MMAP 0x2aaaaab000ULL -#define elf_check_arch(x) ( ((x) == ELF_ARCH) ) #define ELF_CLASS ELFCLASS64 #define ELF_ARCH EM_X86_64 @@ -273,9 +265,7 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *en #define ELF_START_MMAP 0x80000000 -#define elf_check_arch(x) ((x) == ELF_MACHINE) - -#define ELF_ARCH ELF_MACHINE +#define ELF_ARCH EM_ARM #define ELF_CLASS ELFCLASS32 static inline void init_thread(struct target_pt_regs *regs, @@ -481,9 +471,7 @@ static uint32_t get_elf_hwcap2(void) /* 64 bit ARM definitions */ #define ELF_START_MMAP 0x80000000 -#define elf_check_arch(x) ((x) == ELF_MACHINE) - -#define ELF_ARCH ELF_MACHINE +#define ELF_ARCH EM_AARCH64 #define ELF_CLASS ELFCLASS64 #define ELF_PLATFORM "aarch64" @@ -556,8 +544,6 @@ static uint32_t get_elf_hwcap(void) #define ELF_START_MMAP 0x80000000 -#define elf_check_arch(x) ((x) == EM_UNICORE32) - #define ELF_CLASS ELFCLASS32 #define ELF_DATA ELFDATA2LSB #define ELF_ARCH EM_UNICORE32 @@ -666,7 +652,6 @@ static inline void init_thread(struct target_pt_regs *regs, #define ELF_START_MMAP 0x80000000 #define ELF_HWCAP (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | HWCAP_SPARC_SWAP \ | HWCAP_SPARC_MULDIV) -#define elf_check_arch(x) ( (x) == EM_SPARC ) #define ELF_CLASS ELFCLASS32 #define ELF_ARCH EM_SPARC @@ -686,6 +671,7 @@ static inline void init_thread(struct target_pt_regs *regs, #ifdef TARGET_PPC +#define ELF_MACHINE PPC_ELF_MACHINE #define ELF_START_MMAP 0x80000000 #if defined(TARGET_PPC64) && !defined(TARGET_ABI32) @@ -696,8 +682,6 @@ static inline void init_thread(struct target_pt_regs *regs, #else -#define elf_check_arch(x) ( (x) == EM_PPC ) - #define ELF_CLASS ELFCLASS32 #endif @@ -875,8 +859,6 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUPPCState *en #define ELF_START_MMAP 0x80000000 -#define elf_check_arch(x) ( (x) == EM_MIPS ) - #ifdef TARGET_MIPS64 #define ELF_CLASS ELFCLASS64 #else @@ -985,8 +967,6 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUMBState *env #define ELF_START_MMAP 0x08000000 -#define elf_check_arch(x) ((x) == EM_OPENRISC) - #define ELF_ARCH EM_OPENRISC #define ELF_CLASS ELFCLASS32 #define ELF_DATA ELFDATA2MSB @@ -1026,8 +1006,6 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, #define ELF_START_MMAP 0x80000000 -#define elf_check_arch(x) ( (x) == EM_SH ) - #define ELF_CLASS ELFCLASS32 #define ELF_ARCH EM_SH @@ -1110,8 +1088,6 @@ static uint32_t get_elf_hwcap(void) #define ELF_START_MMAP 0x80000000 -#define elf_check_arch(x) ( (x) == EM_CRIS ) - #define ELF_CLASS ELFCLASS32 #define ELF_ARCH EM_CRIS @@ -1129,8 +1105,6 @@ static inline void init_thread(struct target_pt_regs *regs, #define ELF_START_MMAP 0x80000000 -#define elf_check_arch(x) ( (x) == EM_68K ) - #define ELF_CLASS ELFCLASS32 #define ELF_ARCH EM_68K @@ -1182,8 +1156,6 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUM68KState *e #define ELF_START_MMAP (0x30000000000ULL) -#define elf_check_arch(x) ( (x) == ELF_ARCH ) - #define ELF_CLASS ELFCLASS64 #define ELF_ARCH EM_ALPHA @@ -1203,8 +1175,6 @@ static inline void init_thread(struct target_pt_regs *regs, #define ELF_START_MMAP (0x20000000000ULL) -#define elf_check_arch(x) ( (x) == ELF_ARCH ) - #define ELF_CLASS ELFCLASS64 #define ELF_DATA ELFDATA2MSB #define ELF_ARCH EM_S390 @@ -1218,10 +1188,41 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #endif /* TARGET_S390X */ +#ifdef TARGET_TILEGX + +/* 42 bits real used address, a half for user mode */ +#define ELF_START_MMAP (0x00000020000000000ULL) + +#define elf_check_arch(x) ((x) == EM_TILEGX) + +#define ELF_CLASS ELFCLASS64 +#define ELF_DATA ELFDATA2LSB +#define ELF_ARCH EM_TILEGX + +static inline void init_thread(struct target_pt_regs *regs, + struct image_info *infop) +{ + regs->pc = infop->entry; + regs->sp = infop->start_stack; + +} + +#define ELF_EXEC_PAGESIZE 65536 /* TILE-Gx page size is 64KB */ + +#endif /* TARGET_TILEGX */ + #ifndef ELF_PLATFORM #define ELF_PLATFORM (NULL) #endif +#ifndef ELF_MACHINE +#define ELF_MACHINE ELF_ARCH +#endif + +#ifndef elf_check_arch +#define elf_check_arch(x) ((x) == ELF_ARCH) +#endif + #ifndef ELF_HWCAP #define ELF_HWCAP 0 #endif @@ -1365,66 +1366,69 @@ static bool elf_check_ehdr(struct elfhdr *ehdr) * to be put directly into the top of new user memory. * */ -static abi_ulong copy_elf_strings(int argc,char ** argv, void **page, - abi_ulong p) +static abi_ulong copy_elf_strings(int argc, char **argv, char *scratch, + abi_ulong p, abi_ulong stack_limit) { - char *tmp, *tmp1, *pag = NULL; - int len, offset = 0; + char *tmp; + int len, offset; + abi_ulong top = p; if (!p) { return 0; /* bullet-proofing */ } + + offset = ((p - 1) % TARGET_PAGE_SIZE) + 1; + while (argc-- > 0) { tmp = argv[argc]; if (!tmp) { fprintf(stderr, "VFS: argc is wrong"); exit(-1); } - tmp1 = tmp; - while (*tmp++); - len = tmp - tmp1; - if (p < len) { /* this shouldn't happen - 128kB */ + len = strlen(tmp) + 1; + tmp += len; + + if (len > (p - stack_limit)) { return 0; } while (len) { - --p; --tmp; --len; - if (--offset < 0) { - offset = p % TARGET_PAGE_SIZE; - pag = (char *)page[p/TARGET_PAGE_SIZE]; - if (!pag) { - pag = g_try_malloc0(TARGET_PAGE_SIZE); - page[p/TARGET_PAGE_SIZE] = pag; - if (!pag) - return 0; - } - } - if (len == 0 || offset == 0) { - *(pag + offset) = *tmp; - } - else { - 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(pag + offset, tmp, bytes_to_copy + 1); + 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; } } } + if (offset) { + memcpy_to_target(p, scratch + offset, top - p); + } + return p; } -static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm, +/* Older linux kernels provide up to MAX_ARG_PAGES (default: 32) of + * argument/environment space. Newer kernels (>2.6.33) allow more, + * dependent on stack size, but guarantee at least 32 pages for + * backwards compatibility. + */ +#define STACK_LOWER_LIMIT (32 * TARGET_PAGE_SIZE) + +static abi_ulong setup_arg_pages(struct linux_binprm *bprm, struct image_info *info) { - abi_ulong stack_base, size, error, guard; - int i; + abi_ulong size, error, guard; - /* Create enough stack to hold everything. If we don't use - it for args, we'll use it for something else. */ size = guest_stack_size; - if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) { - size = MAX_ARG_PAGES*TARGET_PAGE_SIZE; + if (size < STACK_LOWER_LIMIT) { + size = STACK_LOWER_LIMIT; } guard = TARGET_PAGE_SIZE; if (guard < qemu_real_host_page_size) { @@ -1442,19 +1446,8 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm, target_mprotect(error, guard, PROT_NONE); info->stack_limit = error + guard; - stack_base = info->stack_limit + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE; - p += stack_base; - - for (i = 0 ; i < MAX_ARG_PAGES ; i++) { - if (bprm->page[i]) { - info->rss++; - /* FIXME - check return value of memcpy_to_target() for failure */ - memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE); - g_free(bprm->page[i]); - } - stack_base += TARGET_PAGE_SIZE; - } - return p; + + return info->stack_limit + size - sizeof(void *); } /* Map and zero the bss. We need to explicitly zero any fractional pages @@ -1478,8 +1471,7 @@ static void zero_bss(abi_ulong elf_bss, abi_ulong last_bss, int prot) host_start = (uintptr_t) g2h(elf_bss); host_end = (uintptr_t) g2h(last_bss); - host_map_start = (host_start + qemu_real_host_page_size - 1); - host_map_start &= -qemu_real_host_page_size; + host_map_start = REAL_HOST_PAGE_ALIGN(host_start); if (host_map_start < host_end) { void *p = mmap((void *)host_map_start, host_end - host_map_start, @@ -1744,7 +1736,7 @@ unsigned long init_guest_space(unsigned long host_start, } } - qemu_log("Reserved 0x%lx bytes of guest address space\n", host_size); + qemu_log_mask(CPU_LOG_PAGE, "Reserved 0x%lx bytes of guest address space\n", host_size); return real_start; } @@ -1756,7 +1748,6 @@ static void probe_guest_base(const char *image_name, * it explicitly, and set guest_base appropriately. * In case of error we will print a suitable message and exit. */ -#if defined(CONFIG_USE_GUEST_BASE) const char *errmsg; if (!have_guest_base && !reserved_va) { unsigned long host_start, real_start, host_size; @@ -1786,16 +1777,15 @@ static void probe_guest_base(const char *image_name, } guest_base = real_start - loaddr; - qemu_log("Relocating guest address space from 0x" - TARGET_ABI_FMT_lx " to 0x%lx\n", - loaddr, real_start); + qemu_log_mask(CPU_LOG_PAGE, "Relocating guest address space from 0x" + TARGET_ABI_FMT_lx " to 0x%lx\n", + loaddr, real_start); } return; exit_errmsg: fprintf(stderr, "%s: %s\n", image_name, errmsg); exit(-1); -#endif } @@ -2198,10 +2188,9 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info) struct image_info interp_info; struct elfhdr elf_ex; char *elf_interpreter = NULL; + char *scratch; info->start_mmap = (abi_ulong)ELF_START_MMAP; - info->mmap = 0; - info->rss = 0; load_elf_image(bprm->filename, bprm->fd, info, &elf_interpreter, bprm->buf); @@ -2211,18 +2200,24 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info) when we load the interpreter. */ elf_ex = *(struct elfhdr *)bprm->buf; - bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p); - bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p); - bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p); + /* Do this so that we can load the interpreter, if need be. We will + change some of these later */ + 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); + g_free(scratch); + if (!bprm->p) { fprintf(stderr, "%s: %s\n", bprm->filename, strerror(E2BIG)); exit(-1); } - /* Do this so that we can load the interpreter, if need be. We will - change some of these later */ - bprm->p = setup_arg_pages(bprm->p, bprm, info); - if (elf_interpreter) { load_elf_interp(elf_interpreter, &interp_info, bprm->buf); @@ -2850,7 +2845,7 @@ static int fill_note_info(struct elf_note_info *info, TaskState *ts = (TaskState *)cpu->opaque; int i; - info->notes = g_malloc0(NUMNOTES * sizeof (struct memelfnote)); + info->notes = g_new0(struct memelfnote, NUMNOTES); if (info->notes == NULL) return (-ENOMEM); info->prstatus = g_malloc0(sizeof (*info->prstatus)); @@ -3016,7 +3011,7 @@ static int elf_core_dump(int signr, const CPUArchState *env) if (dump_write(fd, &elf, sizeof (elf)) != 0) goto out; - /* fill in in-memory version of notes */ + /* fill in the in-memory version of notes */ if (fill_note_info(&info, signr, env) < 0) goto out; |