xref: /qemu/linux-user/mips/signal.c (revision ba49d760eb04630e7b15f423ebecf6c871b8f77b)
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" (&regs));
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