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" 21*3b249d26SPeter 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 */ 908949bef1SLaurent Vivier static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall) 918949bef1SLaurent Vivier { 928949bef1SLaurent Vivier int err = 0; 938949bef1SLaurent Vivier 948949bef1SLaurent Vivier /* 958949bef1SLaurent Vivier * Set up the return code ... 968949bef1SLaurent Vivier * 978949bef1SLaurent Vivier * li v0, __NR__foo_sigreturn 988949bef1SLaurent Vivier * syscall 998949bef1SLaurent Vivier */ 1008949bef1SLaurent Vivier 1018949bef1SLaurent Vivier __put_user(0x24020000 + syscall, tramp + 0); 1028949bef1SLaurent Vivier __put_user(0x0000000c , tramp + 1); 1038949bef1SLaurent Vivier return err; 1048949bef1SLaurent Vivier } 1058949bef1SLaurent Vivier 1068949bef1SLaurent Vivier static inline void setup_sigcontext(CPUMIPSState *regs, 1078949bef1SLaurent Vivier struct target_sigcontext *sc) 1088949bef1SLaurent Vivier { 1098949bef1SLaurent Vivier int i; 1108949bef1SLaurent Vivier 1118949bef1SLaurent Vivier __put_user(exception_resume_pc(regs), &sc->sc_pc); 1128949bef1SLaurent Vivier regs->hflags &= ~MIPS_HFLAG_BMASK; 1138949bef1SLaurent Vivier 1148949bef1SLaurent Vivier __put_user(0, &sc->sc_regs[0]); 1158949bef1SLaurent Vivier for (i = 1; i < 32; ++i) { 1168949bef1SLaurent Vivier __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); 1178949bef1SLaurent Vivier } 1188949bef1SLaurent Vivier 1198949bef1SLaurent Vivier __put_user(regs->active_tc.HI[0], &sc->sc_mdhi); 1208949bef1SLaurent Vivier __put_user(regs->active_tc.LO[0], &sc->sc_mdlo); 1218949bef1SLaurent Vivier 1228949bef1SLaurent Vivier /* Rather than checking for dsp existence, always copy. The storage 1238949bef1SLaurent Vivier would just be garbage otherwise. */ 1248949bef1SLaurent Vivier __put_user(regs->active_tc.HI[1], &sc->sc_hi1); 1258949bef1SLaurent Vivier __put_user(regs->active_tc.HI[2], &sc->sc_hi2); 1268949bef1SLaurent Vivier __put_user(regs->active_tc.HI[3], &sc->sc_hi3); 1278949bef1SLaurent Vivier __put_user(regs->active_tc.LO[1], &sc->sc_lo1); 1288949bef1SLaurent Vivier __put_user(regs->active_tc.LO[2], &sc->sc_lo2); 1298949bef1SLaurent Vivier __put_user(regs->active_tc.LO[3], &sc->sc_lo3); 1308949bef1SLaurent Vivier { 1318949bef1SLaurent Vivier uint32_t dsp = cpu_rddsp(0x3ff, regs); 1328949bef1SLaurent Vivier __put_user(dsp, &sc->sc_dsp); 1338949bef1SLaurent Vivier } 1348949bef1SLaurent Vivier 1358949bef1SLaurent Vivier __put_user(1, &sc->sc_used_math); 1368949bef1SLaurent Vivier 1378949bef1SLaurent Vivier for (i = 0; i < 32; ++i) { 1388949bef1SLaurent Vivier __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]); 1398949bef1SLaurent Vivier } 1408949bef1SLaurent Vivier } 1418949bef1SLaurent Vivier 1428949bef1SLaurent Vivier static inline void 1438949bef1SLaurent Vivier restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc) 1448949bef1SLaurent Vivier { 1458949bef1SLaurent Vivier int i; 1468949bef1SLaurent Vivier 1478949bef1SLaurent Vivier __get_user(regs->CP0_EPC, &sc->sc_pc); 1488949bef1SLaurent Vivier 1498949bef1SLaurent Vivier __get_user(regs->active_tc.HI[0], &sc->sc_mdhi); 1508949bef1SLaurent Vivier __get_user(regs->active_tc.LO[0], &sc->sc_mdlo); 1518949bef1SLaurent Vivier 1528949bef1SLaurent Vivier for (i = 1; i < 32; ++i) { 1538949bef1SLaurent Vivier __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); 1548949bef1SLaurent Vivier } 1558949bef1SLaurent Vivier 1568949bef1SLaurent Vivier __get_user(regs->active_tc.HI[1], &sc->sc_hi1); 1578949bef1SLaurent Vivier __get_user(regs->active_tc.HI[2], &sc->sc_hi2); 1588949bef1SLaurent Vivier __get_user(regs->active_tc.HI[3], &sc->sc_hi3); 1598949bef1SLaurent Vivier __get_user(regs->active_tc.LO[1], &sc->sc_lo1); 1608949bef1SLaurent Vivier __get_user(regs->active_tc.LO[2], &sc->sc_lo2); 1618949bef1SLaurent Vivier __get_user(regs->active_tc.LO[3], &sc->sc_lo3); 1628949bef1SLaurent Vivier { 1638949bef1SLaurent Vivier uint32_t dsp; 1648949bef1SLaurent Vivier __get_user(dsp, &sc->sc_dsp); 1658949bef1SLaurent Vivier cpu_wrdsp(dsp, 0x3ff, regs); 1668949bef1SLaurent Vivier } 1678949bef1SLaurent Vivier 1688949bef1SLaurent Vivier for (i = 0; i < 32; ++i) { 1698949bef1SLaurent Vivier __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]); 1708949bef1SLaurent Vivier } 1718949bef1SLaurent Vivier } 1728949bef1SLaurent Vivier 1738949bef1SLaurent Vivier /* 1748949bef1SLaurent Vivier * Determine which stack to use.. 1758949bef1SLaurent Vivier */ 1768949bef1SLaurent Vivier static inline abi_ulong 1778949bef1SLaurent Vivier get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size) 1788949bef1SLaurent Vivier { 1798949bef1SLaurent Vivier unsigned long sp; 1808949bef1SLaurent Vivier 1818949bef1SLaurent Vivier /* 1828949bef1SLaurent Vivier * FPU emulator may have its own trampoline active just 1838949bef1SLaurent Vivier * above the user stack, 16-bytes before the next lowest 1848949bef1SLaurent Vivier * 16 byte boundary. Try to avoid trashing it. 1858949bef1SLaurent Vivier */ 186465e237bSLaurent Vivier sp = target_sigsp(get_sp_from_cpustate(regs) - 32, ka); 1878949bef1SLaurent Vivier 1888949bef1SLaurent Vivier return (sp - frame_size) & ~7; 1898949bef1SLaurent Vivier } 1908949bef1SLaurent Vivier 1918949bef1SLaurent Vivier static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState *env) 1928949bef1SLaurent Vivier { 1938949bef1SLaurent Vivier if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) { 1948949bef1SLaurent Vivier env->hflags &= ~MIPS_HFLAG_M16; 1958949bef1SLaurent Vivier env->hflags |= (env->active_tc.PC & 1) << MIPS_HFLAG_M16_SHIFT; 1968949bef1SLaurent Vivier env->active_tc.PC &= ~(target_ulong) 1; 1978949bef1SLaurent Vivier } 1988949bef1SLaurent Vivier } 1998949bef1SLaurent Vivier 2008949bef1SLaurent Vivier # if defined(TARGET_ABI_MIPSO32) 2018949bef1SLaurent Vivier /* compare linux/arch/mips/kernel/signal.c:setup_frame() */ 2028949bef1SLaurent Vivier void setup_frame(int sig, struct target_sigaction * ka, 2038949bef1SLaurent Vivier target_sigset_t *set, CPUMIPSState *regs) 2048949bef1SLaurent Vivier { 2058949bef1SLaurent Vivier struct sigframe *frame; 2068949bef1SLaurent Vivier abi_ulong frame_addr; 2078949bef1SLaurent Vivier int i; 2088949bef1SLaurent Vivier 2098949bef1SLaurent Vivier frame_addr = get_sigframe(ka, regs, sizeof(*frame)); 2108949bef1SLaurent Vivier trace_user_setup_frame(regs, frame_addr); 2118949bef1SLaurent Vivier if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { 2128949bef1SLaurent Vivier goto give_sigsegv; 2138949bef1SLaurent Vivier } 2148949bef1SLaurent Vivier 2158949bef1SLaurent Vivier install_sigtramp(frame->sf_code, TARGET_NR_sigreturn); 2168949bef1SLaurent Vivier 2178949bef1SLaurent Vivier setup_sigcontext(regs, &frame->sf_sc); 2188949bef1SLaurent Vivier 2198949bef1SLaurent Vivier for(i = 0; i < TARGET_NSIG_WORDS; i++) { 2208949bef1SLaurent Vivier __put_user(set->sig[i], &frame->sf_mask.sig[i]); 2218949bef1SLaurent Vivier } 2228949bef1SLaurent Vivier 2238949bef1SLaurent Vivier /* 2248949bef1SLaurent Vivier * Arguments to signal handler: 2258949bef1SLaurent Vivier * 2268949bef1SLaurent Vivier * a0 = signal number 2278949bef1SLaurent Vivier * a1 = 0 (should be cause) 2288949bef1SLaurent Vivier * a2 = pointer to struct sigcontext 2298949bef1SLaurent Vivier * 2308949bef1SLaurent Vivier * $25 and PC point to the signal handler, $29 points to the 2318949bef1SLaurent Vivier * struct sigframe. 2328949bef1SLaurent Vivier */ 2338949bef1SLaurent Vivier regs->active_tc.gpr[ 4] = sig; 2348949bef1SLaurent Vivier regs->active_tc.gpr[ 5] = 0; 2358949bef1SLaurent Vivier regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc); 2368949bef1SLaurent Vivier regs->active_tc.gpr[29] = frame_addr; 2378949bef1SLaurent Vivier regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code); 2388949bef1SLaurent Vivier /* The original kernel code sets CP0_EPC to the handler 2398949bef1SLaurent Vivier * since it returns to userland using eret 2408949bef1SLaurent Vivier * we cannot do this here, and we must set PC directly */ 2418949bef1SLaurent Vivier regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler; 2428949bef1SLaurent Vivier mips_set_hflags_isa_mode_from_pc(regs); 2438949bef1SLaurent Vivier unlock_user_struct(frame, frame_addr, 1); 2448949bef1SLaurent Vivier return; 2458949bef1SLaurent Vivier 2468949bef1SLaurent Vivier give_sigsegv: 2478949bef1SLaurent Vivier force_sigsegv(sig); 2488949bef1SLaurent Vivier } 2498949bef1SLaurent Vivier 2508949bef1SLaurent Vivier long do_sigreturn(CPUMIPSState *regs) 2518949bef1SLaurent Vivier { 2528949bef1SLaurent Vivier struct sigframe *frame; 2538949bef1SLaurent Vivier abi_ulong frame_addr; 2548949bef1SLaurent Vivier sigset_t blocked; 2558949bef1SLaurent Vivier target_sigset_t target_set; 2568949bef1SLaurent Vivier int i; 2578949bef1SLaurent Vivier 2588949bef1SLaurent Vivier frame_addr = regs->active_tc.gpr[29]; 2598949bef1SLaurent Vivier trace_user_do_sigreturn(regs, frame_addr); 2608949bef1SLaurent Vivier if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) 2618949bef1SLaurent Vivier goto badframe; 2628949bef1SLaurent Vivier 2638949bef1SLaurent Vivier for(i = 0; i < TARGET_NSIG_WORDS; i++) { 2648949bef1SLaurent Vivier __get_user(target_set.sig[i], &frame->sf_mask.sig[i]); 2658949bef1SLaurent Vivier } 2668949bef1SLaurent Vivier 2678949bef1SLaurent Vivier target_to_host_sigset_internal(&blocked, &target_set); 2688949bef1SLaurent Vivier set_sigmask(&blocked); 2698949bef1SLaurent Vivier 2708949bef1SLaurent Vivier restore_sigcontext(regs, &frame->sf_sc); 2718949bef1SLaurent Vivier 2728949bef1SLaurent Vivier #if 0 2738949bef1SLaurent Vivier /* 2748949bef1SLaurent Vivier * Don't let your children do this ... 2758949bef1SLaurent Vivier */ 2768949bef1SLaurent Vivier __asm__ __volatile__( 2778949bef1SLaurent Vivier "move\t$29, %0\n\t" 2788949bef1SLaurent Vivier "j\tsyscall_exit" 2798949bef1SLaurent Vivier :/* no outputs */ 2808949bef1SLaurent Vivier :"r" (®s)); 2818949bef1SLaurent Vivier /* Unreached */ 2828949bef1SLaurent Vivier #endif 2838949bef1SLaurent Vivier 2848949bef1SLaurent Vivier regs->active_tc.PC = regs->CP0_EPC; 2858949bef1SLaurent Vivier mips_set_hflags_isa_mode_from_pc(regs); 2868949bef1SLaurent Vivier /* I am not sure this is right, but it seems to work 2878949bef1SLaurent Vivier * maybe a problem with nested signals ? */ 2888949bef1SLaurent Vivier regs->CP0_EPC = 0; 2898949bef1SLaurent Vivier return -TARGET_QEMU_ESIGRETURN; 2908949bef1SLaurent Vivier 2918949bef1SLaurent Vivier badframe: 2928949bef1SLaurent Vivier force_sig(TARGET_SIGSEGV); 2938949bef1SLaurent Vivier return -TARGET_QEMU_ESIGRETURN; 2948949bef1SLaurent Vivier } 2958949bef1SLaurent Vivier # endif /* O32 */ 2968949bef1SLaurent Vivier 2978949bef1SLaurent Vivier void setup_rt_frame(int sig, struct target_sigaction *ka, 2988949bef1SLaurent Vivier target_siginfo_t *info, 2998949bef1SLaurent Vivier target_sigset_t *set, CPUMIPSState *env) 3008949bef1SLaurent Vivier { 3018949bef1SLaurent Vivier struct target_rt_sigframe *frame; 3028949bef1SLaurent Vivier abi_ulong frame_addr; 3038949bef1SLaurent Vivier int i; 3048949bef1SLaurent Vivier 3058949bef1SLaurent Vivier frame_addr = get_sigframe(ka, env, sizeof(*frame)); 3068949bef1SLaurent Vivier trace_user_setup_rt_frame(env, frame_addr); 3078949bef1SLaurent Vivier if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { 3088949bef1SLaurent Vivier goto give_sigsegv; 3098949bef1SLaurent Vivier } 3108949bef1SLaurent Vivier 3118949bef1SLaurent Vivier install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn); 3128949bef1SLaurent Vivier 3138949bef1SLaurent Vivier tswap_siginfo(&frame->rs_info, info); 3148949bef1SLaurent Vivier 3158949bef1SLaurent Vivier __put_user(0, &frame->rs_uc.tuc_flags); 3168949bef1SLaurent Vivier __put_user(0, &frame->rs_uc.tuc_link); 317465e237bSLaurent Vivier target_save_altstack(&frame->rs_uc.tuc_stack, env); 3188949bef1SLaurent Vivier 3198949bef1SLaurent Vivier setup_sigcontext(env, &frame->rs_uc.tuc_mcontext); 3208949bef1SLaurent Vivier 3218949bef1SLaurent Vivier for(i = 0; i < TARGET_NSIG_WORDS; i++) { 3228949bef1SLaurent Vivier __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]); 3238949bef1SLaurent Vivier } 3248949bef1SLaurent Vivier 3258949bef1SLaurent Vivier /* 3268949bef1SLaurent Vivier * Arguments to signal handler: 3278949bef1SLaurent Vivier * 3288949bef1SLaurent Vivier * a0 = signal number 3298949bef1SLaurent Vivier * a1 = pointer to siginfo_t 3308949bef1SLaurent Vivier * a2 = pointer to ucontext_t 3318949bef1SLaurent Vivier * 3328949bef1SLaurent Vivier * $25 and PC point to the signal handler, $29 points to the 3338949bef1SLaurent Vivier * struct sigframe. 3348949bef1SLaurent Vivier */ 3358949bef1SLaurent Vivier env->active_tc.gpr[ 4] = sig; 3368949bef1SLaurent Vivier env->active_tc.gpr[ 5] = frame_addr 3378949bef1SLaurent Vivier + offsetof(struct target_rt_sigframe, rs_info); 3388949bef1SLaurent Vivier env->active_tc.gpr[ 6] = frame_addr 3398949bef1SLaurent Vivier + offsetof(struct target_rt_sigframe, rs_uc); 3408949bef1SLaurent Vivier env->active_tc.gpr[29] = frame_addr; 3418949bef1SLaurent Vivier env->active_tc.gpr[31] = frame_addr 3428949bef1SLaurent Vivier + offsetof(struct target_rt_sigframe, rs_code); 3438949bef1SLaurent Vivier /* The original kernel code sets CP0_EPC to the handler 3448949bef1SLaurent Vivier * since it returns to userland using eret 3458949bef1SLaurent Vivier * we cannot do this here, and we must set PC directly */ 3468949bef1SLaurent Vivier env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler; 3478949bef1SLaurent Vivier mips_set_hflags_isa_mode_from_pc(env); 3488949bef1SLaurent Vivier unlock_user_struct(frame, frame_addr, 1); 3498949bef1SLaurent Vivier return; 3508949bef1SLaurent Vivier 3518949bef1SLaurent Vivier give_sigsegv: 3528949bef1SLaurent Vivier unlock_user_struct(frame, frame_addr, 1); 3538949bef1SLaurent Vivier force_sigsegv(sig); 3548949bef1SLaurent Vivier } 3558949bef1SLaurent Vivier 3568949bef1SLaurent Vivier long do_rt_sigreturn(CPUMIPSState *env) 3578949bef1SLaurent Vivier { 3588949bef1SLaurent Vivier struct target_rt_sigframe *frame; 3598949bef1SLaurent Vivier abi_ulong frame_addr; 3608949bef1SLaurent Vivier sigset_t blocked; 3618949bef1SLaurent Vivier 3628949bef1SLaurent Vivier frame_addr = env->active_tc.gpr[29]; 3638949bef1SLaurent Vivier trace_user_do_rt_sigreturn(env, frame_addr); 3648949bef1SLaurent Vivier if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { 3658949bef1SLaurent Vivier goto badframe; 3668949bef1SLaurent Vivier } 3678949bef1SLaurent Vivier 3688949bef1SLaurent Vivier target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask); 3698949bef1SLaurent Vivier set_sigmask(&blocked); 3708949bef1SLaurent Vivier 3718949bef1SLaurent Vivier restore_sigcontext(env, &frame->rs_uc.tuc_mcontext); 372ddc3e74dSRichard Henderson target_restore_altstack(&frame->rs_uc.tuc_stack, env); 3738949bef1SLaurent Vivier 3748949bef1SLaurent Vivier env->active_tc.PC = env->CP0_EPC; 3758949bef1SLaurent Vivier mips_set_hflags_isa_mode_from_pc(env); 3768949bef1SLaurent Vivier /* I am not sure this is right, but it seems to work 3778949bef1SLaurent Vivier * maybe a problem with nested signals ? */ 3788949bef1SLaurent Vivier env->CP0_EPC = 0; 3798949bef1SLaurent Vivier return -TARGET_QEMU_ESIGRETURN; 3808949bef1SLaurent Vivier 3818949bef1SLaurent Vivier badframe: 3828949bef1SLaurent Vivier force_sig(TARGET_SIGSEGV); 3838949bef1SLaurent Vivier return -TARGET_QEMU_ESIGRETURN; 3848949bef1SLaurent Vivier } 385