diff options
Diffstat (limited to 'bsd-user/main.c')
| -rw-r--r-- | bsd-user/main.c | 832 |
1 files changed, 181 insertions, 651 deletions
diff --git a/bsd-user/main.c b/bsd-user/main.c index fe66204b6b..48643eeabc 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -1,7 +1,8 @@ /* - * qemu user main + * qemu bsd user main * * Copyright (c) 2003-2008 Fabrice Bellard + * Copyright (c) 2013-14 Stacey Son * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,6 +18,11 @@ * along with this program; if not, see <http://www.gnu.org/licenses/>. */ +#include <sys/types.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/sysctl.h> + #include "qemu/osdep.h" #include "qemu-common.h" #include "qemu/units.h" @@ -39,496 +45,108 @@ #include "qemu/cutils.h" #include "exec/log.h" #include "trace/control.h" +#include "crypto/init.h" +#include "qemu/guest-random.h" + +#include "host-os.h" +#include "target_arch_cpu.h" int singlestep; -unsigned long mmap_min_addr; uintptr_t guest_base; bool have_guest_base; +/* + * When running 32-on-64 we should make sure we can fit all of the possible + * guest address space into a contiguous chunk of virtual host memory. + * + * This way we will never overlap with our own libraries or binaries or stack + * or anything else that QEMU maps. + * + * Many cpus reserve the high bit (or more than one for some 64-bit cpus) + * of the address for the kernel. Some cpus rely on this and user space + * uses the high bit(s) for pointer tagging and the like. For them, we + * must preserve the expected address space. + */ +#ifndef MAX_RESERVED_VA +# if HOST_LONG_BITS > TARGET_VIRT_ADDR_SPACE_BITS +# if TARGET_VIRT_ADDR_SPACE_BITS == 32 && \ + (TARGET_LONG_BITS == 32 || defined(TARGET_ABI32)) +/* + * There are a number of places where we assign reserved_va to a variable + * of type abi_ulong and expect it to fit. Avoid the last page. + */ +# define MAX_RESERVED_VA (0xfffffffful & TARGET_PAGE_MASK) +# else +# define MAX_RESERVED_VA (1ul << TARGET_VIRT_ADDR_SPACE_BITS) +# endif +# else +# define MAX_RESERVED_VA 0 +# endif +#endif + +/* + * That said, reserving *too* much vm space via mmap can run into problems + * with rlimits, oom due to page table creation, etc. We will still try it, + * if directed by the command-line option, but not by default. + */ +#if HOST_LONG_BITS == 64 && TARGET_VIRT_ADDR_SPACE_BITS <= 32 +unsigned long reserved_va = MAX_RESERVED_VA; +#else unsigned long reserved_va; +#endif static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX; const char *qemu_uname_release; enum BSDType bsd_type; +char qemu_proc_pathname[PATH_MAX]; /* full path to exeutable */ -/* - * XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so - * we allocate a bigger stack. Need a better solution, for example - * by remapping the process stack directly at the right place - */ -unsigned long x86_stack_size = 512 * 1024; - -void gemu_log(const char *fmt, ...) -{ - va_list ap; +unsigned long target_maxtsiz = TARGET_MAXTSIZ; /* max text size */ +unsigned long target_dfldsiz = TARGET_DFLDSIZ; /* initial data size limit */ +unsigned long target_maxdsiz = TARGET_MAXDSIZ; /* max data size */ +unsigned long target_dflssiz = TARGET_DFLSSIZ; /* initial data size limit */ +unsigned long target_maxssiz = TARGET_MAXSSIZ; /* max stack size */ +unsigned long target_sgrowsiz = TARGET_SGROWSIZ; /* amount to grow stack */ - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); -} - -#if defined(TARGET_I386) -int cpu_get_pic_interrupt(CPUX86State *env) -{ - return -1; -} -#endif +/* Helper routines for implementing atomic operations. */ void fork_start(void) { + start_exclusive(); + cpu_list_lock(); + mmap_fork_start(); } void fork_end(int child) { if (child) { - gdbserver_fork(thread_cpu); - } -} - -#ifdef TARGET_I386 -/***********************************************************/ -/* CPUX86 core interface */ - -uint64_t cpu_get_tsc(CPUX86State *env) -{ - return cpu_get_host_ticks(); -} - -static void write_dt(void *ptr, unsigned long addr, unsigned long limit, - int flags) -{ - unsigned int e1, e2; - uint32_t *p; - e1 = (addr << 16) | (limit & 0xffff); - e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000); - e2 |= flags; - p = ptr; - p[0] = tswap32(e1); - p[1] = tswap32(e2); -} - -static uint64_t *idt_table; -#ifdef TARGET_X86_64 -static void set_gate64(void *ptr, unsigned int type, unsigned int dpl, - uint64_t addr, unsigned int sel) -{ - uint32_t *p, e1, e2; - e1 = (addr & 0xffff) | (sel << 16); - e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8); - p = ptr; - p[0] = tswap32(e1); - p[1] = tswap32(e2); - p[2] = tswap32(addr >> 32); - p[3] = 0; -} -/* only dpl matters as we do only user space emulation */ -static void set_idt(int n, unsigned int dpl) -{ - set_gate64(idt_table + n * 2, 0, dpl, 0, 0); -} -#else -static void set_gate(void *ptr, unsigned int type, unsigned int dpl, - uint32_t addr, unsigned int sel) -{ - uint32_t *p, e1, e2; - e1 = (addr & 0xffff) | (sel << 16); - e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8); - p = ptr; - p[0] = tswap32(e1); - p[1] = tswap32(e2); -} - -/* only dpl matters as we do only user space emulation */ -static void set_idt(int n, unsigned int dpl) -{ - set_gate(idt_table + n, 0, dpl, 0, 0); -} -#endif - -void cpu_loop(CPUX86State *env) -{ - CPUState *cs = env_cpu(env); - int trapnr; - abi_ulong pc; - /* target_siginfo_t info; */ - - for (;;) { - cpu_exec_start(cs); - trapnr = cpu_exec(cs); - cpu_exec_end(cs); - process_queued_cpu_work(cs); - - switch (trapnr) { - case 0x80: - /* syscall from int $0x80 */ - if (bsd_type == target_freebsd) { - abi_ulong params = (abi_ulong) env->regs[R_ESP] + - sizeof(int32_t); - int32_t syscall_nr = env->regs[R_EAX]; - int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8; - - if (syscall_nr == TARGET_FREEBSD_NR_syscall) { - get_user_s32(syscall_nr, params); - params += sizeof(int32_t); - } else if (syscall_nr == TARGET_FREEBSD_NR___syscall) { - get_user_s32(syscall_nr, params); - params += sizeof(int64_t); - } - get_user_s32(arg1, params); - params += sizeof(int32_t); - get_user_s32(arg2, params); - params += sizeof(int32_t); - get_user_s32(arg3, params); - params += sizeof(int32_t); - get_user_s32(arg4, params); - params += sizeof(int32_t); - get_user_s32(arg5, params); - params += sizeof(int32_t); - get_user_s32(arg6, params); - params += sizeof(int32_t); - get_user_s32(arg7, params); - params += sizeof(int32_t); - get_user_s32(arg8, params); - env->regs[R_EAX] = do_freebsd_syscall(env, - syscall_nr, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8); - } else { /* if (bsd_type == target_openbsd) */ - env->regs[R_EAX] = do_openbsd_syscall(env, - env->regs[R_EAX], - env->regs[R_EBX], - env->regs[R_ECX], - env->regs[R_EDX], - env->regs[R_ESI], - env->regs[R_EDI], - env->regs[R_EBP]); - } - if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) { - env->regs[R_EAX] = -env->regs[R_EAX]; - env->eflags |= CC_C; - } else { - env->eflags &= ~CC_C; - } - break; -#ifndef TARGET_ABI32 - case EXCP_SYSCALL: - /* syscall from syscall instruction */ - if (bsd_type == target_freebsd) { - env->regs[R_EAX] = do_freebsd_syscall(env, - env->regs[R_EAX], - env->regs[R_EDI], - env->regs[R_ESI], - env->regs[R_EDX], - env->regs[R_ECX], - env->regs[8], - env->regs[9], 0, 0); - } else { /* if (bsd_type == target_openbsd) */ - env->regs[R_EAX] = do_openbsd_syscall(env, - env->regs[R_EAX], - env->regs[R_EDI], - env->regs[R_ESI], - env->regs[R_EDX], - env->regs[10], - env->regs[8], - env->regs[9]); - } - env->eip = env->exception_next_eip; - if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) { - env->regs[R_EAX] = -env->regs[R_EAX]; - env->eflags |= CC_C; - } else { - env->eflags &= ~CC_C; + CPUState *cpu, *next_cpu; + /* + * Child processes created by fork() only have a single thread. Discard + * information about the parent threads. + */ + CPU_FOREACH_SAFE(cpu, next_cpu) { + if (cpu != thread_cpu) { + QTAILQ_REMOVE_RCU(&cpus, cpu, node); } - break; -#endif - case EXCP_INTERRUPT: - /* just indicate that signals should be handled asap */ - break; - default: - pc = env->segs[R_CS].base + env->eip; - fprintf(stderr, - "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n", - (long)pc, trapnr); - abort(); } - process_pending_signals(env); - } -} -#endif - -#ifdef TARGET_SPARC -#define SPARC64_STACK_BIAS 2047 - -/* #define DEBUG_WIN */ -/* - * WARNING: dealing with register windows _is_ complicated. More info - * can be found at http://www.sics.se/~psm/sparcstack.html - */ -static inline int get_reg_index(CPUSPARCState *env, int cwp, int index) -{ - index = (index + cwp * 16) % (16 * env->nwindows); - /* - * wrap handling : if cwp is on the last window, then we use the - * registers 'after' the end - */ - if (index < 8 && env->cwp == env->nwindows - 1) { - index += 16 * env->nwindows; - } - return index; -} - -/* save the register window 'cwp1' */ -static inline void save_window_offset(CPUSPARCState *env, int cwp1) -{ - unsigned int i; - abi_ulong sp_ptr; - - sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)]; -#ifdef TARGET_SPARC64 - if (sp_ptr & 3) { - sp_ptr += SPARC64_STACK_BIAS; - } -#endif -#if defined(DEBUG_WIN) - printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n", - sp_ptr, cwp1); -#endif - for (i = 0; i < 16; i++) { - /* FIXME - what to do if put_user() fails? */ - put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr); - sp_ptr += sizeof(abi_ulong); - } -} - -static void save_window(CPUSPARCState *env) -{ -#ifndef TARGET_SPARC64 - unsigned int new_wim; - new_wim = ((env->wim >> 1) | (env->wim << (env->nwindows - 1))) & - ((1LL << env->nwindows) - 1); - save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2)); - env->wim = new_wim; -#else - /* - * cansave is zero if the spill trap handler is triggered by `save` and - * nonzero if triggered by a `flushw` - */ - save_window_offset(env, cpu_cwp_dec(env, env->cwp - env->cansave - 2)); - env->cansave++; - env->canrestore--; -#endif -} - -static void restore_window(CPUSPARCState *env) -{ -#ifndef TARGET_SPARC64 - unsigned int new_wim; -#endif - unsigned int i, cwp1; - abi_ulong sp_ptr; - -#ifndef TARGET_SPARC64 - new_wim = ((env->wim << 1) | (env->wim >> (env->nwindows - 1))) & - ((1LL << env->nwindows) - 1); -#endif - - /* restore the invalid window */ - cwp1 = cpu_cwp_inc(env, env->cwp + 1); - sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)]; -#ifdef TARGET_SPARC64 - if (sp_ptr & 3) { - sp_ptr += SPARC64_STACK_BIAS; - } -#endif -#if defined(DEBUG_WIN) - printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n", - sp_ptr, cwp1); -#endif - for (i = 0; i < 16; i++) { - /* FIXME - what to do if get_user() fails? */ - get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr); - sp_ptr += sizeof(abi_ulong); - } -#ifdef TARGET_SPARC64 - env->canrestore++; - if (env->cleanwin < env->nwindows - 1) { - env->cleanwin++; - } - env->cansave--; -#else - env->wim = new_wim; -#endif -} - -static void flush_windows(CPUSPARCState *env) -{ - int offset, cwp1; - - offset = 1; - for (;;) { - /* if restore would invoke restore_window(), then we can stop */ - cwp1 = cpu_cwp_inc(env, env->cwp + offset); -#ifndef TARGET_SPARC64 - if (env->wim & (1 << cwp1)) { - break; - } -#else - if (env->canrestore == 0) { - break; - } - env->cansave++; - env->canrestore--; -#endif - save_window_offset(env, cwp1); - offset++; + mmap_fork_end(child); + /* + * qemu_init_cpu_list() takes care of reinitializing the exclusive + * state, so we don't need to end_exclusive() here. + */ + qemu_init_cpu_list(); + gdbserver_fork(thread_cpu); + } else { + mmap_fork_end(child); + cpu_list_unlock(); + end_exclusive(); } - cwp1 = cpu_cwp_inc(env, env->cwp + 1); -#ifndef TARGET_SPARC64 - /* set wim so that restore will reload the registers */ - env->wim = 1 << cwp1; -#endif -#if defined(DEBUG_WIN) - printf("flush_windows: nb=%d\n", offset - 1); -#endif } -void cpu_loop(CPUSPARCState *env) +void cpu_loop(CPUArchState *env) { - CPUState *cs = env_cpu(env); - int trapnr, ret, syscall_nr; - /* target_siginfo_t info; */ - - while (1) { - cpu_exec_start(cs); - trapnr = cpu_exec(cs); - cpu_exec_end(cs); - process_queued_cpu_work(cs); - - switch (trapnr) { -#ifndef TARGET_SPARC64 - case 0x80: -#else - /* FreeBSD uses 0x141 for syscalls too */ - case 0x141: - if (bsd_type != target_freebsd) { - goto badtrap; - } - /* fallthrough */ - case 0x100: -#endif - syscall_nr = env->gregs[1]; - if (bsd_type == target_freebsd) - ret = do_freebsd_syscall(env, syscall_nr, - env->regwptr[0], env->regwptr[1], - env->regwptr[2], env->regwptr[3], - env->regwptr[4], env->regwptr[5], - 0, 0); - else if (bsd_type == target_netbsd) - ret = do_netbsd_syscall(env, syscall_nr, - env->regwptr[0], env->regwptr[1], - env->regwptr[2], env->regwptr[3], - env->regwptr[4], env->regwptr[5]); - else { /* if (bsd_type == target_openbsd) */ -#if defined(TARGET_SPARC64) - syscall_nr &= ~(TARGET_OPENBSD_SYSCALL_G7RFLAG | - TARGET_OPENBSD_SYSCALL_G2RFLAG); -#endif - ret = do_openbsd_syscall(env, syscall_nr, - env->regwptr[0], env->regwptr[1], - env->regwptr[2], env->regwptr[3], - env->regwptr[4], env->regwptr[5]); - } - if ((unsigned int)ret >= (unsigned int)(-515)) { - ret = -ret; -#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) - env->xcc |= PSR_CARRY; -#else - env->psr |= PSR_CARRY; -#endif - } else { -#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) - env->xcc &= ~PSR_CARRY; -#else - env->psr &= ~PSR_CARRY; -#endif - } - env->regwptr[0] = ret; - /* next instruction */ -#if defined(TARGET_SPARC64) - if (bsd_type == target_openbsd && - env->gregs[1] & TARGET_OPENBSD_SYSCALL_G2RFLAG) { - env->pc = env->gregs[2]; - env->npc = env->pc + 4; - } else if (bsd_type == target_openbsd && - env->gregs[1] & TARGET_OPENBSD_SYSCALL_G7RFLAG) { - env->pc = env->gregs[7]; - env->npc = env->pc + 4; - } else { - env->pc = env->npc; - env->npc = env->npc + 4; - } -#else - env->pc = env->npc; - env->npc = env->npc + 4; -#endif - break; - case 0x83: /* flush windows */ -#ifdef TARGET_ABI32 - case 0x103: -#endif - flush_windows(env); - /* next instruction */ - env->pc = env->npc; - env->npc = env->npc + 4; - break; -#ifndef TARGET_SPARC64 - case TT_WIN_OVF: /* window overflow */ - save_window(env); - break; - case TT_WIN_UNF: /* window underflow */ - restore_window(env); - break; - case TT_TFAULT: - case TT_DFAULT: - break; -#else - case TT_SPILL: /* window overflow */ - save_window(env); - break; - case TT_FILL: /* window underflow */ - restore_window(env); - break; - case TT_TFAULT: - case TT_DFAULT: - break; -#endif - case EXCP_INTERRUPT: - /* just indicate that signals should be handled asap */ - break; - case EXCP_DEBUG: - { - gdb_handlesig(cs, TARGET_SIGTRAP); - } - break; - default: -#ifdef TARGET_SPARC64 - badtrap: -#endif - printf("Unhandled trap: 0x%x\n", trapnr); - cpu_dump_state(cs, stderr, 0); - exit(1); - } - process_pending_signals(env); - } + target_cpu_loop(env); } -#endif - static void usage(void) { printf("qemu-" TARGET_NAME " version " QEMU_FULL_VERSION @@ -552,7 +170,6 @@ static void usage(void) "-d item1[,...] enable logging of specified items\n" " (use '-d help' for a list of log items)\n" "-D logfile write logs to 'logfile' (default stderr)\n" - "-p pagesize set the host page size to 'pagesize'\n" "-singlestep always run in singlestep mode\n" "-strace log system calls\n" "-trace [[enable=]<pattern>][,events=<file>][,file=<file>]\n" @@ -572,11 +189,11 @@ static void usage(void) , TARGET_NAME, interp_prefix, - x86_stack_size); + target_dflssiz); exit(1); } -THREAD CPUState *thread_cpu; +__thread CPUState *thread_cpu; bool qemu_cpu_is_self(CPUState *cpu) { @@ -601,6 +218,48 @@ void init_task_state(TaskState *ts) ts->sigqueue_table[i].next = NULL; } +void gemu_log(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + +static void +adjust_ssize(void) +{ + struct rlimit rl; + + if (getrlimit(RLIMIT_STACK, &rl) != 0) { + return; + } + + target_maxssiz = MIN(target_maxssiz, rl.rlim_max); + target_dflssiz = MIN(MAX(target_dflssiz, rl.rlim_cur), target_maxssiz); + + rl.rlim_max = target_maxssiz; + rl.rlim_cur = target_dflssiz; + setrlimit(RLIMIT_STACK, &rl); +} + +static void save_proc_pathname(char *argv0) +{ + int mib[4]; + size_t len; + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PATHNAME; + mib[3] = -1; + + len = sizeof(qemu_proc_pathname); + if (sysctl(mib, 4, qemu_proc_pathname, &len, NULL, 0)) { + perror("sysctl"); + } +} + int main(int argc, char **argv) { const char *filename; @@ -608,9 +267,11 @@ int main(int argc, char **argv) const char *cpu_type; const char *log_file = NULL; const char *log_mask = NULL; + const char *seed_optarg = NULL; struct target_pt_regs regs1, *regs = ®s1; struct image_info info1, *info = &info1; - TaskState ts1, *ts = &ts1; + struct bsd_binprm bprm; + TaskState *ts; CPUArchState *env; CPUState *cpu; int optind, rv; @@ -618,12 +279,17 @@ int main(int argc, char **argv) const char *gdbstub = NULL; char **target_environ, **wrk; envlist_t *envlist = NULL; - bsd_type = target_openbsd; + bsd_type = HOST_DEFAULT_BSD_TYPE; + char *argv0 = NULL; + + adjust_ssize(); if (argc <= 1) { usage(); } + save_proc_pathname(argv[0]); + error_init(argv[0]); module_call_init(MODULE_INIT_TRACE); qemu_init_cpu_list(); @@ -678,14 +344,17 @@ int main(int argc, char **argv) } } else if (!strcmp(r, "s")) { r = argv[optind++]; - rv = qemu_strtoul(r, &r, 0, &x86_stack_size); - if (rv < 0 || x86_stack_size <= 0) { + rv = qemu_strtoul(r, &r, 0, &target_dflssiz); + if (rv < 0 || target_dflssiz <= 0) { usage(); } if (*r == 'M') { - x86_stack_size *= MiB; + target_dflssiz *= 1024 * 1024; } else if (*r == 'k' || *r == 'K') { - x86_stack_size *= KiB; + target_dflssiz *= 1024; + } + if (target_dflssiz > target_maxssiz) { + usage(); } } else if (!strcmp(r, "L")) { interp_prefix = argv[optind++]; @@ -728,12 +397,16 @@ int main(int argc, char **argv) usage(); } optind++; + } else if (!strcmp(r, "seed")) { + seed_optarg = optarg; } else if (!strcmp(r, "singlestep")) { singlestep = 1; } else if (!strcmp(r, "strace")) { do_strace = 1; } else if (!strcmp(r, "trace")) { trace_opt_parse(optarg); + } else if (!strcmp(r, "0")) { + argv0 = argv[optind++]; } else { usage(); } @@ -757,6 +430,9 @@ int main(int argc, char **argv) usage(); } filename = argv[optind]; + if (argv0) { + argv[optind] = argv0; + } if (!trace_init_backends()) { exit(1); @@ -766,6 +442,9 @@ int main(int argc, char **argv) /* Zero out regs */ memset(regs, 0, sizeof(struct target_pt_regs)); + /* Zero bsd params */ + memset(&bprm, 0, sizeof(bprm)); + /* Zero out image_info */ memset(info, 0, sizeof(struct image_info)); @@ -773,24 +452,11 @@ int main(int argc, char **argv) init_paths(interp_prefix); if (cpu_model == NULL) { -#if defined(TARGET_I386) -#ifdef TARGET_X86_64 - cpu_model = "qemu64"; -#else - cpu_model = "qemu32"; -#endif -#elif defined(TARGET_SPARC) -#ifdef TARGET_SPARC64 - cpu_model = "TI UltraSparc II"; -#else - cpu_model = "Fujitsu MB86904"; -#endif -#else - cpu_model = "any"; -#endif + cpu_model = TARGET_DEFAULT_CPU_MODEL; } cpu_type = parse_cpu_option(cpu_model); + /* init tcg before creating CPUs and to get qemu_host_page_size */ { AccelClass *ac = ACCEL_GET_CLASS(current_accel()); @@ -800,9 +466,7 @@ int main(int argc, char **argv) } cpu = cpu_create(cpu_type); env = cpu->env_ptr; -#if defined(TARGET_SPARC) || defined(TARGET_PPC) cpu_reset(cpu); -#endif thread_cpu = cpu; if (getenv("QEMU_STRACE")) { @@ -812,36 +476,31 @@ int main(int argc, char **argv) target_environ = envlist_to_environ(envlist, NULL); envlist_free(envlist); + if (reserved_va) { + mmap_next_start = reserved_va; + } + + { + Error *err = NULL; + if (seed_optarg != NULL) { + qemu_guest_random_seed_main(seed_optarg, &err); + } else { + qcrypto_init(&err); + } + if (err) { + error_reportf_err(err, "cannot initialize crypto: "); + exit(1); + } + } + /* * Now that page sizes are configured we can do * proper page alignment for guest_base. */ guest_base = HOST_PAGE_ALIGN(guest_base); - /* - * Read in mmap_min_addr kernel parameter. This value is used - * When loading the ELF image to determine whether guest_base - * is needed. - * - * When user has explicitly set the quest base, we skip this - * test. - */ - if (!have_guest_base) { - FILE *fp; - - fp = fopen("/proc/sys/vm/mmap_min_addr", "r"); - if (fp != NULL) { - unsigned long tmp; - if (fscanf(fp, "%lu", &tmp) == 1) { - mmap_min_addr = tmp; - qemu_log_mask(CPU_LOG_PAGE, "host mmap_min_addr=0x%lx\n", - mmap_min_addr); - } - fclose(fp); - } - } - - if (loader_exec(filename, argv + optind, target_environ, regs, info) != 0) { + if (loader_exec(filename, argv + optind, target_environ, regs, info, + &bprm) != 0) { printf("Error loading %s\n", filename); _exit(1); } @@ -869,6 +528,13 @@ int main(int argc, char **argv) qemu_log("entry 0x" TARGET_ABI_FMT_lx "\n", info->entry); } + /* build Task State */ + ts = g_new0(TaskState, 1); + init_task_state(ts); + ts->info = info; + ts->bprm = &bprm; + cpu->opaque = ts; + target_set_brk(info->brk); syscall_init(); signal_init(); @@ -880,143 +546,7 @@ int main(int argc, char **argv) */ tcg_prologue_init(tcg_ctx); - /* build Task State */ - memset(ts, 0, sizeof(TaskState)); - init_task_state(ts); - ts->info = info; - cpu->opaque = ts; - -#if defined(TARGET_I386) - env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK; - env->hflags |= HF_PE_MASK | HF_CPL_MASK; - if (env->features[FEAT_1_EDX] & CPUID_SSE) { - env->cr[4] |= CR4_OSFXSR_MASK; - env->hflags |= HF_OSFXSR_MASK; - } -#ifndef TARGET_ABI32 - /* enable 64 bit mode if possible */ - if (!(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM)) { - fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n"); - exit(1); - } - env->cr[4] |= CR4_PAE_MASK; - env->efer |= MSR_EFER_LMA | MSR_EFER_LME; - env->hflags |= HF_LMA_MASK; -#endif - - /* flags setup : we activate the IRQs by default as in user mode */ - env->eflags |= IF_MASK; - - /* linux register setup */ -#ifndef TARGET_ABI32 - env->regs[R_EAX] = regs->rax; - env->regs[R_EBX] = regs->rbx; - env->regs[R_ECX] = regs->rcx; - env->regs[R_EDX] = regs->rdx; - env->regs[R_ESI] = regs->rsi; - env->regs[R_EDI] = regs->rdi; - env->regs[R_EBP] = regs->rbp; - env->regs[R_ESP] = regs->rsp; - env->eip = regs->rip; -#else - env->regs[R_EAX] = regs->eax; - env->regs[R_EBX] = regs->ebx; - env->regs[R_ECX] = regs->ecx; - env->regs[R_EDX] = regs->edx; - env->regs[R_ESI] = regs->esi; - env->regs[R_EDI] = regs->edi; - env->regs[R_EBP] = regs->ebp; - env->regs[R_ESP] = regs->esp; - env->eip = regs->eip; -#endif - - /* linux interrupt setup */ -#ifndef TARGET_ABI32 - env->idt.limit = 511; -#else - env->idt.limit = 255; -#endif - env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1), - PROT_READ | PROT_WRITE, - MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - idt_table = g2h_untagged(env->idt.base); - set_idt(0, 0); - set_idt(1, 0); - set_idt(2, 0); - set_idt(3, 3); - set_idt(4, 3); - set_idt(5, 0); - set_idt(6, 0); - set_idt(7, 0); - set_idt(8, 0); - set_idt(9, 0); - set_idt(10, 0); - set_idt(11, 0); - set_idt(12, 0); - set_idt(13, 0); - set_idt(14, 0); - set_idt(15, 0); - set_idt(16, 0); - set_idt(17, 0); - set_idt(18, 0); - set_idt(19, 0); - set_idt(0x80, 3); - - /* linux segment setup */ - { - uint64_t *gdt_table; - env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES, - PROT_READ | PROT_WRITE, - MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1; - gdt_table = g2h_untagged(env->gdt.base); -#ifdef TARGET_ABI32 - write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff, - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | - (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT)); -#else - /* 64 bit code segment */ - write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff, - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | - DESC_L_MASK | - (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT)); -#endif - write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff, - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | - (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT)); - } - - cpu_x86_load_seg(env, R_CS, __USER_CS); - cpu_x86_load_seg(env, R_SS, __USER_DS); -#ifdef TARGET_ABI32 - cpu_x86_load_seg(env, R_DS, __USER_DS); - cpu_x86_load_seg(env, R_ES, __USER_DS); - cpu_x86_load_seg(env, R_FS, __USER_DS); - cpu_x86_load_seg(env, R_GS, __USER_DS); - /* This hack makes Wine work... */ - env->segs[R_FS].selector = 0; -#else - cpu_x86_load_seg(env, R_DS, 0); - cpu_x86_load_seg(env, R_ES, 0); - cpu_x86_load_seg(env, R_FS, 0); - cpu_x86_load_seg(env, R_GS, 0); -#endif -#elif defined(TARGET_SPARC) - { - int i; - env->pc = regs->pc; - env->npc = regs->npc; - env->y = regs->y; - for (i = 0; i < 8; i++) { - env->gregs[i] = regs->u_regs[i]; - } - for (i = 0; i < 8; i++) { - env->regwptr[i] = regs->u_regs[i + 8]; - } - } -#else -#error unsupported target CPU -#endif + target_cpu_init(env, regs); if (gdbstub) { gdbserver_start(gdbstub); |