X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=linux-user%2Fmain.c;h=d8b0cd65fa71a48b55c00bb5cbf59c321f065a85;hb=f2b79ce9dc65753c6833921dd5ef6fa59632851f;hp=0181bc211257ec10424f36c2b3a5a5b511fcc3cd;hpb=63fb2590839162afdf14d7c0ee02d460766c0956;p=qemu.git diff --git a/linux-user/main.c b/linux-user/main.c index 0181bc211..d8b0cd65f 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -35,8 +35,6 @@ #include "qemu/envlist.h" #include "elf.h" -#define DEBUG_LOGFILE "/tmp/qemu.log" - char *exec_path; int singlestep; @@ -111,7 +109,7 @@ static int pending_cpus; /* Make sure everything is in a consistent state for calling fork(). */ void fork_start(void) { - pthread_mutex_lock(&tb_lock); + pthread_mutex_lock(&tcg_ctx.tb_ctx.tb_lock); pthread_mutex_lock(&exclusive_lock); mmap_fork_start(); } @@ -129,11 +127,11 @@ void fork_end(int child) pthread_mutex_init(&cpu_list_mutex, NULL); pthread_cond_init(&exclusive_cond, NULL); pthread_cond_init(&exclusive_resume, NULL); - pthread_mutex_init(&tb_lock, NULL); + pthread_mutex_init(&tcg_ctx.tb_ctx.tb_lock, NULL); gdbserver_fork(thread_env); } else { pthread_mutex_unlock(&exclusive_lock); - pthread_mutex_unlock(&tb_lock); + pthread_mutex_unlock(&tcg_ctx.tb_ctx.tb_lock); } } @@ -151,13 +149,16 @@ static inline void exclusive_idle(void) static inline void start_exclusive(void) { CPUArchState *other; + CPUState *other_cpu; + pthread_mutex_lock(&exclusive_lock); exclusive_idle(); pending_cpus = 1; /* Make all other cpus stop executing. */ for (other = first_cpu; other; other = other->next_cpu) { - if (other->running) { + other_cpu = ENV_GET_CPU(other); + if (other_cpu->running) { pending_cpus++; cpu_exit(other); } @@ -176,19 +177,19 @@ static inline void end_exclusive(void) } /* Wait for exclusive ops to finish, and begin cpu execution. */ -static inline void cpu_exec_start(CPUArchState *env) +static inline void cpu_exec_start(CPUState *cpu) { pthread_mutex_lock(&exclusive_lock); exclusive_idle(); - env->running = 1; + cpu->running = true; pthread_mutex_unlock(&exclusive_lock); } /* Mark cpu as not executing, and release pending exclusive ops. */ -static inline void cpu_exec_end(CPUArchState *env) +static inline void cpu_exec_end(CPUState *cpu) { pthread_mutex_lock(&exclusive_lock); - env->running = 0; + cpu->running = false; if (pending_cpus > 1) { pending_cpus--; if (pending_cpus == 1) { @@ -210,11 +211,11 @@ void cpu_list_unlock(void) } #else /* if !CONFIG_USE_NPTL */ /* These are no-ops because we are not threadsafe. */ -static inline void cpu_exec_start(CPUArchState *env) +static inline void cpu_exec_start(CPUState *cpu) { } -static inline void cpu_exec_end(CPUArchState *env) +static inline void cpu_exec_end(CPUState *cpu) { } @@ -697,15 +698,16 @@ done: void cpu_loop(CPUARMState *env) { + CPUState *cs = CPU(arm_env_get_cpu(env)); int trapnr; unsigned int n, insn; target_siginfo_t info; uint32_t addr; for(;;) { - cpu_exec_start(env); + cpu_exec_start(cs); trapnr = cpu_arm_exec(env); - cpu_exec_end(env); + cpu_exec_end(cs); switch(trapnr) { case EXCP_UDEF: { @@ -912,14 +914,15 @@ void cpu_loop(CPUARMState *env) void cpu_loop(CPUUniCore32State *env) { + CPUState *cs = CPU(uc32_env_get_cpu(env)); int trapnr; unsigned int n, insn; target_siginfo_t info; for (;;) { - cpu_exec_start(env); + cpu_exec_start(cs); trapnr = uc32_cpu_exec(env); - cpu_exec_end(env); + cpu_exec_end(cs); switch (trapnr) { case UC32_EXCP_PRIV: { @@ -1367,14 +1370,15 @@ static int do_store_exclusive(CPUPPCState *env) void cpu_loop(CPUPPCState *env) { + CPUState *cs = CPU(ppc_env_get_cpu(env)); target_siginfo_t info; int trapnr; target_ulong ret; for(;;) { - cpu_exec_start(env); + cpu_exec_start(cs); trapnr = cpu_ppc_exec(env); - cpu_exec_end(env); + cpu_exec_end(cs); switch(trapnr) { case POWERPC_EXCP_NONE: /* Just go on */ @@ -1783,8 +1787,8 @@ void cpu_loop(CPUPPCState *env) #ifdef TARGET_MIPS -#define MIPS_SYS(name, args) args, - +# ifdef TARGET_ABI_MIPSO32 +# define MIPS_SYS(name, args) args, static const uint8_t mips_syscall_args[] = { MIPS_SYS(sys_syscall , 8) /* 4000 */ MIPS_SYS(sys_exit , 1) @@ -2130,8 +2134,8 @@ static const uint8_t mips_syscall_args[] = { MIPS_SYS(sys_clock_adjtime, 2) MIPS_SYS(sys_syncfs, 1) }; - -#undef MIPS_SYS +# undef MIPS_SYS +# endif /* O32 */ static int do_store_exclusive(CPUMIPSState *env) { @@ -2182,20 +2186,52 @@ static int do_store_exclusive(CPUMIPSState *env) return segv; } +/* Break codes */ +enum { + BRK_OVERFLOW = 6, + BRK_DIVZERO = 7 +}; + +static int do_break(CPUMIPSState *env, target_siginfo_t *info, + unsigned int code) +{ + int ret = -1; + + switch (code) { + case BRK_OVERFLOW: + case BRK_DIVZERO: + info->si_signo = TARGET_SIGFPE; + info->si_errno = 0; + info->si_code = (code == BRK_OVERFLOW) ? FPE_INTOVF : FPE_INTDIV; + queue_signal(env, info->si_signo, &*info); + ret = 0; + break; + default: + break; + } + + return ret; +} + void cpu_loop(CPUMIPSState *env) { + CPUState *cs = CPU(mips_env_get_cpu(env)); target_siginfo_t info; - int trapnr, ret; + int trapnr; + abi_long ret; +# ifdef TARGET_ABI_MIPSO32 unsigned int syscall_num; +# endif for(;;) { - cpu_exec_start(env); + cpu_exec_start(cs); trapnr = cpu_mips_exec(env); - cpu_exec_end(env); + cpu_exec_end(cs); switch(trapnr) { case EXCP_SYSCALL: - syscall_num = env->active_tc.gpr[2] - 4000; env->active_tc.PC += 4; +# ifdef TARGET_ABI_MIPSO32 + syscall_num = env->active_tc.gpr[2] - 4000; if (syscall_num >= sizeof(mips_syscall_args)) { ret = -TARGET_ENOSYS; } else { @@ -2234,12 +2270,19 @@ void cpu_loop(CPUMIPSState *env) arg5, arg6, arg7, arg8); } done_syscall: +# else + ret = do_syscall(env, env->active_tc.gpr[2], + env->active_tc.gpr[4], env->active_tc.gpr[5], + env->active_tc.gpr[6], env->active_tc.gpr[7], + env->active_tc.gpr[8], env->active_tc.gpr[9], + env->active_tc.gpr[10], env->active_tc.gpr[11]); +# endif /* O32 */ if (ret == -TARGET_QEMU_ESIGRETURN) { /* Returning from a successful sigreturn syscall. Avoid clobbering register state. */ break; } - if ((unsigned int)ret >= (unsigned int)(-1133)) { + if ((abi_ulong)ret >= (abi_ulong)-1133) { env->active_tc.gpr[7] = 1; /* error flag */ ret = -ret; } else { @@ -2297,8 +2340,55 @@ done_syscall: info.si_code = TARGET_ILL_ILLOPC; queue_signal(env, info.si_signo, &info); break; + /* The code below was inspired by the MIPS Linux kernel trap + * handling code in arch/mips/kernel/traps.c. + */ + case EXCP_BREAK: + { + abi_ulong trap_instr; + unsigned int code; + + ret = get_user_ual(trap_instr, env->active_tc.PC); + if (ret != 0) { + goto error; + } + + /* As described in the original Linux kernel code, the + * below checks on 'code' are to work around an old + * assembly bug. + */ + code = ((trap_instr >> 6) & ((1 << 20) - 1)); + if (code >= (1 << 10)) { + code >>= 10; + } + + if (do_break(env, &info, code) != 0) { + goto error; + } + } + break; + case EXCP_TRAP: + { + abi_ulong trap_instr; + unsigned int code = 0; + + ret = get_user_ual(trap_instr, env->active_tc.PC); + if (ret != 0) { + goto error; + } + + /* The immediate versions don't provide a code. */ + if (!(trap_instr & 0xFC000000)) { + code = ((trap_instr >> 6) & ((1 << 10) - 1)); + } + + if (do_break(env, &info, code) != 0) { + goto error; + } + } + break; default: - // error: +error: fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr); cpu_dump_state(env, stderr, fprintf, 0); @@ -3098,22 +3188,18 @@ static void handle_arg_help(const char *arg) static void handle_arg_log(const char *arg) { int mask; - const CPULogItem *item; - mask = cpu_str_to_log_mask(arg); + mask = qemu_str_to_log_mask(arg); if (!mask) { - printf("Log items (comma separated):\n"); - for (item = cpu_log_items; item->mask != 0; item++) { - printf("%-10s %s\n", item->name, item->help); - } + qemu_print_log_usage(stdout); exit(1); } - cpu_set_log(mask); + qemu_set_log(mask); } static void handle_arg_log_filename(const char *arg) { - cpu_set_log_filename(arg); + qemu_set_log_filename(arg); } static void handle_arg_set_env(const char *arg) @@ -3293,9 +3379,10 @@ static const struct qemu_argument arg_table[] = { "size", "reserve 'size' bytes for guest virtual address space"}, #endif {"d", "QEMU_LOG", true, handle_arg_log, - "options", "activate log"}, + "item[,...]", "enable logging of specified items " + "(use '-d help' for a list of items)"}, {"D", "QEMU_LOG_FILENAME", true, handle_arg_log_filename, - "logfile", "override default logfile location"}, + "logfile", "write logs to 'logfile' (default stderr)"}, {"p", "QEMU_PAGESIZE", true, handle_arg_pagesize, "pagesize", "set the host page size to 'pagesize'"}, {"singlestep", "QEMU_SINGLESTEP", false, handle_arg_singlestep, @@ -3348,11 +3435,9 @@ static void usage(void) printf("\n" "Defaults:\n" "QEMU_LD_PREFIX = %s\n" - "QEMU_STACK_SIZE = %ld byte\n" - "QEMU_LOG = %s\n", + "QEMU_STACK_SIZE = %ld byte\n", interp_prefix, - guest_stack_size, - DEBUG_LOGFILE); + guest_stack_size); printf("\n" "You can use -E and -U options or the QEMU_SET_ENV and\n" @@ -3436,7 +3521,6 @@ static int parse_args(int argc, char **argv) int main(int argc, char **argv, char **envp) { - const char *log_file = DEBUG_LOGFILE; struct target_pt_regs regs1, *regs = ®s1; struct image_info info1, *info = &info1; struct linux_binprm bprm; @@ -3479,8 +3563,6 @@ int main(int argc, char **argv, char **envp) cpudef_setup(); /* parse cpu definitions in target config file (TBD) */ #endif - /* init debug */ - cpu_set_log_filename(log_file); optind = parse_args(argc, argv); /* Zero out regs */ @@ -3540,7 +3622,7 @@ int main(int argc, char **argv, char **envp) fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } -#if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC) +#if defined(TARGET_SPARC) || defined(TARGET_PPC) cpu_reset(ENV_GET_CPU(env)); #endif