signal.c (5058B)
1/* 2 * Emulation of Linux signals 3 * 4 * Copyright (c) 2003 Fabrice Bellard 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, see <http://www.gnu.org/licenses/>. 18 */ 19#include "qemu/osdep.h" 20#include "qemu.h" 21#include "user-internals.h" 22#include "signal-common.h" 23#include "linux-user/trace.h" 24 25typedef struct target_sigcontext { 26 struct target_pt_regs regs; 27 abi_ulong oldmask; 28} target_sigcontext; 29 30typedef struct target_ucontext { 31 abi_ulong tuc_flags; 32 abi_ulong tuc_link; 33 target_stack_t tuc_stack; 34 target_sigcontext tuc_mcontext; 35 target_sigset_t tuc_sigmask; /* mask last for extensibility */ 36} target_ucontext; 37 38typedef struct target_rt_sigframe { 39 struct target_siginfo info; 40 target_ucontext uc; 41} target_rt_sigframe; 42 43static void restore_sigcontext(CPUOpenRISCState *env, target_sigcontext *sc) 44{ 45 int i; 46 abi_ulong v; 47 48 for (i = 0; i < 32; ++i) { 49 __get_user(v, &sc->regs.gpr[i]); 50 cpu_set_gpr(env, i, v); 51 } 52 __get_user(env->pc, &sc->regs.pc); 53 54 /* Make sure the supervisor flag is clear. */ 55 __get_user(v, &sc->regs.sr); 56 cpu_set_sr(env, v & ~SR_SM); 57} 58 59/* Set up a signal frame. */ 60 61static void setup_sigcontext(target_sigcontext *sc, CPUOpenRISCState *env) 62{ 63 int i; 64 65 for (i = 0; i < 32; ++i) { 66 __put_user(cpu_get_gpr(env, i), &sc->regs.gpr[i]); 67 } 68 69 __put_user(env->pc, &sc->regs.pc); 70 __put_user(cpu_get_sr(env), &sc->regs.sr); 71} 72 73static inline abi_ulong get_sigframe(struct target_sigaction *ka, 74 CPUOpenRISCState *env, 75 size_t frame_size) 76{ 77 target_ulong sp = get_sp_from_cpustate(env); 78 79 /* Honor redzone now. If we swap to signal stack, no need to waste 80 * the 128 bytes by subtracting afterward. 81 */ 82 sp -= 128; 83 84 sp = target_sigsp(sp, ka); 85 sp -= frame_size; 86 sp = QEMU_ALIGN_DOWN(sp, 4); 87 88 return sp; 89} 90 91void setup_rt_frame(int sig, struct target_sigaction *ka, 92 target_siginfo_t *info, 93 target_sigset_t *set, CPUOpenRISCState *env) 94{ 95 abi_ulong frame_addr; 96 target_rt_sigframe *frame; 97 int i; 98 99 frame_addr = get_sigframe(ka, env, sizeof(*frame)); 100 trace_user_setup_rt_frame(env, frame_addr); 101 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { 102 goto give_sigsegv; 103 } 104 105 if (ka->sa_flags & SA_SIGINFO) { 106 tswap_siginfo(&frame->info, info); 107 } 108 109 __put_user(0, &frame->uc.tuc_flags); 110 __put_user(0, &frame->uc.tuc_link); 111 112 target_save_altstack(&frame->uc.tuc_stack, env); 113 setup_sigcontext(&frame->uc.tuc_mcontext, env); 114 for (i = 0; i < TARGET_NSIG_WORDS; ++i) { 115 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]); 116 } 117 118 /* Set up registers for signal handler */ 119 cpu_set_gpr(env, 9, default_rt_sigreturn); 120 cpu_set_gpr(env, 3, sig); 121 cpu_set_gpr(env, 4, frame_addr + offsetof(target_rt_sigframe, info)); 122 cpu_set_gpr(env, 5, frame_addr + offsetof(target_rt_sigframe, uc)); 123 cpu_set_gpr(env, 1, frame_addr); 124 125 /* For debugging convenience, set ppc to the insn that faulted. */ 126 env->ppc = env->pc; 127 /* When setting the PC for the signal handler, exit delay slot. */ 128 env->pc = ka->_sa_handler; 129 env->dflag = 0; 130 return; 131 132give_sigsegv: 133 unlock_user_struct(frame, frame_addr, 1); 134 force_sigsegv(sig); 135} 136 137long do_rt_sigreturn(CPUOpenRISCState *env) 138{ 139 abi_ulong frame_addr = get_sp_from_cpustate(env); 140 target_rt_sigframe *frame; 141 sigset_t set; 142 143 trace_user_do_rt_sigreturn(env, 0); 144 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { 145 goto badframe; 146 } 147 if (frame_addr & 3) { 148 goto badframe; 149 } 150 151 target_to_host_sigset(&set, &frame->uc.tuc_sigmask); 152 set_sigmask(&set); 153 154 restore_sigcontext(env, &frame->uc.tuc_mcontext); 155 target_restore_altstack(&frame->uc.tuc_stack, env); 156 157 unlock_user_struct(frame, frame_addr, 0); 158 return cpu_get_gpr(env, 11); 159 160 badframe: 161 unlock_user_struct(frame, frame_addr, 0); 162 force_sig(TARGET_SIGSEGV); 163 return 0; 164} 165 166void setup_sigtramp(abi_ulong sigtramp_page) 167{ 168 uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 8, 0); 169 assert(tramp != NULL); 170 171 /* This is l.ori r11,r0,__NR_sigreturn; l.sys 1 */ 172 __put_user(0xa9600000 | TARGET_NR_rt_sigreturn, tramp + 0); 173 __put_user(0x20000001, tramp + 1); 174 175 default_rt_sigreturn = sigtramp_page; 176 unlock_user(tramp, sigtramp_page, 8); 177}