1befb7447SLaurent Vivier /*
2befb7447SLaurent Vivier * Emulation of Linux signals
3befb7447SLaurent Vivier *
4befb7447SLaurent Vivier * Copyright (c) 2003 Fabrice Bellard
5befb7447SLaurent Vivier *
6befb7447SLaurent Vivier * This program is free software; you can redistribute it and/or modify
7befb7447SLaurent Vivier * it under the terms of the GNU General Public License as published by
8befb7447SLaurent Vivier * the Free Software Foundation; either version 2 of the License, or
9befb7447SLaurent Vivier * (at your option) any later version.
10befb7447SLaurent Vivier *
11befb7447SLaurent Vivier * This program is distributed in the hope that it will be useful,
12befb7447SLaurent Vivier * but WITHOUT ANY WARRANTY; without even the implied warranty of
13befb7447SLaurent Vivier * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14befb7447SLaurent Vivier * GNU General Public License for more details.
15befb7447SLaurent Vivier *
16befb7447SLaurent Vivier * You should have received a copy of the GNU General Public License
17befb7447SLaurent Vivier * along with this program; if not, see <http://www.gnu.org/licenses/>.
18befb7447SLaurent Vivier */
199c3221c1SLaurent Vivier #include "qemu/osdep.h"
209c3221c1SLaurent Vivier #include "qemu.h"
213b249d26SPeter Maydell #include "user-internals.h"
229c3221c1SLaurent Vivier #include "signal-common.h"
239c3221c1SLaurent Vivier #include "linux-user/trace.h"
24468c1bb5SRichard Henderson #include "vdso-asmoffset.h"
259c3221c1SLaurent Vivier
269c3221c1SLaurent Vivier /* Signal handler invocation must be transparent for the code being
279c3221c1SLaurent Vivier interrupted. Complete CPU (hart) state is saved on entry and restored
289c3221c1SLaurent Vivier before returning from the handler. Process sigmask is also saved to block
299c3221c1SLaurent Vivier signals while the handler is running. The handler gets its own stack,
309c3221c1SLaurent Vivier which also doubles as storage for the CPU state and sigmask.
319c3221c1SLaurent Vivier
329c3221c1SLaurent Vivier The code below is qemu re-implementation of arch/riscv/kernel/signal.c */
339c3221c1SLaurent Vivier
349c3221c1SLaurent Vivier struct target_sigcontext {
359c3221c1SLaurent Vivier abi_long pc;
369c3221c1SLaurent Vivier abi_long gpr[31]; /* x0 is not present, so all offsets must be -1 */
379c3221c1SLaurent Vivier uint64_t fpr[32];
389c3221c1SLaurent Vivier uint32_t fcsr;
399c3221c1SLaurent Vivier }; /* cf. riscv-linux:arch/riscv/include/uapi/asm/ptrace.h */
409c3221c1SLaurent Vivier
41468c1bb5SRichard Henderson QEMU_BUILD_BUG_ON(offsetof(struct target_sigcontext, fpr) != offsetof_freg0);
42468c1bb5SRichard Henderson
439c3221c1SLaurent Vivier struct target_ucontext {
44ae7d4d62SLIU Zhiwei abi_ulong uc_flags;
45ae7d4d62SLIU Zhiwei abi_ptr uc_link;
469c3221c1SLaurent Vivier target_stack_t uc_stack;
479c3221c1SLaurent Vivier target_sigset_t uc_sigmask;
4864ce00a6SLIU Zhiwei uint8_t __unused[1024 / 8 - sizeof(target_sigset_t)];
4964ce00a6SLIU Zhiwei struct target_sigcontext uc_mcontext QEMU_ALIGNED(16);
509c3221c1SLaurent Vivier };
519c3221c1SLaurent Vivier
529c3221c1SLaurent Vivier struct target_rt_sigframe {
539c3221c1SLaurent Vivier struct target_siginfo info;
549c3221c1SLaurent Vivier struct target_ucontext uc;
559c3221c1SLaurent Vivier };
569c3221c1SLaurent Vivier
57468c1bb5SRichard Henderson QEMU_BUILD_BUG_ON(sizeof(struct target_rt_sigframe)
58468c1bb5SRichard Henderson != sizeof_rt_sigframe);
59468c1bb5SRichard Henderson QEMU_BUILD_BUG_ON(offsetof(struct target_rt_sigframe, uc.uc_mcontext)
60468c1bb5SRichard Henderson != offsetof_uc_mcontext);
61468c1bb5SRichard Henderson
get_sigframe(struct target_sigaction * ka,CPURISCVState * regs,size_t framesize)629c3221c1SLaurent Vivier static abi_ulong get_sigframe(struct target_sigaction *ka,
639c3221c1SLaurent Vivier CPURISCVState *regs, size_t framesize)
649c3221c1SLaurent Vivier {
65465e237bSLaurent Vivier abi_ulong sp = get_sp_from_cpustate(regs);
669c3221c1SLaurent Vivier
679c3221c1SLaurent Vivier /* If we are on the alternate signal stack and would overflow it, don't.
689c3221c1SLaurent Vivier Return an always-bogus address instead so we will die with SIGSEGV. */
69465e237bSLaurent Vivier if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize))) {
709c3221c1SLaurent Vivier return -1L;
719c3221c1SLaurent Vivier }
729c3221c1SLaurent Vivier
73465e237bSLaurent Vivier /* This is the X/Open sanctioned signal stack switching. */
74465e237bSLaurent Vivier sp = target_sigsp(sp, ka) - framesize;
751eaa6342SRichard Henderson sp &= ~0xf;
76465e237bSLaurent Vivier
779c3221c1SLaurent Vivier return sp;
789c3221c1SLaurent Vivier }
799c3221c1SLaurent Vivier
setup_sigcontext(struct target_sigcontext * sc,CPURISCVState * env)809c3221c1SLaurent Vivier static void setup_sigcontext(struct target_sigcontext *sc, CPURISCVState *env)
819c3221c1SLaurent Vivier {
829c3221c1SLaurent Vivier int i;
839c3221c1SLaurent Vivier
849c3221c1SLaurent Vivier __put_user(env->pc, &sc->pc);
859c3221c1SLaurent Vivier
869c3221c1SLaurent Vivier for (i = 1; i < 32; i++) {
879c3221c1SLaurent Vivier __put_user(env->gpr[i], &sc->gpr[i - 1]);
889c3221c1SLaurent Vivier }
899c3221c1SLaurent Vivier for (i = 0; i < 32; i++) {
909c3221c1SLaurent Vivier __put_user(env->fpr[i], &sc->fpr[i]);
919c3221c1SLaurent Vivier }
929c3221c1SLaurent Vivier
93fb738839SMichael Clark uint32_t fcsr = riscv_csr_read(env, CSR_FCSR);
949c3221c1SLaurent Vivier __put_user(fcsr, &sc->fcsr);
959c3221c1SLaurent Vivier }
969c3221c1SLaurent Vivier
setup_ucontext(struct target_ucontext * uc,CPURISCVState * env,target_sigset_t * set)979c3221c1SLaurent Vivier static void setup_ucontext(struct target_ucontext *uc,
989c3221c1SLaurent Vivier CPURISCVState *env, target_sigset_t *set)
999c3221c1SLaurent Vivier {
1009c3221c1SLaurent Vivier __put_user(0, &(uc->uc_flags));
1019c3221c1SLaurent Vivier __put_user(0, &(uc->uc_link));
1029c3221c1SLaurent Vivier
103465e237bSLaurent Vivier target_save_altstack(&uc->uc_stack, env);
1049c3221c1SLaurent Vivier
1059c3221c1SLaurent Vivier int i;
1069c3221c1SLaurent Vivier for (i = 0; i < TARGET_NSIG_WORDS; i++) {
1079c3221c1SLaurent Vivier __put_user(set->sig[i], &(uc->uc_sigmask.sig[i]));
1089c3221c1SLaurent Vivier }
1099c3221c1SLaurent Vivier
1109c3221c1SLaurent Vivier setup_sigcontext(&uc->uc_mcontext, env);
1119c3221c1SLaurent Vivier }
1129c3221c1SLaurent Vivier
setup_rt_frame(int sig,struct target_sigaction * ka,target_siginfo_t * info,target_sigset_t * set,CPURISCVState * env)1139c3221c1SLaurent Vivier void setup_rt_frame(int sig, struct target_sigaction *ka,
1149c3221c1SLaurent Vivier target_siginfo_t *info,
1159c3221c1SLaurent Vivier target_sigset_t *set, CPURISCVState *env)
1169c3221c1SLaurent Vivier {
1179c3221c1SLaurent Vivier abi_ulong frame_addr;
1189c3221c1SLaurent Vivier struct target_rt_sigframe *frame;
1199c3221c1SLaurent Vivier
1209c3221c1SLaurent Vivier frame_addr = get_sigframe(ka, env, sizeof(*frame));
1219c3221c1SLaurent Vivier trace_user_setup_rt_frame(env, frame_addr);
1229c3221c1SLaurent Vivier
1239c3221c1SLaurent Vivier if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1249c3221c1SLaurent Vivier goto badframe;
1259c3221c1SLaurent Vivier }
1269c3221c1SLaurent Vivier
1279c3221c1SLaurent Vivier setup_ucontext(&frame->uc, env, set);
128*4d6d8a05SGustavo Romero frame->info = *info;
1299c3221c1SLaurent Vivier
1309c3221c1SLaurent Vivier env->pc = ka->_sa_handler;
1319c3221c1SLaurent Vivier env->gpr[xSP] = frame_addr;
1329c3221c1SLaurent Vivier env->gpr[xA0] = sig;
1339c3221c1SLaurent Vivier env->gpr[xA1] = frame_addr + offsetof(struct target_rt_sigframe, info);
1349c3221c1SLaurent Vivier env->gpr[xA2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
1353c62b5d2SRichard Henderson env->gpr[xRA] = default_rt_sigreturn;
1369c3221c1SLaurent Vivier
1379c3221c1SLaurent Vivier return;
1389c3221c1SLaurent Vivier
1399c3221c1SLaurent Vivier badframe:
1409c3221c1SLaurent Vivier unlock_user_struct(frame, frame_addr, 1);
1419c3221c1SLaurent Vivier if (sig == TARGET_SIGSEGV) {
1429c3221c1SLaurent Vivier ka->_sa_handler = TARGET_SIG_DFL;
1439c3221c1SLaurent Vivier }
1449c3221c1SLaurent Vivier force_sig(TARGET_SIGSEGV);
1459c3221c1SLaurent Vivier }
1469c3221c1SLaurent Vivier
restore_sigcontext(CPURISCVState * env,struct target_sigcontext * sc)1479c3221c1SLaurent Vivier static void restore_sigcontext(CPURISCVState *env, struct target_sigcontext *sc)
1489c3221c1SLaurent Vivier {
1499c3221c1SLaurent Vivier int i;
1509c3221c1SLaurent Vivier
1519c3221c1SLaurent Vivier __get_user(env->pc, &sc->pc);
1529c3221c1SLaurent Vivier
1539c3221c1SLaurent Vivier for (i = 1; i < 32; ++i) {
1549c3221c1SLaurent Vivier __get_user(env->gpr[i], &sc->gpr[i - 1]);
1559c3221c1SLaurent Vivier }
1569c3221c1SLaurent Vivier for (i = 0; i < 32; ++i) {
1579c3221c1SLaurent Vivier __get_user(env->fpr[i], &sc->fpr[i]);
1589c3221c1SLaurent Vivier }
1599c3221c1SLaurent Vivier
1609c3221c1SLaurent Vivier uint32_t fcsr;
1619c3221c1SLaurent Vivier __get_user(fcsr, &sc->fcsr);
162fb738839SMichael Clark riscv_csr_write(env, CSR_FCSR, fcsr);
1639c3221c1SLaurent Vivier }
1649c3221c1SLaurent Vivier
restore_ucontext(CPURISCVState * env,struct target_ucontext * uc)1659c3221c1SLaurent Vivier static void restore_ucontext(CPURISCVState *env, struct target_ucontext *uc)
1669c3221c1SLaurent Vivier {
1679c3221c1SLaurent Vivier sigset_t blocked;
1689c3221c1SLaurent Vivier target_sigset_t target_set;
1699c3221c1SLaurent Vivier int i;
1709c3221c1SLaurent Vivier
1719c3221c1SLaurent Vivier target_sigemptyset(&target_set);
1729c3221c1SLaurent Vivier for (i = 0; i < TARGET_NSIG_WORDS; i++) {
1739c3221c1SLaurent Vivier __get_user(target_set.sig[i], &(uc->uc_sigmask.sig[i]));
1749c3221c1SLaurent Vivier }
1759c3221c1SLaurent Vivier
1769c3221c1SLaurent Vivier target_to_host_sigset_internal(&blocked, &target_set);
1779c3221c1SLaurent Vivier set_sigmask(&blocked);
1789c3221c1SLaurent Vivier
1799c3221c1SLaurent Vivier restore_sigcontext(env, &uc->uc_mcontext);
1809c3221c1SLaurent Vivier }
1819c3221c1SLaurent Vivier
do_rt_sigreturn(CPURISCVState * env)1829c3221c1SLaurent Vivier long do_rt_sigreturn(CPURISCVState *env)
1839c3221c1SLaurent Vivier {
1849c3221c1SLaurent Vivier struct target_rt_sigframe *frame;
1859c3221c1SLaurent Vivier abi_ulong frame_addr;
1869c3221c1SLaurent Vivier
1879c3221c1SLaurent Vivier frame_addr = env->gpr[xSP];
1889c3221c1SLaurent Vivier trace_user_do_sigreturn(env, frame_addr);
1899c3221c1SLaurent Vivier if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
1909c3221c1SLaurent Vivier goto badframe;
1919c3221c1SLaurent Vivier }
1929c3221c1SLaurent Vivier
1939c3221c1SLaurent Vivier restore_ucontext(env, &frame->uc);
194ddc3e74dSRichard Henderson target_restore_altstack(&frame->uc.uc_stack, env);
1959c3221c1SLaurent Vivier
1969c3221c1SLaurent Vivier unlock_user_struct(frame, frame_addr, 0);
19757a0c938SRichard Henderson return -QEMU_ESIGRETURN;
1989c3221c1SLaurent Vivier
1999c3221c1SLaurent Vivier badframe:
2009c3221c1SLaurent Vivier unlock_user_struct(frame, frame_addr, 0);
2019c3221c1SLaurent Vivier force_sig(TARGET_SIGSEGV);
2029c3221c1SLaurent Vivier return 0;
2039c3221c1SLaurent Vivier }
2043c62b5d2SRichard Henderson
setup_sigtramp(abi_ulong sigtramp_page)2053c62b5d2SRichard Henderson void setup_sigtramp(abi_ulong sigtramp_page)
2063c62b5d2SRichard Henderson {
2073c62b5d2SRichard Henderson uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 8, 0);
2083c62b5d2SRichard Henderson assert(tramp != NULL);
2093c62b5d2SRichard Henderson
2103c62b5d2SRichard Henderson __put_user(0x08b00893, tramp + 0); /* li a7, 139 = __NR_rt_sigreturn */
2113c62b5d2SRichard Henderson __put_user(0x00000073, tramp + 1); /* ecall */
2123c62b5d2SRichard Henderson
2133c62b5d2SRichard Henderson default_rt_sigreturn = sigtramp_page;
2143c62b5d2SRichard Henderson unlock_user(tramp, sigtramp_page, 8);
2153c62b5d2SRichard Henderson }
216