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 */ 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 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 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 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 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() */ 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 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 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 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 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