env->regs[R_EDX],
env->regs[R_ESI],
env->regs[R_EDI],
- env->regs[R_EBP]);
+ env->regs[R_EBP],
+ 0, 0);
break;
#ifndef TARGET_ABI32
case EXCP_SYSCALL:
env->regs[R_EDX],
env->regs[10],
env->regs[8],
- env->regs[9]);
+ env->regs[9],
+ 0, 0);
env->eip = env->exception_next_eip;
break;
#endif
#ifdef TARGET_ARM
+/*
+ * See the Linux kernel's Documentation/arm/kernel_user_helpers.txt
+ * Input:
+ * r0 = pointer to oldval
+ * r1 = pointer to newval
+ * r2 = pointer to target value
+ *
+ * Output:
+ * r0 = 0 if *ptr was changed, non-0 if no exchange happened
+ * C set if *ptr was changed, clear if no exchange happened
+ *
+ * Note segv's in kernel helpers are a bit tricky, we can set the
+ * data address sensibly but the PC address is just the entry point.
+ */
+static void arm_kernel_cmpxchg64_helper(CPUARMState *env)
+{
+ uint64_t oldval, newval, val;
+ uint32_t addr, cpsr;
+ target_siginfo_t info;
+
+ /* Based on the 32 bit code in do_kernel_trap */
+
+ /* XXX: This only works between threads, not between processes.
+ It's probably possible to implement this with native host
+ operations. However things like ldrex/strex are much harder so
+ there's not much point trying. */
+ start_exclusive();
+ cpsr = cpsr_read(env);
+ addr = env->regs[2];
+
+ if (get_user_u64(oldval, env->regs[0])) {
+ env->cp15.c6_data = env->regs[0];
+ goto segv;
+ };
+
+ if (get_user_u64(newval, env->regs[1])) {
+ env->cp15.c6_data = env->regs[1];
+ goto segv;
+ };
+
+ if (get_user_u64(val, addr)) {
+ env->cp15.c6_data = addr;
+ goto segv;
+ }
+
+ if (val == oldval) {
+ val = newval;
+
+ if (put_user_u64(val, addr)) {
+ env->cp15.c6_data = addr;
+ goto segv;
+ };
+
+ env->regs[0] = 0;
+ cpsr |= CPSR_C;
+ } else {
+ env->regs[0] = -1;
+ cpsr &= ~CPSR_C;
+ }
+ cpsr_write(env, cpsr, CPSR_C);
+ end_exclusive();
+ return;
+
+segv:
+ end_exclusive();
+ /* We get the PC of the entry address - which is as good as anything,
+ on a real kernel what you get depends on which mode it uses. */
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ /* XXX: check env->error_code */
+ info.si_code = TARGET_SEGV_MAPERR;
+ info._sifields._sigfault._addr = env->cp15.c6_data;
+ queue_signal(env, info.si_signo, &info);
+
+ end_exclusive();
+}
+
/* Handle a jump to the kernel code page. */
static int
do_kernel_trap(CPUARMState *env)
case 0xffff0fe0: /* __kernel_get_tls */
env->regs[0] = env->cp15.c13_tls2;
break;
+ case 0xffff0f60: /* __kernel_cmpxchg64 */
+ arm_kernel_cmpxchg64_helper(env);
+ break;
+
default:
return 1;
}
env->regs[2],
env->regs[3],
env->regs[4],
- env->regs[5]);
+ env->regs[5],
+ 0, 0);
}
} else {
goto error;
goto do_segv;
case EXCP_DATA_ABORT:
addr = env->cp15.c6_data;
- goto do_segv;
do_segv:
{
info.si_signo = SIGSEGV;
env->regs[2],
env->regs[3],
env->regs[4],
- env->regs[5]);
+ env->regs[5],
+ 0, 0);
}
} else {
goto error;
ret = do_syscall (env, env->gregs[1],
env->regwptr[0], env->regwptr[1],
env->regwptr[2], env->regwptr[3],
- env->regwptr[4], env->regwptr[5]);
+ env->regwptr[4], env->regwptr[5],
+ 0, 0);
if ((abi_ulong)ret >= (abi_ulong)(-515)) {
#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
env->xcc |= PSR_CARRY;
env->crf[0] &= ~0x1;
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]);
+ env->gpr[8], 0, 0);
if (ret == (uint32_t)(-TARGET_QEMU_ESIGRETURN)) {
/* Returning from a successful sigreturn syscall.
Avoid corrupting register state. */
MIPS_SYS(sys_getcwd , 2)
MIPS_SYS(sys_capget , 2)
MIPS_SYS(sys_capset , 2) /* 4205 */
- MIPS_SYS(sys_sigaltstack , 0)
+ MIPS_SYS(sys_sigaltstack , 2)
MIPS_SYS(sys_sendfile , 4)
MIPS_SYS(sys_ni_syscall , 0)
MIPS_SYS(sys_ni_syscall , 0)
MIPS_SYS(sys_epoll_pwait, 6)
MIPS_SYS(sys_ioprio_set, 3)
MIPS_SYS(sys_ioprio_get, 2)
+ MIPS_SYS(sys_utimensat, 4)
+ MIPS_SYS(sys_signalfd, 3)
+ MIPS_SYS(sys_ni_syscall, 0) /* was timerfd */
+ MIPS_SYS(sys_eventfd, 1)
+ MIPS_SYS(sys_fallocate, 6) /* 4320 */
+ MIPS_SYS(sys_timerfd_create, 2)
+ MIPS_SYS(sys_timerfd_gettime, 2)
+ MIPS_SYS(sys_timerfd_settime, 4)
+ MIPS_SYS(sys_signalfd4, 4)
+ MIPS_SYS(sys_eventfd2, 2) /* 4325 */
+ MIPS_SYS(sys_epoll_create1, 1)
+ MIPS_SYS(sys_dup3, 3)
+ MIPS_SYS(sys_pipe2, 2)
+ MIPS_SYS(sys_inotify_init1, 1)
+ MIPS_SYS(sys_preadv, 6) /* 4330 */
+ MIPS_SYS(sys_pwritev, 6)
+ MIPS_SYS(sys_rt_tgsigqueueinfo, 4)
+ MIPS_SYS(sys_perf_event_open, 5)
+ MIPS_SYS(sys_accept4, 4)
+ MIPS_SYS(sys_recvmmsg, 5) /* 4335 */
+ MIPS_SYS(sys_fanotify_init, 2)
+ MIPS_SYS(sys_fanotify_mark, 6)
+ MIPS_SYS(sys_prlimit64, 4)
+ MIPS_SYS(sys_name_to_handle_at, 5)
+ MIPS_SYS(sys_open_by_handle_at, 3) /* 4340 */
+ MIPS_SYS(sys_clock_adjtime, 2)
+ MIPS_SYS(sys_syncfs, 1)
};
#undef MIPS_SYS
syscall_num = env->active_tc.gpr[2] - 4000;
env->active_tc.PC += 4;
if (syscall_num >= sizeof(mips_syscall_args)) {
- ret = -ENOSYS;
+ ret = -TARGET_ENOSYS;
} else {
int nb_args;
abi_ulong sp_reg;
env->active_tc.gpr[5],
env->active_tc.gpr[6],
env->active_tc.gpr[7],
- arg5, arg6/*, arg7, arg8*/);
+ arg5, arg6, arg7, arg8);
}
if (ret == -TARGET_QEMU_ESIGRETURN) {
/* Returning from a successful sigreturn syscall.
break;
case EXCP_TLBL:
case EXCP_TLBS:
+ case EXCP_AdEL:
+ case EXCP_AdES:
info.si_signo = TARGET_SIGSEGV;
info.si_errno = 0;
/* XXX: check env->error_code */
env->gregs[6],
env->gregs[7],
env->gregs[0],
- env->gregs[1]);
+ env->gregs[1],
+ 0, 0);
env->gregs[0] = ret;
break;
case EXCP_INTERRUPT:
env->regs[12],
env->regs[13],
env->pregs[7],
- env->pregs[11]);
+ env->pregs[11],
+ 0, 0);
env->regs[10] = ret;
break;
case EXCP_DEBUG:
env->regs[7],
env->regs[8],
env->regs[9],
- env->regs[10]);
+ env->regs[10],
+ 0, 0);
env->regs[3] = ret;
env->sregs[SR_PC] = env->regs[14];
break;
env->iflags &= ~(IMM_FLAG | D_FLAG);
switch (env->sregs[SR_ESR] & 31) {
+ case ESR_EC_DIVZERO:
+ info.si_signo = SIGFPE;
+ info.si_errno = 0;
+ info.si_code = TARGET_FPE_FLTDIV;
+ info._sifields._sigfault._addr = 0;
+ queue_signal(env, info.si_signo, &info);
+ break;
case ESR_EC_FPU:
info.si_signo = SIGFPE;
info.si_errno = 0;
env->dregs[3],
env->dregs[4],
env->dregs[5],
- env->aregs[0]);
+ env->aregs[0],
+ 0, 0);
}
break;
case EXCP_INTERRUPT:
sysret = do_syscall(env, trapnr,
env->ir[IR_A0], env->ir[IR_A1],
env->ir[IR_A2], env->ir[IR_A3],
- env->ir[IR_A4], env->ir[IR_A5]);
+ env->ir[IR_A4], env->ir[IR_A5],
+ 0, 0);
if (trapnr == TARGET_NR_sigreturn
|| trapnr == TARGET_NR_rt_sigreturn) {
break;
env->regs[4],
env->regs[5],
env->regs[6],
- env->regs[7]);
+ env->regs[7],
+ 0, 0);
}
break;
case EXCP_ADDR:
usage();
}
}
- if (optind >= argc)
- usage();
- filename = argv[optind];
- exec_path = argv[optind];
-
/* init debug */
cpu_set_log_filename(log_file);
if (log_mask) {
int mask;
const CPULogItem *item;
- mask = cpu_str_to_log_mask(r);
+ mask = cpu_str_to_log_mask(log_mask);
if (!mask) {
printf("Log items (comma separated):\n");
for (item = cpu_log_items; item->mask != 0; item++) {
cpu_set_log(mask);
}
+ if (optind >= argc) {
+ usage();
+ }
+ filename = argv[optind];
+ exec_path = argv[optind];
+
/* Zero out regs */
memset(regs, 0, sizeof(struct target_pt_regs));
cpu_model = "any";
#endif
}
- cpu_exec_init_all(0);
+ tcg_exec_init(0);
+ cpu_exec_init_all();
/* NOTE: we need to init the CPU at this stage to get
qemu_host_page_size */
env = cpu_init(cpu_model);
}
qemu_log("Reserved 0x%lx bytes of guest address space\n", reserved_va);
}
+
+ if (reserved_va || have_guest_base) {
+ if (!guest_validate_base(guest_base)) {
+ fprintf(stderr, "Guest base/Reserved VA rejected by guest code\n");
+ exit(1);
+ }
+ }
#endif /* CONFIG_USE_GUEST_BASE */
/*
}
target_argv[target_argc] = NULL;
- ts = qemu_mallocz (sizeof(TaskState));
+ ts = g_malloc0 (sizeof(TaskState));
init_task_state(ts);
/* build Task State */
ts->info = info;
#endif
if (gdbstub_port) {
- gdbserver_start (gdbstub_port);
+ if (gdbserver_start(gdbstub_port) < 0) {
+ fprintf(stderr, "qemu: could not open gdbserver on port %d\n",
+ gdbstub_port);
+ exit(1);
+ }
gdb_handlesig(env, 0);
}
cpu_loop(env);