char *exec_path;
int singlestep;
-const char *filename;
-const char *argv0;
-int gdbstub_port;
-envlist_t *envlist;
+static const char *filename;
+static const char *argv0;
+static int gdbstub_port;
+static envlist_t *envlist;
static const char *cpu_model;
unsigned long mmap_min_addr;
-#if defined(CONFIG_USE_GUEST_BASE)
unsigned long guest_base;
int have_guest_base;
#if (TARGET_LONG_BITS == 32) && (HOST_LONG_BITS == 64)
#else
unsigned long reserved_va;
#endif
-#endif
-static void usage(void);
+static void usage(int exitcode);
static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
const char *qemu_uname_release;
/* Make sure everything is in a consistent state for calling fork(). */
void fork_start(void)
{
- pthread_mutex_lock(&tcg_ctx.tb_ctx.tb_lock);
+ qemu_mutex_lock(&tcg_ctx.tb_ctx.tb_lock);
pthread_mutex_lock(&exclusive_lock);
mmap_fork_start();
}
pthread_mutex_init(&cpu_list_mutex, NULL);
pthread_cond_init(&exclusive_cond, NULL);
pthread_cond_init(&exclusive_resume, NULL);
- pthread_mutex_init(&tcg_ctx.tb_ctx.tb_lock, NULL);
- gdbserver_fork((CPUArchState *)thread_cpu->env_ptr);
+ qemu_mutex_init(&tcg_ctx.tb_ctx.tb_lock);
+ gdbserver_fork(thread_cpu);
} else {
pthread_mutex_unlock(&exclusive_lock);
- pthread_mutex_unlock(&tcg_ctx.tb_ctx.tb_lock);
+ qemu_mutex_unlock(&tcg_ctx.tb_ctx.tb_lock);
}
}
for(;;) {
cpu_exec_start(cs);
- trapnr = cpu_x86_exec(env);
+ trapnr = cpu_x86_exec(cs);
cpu_exec_end(cs);
switch(trapnr) {
case 0x80:
for(;;) {
cpu_exec_start(cs);
- trapnr = cpu_arm_exec(env);
+ trapnr = cpu_arm_exec(cs);
cpu_exec_end(cs);
switch(trapnr) {
case EXCP_UDEF:
for (;;) {
cpu_exec_start(cs);
- trapnr = cpu_arm_exec(env);
+ trapnr = cpu_arm_exec(cs);
cpu_exec_end(cs);
switch (trapnr) {
queue_signal(env, info.si_signo, &info);
}
break;
+ case EXCP_SEMIHOST:
+ env->xregs[0] = do_arm_semihosting(env);
+ break;
default:
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
trapnr);
for (;;) {
cpu_exec_start(cs);
- trapnr = uc32_cpu_exec(env);
+ trapnr = uc32_cpu_exec(cs);
cpu_exec_end(cs);
switch (trapnr) {
case UC32_EXCP_PRIV:
while (1) {
cpu_exec_start(cs);
- trapnr = cpu_sparc_exec (env);
+ trapnr = cpu_sparc_exec(cs);
cpu_exec_end(cs);
/* Compute PSR before exposing state. */
#ifdef TARGET_PPC
static inline uint64_t cpu_ppc_get_tb(CPUPPCState *env)
{
- /* TO FIX */
- return 0;
+ return cpu_get_real_ticks();
}
uint64_t cpu_ppc_load_tbl(CPUPPCState *env)
for(;;) {
cpu_exec_start(cs);
- trapnr = cpu_ppc_exec(env);
+ trapnr = cpu_ppc_exec(cs);
cpu_exec_end(cs);
switch(trapnr) {
case POWERPC_EXCP_NONE:
info.si_signo = TARGET_SIGBUS;
info.si_errno = 0;
info.si_code = TARGET_BUS_ADRALN;
- info._sifields._sigfault._addr = env->nip - 4;
+ info._sifields._sigfault._addr = env->nip;
queue_signal(env, info.si_signo, &info);
break;
case POWERPC_EXCP_PROGRAM: /* Program exception */
for(;;) {
cpu_exec_start(cs);
- trapnr = cpu_mips_exec(env);
+ trapnr = cpu_mips_exec(cs);
cpu_exec_end(cs);
switch(trapnr) {
case EXCP_SYSCALL:
code = (trap_instr >> 6) & 0x3f;
}
} else {
- ret = get_user_ual(trap_instr, env->active_tc.PC);
+ ret = get_user_u32(trap_instr, env->active_tc.PC);
if (ret != 0) {
goto error;
}
trap_instr = (instr[0] << 16) | instr[1];
} else {
- ret = get_user_ual(trap_instr, env->active_tc.PC);
+ ret = get_user_u32(trap_instr, env->active_tc.PC);
}
if (ret != 0) {
for (;;) {
cpu_exec_start(cs);
- trapnr = cpu_exec(env);
+ trapnr = cpu_openrisc_exec(cs);
cpu_exec_end(cs);
gdbsig = 0;
while (1) {
cpu_exec_start(cs);
- trapnr = cpu_sh4_exec (env);
+ trapnr = cpu_sh4_exec(cs);
cpu_exec_end(cs);
switch (trapnr) {
while (1) {
cpu_exec_start(cs);
- trapnr = cpu_cris_exec (env);
+ trapnr = cpu_cris_exec(cs);
cpu_exec_end(cs);
switch (trapnr) {
case 0xaa:
while (1) {
cpu_exec_start(cs);
- trapnr = cpu_mb_exec (env);
+ trapnr = cpu_mb_exec(cs);
cpu_exec_end(cs);
switch (trapnr) {
case 0xaa:
for(;;) {
cpu_exec_start(cs);
- trapnr = cpu_m68k_exec(env);
+ trapnr = cpu_m68k_exec(cs);
cpu_exec_end(cs);
switch(trapnr) {
case EXCP_ILLEGAL:
while (1) {
cpu_exec_start(cs);
- trapnr = cpu_alpha_exec (env);
+ trapnr = cpu_alpha_exec(cs);
cpu_exec_end(cs);
/* All of the traps imply a transition through PALcode, which
while (1) {
cpu_exec_start(cs);
- trapnr = cpu_s390x_exec(env);
+ trapnr = cpu_s390x_exec(cs);
cpu_exec_end(cs);
switch (trapnr) {
case EXCP_INTERRUPT:
#endif /* TARGET_S390X */
+#ifdef TARGET_TILEGX
+
+static void gen_sigsegv_maperr(CPUTLGState *env, target_ulong addr)
+{
+ target_siginfo_t info;
+
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SEGV_MAPERR;
+ info._sifields._sigfault._addr = addr;
+ queue_signal(env, info.si_signo, &info);
+}
+
+static void gen_sigill_reg(CPUTLGState *env)
+{
+ target_siginfo_t info;
+
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ info.si_code = TARGET_ILL_PRVREG;
+ info._sifields._sigfault._addr = env->pc;
+ queue_signal(env, info.si_signo, &info);
+}
+
+static void set_regval(CPUTLGState *env, uint8_t reg, uint64_t val)
+{
+ if (unlikely(reg >= TILEGX_R_COUNT)) {
+ switch (reg) {
+ case TILEGX_R_SN:
+ case TILEGX_R_ZERO:
+ return;
+ case TILEGX_R_IDN0:
+ case TILEGX_R_IDN1:
+ case TILEGX_R_UDN0:
+ case TILEGX_R_UDN1:
+ case TILEGX_R_UDN2:
+ case TILEGX_R_UDN3:
+ gen_sigill_reg(env);
+ return;
+ default:
+ g_assert_not_reached();
+ }
+ }
+ env->regs[reg] = val;
+}
+
+/*
+ * Compare the 8-byte contents of the CmpValue SPR with the 8-byte value in
+ * memory at the address held in the first source register. If the values are
+ * not equal, then no memory operation is performed. If the values are equal,
+ * the 8-byte quantity from the second source register is written into memory
+ * at the address held in the first source register. In either case, the result
+ * of the instruction is the value read from memory. The compare and write to
+ * memory are atomic and thus can be used for synchronization purposes. This
+ * instruction only operates for addresses aligned to a 8-byte boundary.
+ * Unaligned memory access causes an Unaligned Data Reference interrupt.
+ *
+ * Functional Description (64-bit)
+ * uint64_t memVal = memoryReadDoubleWord (rf[SrcA]);
+ * rf[Dest] = memVal;
+ * if (memVal == SPR[CmpValueSPR])
+ * memoryWriteDoubleWord (rf[SrcA], rf[SrcB]);
+ *
+ * Functional Description (32-bit)
+ * uint64_t memVal = signExtend32 (memoryReadWord (rf[SrcA]));
+ * rf[Dest] = memVal;
+ * if (memVal == signExtend32 (SPR[CmpValueSPR]))
+ * memoryWriteWord (rf[SrcA], rf[SrcB]);
+ *
+ *
+ * This function also processes exch and exch4 which need not process SPR.
+ */
+static void do_exch(CPUTLGState *env, bool quad, bool cmp)
+{
+ target_ulong addr;
+ target_long val, sprval;
+
+ start_exclusive();
+
+ addr = env->atomic_srca;
+ if (quad ? get_user_s64(val, addr) : get_user_s32(val, addr)) {
+ goto sigsegv_maperr;
+ }
+
+ if (cmp) {
+ if (quad) {
+ sprval = env->spregs[TILEGX_SPR_CMPEXCH];
+ } else {
+ sprval = sextract64(env->spregs[TILEGX_SPR_CMPEXCH], 0, 32);
+ }
+ }
+
+ if (!cmp || val == sprval) {
+ target_long valb = env->atomic_srcb;
+ if (quad ? put_user_u64(valb, addr) : put_user_u32(valb, addr)) {
+ goto sigsegv_maperr;
+ }
+ }
+
+ set_regval(env, env->atomic_dstr, val);
+ end_exclusive();
+ return;
+
+ sigsegv_maperr:
+ end_exclusive();
+ gen_sigsegv_maperr(env, addr);
+}
+
+static void do_fetch(CPUTLGState *env, int trapnr, bool quad)
+{
+ int8_t write = 1;
+ target_ulong addr;
+ target_long val, valb;
+
+ start_exclusive();
+
+ addr = env->atomic_srca;
+ valb = env->atomic_srcb;
+ if (quad ? get_user_s64(val, addr) : get_user_s32(val, addr)) {
+ goto sigsegv_maperr;
+ }
+
+ switch (trapnr) {
+ case TILEGX_EXCP_OPCODE_FETCHADD:
+ case TILEGX_EXCP_OPCODE_FETCHADD4:
+ valb += val;
+ break;
+ case TILEGX_EXCP_OPCODE_FETCHADDGEZ:
+ valb += val;
+ if (valb < 0) {
+ write = 0;
+ }
+ break;
+ case TILEGX_EXCP_OPCODE_FETCHADDGEZ4:
+ valb += val;
+ if ((int32_t)valb < 0) {
+ write = 0;
+ }
+ break;
+ case TILEGX_EXCP_OPCODE_FETCHAND:
+ case TILEGX_EXCP_OPCODE_FETCHAND4:
+ valb &= val;
+ break;
+ case TILEGX_EXCP_OPCODE_FETCHOR:
+ case TILEGX_EXCP_OPCODE_FETCHOR4:
+ valb |= val;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ if (write) {
+ if (quad ? put_user_u64(valb, addr) : put_user_u32(valb, addr)) {
+ goto sigsegv_maperr;
+ }
+ }
+
+ set_regval(env, env->atomic_dstr, val);
+ end_exclusive();
+ return;
+
+ sigsegv_maperr:
+ end_exclusive();
+ gen_sigsegv_maperr(env, addr);
+}
+
+void cpu_loop(CPUTLGState *env)
+{
+ CPUState *cs = CPU(tilegx_env_get_cpu(env));
+ int trapnr;
+
+ while (1) {
+ cpu_exec_start(cs);
+ trapnr = cpu_tilegx_exec(cs);
+ cpu_exec_end(cs);
+ switch (trapnr) {
+ case TILEGX_EXCP_SYSCALL:
+ env->regs[TILEGX_R_RE] = do_syscall(env, env->regs[TILEGX_R_NR],
+ env->regs[0], env->regs[1],
+ env->regs[2], env->regs[3],
+ env->regs[4], env->regs[5],
+ env->regs[6], env->regs[7]);
+ env->regs[TILEGX_R_ERR] = TILEGX_IS_ERRNO(env->regs[TILEGX_R_RE])
+ ? - env->regs[TILEGX_R_RE]
+ : 0;
+ break;
+ case TILEGX_EXCP_OPCODE_EXCH:
+ do_exch(env, true, false);
+ break;
+ case TILEGX_EXCP_OPCODE_EXCH4:
+ do_exch(env, false, false);
+ break;
+ case TILEGX_EXCP_OPCODE_CMPEXCH:
+ do_exch(env, true, true);
+ break;
+ case TILEGX_EXCP_OPCODE_CMPEXCH4:
+ do_exch(env, false, true);
+ break;
+ case TILEGX_EXCP_OPCODE_FETCHADD:
+ case TILEGX_EXCP_OPCODE_FETCHADDGEZ:
+ case TILEGX_EXCP_OPCODE_FETCHAND:
+ case TILEGX_EXCP_OPCODE_FETCHOR:
+ do_fetch(env, trapnr, true);
+ break;
+ case TILEGX_EXCP_OPCODE_FETCHADD4:
+ case TILEGX_EXCP_OPCODE_FETCHADDGEZ4:
+ case TILEGX_EXCP_OPCODE_FETCHAND4:
+ case TILEGX_EXCP_OPCODE_FETCHOR4:
+ do_fetch(env, trapnr, false);
+ break;
+ case TILEGX_EXCP_REG_IDN_ACCESS:
+ case TILEGX_EXCP_REG_UDN_ACCESS:
+ gen_sigill_reg(env);
+ break;
+ case TILEGX_EXCP_SEGV:
+ gen_sigsegv_maperr(env, env->excaddr);
+ break;
+ default:
+ fprintf(stderr, "trapnr is %d[0x%x].\n", trapnr, trapnr);
+ g_assert_not_reached();
+ }
+ process_pending_signals(env);
+ }
+}
+
+#endif
+
THREAD CPUState *thread_cpu;
void task_settid(TaskState *ts)
/* Clone all break/watchpoints.
Note: Once we support ptrace with hw-debug register access, make sure
BP_CPU break/watchpoints are handled correctly on clone. */
- QTAILQ_INIT(&cpu->breakpoints);
- QTAILQ_INIT(&cpu->watchpoints);
+ QTAILQ_INIT(&new_cpu->breakpoints);
+ QTAILQ_INIT(&new_cpu->watchpoints);
QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
cpu_breakpoint_insert(new_cpu, bp->pc, bp->flags, NULL);
}
static void handle_arg_help(const char *arg)
{
- usage();
+ usage(0);
}
static void handle_arg_log(const char *arg)
r = p = strdup(arg);
while ((token = strsep(&p, ",")) != NULL) {
if (envlist_setenv(envlist, token) != 0) {
- usage();
+ usage(1);
}
}
free(r);
r = p = strdup(arg);
while ((token = strsep(&p, ",")) != NULL) {
if (envlist_unsetenv(envlist, token) != 0) {
- usage();
+ usage(1);
}
}
free(r);
char *p;
guest_stack_size = strtoul(arg, &p, 0);
if (guest_stack_size == 0) {
- usage();
+ usage(1);
}
if (*p == 'M') {
}
}
-#if defined(CONFIG_USE_GUEST_BASE)
static void handle_arg_guest_base(const char *arg)
{
guest_base = strtol(arg, NULL, 0);
exit(1);
}
}
-#endif
static void handle_arg_singlestep(const char *arg)
{
static const struct qemu_argument arg_table[] = {
{"h", "", false, handle_arg_help,
"", "print this help"},
+ {"help", "", false, handle_arg_help,
+ "", ""},
{"g", "QEMU_GDB", true, handle_arg_gdb,
"port", "wait gdb connection to 'port'"},
{"L", "QEMU_LD_PREFIX", true, handle_arg_ld_prefix,
"argv0", "forces target process argv[0] to be 'argv0'"},
{"r", "QEMU_UNAME", true, handle_arg_uname,
"uname", "set qemu uname release string to 'uname'"},
-#if defined(CONFIG_USE_GUEST_BASE)
{"B", "QEMU_GUEST_BASE", true, handle_arg_guest_base,
"address", "set guest_base address to 'address'"},
{"R", "QEMU_RESERVED_VA", true, handle_arg_reserved_va,
"size", "reserve 'size' bytes for guest virtual address space"},
-#endif
{"d", "QEMU_LOG", true, handle_arg_log,
"item[,...]", "enable logging of specified items "
"(use '-d help' for a list of items)"},
{NULL, NULL, false, NULL, NULL, NULL}
};
-static void usage(void)
+static void usage(int exitcode)
{
const struct qemu_argument *arginfo;
int maxarglen;
"Note that if you provide several changes to a single variable\n"
"the last change will stay in effect.\n");
- exit(1);
+ exit(exitcode);
}
static int parse_args(int argc, char **argv)
if (!strcmp(r, arginfo->argv)) {
if (arginfo->has_arg) {
if (optind >= argc) {
- usage();
+ usage(1);
}
arginfo->handle_opt(argv[optind]);
optind++;
/* no option matched the current argv */
if (arginfo->handle_opt == NULL) {
- usage();
+ usage(1);
}
}
if (optind >= argc) {
- usage();
+ usage(1);
}
filename = argv[optind];
# else
cpu_model = "750";
# endif
+#elif defined TARGET_SH4
+ cpu_model = TYPE_SH7785_CPU;
#else
cpu_model = "any";
#endif
target_environ = envlist_to_environ(envlist, NULL);
envlist_free(envlist);
-#if defined(CONFIG_USE_GUEST_BASE)
/*
* Now that page sizes are configured in cpu_init() we can do
* proper page alignment for guest_base.
mmap_next_start = reserved_va;
}
}
-#endif /* CONFIG_USE_GUEST_BASE */
/*
* Read in mmap_min_addr kernel parameter. This value is used
free(target_environ);
if (qemu_log_enabled()) {
-#if defined(CONFIG_USE_GUEST_BASE)
qemu_log("guest_base 0x%lx\n", guest_base);
-#endif
log_page_dump();
qemu_log("start_brk 0x" TARGET_ABI_FMT_lx "\n", info->start_brk);
syscall_init();
signal_init();
-#if defined(CONFIG_USE_GUEST_BASE)
/* Now that we've loaded the binary, GUEST_BASE is fixed. Delay
generating the prologue until now so that the prologue can take
the real value of GUEST_BASE into account. */
tcg_prologue_init(&tcg_ctx);
-#endif
#if defined(TARGET_I386)
env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
env->psw.mask = regs->psw.mask;
env->psw.addr = regs->psw.addr;
}
+#elif defined(TARGET_TILEGX)
+ {
+ int i;
+ for (i = 0; i < TILEGX_R_COUNT; i++) {
+ env->regs[i] = regs->regs[i];
+ }
+ for (i = 0; i < TILEGX_SPR_COUNT; i++) {
+ env->spregs[i] = 0;
+ }
+ env->pc = regs->pc;
+ }
#else
#error unsupported target CPU
#endif