* This way we will never overlap with our own libraries or binaries or stack
* or anything else that QEMU maps.
*/
-# ifdef TARGET_MIPS
-/* MIPS only supports 31 bits of virtual address space for user space */
+# if defined(TARGET_MIPS) || defined(TARGET_NIOS2)
+/*
+ * MIPS only supports 31 bits of virtual address space for user space.
+ * Nios2 also only supports 31 bits.
+ */
unsigned long reserved_va = 0x77000000;
# else
unsigned long reserved_va = 0xf7000000;
switch(trapnr) {
case EXCP_UDEF:
+ case EXCP_NOCP:
+ case EXCP_INVSTATE:
{
TaskState *ts = cs->opaque;
uint32_t opcode;
/* XXX: check env->error_code */
info.si_code = TARGET_SEGV_MAPERR;
if (trapnr == TT_DFAULT)
- info._sifields._sigfault._addr = env->dmmuregs[4];
+ info._sifields._sigfault._addr = env->dmmu.mmuregs[4];
else
info._sifields._sigfault._addr = cpu_tsptr(env)->tpc;
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
* in syscalls.
*/
env->crf[0] &= ~0x1;
+ env->nip += 4;
ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
env->gpr[5], env->gpr[6], env->gpr[7],
env->gpr[8], 0, 0);
if (ret == -TARGET_ERESTARTSYS) {
+ env->nip -= 4;
break;
}
if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) {
Avoid corrupting register state. */
break;
}
- env->nip += 4;
if (ret > (target_ulong)(-515)) {
env->crf[0] |= 0x1;
ret = -ret;
}
#endif
-#ifdef TARGET_OPENRISC
+#ifdef TARGET_NIOS2
-void cpu_loop(CPUOpenRISCState *env)
+void cpu_loop(CPUNios2State *env)
{
- CPUState *cs = CPU(openrisc_env_get_cpu(env));
- int trapnr, gdbsig;
- abi_long ret;
+ CPUState *cs = ENV_GET_CPU(env);
+ Nios2CPU *cpu = NIOS2_CPU(cs);
+ target_siginfo_t info;
+ int trapnr, gdbsig, ret;
for (;;) {
cpu_exec_start(cs);
trapnr = cpu_exec(cs);
cpu_exec_end(cs);
- process_queued_cpu_work(cs);
gdbsig = 0;
switch (trapnr) {
- case EXCP_RESET:
- qemu_log_mask(CPU_LOG_INT, "\nReset request, exit, pc is %#x\n", env->pc);
- exit(EXIT_FAILURE);
- break;
- case EXCP_BUSERR:
- qemu_log_mask(CPU_LOG_INT, "\nBus error, exit, pc is %#x\n", env->pc);
- gdbsig = TARGET_SIGBUS;
- break;
- case EXCP_DPF:
- case EXCP_IPF:
- cpu_dump_state(cs, stderr, fprintf, 0);
- gdbsig = TARGET_SIGSEGV;
- break;
- case EXCP_TICK:
- qemu_log_mask(CPU_LOG_INT, "\nTick time interrupt pc is %#x\n", env->pc);
+ case EXCP_INTERRUPT:
+ /* just indicate that signals should be handled asap */
break;
- case EXCP_ALIGN:
- qemu_log_mask(CPU_LOG_INT, "\nAlignment pc is %#x\n", env->pc);
- gdbsig = TARGET_SIGBUS;
+ case EXCP_TRAP:
+ if (env->regs[R_AT] == 0) {
+ abi_long ret;
+ qemu_log_mask(CPU_LOG_INT, "\nSyscall\n");
+
+ ret = do_syscall(env, env->regs[2],
+ env->regs[4], env->regs[5], env->regs[6],
+ env->regs[7], env->regs[8], env->regs[9],
+ 0, 0);
+
+ if (env->regs[2] == 0) { /* FIXME: syscall 0 workaround */
+ ret = 0;
+ }
+
+ env->regs[2] = abs(ret);
+ /* Return value is 0..4096 */
+ env->regs[7] = (ret > 0xfffffffffffff000ULL);
+ env->regs[CR_ESTATUS] = env->regs[CR_STATUS];
+ env->regs[CR_STATUS] &= ~0x3;
+ env->regs[R_EA] = env->regs[R_PC] + 4;
+ env->regs[R_PC] += 4;
+ break;
+ } else {
+ qemu_log_mask(CPU_LOG_INT, "\nTrap\n");
+
+ env->regs[CR_ESTATUS] = env->regs[CR_STATUS];
+ env->regs[CR_STATUS] &= ~0x3;
+ env->regs[R_EA] = env->regs[R_PC] + 4;
+ env->regs[R_PC] = cpu->exception_addr;
+
+ gdbsig = TARGET_SIGTRAP;
+ break;
+ }
+ case 0xaa:
+ switch (env->regs[R_PC]) {
+ /*case 0x1000:*/ /* TODO:__kuser_helper_version */
+ case 0x1004: /* __kuser_cmpxchg */
+ start_exclusive();
+ if (env->regs[4] & 0x3) {
+ goto kuser_fail;
+ }
+ ret = get_user_u32(env->regs[2], env->regs[4]);
+ if (ret) {
+ end_exclusive();
+ goto kuser_fail;
+ }
+ env->regs[2] -= env->regs[5];
+ if (env->regs[2] == 0) {
+ put_user_u32(env->regs[6], env->regs[4]);
+ }
+ end_exclusive();
+ env->regs[R_PC] = env->regs[R_RA];
+ break;
+ /*case 0x1040:*/ /* TODO:__kuser_sigtramp */
+ default:
+ ;
+kuser_fail:
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ /* TODO: check env->error_code */
+ info.si_code = TARGET_SEGV_MAPERR;
+ info._sifields._sigfault._addr = env->regs[R_PC];
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ }
break;
- case EXCP_ILLEGAL:
- qemu_log_mask(CPU_LOG_INT, "\nIllegal instructionpc is %#x\n", env->pc);
+ default:
+ EXCP_DUMP(env, "\nqemu: unhandled CPU exception %#x - aborting\n",
+ trapnr);
gdbsig = TARGET_SIGILL;
break;
- case EXCP_INT:
- qemu_log_mask(CPU_LOG_INT, "\nExternal interruptpc is %#x\n", env->pc);
- break;
- case EXCP_DTLBMISS:
- case EXCP_ITLBMISS:
- qemu_log_mask(CPU_LOG_INT, "\nTLB miss\n");
- break;
- case EXCP_RANGE:
- qemu_log_mask(CPU_LOG_INT, "\nRange\n");
- gdbsig = TARGET_SIGSEGV;
- break;
+ }
+ if (gdbsig) {
+ gdb_handlesig(cs, gdbsig);
+ if (gdbsig != TARGET_SIGTRAP) {
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ process_pending_signals(env);
+ }
+}
+
+#endif /* TARGET_NIOS2 */
+
+#ifdef TARGET_OPENRISC
+
+void cpu_loop(CPUOpenRISCState *env)
+{
+ CPUState *cs = CPU(openrisc_env_get_cpu(env));
+ int trapnr;
+ abi_long ret;
+ 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 EXCP_SYSCALL:
env->pc += 4; /* 0xc00; */
ret = do_syscall(env,
- env->gpr[11], /* return value */
- env->gpr[3], /* r3 - r7 are params */
- env->gpr[4],
- env->gpr[5],
- env->gpr[6],
- env->gpr[7],
- env->gpr[8], 0, 0);
+ cpu_get_gpr(env, 11), /* return value */
+ cpu_get_gpr(env, 3), /* r3 - r7 are params */
+ cpu_get_gpr(env, 4),
+ cpu_get_gpr(env, 5),
+ cpu_get_gpr(env, 6),
+ cpu_get_gpr(env, 7),
+ cpu_get_gpr(env, 8), 0, 0);
if (ret == -TARGET_ERESTARTSYS) {
env->pc -= 4;
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
- env->gpr[11] = ret;
+ cpu_set_gpr(env, 11, ret);
}
break;
+ case EXCP_DPF:
+ case EXCP_IPF:
+ case EXCP_RANGE:
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SEGV_MAPERR;
+ info._sifields._sigfault._addr = env->pc;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_ALIGN:
+ info.si_signo = TARGET_SIGBUS;
+ info.si_errno = 0;
+ info.si_code = TARGET_BUS_ADRALN;
+ info._sifields._sigfault._addr = env->pc;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_ILLEGAL:
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ info.si_code = TARGET_ILL_ILLOPC;
+ info._sifields._sigfault._addr = env->pc;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
case EXCP_FPE:
- qemu_log_mask(CPU_LOG_INT, "\nFloating point error\n");
+ info.si_signo = TARGET_SIGFPE;
+ info.si_errno = 0;
+ info.si_code = 0;
+ info._sifields._sigfault._addr = env->pc;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
- case EXCP_TRAP:
- qemu_log_mask(CPU_LOG_INT, "\nTrap\n");
- gdbsig = TARGET_SIGTRAP;
+ case EXCP_INTERRUPT:
+ /* We processed the pending cpu work above. */
break;
- case EXCP_NR:
- qemu_log_mask(CPU_LOG_INT, "\nNR\n");
+ case EXCP_DEBUG:
+ trapnr = gdb_handlesig(cs, TARGET_SIGTRAP);
+ if (trapnr) {
+ info.si_signo = trapnr;
+ info.si_errno = 0;
+ info.si_code = TARGET_TRAP_BRKPT;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ }
break;
case EXCP_ATOMIC:
cpu_exec_step_atomic(cs);
break;
default:
- EXCP_DUMP(env, "\nqemu: unhandled CPU exception %#x - aborting\n",
- trapnr);
- gdbsig = TARGET_SIGILL;
- break;
- }
- if (gdbsig) {
- gdb_handlesig(cs, gdbsig);
- if (gdbsig != TARGET_SIGTRAP) {
- exit(EXIT_FAILURE);
- }
+ g_assert_not_reached();
}
-
process_pending_signals(env);
}
}
#endif
+#ifdef TARGET_HPPA
+
+static abi_ulong hppa_lws(CPUHPPAState *env)
+{
+ uint32_t which = env->gr[20];
+ abi_ulong addr = env->gr[26];
+ abi_ulong old = env->gr[25];
+ abi_ulong new = env->gr[24];
+ abi_ulong size, ret;
+
+ switch (which) {
+ default:
+ return -TARGET_ENOSYS;
+
+ case 0: /* elf32 atomic 32bit cmpxchg */
+ if ((addr & 3) || !access_ok(VERIFY_WRITE, addr, 4)) {
+ return -TARGET_EFAULT;
+ }
+ old = tswap32(old);
+ new = tswap32(new);
+ ret = atomic_cmpxchg((uint32_t *)g2h(addr), old, new);
+ ret = tswap32(ret);
+ break;
+
+ case 2: /* elf32 atomic "new" cmpxchg */
+ size = env->gr[23];
+ if (size >= 4) {
+ return -TARGET_ENOSYS;
+ }
+ if (((addr | old | new) & ((1 << size) - 1))
+ || !access_ok(VERIFY_WRITE, addr, 1 << size)
+ || !access_ok(VERIFY_READ, old, 1 << size)
+ || !access_ok(VERIFY_READ, new, 1 << size)) {
+ return -TARGET_EFAULT;
+ }
+ /* Note that below we use host-endian loads so that the cmpxchg
+ can be host-endian as well. */
+ switch (size) {
+ case 0:
+ old = *(uint8_t *)g2h(old);
+ new = *(uint8_t *)g2h(new);
+ ret = atomic_cmpxchg((uint8_t *)g2h(addr), old, new);
+ ret = ret != old;
+ break;
+ case 1:
+ old = *(uint16_t *)g2h(old);
+ new = *(uint16_t *)g2h(new);
+ ret = atomic_cmpxchg((uint16_t *)g2h(addr), old, new);
+ ret = ret != old;
+ break;
+ case 2:
+ old = *(uint32_t *)g2h(old);
+ new = *(uint32_t *)g2h(new);
+ ret = atomic_cmpxchg((uint32_t *)g2h(addr), old, new);
+ ret = ret != old;
+ break;
+ case 3:
+ {
+ uint64_t o64, n64, r64;
+ o64 = *(uint64_t *)g2h(old);
+ n64 = *(uint64_t *)g2h(new);
+#ifdef CONFIG_ATOMIC64
+ r64 = atomic_cmpxchg__nocheck((uint64_t *)g2h(addr), o64, n64);
+ ret = r64 != o64;
+#else
+ start_exclusive();
+ r64 = *(uint64_t *)g2h(addr);
+ ret = 1;
+ if (r64 == o64) {
+ *(uint64_t *)g2h(addr) = n64;
+ ret = 0;
+ }
+ end_exclusive();
+#endif
+ }
+ break;
+ }
+ break;
+ }
+
+ env->gr[28] = ret;
+ return 0;
+}
+
+void cpu_loop(CPUHPPAState *env)
+{
+ CPUState *cs = CPU(hppa_env_get_cpu(env));
+ target_siginfo_t info;
+ abi_ulong ret;
+ int trapnr;
+
+ while (1) {
+ cpu_exec_start(cs);
+ trapnr = cpu_exec(cs);
+ cpu_exec_end(cs);
+ process_queued_cpu_work(cs);
+
+ switch (trapnr) {
+ case EXCP_SYSCALL:
+ ret = do_syscall(env, env->gr[20],
+ env->gr[26], env->gr[25],
+ env->gr[24], env->gr[23],
+ env->gr[22], env->gr[21], 0, 0);
+ switch (ret) {
+ default:
+ env->gr[28] = ret;
+ /* We arrived here by faking the gateway page. Return. */
+ env->iaoq_f = env->gr[31];
+ env->iaoq_b = env->gr[31] + 4;
+ break;
+ case -TARGET_ERESTARTSYS:
+ case -TARGET_QEMU_ESIGRETURN:
+ break;
+ }
+ break;
+ case EXCP_SYSCALL_LWS:
+ env->gr[21] = hppa_lws(env);
+ /* We arrived here by faking the gateway page. Return. */
+ env->iaoq_f = env->gr[31];
+ env->iaoq_b = env->gr[31] + 4;
+ break;
+ case EXCP_SIGSEGV:
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SEGV_ACCERR;
+ info._sifields._sigfault._addr = env->ior;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_SIGILL:
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ info.si_code = TARGET_ILL_ILLOPN;
+ info._sifields._sigfault._addr = env->iaoq_f;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_SIGFPE:
+ info.si_signo = TARGET_SIGFPE;
+ info.si_errno = 0;
+ info.si_code = 0;
+ info._sifields._sigfault._addr = env->iaoq_f;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_DEBUG:
+ trapnr = gdb_handlesig(cs, TARGET_SIGTRAP);
+ if (trapnr) {
+ info.si_signo = trapnr;
+ info.si_errno = 0;
+ info.si_code = TARGET_TRAP_BRKPT;
+ queue_signal(env, trapnr, QEMU_SI_FAULT, &info);
+ }
+ break;
+ case EXCP_INTERRUPT:
+ /* just indicate that signals should be handled asap */
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ process_pending_signals(env);
+ }
+}
+
+#endif /* TARGET_HPPA */
+
THREAD CPUState *thread_cpu;
bool qemu_cpu_is_self(CPUState *cpu)
qemu_init_cpu_list();
module_call_init(MODULE_INIT_QOM);
- if ((envlist = envlist_create()) == NULL) {
- (void) fprintf(stderr, "Unable to allocate envlist\n");
- exit(EXIT_FAILURE);
- }
+ envlist = envlist_create();
/* add current environment into the list */
for (wrk = environ; *wrk != NULL; wrk++) {
# endif
#elif defined TARGET_SH4
cpu_model = TYPE_SH7785_CPU;
+#elif defined TARGET_S390X
+ cpu_model = "qemu";
#else
cpu_model = "any";
#endif
}
for (wrk = target_environ; *wrk; wrk++) {
- free(*wrk);
+ g_free(*wrk);
}
- free(target_environ);
+ g_free(target_environ);
if (qemu_loglevel_mask(CPU_LOG_PAGE)) {
qemu_log("guest_base 0x%lx\n", guest_base);
qemu_log("start_brk 0x" TARGET_ABI_FMT_lx "\n", info->start_brk);
qemu_log("end_code 0x" TARGET_ABI_FMT_lx "\n", info->end_code);
- qemu_log("start_code 0x" TARGET_ABI_FMT_lx "\n",
- info->start_code);
- qemu_log("start_data 0x" TARGET_ABI_FMT_lx "\n",
- info->start_data);
+ qemu_log("start_code 0x" TARGET_ABI_FMT_lx "\n", info->start_code);
+ qemu_log("start_data 0x" TARGET_ABI_FMT_lx "\n", info->start_data);
qemu_log("end_data 0x" TARGET_ABI_FMT_lx "\n", info->end_data);
- qemu_log("start_stack 0x" TARGET_ABI_FMT_lx "\n",
- info->start_stack);
+ qemu_log("start_stack 0x" TARGET_ABI_FMT_lx "\n", info->start_stack);
qemu_log("brk 0x" TARGET_ABI_FMT_lx "\n", info->brk);
qemu_log("entry 0x" TARGET_ABI_FMT_lx "\n", info->entry);
+ qemu_log("argv_start 0x" TARGET_ABI_FMT_lx "\n", info->arg_start);
+ qemu_log("env_start 0x" TARGET_ABI_FMT_lx "\n",
+ info->arg_end + (abi_ulong)sizeof(abi_ulong));
+ qemu_log("auxv_start 0x" TARGET_ABI_FMT_lx "\n", info->saved_auxv);
}
target_set_brk(info->brk);
restore_snan_bit_mode(env);
}
}
+#elif defined(TARGET_NIOS2)
+ {
+ env->regs[0] = 0;
+ env->regs[1] = regs->r1;
+ env->regs[2] = regs->r2;
+ env->regs[3] = regs->r3;
+ env->regs[4] = regs->r4;
+ env->regs[5] = regs->r5;
+ env->regs[6] = regs->r6;
+ env->regs[7] = regs->r7;
+ env->regs[8] = regs->r8;
+ env->regs[9] = regs->r9;
+ env->regs[10] = regs->r10;
+ env->regs[11] = regs->r11;
+ env->regs[12] = regs->r12;
+ env->regs[13] = regs->r13;
+ env->regs[14] = regs->r14;
+ env->regs[15] = regs->r15;
+ /* TODO: unsigned long orig_r2; */
+ env->regs[R_RA] = regs->ra;
+ env->regs[R_FP] = regs->fp;
+ env->regs[R_SP] = regs->sp;
+ env->regs[R_GP] = regs->gp;
+ env->regs[CR_ESTATUS] = regs->estatus;
+ env->regs[R_EA] = regs->ea;
+ /* TODO: unsigned long orig_r7; */
+
+ /* Emulate eret when starting thread. */
+ env->regs[R_PC] = regs->ea;
+ }
#elif defined(TARGET_OPENRISC)
{
int i;
for (i = 0; i < 32; i++) {
- env->gpr[i] = regs->gpr[i];
+ cpu_set_gpr(env, i, regs->gpr[i]);
}
-
- env->sr = regs->sr;
env->pc = regs->pc;
+ cpu_set_sr(env, regs->sr);
}
#elif defined(TARGET_SH4)
{
}
env->pc = regs->pc;
}
+#elif defined(TARGET_HPPA)
+ {
+ int i;
+ for (i = 1; i < 32; i++) {
+ env->gr[i] = regs->gr[i];
+ }
+ env->iaoq_f = regs->iaoq[0];
+ env->iaoq_b = regs->iaoq[1];
+ }
#else
#error unsupported target CPU
#endif