+void queue_signal(CPUArchState *env, int sig, int si_type,
+ target_siginfo_t *info)
+{
+ CPUState *cpu = env_cpu(env);
+ TaskState *ts = cpu->opaque;
+
+ trace_user_queue_signal(env, sig);
+
+ info->si_code = deposit32(info->si_code, 24, 8, si_type);
+
+ ts->sync_signal.info = *info;
+ ts->sync_signal.pending = sig;
+ /* Signal that a new signal is pending. */
+ qatomic_set(&ts->signal_pending, 1);
+ return;
+}
+
+static int fatal_signal(int sig)
+{
+
+ switch (sig) {
+ case TARGET_SIGCHLD:
+ case TARGET_SIGURG:
+ case TARGET_SIGWINCH:
+ case TARGET_SIGINFO:
+ /* Ignored by default. */
+ return 0;
+ case TARGET_SIGCONT:
+ case TARGET_SIGSTOP:
+ case TARGET_SIGTSTP:
+ case TARGET_SIGTTIN:
+ case TARGET_SIGTTOU:
+ /* Job control signals. */
+ return 0;
+ default:
+ return 1;
+ }
+}
+
+/*
+ * Force a synchronously taken QEMU_SI_FAULT signal. For QEMU the
+ * 'force' part is handled in process_pending_signals().
+ */
+void force_sig_fault(int sig, int code, abi_ulong addr)
+{
+ CPUState *cpu = thread_cpu;
+ CPUArchState *env = cpu->env_ptr;
+ target_siginfo_t info = {};
+
+ info.si_signo = sig;
+ info.si_errno = 0;
+ info.si_code = code;
+ info.si_addr = addr;
+ queue_signal(env, sig, QEMU_SI_FAULT, &info);
+}
+
+static void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
+{
+ CPUArchState *env = thread_cpu->env_ptr;
+ CPUState *cpu = env_cpu(env);
+ TaskState *ts = cpu->opaque;
+ target_siginfo_t tinfo;
+ ucontext_t *uc = puc;
+ struct emulated_sigtable *k;
+ int guest_sig;
+ uintptr_t pc = 0;
+ bool sync_sig = false;
+
+ /*
+ * Non-spoofed SIGSEGV and SIGBUS are synchronous, and need special
+ * handling wrt signal blocking and unwinding.
+ */
+ if ((host_sig == SIGSEGV || host_sig == SIGBUS) && info->si_code > 0) {
+ MMUAccessType access_type;
+ uintptr_t host_addr;
+ abi_ptr guest_addr;
+ bool is_write;
+
+ host_addr = (uintptr_t)info->si_addr;
+
+ /*
+ * Convert forcefully to guest address space: addresses outside
+ * reserved_va are still valid to report via SEGV_MAPERR.
+ */
+ guest_addr = h2g_nocheck(host_addr);
+
+ pc = host_signal_pc(uc);
+ is_write = host_signal_write(info, uc);
+ access_type = adjust_signal_pc(&pc, is_write);
+
+ if (host_sig == SIGSEGV) {
+ bool maperr = true;
+
+ if (info->si_code == SEGV_ACCERR && h2g_valid(host_addr)) {
+ /* If this was a write to a TB protected page, restart. */
+ if (is_write &&
+ handle_sigsegv_accerr_write(cpu, &uc->uc_sigmask,
+ pc, guest_addr)) {
+ return;
+ }
+
+ /*
+ * With reserved_va, the whole address space is PROT_NONE,
+ * which means that we may get ACCERR when we want MAPERR.
+ */
+ if (page_get_flags(guest_addr) & PAGE_VALID) {
+ maperr = false;
+ } else {
+ info->si_code = SEGV_MAPERR;
+ }
+ }
+
+ sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
+ cpu_loop_exit_sigsegv(cpu, guest_addr, access_type, maperr, pc);
+ } else {
+ sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
+ if (info->si_code == BUS_ADRALN) {
+ cpu_loop_exit_sigbus(cpu, guest_addr, access_type, pc);
+ }
+ }
+
+ sync_sig = true;
+ }
+
+ /* Get the target signal number. */
+ guest_sig = host_to_target_signal(host_sig);
+ if (guest_sig < 1 || guest_sig > TARGET_NSIG) {
+ return;
+ }
+ trace_user_host_signal(cpu, host_sig, guest_sig);
+
+ host_to_target_siginfo_noswap(&tinfo, info);
+
+ k = &ts->sigtab[guest_sig - 1];
+ k->info = tinfo;
+ k->pending = guest_sig;
+ ts->signal_pending = 1;
+
+ /*
+ * For synchronous signals, unwind the cpu state to the faulting
+ * insn and then exit back to the main loop so that the signal
+ * is delivered immediately.
+ */
+ if (sync_sig) {
+ cpu->exception_index = EXCP_INTERRUPT;
+ cpu_loop_exit_restore(cpu, pc);
+ }
+
+ rewind_if_in_safe_syscall(puc);
+
+ /*
+ * Block host signals until target signal handler entered. We
+ * can't block SIGSEGV or SIGBUS while we're executing guest
+ * code in case the guest code provokes one in the window between
+ * now and it getting out to the main loop. Signals will be
+ * unblocked again in process_pending_signals().
+ */
+ sigfillset(&uc->uc_sigmask);
+ sigdelset(&uc->uc_sigmask, SIGSEGV);
+ sigdelset(&uc->uc_sigmask, SIGBUS);
+
+ /* Interrupt the virtual CPU as soon as possible. */
+ cpu_exit(thread_cpu);
+}
+
+/* do_sigaltstack() returns target values and errnos. */
+/* compare to kern/kern_sig.c sys_sigaltstack() and kern_sigaltstack() */
+abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
+{
+ TaskState *ts = (TaskState *)thread_cpu->opaque;
+ int ret;
+ target_stack_t oss;
+
+ if (uoss_addr) {
+ /* Save current signal stack params */
+ oss.ss_sp = tswapl(ts->sigaltstack_used.ss_sp);
+ oss.ss_size = tswapl(ts->sigaltstack_used.ss_size);
+ oss.ss_flags = tswapl(sas_ss_flags(ts, sp));
+ }
+
+ if (uss_addr) {
+ target_stack_t *uss;
+ target_stack_t ss;
+ size_t minstacksize = TARGET_MINSIGSTKSZ;
+
+ ret = -TARGET_EFAULT;
+ if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)) {
+ goto out;
+ }
+ __get_user(ss.ss_sp, &uss->ss_sp);
+ __get_user(ss.ss_size, &uss->ss_size);
+ __get_user(ss.ss_flags, &uss->ss_flags);
+ unlock_user_struct(uss, uss_addr, 0);
+
+ ret = -TARGET_EPERM;
+ if (on_sig_stack(ts, sp)) {
+ goto out;
+ }
+
+ ret = -TARGET_EINVAL;
+ if (ss.ss_flags != TARGET_SS_DISABLE
+ && ss.ss_flags != TARGET_SS_ONSTACK
+ && ss.ss_flags != 0) {
+ goto out;
+ }
+
+ if (ss.ss_flags == TARGET_SS_DISABLE) {
+ ss.ss_size = 0;
+ ss.ss_sp = 0;
+ } else {
+ ret = -TARGET_ENOMEM;
+ if (ss.ss_size < minstacksize) {
+ goto out;
+ }
+ }
+
+ ts->sigaltstack_used.ss_sp = ss.ss_sp;
+ ts->sigaltstack_used.ss_size = ss.ss_size;
+ }
+
+ if (uoss_addr) {
+ ret = -TARGET_EFAULT;
+ if (copy_to_user(uoss_addr, &oss, sizeof(oss))) {
+ goto out;
+ }
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
+/* do_sigaction() return host values and errnos */
+int do_sigaction(int sig, const struct target_sigaction *act,
+ struct target_sigaction *oact)
+{
+ struct target_sigaction *k;
+ struct sigaction act1;
+ int host_sig;
+ int ret = 0;
+
+ if (sig < 1 || sig > TARGET_NSIG) {
+ return -TARGET_EINVAL;
+ }
+
+ if ((sig == TARGET_SIGKILL || sig == TARGET_SIGSTOP) &&
+ act != NULL && act->_sa_handler != TARGET_SIG_DFL) {
+ return -TARGET_EINVAL;
+ }
+
+ if (block_signals()) {
+ return -TARGET_ERESTART;
+ }
+
+ k = &sigact_table[sig - 1];
+ if (oact) {
+ oact->_sa_handler = tswapal(k->_sa_handler);
+ oact->sa_flags = tswap32(k->sa_flags);
+ oact->sa_mask = k->sa_mask;
+ }
+ if (act) {
+ k->_sa_handler = tswapal(act->_sa_handler);
+ k->sa_flags = tswap32(act->sa_flags);
+ k->sa_mask = act->sa_mask;
+
+ /* Update the host signal state. */
+ host_sig = target_to_host_signal(sig);
+ if (host_sig != SIGSEGV && host_sig != SIGBUS) {
+ memset(&act1, 0, sizeof(struct sigaction));
+ sigfillset(&act1.sa_mask);
+ act1.sa_flags = SA_SIGINFO;
+ if (k->sa_flags & TARGET_SA_RESTART) {
+ act1.sa_flags |= SA_RESTART;
+ }
+ /*
+ * Note: It is important to update the host kernel signal mask to
+ * avoid getting unexpected interrupted system calls.
+ */
+ if (k->_sa_handler == TARGET_SIG_IGN) {
+ act1.sa_sigaction = (void *)SIG_IGN;
+ } else if (k->_sa_handler == TARGET_SIG_DFL) {
+ if (fatal_signal(sig)) {
+ act1.sa_sigaction = host_signal_handler;
+ } else {
+ act1.sa_sigaction = (void *)SIG_DFL;
+ }
+ } else {
+ act1.sa_sigaction = host_signal_handler;
+ }
+ ret = sigaction(host_sig, &act1, NULL);
+ }
+ }
+ return ret;
+}
+
+static inline abi_ulong get_sigframe(struct target_sigaction *ka,
+ CPUArchState *env, size_t frame_size)
+{
+ TaskState *ts = (TaskState *)thread_cpu->opaque;
+ abi_ulong sp;
+
+ /* Use default user stack */
+ sp = get_sp_from_cpustate(env);
+
+ if ((ka->sa_flags & TARGET_SA_ONSTACK) && sas_ss_flags(ts, sp) == 0) {
+ sp = ts->sigaltstack_used.ss_sp + ts->sigaltstack_used.ss_size;
+ }
+
+/* TODO: make this a target_arch function / define */
+#if defined(TARGET_ARM)
+ return (sp - frame_size) & ~7;
+#elif defined(TARGET_AARCH64)
+ return (sp - frame_size) & ~15;
+#else
+ return sp - frame_size;
+#endif
+}
+
+/* compare to $M/$M/exec_machdep.c sendsig and sys/kern/kern_sig.c sigexit */
+
+static void setup_frame(int sig, int code, struct target_sigaction *ka,
+ target_sigset_t *set, target_siginfo_t *tinfo, CPUArchState *env)
+{
+ struct target_sigframe *frame;
+ abi_ulong frame_addr;
+ int i;
+
+ frame_addr = get_sigframe(ka, env, sizeof(*frame));
+ trace_user_setup_frame(env, frame_addr);
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+ unlock_user_struct(frame, frame_addr, 1);
+ dump_core_and_abort(TARGET_SIGILL);
+ return;
+ }
+
+ memset(frame, 0, sizeof(*frame));
+ setup_sigframe_arch(env, frame_addr, frame, 0);
+
+ for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+ __put_user(set->__bits[i], &frame->sf_uc.uc_sigmask.__bits[i]);
+ }
+
+ if (tinfo) {
+ frame->sf_si.si_signo = tinfo->si_signo;
+ frame->sf_si.si_errno = tinfo->si_errno;
+ frame->sf_si.si_code = tinfo->si_code;
+ frame->sf_si.si_pid = tinfo->si_pid;
+ frame->sf_si.si_uid = tinfo->si_uid;
+ frame->sf_si.si_status = tinfo->si_status;
+ frame->sf_si.si_addr = tinfo->si_addr;
+ /* see host_to_target_siginfo_noswap() for more details */
+ frame->sf_si.si_value.sival_ptr = tinfo->si_value.sival_ptr;
+ /*
+ * At this point, whatever is in the _reason union is complete
+ * and in target order, so just copy the whole thing over, even
+ * if it's too large for this specific signal.
+ * host_to_target_siginfo_noswap() and tswap_siginfo() have ensured
+ * that's so.
+ */
+ memcpy(&frame->sf_si._reason, &tinfo->_reason,
+ sizeof(tinfo->_reason));
+ }
+
+ set_sigtramp_args(env, sig, frame, frame_addr, ka);
+
+ unlock_user_struct(frame, frame_addr, 1);
+}
+
+static int reset_signal_mask(target_ucontext_t *ucontext)
+{
+ int i;
+ sigset_t blocked;
+ target_sigset_t target_set;
+ TaskState *ts = (TaskState *)thread_cpu->opaque;
+
+ for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+ __get_user(target_set.__bits[i], &ucontext->uc_sigmask.__bits[i]);
+ }
+ target_to_host_sigset_internal(&blocked, &target_set);
+ ts->signal_mask = blocked;
+
+ return 0;
+}
+
+/* See sys/$M/$M/exec_machdep.c sigreturn() */
+long do_sigreturn(CPUArchState *env, abi_ulong addr)