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 */
198949bef1SLaurent Vivier #include "qemu/osdep.h"
208949bef1SLaurent Vivier #include "qemu.h"
213b249d26SPeter Maydell #include "user-internals.h"
228949bef1SLaurent Vivier #include "signal-common.h"
238949bef1SLaurent Vivier #include "linux-user/trace.h"
248949bef1SLaurent Vivier
258949bef1SLaurent Vivier # if defined(TARGET_ABI_MIPSO32)
268949bef1SLaurent Vivier struct target_sigcontext {
278949bef1SLaurent Vivier uint32_t sc_regmask; /* Unused */
288949bef1SLaurent Vivier uint32_t sc_status;
298949bef1SLaurent Vivier uint64_t sc_pc;
308949bef1SLaurent Vivier uint64_t sc_regs[32];
318949bef1SLaurent Vivier uint64_t sc_fpregs[32];
328949bef1SLaurent Vivier uint32_t sc_ownedfp; /* Unused */
338949bef1SLaurent Vivier uint32_t sc_fpc_csr;
348949bef1SLaurent Vivier uint32_t sc_fpc_eir; /* Unused */
358949bef1SLaurent Vivier uint32_t sc_used_math;
368949bef1SLaurent Vivier uint32_t sc_dsp; /* dsp status, was sc_ssflags */
378949bef1SLaurent Vivier uint32_t pad0;
388949bef1SLaurent Vivier uint64_t sc_mdhi;
398949bef1SLaurent Vivier uint64_t sc_mdlo;
408949bef1SLaurent Vivier target_ulong sc_hi1; /* Was sc_cause */
418949bef1SLaurent Vivier target_ulong sc_lo1; /* Was sc_badvaddr */
428949bef1SLaurent Vivier target_ulong sc_hi2; /* Was sc_sigset[4] */
438949bef1SLaurent Vivier target_ulong sc_lo2;
448949bef1SLaurent Vivier target_ulong sc_hi3;
458949bef1SLaurent Vivier target_ulong sc_lo3;
468949bef1SLaurent Vivier };
478949bef1SLaurent Vivier # else /* N32 || N64 */
488949bef1SLaurent Vivier struct target_sigcontext {
498949bef1SLaurent Vivier uint64_t sc_regs[32];
508949bef1SLaurent Vivier uint64_t sc_fpregs[32];
518949bef1SLaurent Vivier uint64_t sc_mdhi;
528949bef1SLaurent Vivier uint64_t sc_hi1;
538949bef1SLaurent Vivier uint64_t sc_hi2;
548949bef1SLaurent Vivier uint64_t sc_hi3;
558949bef1SLaurent Vivier uint64_t sc_mdlo;
568949bef1SLaurent Vivier uint64_t sc_lo1;
578949bef1SLaurent Vivier uint64_t sc_lo2;
588949bef1SLaurent Vivier uint64_t sc_lo3;
598949bef1SLaurent Vivier uint64_t sc_pc;
608949bef1SLaurent Vivier uint32_t sc_fpc_csr;
618949bef1SLaurent Vivier uint32_t sc_used_math;
628949bef1SLaurent Vivier uint32_t sc_dsp;
638949bef1SLaurent Vivier uint32_t sc_reserved;
648949bef1SLaurent Vivier };
658949bef1SLaurent Vivier # endif /* O32 */
668949bef1SLaurent Vivier
678949bef1SLaurent Vivier struct sigframe {
688949bef1SLaurent Vivier uint32_t sf_ass[4]; /* argument save space for o32 */
698949bef1SLaurent Vivier uint32_t sf_code[2]; /* signal trampoline */
708949bef1SLaurent Vivier struct target_sigcontext sf_sc;
718949bef1SLaurent Vivier target_sigset_t sf_mask;
728949bef1SLaurent Vivier };
738949bef1SLaurent Vivier
748949bef1SLaurent Vivier struct target_ucontext {
754ced996fSAleksandar Markovic abi_ulong tuc_flags;
764ced996fSAleksandar Markovic abi_ulong tuc_link;
778949bef1SLaurent Vivier target_stack_t tuc_stack;
788949bef1SLaurent Vivier struct target_sigcontext tuc_mcontext;
798949bef1SLaurent Vivier target_sigset_t tuc_sigmask;
808949bef1SLaurent Vivier };
818949bef1SLaurent Vivier
828949bef1SLaurent Vivier struct target_rt_sigframe {
838949bef1SLaurent Vivier uint32_t rs_ass[4]; /* argument save space for o32 */
848949bef1SLaurent Vivier uint32_t rs_code[2]; /* signal trampoline */
858949bef1SLaurent Vivier struct target_siginfo rs_info;
868949bef1SLaurent Vivier struct target_ucontext rs_uc;
878949bef1SLaurent Vivier };
888949bef1SLaurent Vivier
898949bef1SLaurent Vivier /* Install trampoline to jump back from signal handler */
install_sigtramp(uint32_t * tramp,unsigned int syscall)904f7a0a4cSRichard Henderson static void install_sigtramp(uint32_t *tramp, unsigned int syscall)
918949bef1SLaurent Vivier {
928949bef1SLaurent Vivier /*
938949bef1SLaurent Vivier * Set up the return code ...
948949bef1SLaurent Vivier *
958949bef1SLaurent Vivier * li v0, __NR__foo_sigreturn
968949bef1SLaurent Vivier * syscall
978949bef1SLaurent Vivier */
988949bef1SLaurent Vivier
998949bef1SLaurent Vivier __put_user(0x24020000 + syscall, tramp + 0);
1008949bef1SLaurent Vivier __put_user(0x0000000c , tramp + 1);
1018949bef1SLaurent Vivier }
1028949bef1SLaurent Vivier
setup_sigcontext(CPUMIPSState * regs,struct target_sigcontext * sc)1038949bef1SLaurent Vivier static inline void setup_sigcontext(CPUMIPSState *regs,
1048949bef1SLaurent Vivier struct target_sigcontext *sc)
1058949bef1SLaurent Vivier {
1068949bef1SLaurent Vivier int i;
1078949bef1SLaurent Vivier
1088949bef1SLaurent Vivier __put_user(exception_resume_pc(regs), &sc->sc_pc);
1098949bef1SLaurent Vivier regs->hflags &= ~MIPS_HFLAG_BMASK;
1108949bef1SLaurent Vivier
1118949bef1SLaurent Vivier __put_user(0, &sc->sc_regs[0]);
1128949bef1SLaurent Vivier for (i = 1; i < 32; ++i) {
1138949bef1SLaurent Vivier __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
1148949bef1SLaurent Vivier }
1158949bef1SLaurent Vivier
1168949bef1SLaurent Vivier __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
1178949bef1SLaurent Vivier __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
1188949bef1SLaurent Vivier
1198949bef1SLaurent Vivier /* Rather than checking for dsp existence, always copy. The storage
1208949bef1SLaurent Vivier would just be garbage otherwise. */
1218949bef1SLaurent Vivier __put_user(regs->active_tc.HI[1], &sc->sc_hi1);
1228949bef1SLaurent Vivier __put_user(regs->active_tc.HI[2], &sc->sc_hi2);
1238949bef1SLaurent Vivier __put_user(regs->active_tc.HI[3], &sc->sc_hi3);
1248949bef1SLaurent Vivier __put_user(regs->active_tc.LO[1], &sc->sc_lo1);
1258949bef1SLaurent Vivier __put_user(regs->active_tc.LO[2], &sc->sc_lo2);
1268949bef1SLaurent Vivier __put_user(regs->active_tc.LO[3], &sc->sc_lo3);
1278949bef1SLaurent Vivier {
1288949bef1SLaurent Vivier uint32_t dsp = cpu_rddsp(0x3ff, regs);
1298949bef1SLaurent Vivier __put_user(dsp, &sc->sc_dsp);
1308949bef1SLaurent Vivier }
1318949bef1SLaurent Vivier
1328949bef1SLaurent Vivier __put_user(1, &sc->sc_used_math);
1338949bef1SLaurent Vivier
1348949bef1SLaurent Vivier for (i = 0; i < 32; ++i) {
1358949bef1SLaurent Vivier __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
1368949bef1SLaurent Vivier }
1378949bef1SLaurent Vivier }
1388949bef1SLaurent Vivier
1398949bef1SLaurent Vivier static inline void
restore_sigcontext(CPUMIPSState * regs,struct target_sigcontext * sc)1408949bef1SLaurent Vivier restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
1418949bef1SLaurent Vivier {
1428949bef1SLaurent Vivier int i;
1438949bef1SLaurent Vivier
1448949bef1SLaurent Vivier __get_user(regs->CP0_EPC, &sc->sc_pc);
1458949bef1SLaurent Vivier
1468949bef1SLaurent Vivier __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
1478949bef1SLaurent Vivier __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
1488949bef1SLaurent Vivier
1498949bef1SLaurent Vivier for (i = 1; i < 32; ++i) {
1508949bef1SLaurent Vivier __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
1518949bef1SLaurent Vivier }
1528949bef1SLaurent Vivier
1538949bef1SLaurent Vivier __get_user(regs->active_tc.HI[1], &sc->sc_hi1);
1548949bef1SLaurent Vivier __get_user(regs->active_tc.HI[2], &sc->sc_hi2);
1558949bef1SLaurent Vivier __get_user(regs->active_tc.HI[3], &sc->sc_hi3);
1568949bef1SLaurent Vivier __get_user(regs->active_tc.LO[1], &sc->sc_lo1);
1578949bef1SLaurent Vivier __get_user(regs->active_tc.LO[2], &sc->sc_lo2);
1588949bef1SLaurent Vivier __get_user(regs->active_tc.LO[3], &sc->sc_lo3);
1598949bef1SLaurent Vivier {
1608949bef1SLaurent Vivier uint32_t dsp;
1618949bef1SLaurent Vivier __get_user(dsp, &sc->sc_dsp);
1628949bef1SLaurent Vivier cpu_wrdsp(dsp, 0x3ff, regs);
1638949bef1SLaurent Vivier }
1648949bef1SLaurent Vivier
1658949bef1SLaurent Vivier for (i = 0; i < 32; ++i) {
1668949bef1SLaurent Vivier __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
1678949bef1SLaurent Vivier }
1688949bef1SLaurent Vivier }
1698949bef1SLaurent Vivier
1708949bef1SLaurent Vivier /*
1718949bef1SLaurent Vivier * Determine which stack to use..
1728949bef1SLaurent Vivier */
1738949bef1SLaurent Vivier static inline abi_ulong
get_sigframe(struct target_sigaction * ka,CPUMIPSState * regs,size_t frame_size)1748949bef1SLaurent Vivier get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size)
1758949bef1SLaurent Vivier {
1768949bef1SLaurent Vivier unsigned long sp;
1778949bef1SLaurent Vivier
1788949bef1SLaurent Vivier /*
1798949bef1SLaurent Vivier * FPU emulator may have its own trampoline active just
1808949bef1SLaurent Vivier * above the user stack, 16-bytes before the next lowest
1818949bef1SLaurent Vivier * 16 byte boundary. Try to avoid trashing it.
1828949bef1SLaurent Vivier */
183465e237bSLaurent Vivier sp = target_sigsp(get_sp_from_cpustate(regs) - 32, ka);
1848949bef1SLaurent Vivier
1858949bef1SLaurent Vivier return (sp - frame_size) & ~7;
1868949bef1SLaurent Vivier }
1878949bef1SLaurent Vivier
mips_set_hflags_isa_mode_from_pc(CPUMIPSState * env)1888949bef1SLaurent Vivier static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState *env)
1898949bef1SLaurent Vivier {
1908949bef1SLaurent Vivier if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) {
1918949bef1SLaurent Vivier env->hflags &= ~MIPS_HFLAG_M16;
1928949bef1SLaurent Vivier env->hflags |= (env->active_tc.PC & 1) << MIPS_HFLAG_M16_SHIFT;
1938949bef1SLaurent Vivier env->active_tc.PC &= ~(target_ulong) 1;
1948949bef1SLaurent Vivier }
1958949bef1SLaurent Vivier }
1968949bef1SLaurent Vivier
1978949bef1SLaurent Vivier # if defined(TARGET_ABI_MIPSO32)
1988949bef1SLaurent Vivier /* compare linux/arch/mips/kernel/signal.c:setup_frame() */
setup_frame(int sig,struct target_sigaction * ka,target_sigset_t * set,CPUMIPSState * regs)1998949bef1SLaurent Vivier void setup_frame(int sig, struct target_sigaction * ka,
2008949bef1SLaurent Vivier target_sigset_t *set, CPUMIPSState *regs)
2018949bef1SLaurent Vivier {
2028949bef1SLaurent Vivier struct sigframe *frame;
2038949bef1SLaurent Vivier abi_ulong frame_addr;
2048949bef1SLaurent Vivier int i;
2058949bef1SLaurent Vivier
2068949bef1SLaurent Vivier frame_addr = get_sigframe(ka, regs, sizeof(*frame));
2078949bef1SLaurent Vivier trace_user_setup_frame(regs, frame_addr);
2088949bef1SLaurent Vivier if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
2098949bef1SLaurent Vivier goto give_sigsegv;
2108949bef1SLaurent Vivier }
2118949bef1SLaurent Vivier
2128949bef1SLaurent Vivier setup_sigcontext(regs, &frame->sf_sc);
2138949bef1SLaurent Vivier
2148949bef1SLaurent Vivier for(i = 0; i < TARGET_NSIG_WORDS; i++) {
2158949bef1SLaurent Vivier __put_user(set->sig[i], &frame->sf_mask.sig[i]);
2168949bef1SLaurent Vivier }
2178949bef1SLaurent Vivier
2188949bef1SLaurent Vivier /*
2198949bef1SLaurent Vivier * Arguments to signal handler:
2208949bef1SLaurent Vivier *
2218949bef1SLaurent Vivier * a0 = signal number
2228949bef1SLaurent Vivier * a1 = 0 (should be cause)
2238949bef1SLaurent Vivier * a2 = pointer to struct sigcontext
2248949bef1SLaurent Vivier *
2258949bef1SLaurent Vivier * $25 and PC point to the signal handler, $29 points to the
2268949bef1SLaurent Vivier * struct sigframe.
2278949bef1SLaurent Vivier */
2288949bef1SLaurent Vivier regs->active_tc.gpr[ 4] = sig;
2298949bef1SLaurent Vivier regs->active_tc.gpr[ 5] = 0;
2308949bef1SLaurent Vivier regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
2318949bef1SLaurent Vivier regs->active_tc.gpr[29] = frame_addr;
232317a33b6SRichard Henderson regs->active_tc.gpr[31] = default_sigreturn;
2338949bef1SLaurent Vivier /* The original kernel code sets CP0_EPC to the handler
2348949bef1SLaurent Vivier * since it returns to userland using eret
2358949bef1SLaurent Vivier * we cannot do this here, and we must set PC directly */
2368949bef1SLaurent Vivier regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
2378949bef1SLaurent Vivier mips_set_hflags_isa_mode_from_pc(regs);
2388949bef1SLaurent Vivier unlock_user_struct(frame, frame_addr, 1);
2398949bef1SLaurent Vivier return;
2408949bef1SLaurent Vivier
2418949bef1SLaurent Vivier give_sigsegv:
2428949bef1SLaurent Vivier force_sigsegv(sig);
2438949bef1SLaurent Vivier }
2448949bef1SLaurent Vivier
do_sigreturn(CPUMIPSState * regs)2458949bef1SLaurent Vivier long do_sigreturn(CPUMIPSState *regs)
2468949bef1SLaurent Vivier {
2478949bef1SLaurent Vivier struct sigframe *frame;
2488949bef1SLaurent Vivier abi_ulong frame_addr;
2498949bef1SLaurent Vivier sigset_t blocked;
2508949bef1SLaurent Vivier target_sigset_t target_set;
2518949bef1SLaurent Vivier int i;
2528949bef1SLaurent Vivier
2538949bef1SLaurent Vivier frame_addr = regs->active_tc.gpr[29];
2548949bef1SLaurent Vivier trace_user_do_sigreturn(regs, frame_addr);
2558949bef1SLaurent Vivier if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2568949bef1SLaurent Vivier goto badframe;
2578949bef1SLaurent Vivier
2588949bef1SLaurent Vivier for(i = 0; i < TARGET_NSIG_WORDS; i++) {
2598949bef1SLaurent Vivier __get_user(target_set.sig[i], &frame->sf_mask.sig[i]);
2608949bef1SLaurent Vivier }
2618949bef1SLaurent Vivier
2628949bef1SLaurent Vivier target_to_host_sigset_internal(&blocked, &target_set);
2638949bef1SLaurent Vivier set_sigmask(&blocked);
2648949bef1SLaurent Vivier
2658949bef1SLaurent Vivier restore_sigcontext(regs, &frame->sf_sc);
2668949bef1SLaurent Vivier
2678949bef1SLaurent Vivier #if 0
2688949bef1SLaurent Vivier /*
2698949bef1SLaurent Vivier * Don't let your children do this ...
2708949bef1SLaurent Vivier */
2718949bef1SLaurent Vivier __asm__ __volatile__(
2728949bef1SLaurent Vivier "move\t$29, %0\n\t"
2738949bef1SLaurent Vivier "j\tsyscall_exit"
2748949bef1SLaurent Vivier :/* no outputs */
2758949bef1SLaurent Vivier :"r" (®s));
2768949bef1SLaurent Vivier /* Unreached */
2778949bef1SLaurent Vivier #endif
2788949bef1SLaurent Vivier
2798949bef1SLaurent Vivier regs->active_tc.PC = regs->CP0_EPC;
2808949bef1SLaurent Vivier mips_set_hflags_isa_mode_from_pc(regs);
2818949bef1SLaurent Vivier /* I am not sure this is right, but it seems to work
2828949bef1SLaurent Vivier * maybe a problem with nested signals ? */
2838949bef1SLaurent Vivier regs->CP0_EPC = 0;
28457a0c938SRichard Henderson return -QEMU_ESIGRETURN;
2858949bef1SLaurent Vivier
2868949bef1SLaurent Vivier badframe:
2878949bef1SLaurent Vivier force_sig(TARGET_SIGSEGV);
28857a0c938SRichard Henderson return -QEMU_ESIGRETURN;
2898949bef1SLaurent Vivier }
2908949bef1SLaurent Vivier # endif /* O32 */
2918949bef1SLaurent Vivier
setup_rt_frame(int sig,struct target_sigaction * ka,target_siginfo_t * info,target_sigset_t * set,CPUMIPSState * env)2928949bef1SLaurent Vivier void setup_rt_frame(int sig, struct target_sigaction *ka,
2938949bef1SLaurent Vivier target_siginfo_t *info,
2948949bef1SLaurent Vivier target_sigset_t *set, CPUMIPSState *env)
2958949bef1SLaurent Vivier {
2968949bef1SLaurent Vivier struct target_rt_sigframe *frame;
2978949bef1SLaurent Vivier abi_ulong frame_addr;
2988949bef1SLaurent Vivier int i;
2998949bef1SLaurent Vivier
3008949bef1SLaurent Vivier frame_addr = get_sigframe(ka, env, sizeof(*frame));
3018949bef1SLaurent Vivier trace_user_setup_rt_frame(env, frame_addr);
3028949bef1SLaurent Vivier if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3038949bef1SLaurent Vivier goto give_sigsegv;
3048949bef1SLaurent Vivier }
3058949bef1SLaurent Vivier
306*4d6d8a05SGustavo Romero frame->rs_info = *info;
3078949bef1SLaurent Vivier
3088949bef1SLaurent Vivier __put_user(0, &frame->rs_uc.tuc_flags);
3098949bef1SLaurent Vivier __put_user(0, &frame->rs_uc.tuc_link);
310465e237bSLaurent Vivier target_save_altstack(&frame->rs_uc.tuc_stack, env);
3118949bef1SLaurent Vivier
3128949bef1SLaurent Vivier setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
3138949bef1SLaurent Vivier
3148949bef1SLaurent Vivier for (i = 0; i < TARGET_NSIG_WORDS; i++) {
3158949bef1SLaurent Vivier __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
3168949bef1SLaurent Vivier }
3178949bef1SLaurent Vivier
3188949bef1SLaurent Vivier /*
3198949bef1SLaurent Vivier * Arguments to signal handler:
3208949bef1SLaurent Vivier *
3218949bef1SLaurent Vivier * a0 = signal number
3228949bef1SLaurent Vivier * a1 = pointer to siginfo_t
3238949bef1SLaurent Vivier * a2 = pointer to ucontext_t
3248949bef1SLaurent Vivier *
3258949bef1SLaurent Vivier * $25 and PC point to the signal handler, $29 points to the
3268949bef1SLaurent Vivier * struct sigframe.
3278949bef1SLaurent Vivier */
3288949bef1SLaurent Vivier env->active_tc.gpr[ 4] = sig;
3298949bef1SLaurent Vivier env->active_tc.gpr[ 5] = frame_addr
3308949bef1SLaurent Vivier + offsetof(struct target_rt_sigframe, rs_info);
3318949bef1SLaurent Vivier env->active_tc.gpr[ 6] = frame_addr
3328949bef1SLaurent Vivier + offsetof(struct target_rt_sigframe, rs_uc);
3338949bef1SLaurent Vivier env->active_tc.gpr[29] = frame_addr;
334317a33b6SRichard Henderson env->active_tc.gpr[31] = default_rt_sigreturn;
335317a33b6SRichard Henderson
336317a33b6SRichard Henderson /*
337317a33b6SRichard Henderson * The original kernel code sets CP0_EPC to the handler
3388949bef1SLaurent Vivier * since it returns to userland using eret
339317a33b6SRichard Henderson * we cannot do this here, and we must set PC directly
340317a33b6SRichard Henderson */
3418949bef1SLaurent Vivier env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
3428949bef1SLaurent Vivier mips_set_hflags_isa_mode_from_pc(env);
3438949bef1SLaurent Vivier unlock_user_struct(frame, frame_addr, 1);
3448949bef1SLaurent Vivier return;
3458949bef1SLaurent Vivier
3468949bef1SLaurent Vivier give_sigsegv:
3478949bef1SLaurent Vivier unlock_user_struct(frame, frame_addr, 1);
3488949bef1SLaurent Vivier force_sigsegv(sig);
3498949bef1SLaurent Vivier }
3508949bef1SLaurent Vivier
do_rt_sigreturn(CPUMIPSState * env)3518949bef1SLaurent Vivier long do_rt_sigreturn(CPUMIPSState *env)
3528949bef1SLaurent Vivier {
3538949bef1SLaurent Vivier struct target_rt_sigframe *frame;
3548949bef1SLaurent Vivier abi_ulong frame_addr;
3558949bef1SLaurent Vivier sigset_t blocked;
3568949bef1SLaurent Vivier
3578949bef1SLaurent Vivier frame_addr = env->active_tc.gpr[29];
3588949bef1SLaurent Vivier trace_user_do_rt_sigreturn(env, frame_addr);
3598949bef1SLaurent Vivier if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
3608949bef1SLaurent Vivier goto badframe;
3618949bef1SLaurent Vivier }
3628949bef1SLaurent Vivier
3638949bef1SLaurent Vivier target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
3648949bef1SLaurent Vivier set_sigmask(&blocked);
3658949bef1SLaurent Vivier
3668949bef1SLaurent Vivier restore_sigcontext(env, &frame->rs_uc.tuc_mcontext);
367ddc3e74dSRichard Henderson target_restore_altstack(&frame->rs_uc.tuc_stack, env);
3688949bef1SLaurent Vivier
3698949bef1SLaurent Vivier env->active_tc.PC = env->CP0_EPC;
3708949bef1SLaurent Vivier mips_set_hflags_isa_mode_from_pc(env);
3718949bef1SLaurent Vivier /* I am not sure this is right, but it seems to work
3728949bef1SLaurent Vivier * maybe a problem with nested signals ? */
3738949bef1SLaurent Vivier env->CP0_EPC = 0;
37457a0c938SRichard Henderson return -QEMU_ESIGRETURN;
3758949bef1SLaurent Vivier
3768949bef1SLaurent Vivier badframe:
3778949bef1SLaurent Vivier force_sig(TARGET_SIGSEGV);
37857a0c938SRichard Henderson return -QEMU_ESIGRETURN;
3798949bef1SLaurent Vivier }
380317a33b6SRichard Henderson
setup_sigtramp(abi_ulong sigtramp_page)381317a33b6SRichard Henderson void setup_sigtramp(abi_ulong sigtramp_page)
382317a33b6SRichard Henderson {
383317a33b6SRichard Henderson uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 2 * 8, 0);
384317a33b6SRichard Henderson assert(tramp != NULL);
385317a33b6SRichard Henderson
386317a33b6SRichard Henderson #ifdef TARGET_ARCH_HAS_SETUP_FRAME
387317a33b6SRichard Henderson default_sigreturn = sigtramp_page;
388317a33b6SRichard Henderson install_sigtramp(tramp, TARGET_NR_sigreturn);
389317a33b6SRichard Henderson #endif
390317a33b6SRichard Henderson
391317a33b6SRichard Henderson default_rt_sigreturn = sigtramp_page + 8;
392317a33b6SRichard Henderson install_sigtramp(tramp + 2, TARGET_NR_rt_sigreturn);
393317a33b6SRichard Henderson
394317a33b6SRichard Henderson unlock_user(tramp, sigtramp_page, 2 * 8);
395317a33b6SRichard Henderson }
396