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