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 "target_signal.h" 22 #include "signal-common.h" 23 #include "linux-user/trace.h" 24 25 struct target_sigcontext { 26 struct target_pt_regs regs; 27 abi_ulong oldmask; 28 abi_ulong usp; 29 }; 30 31 struct target_ucontext { 32 abi_ulong tuc_flags; 33 abi_ulong tuc_link; 34 target_stack_t tuc_stack; 35 struct target_sigcontext tuc_mcontext; 36 target_sigset_t tuc_sigmask; /* mask last for extensibility */ 37 }; 38 39 struct target_rt_sigframe { 40 abi_ulong pinfo; 41 uint64_t puc; 42 struct target_siginfo info; 43 struct target_sigcontext sc; 44 struct target_ucontext uc; 45 unsigned char retcode[16]; /* trampoline code */ 46 }; 47 48 /* This is the asm-generic/ucontext.h version */ 49 #if 0 50 static int restore_sigcontext(CPUOpenRISCState *regs, 51 struct target_sigcontext *sc) 52 { 53 unsigned int err = 0; 54 unsigned long old_usp; 55 56 /* Alwys make any pending restarted system call return -EINTR */ 57 current_thread_info()->restart_block.fn = do_no_restart_syscall; 58 59 /* restore the regs from &sc->regs (same as sc, since regs is first) 60 * (sc is already checked for VERIFY_READ since the sigframe was 61 * checked in sys_sigreturn previously) 62 */ 63 64 if (copy_from_user(regs, &sc, sizeof(struct target_pt_regs))) { 65 goto badframe; 66 } 67 68 /* make sure the U-flag is set so user-mode cannot fool us */ 69 70 regs->sr &= ~SR_SM; 71 72 /* restore the old USP as it was before we stacked the sc etc. 73 * (we cannot just pop the sigcontext since we aligned the sp and 74 * stuff after pushing it) 75 */ 76 77 __get_user(old_usp, &sc->usp); 78 phx_signal("old_usp 0x%lx", old_usp); 79 80 __PHX__ REALLY /* ??? */ 81 wrusp(old_usp); 82 regs->gpr[1] = old_usp; 83 84 /* TODO: the other ports use regs->orig_XX to disable syscall checks 85 * after this completes, but we don't use that mechanism. maybe we can 86 * use it now ? 87 */ 88 89 return err; 90 91 badframe: 92 return 1; 93 } 94 #endif 95 96 /* Set up a signal frame. */ 97 98 static void setup_sigcontext(struct target_sigcontext *sc, 99 CPUOpenRISCState *regs, 100 unsigned long mask) 101 { 102 unsigned long usp = cpu_get_gpr(regs, 1); 103 104 /* copy the regs. they are first in sc so we can use sc directly */ 105 106 /*copy_to_user(&sc, regs, sizeof(struct target_pt_regs));*/ 107 108 /* Set the frametype to CRIS_FRAME_NORMAL for the execution of 109 the signal handler. The frametype will be restored to its previous 110 value in restore_sigcontext. */ 111 /*regs->frametype = CRIS_FRAME_NORMAL;*/ 112 113 /* then some other stuff */ 114 __put_user(mask, &sc->oldmask); 115 __put_user(usp, &sc->usp); 116 } 117 118 static inline unsigned long align_sigframe(unsigned long sp) 119 { 120 return sp & ~3UL; 121 } 122 123 static inline abi_ulong get_sigframe(struct target_sigaction *ka, 124 CPUOpenRISCState *regs, 125 size_t frame_size) 126 { 127 unsigned long sp = get_sp_from_cpustate(regs); 128 int onsigstack = on_sig_stack(sp); 129 130 /* redzone */ 131 sp = target_sigsp(sp, ka); 132 133 sp = align_sigframe(sp - frame_size); 134 135 /* 136 * If we are on the alternate signal stack and would overflow it, don't. 137 * Return an always-bogus address instead so we will die with SIGSEGV. 138 */ 139 140 if (onsigstack && !likely(on_sig_stack(sp))) { 141 return -1L; 142 } 143 144 return sp; 145 } 146 147 void setup_rt_frame(int sig, struct target_sigaction *ka, 148 target_siginfo_t *info, 149 target_sigset_t *set, CPUOpenRISCState *env) 150 { 151 int err = 0; 152 abi_ulong frame_addr; 153 unsigned long return_ip; 154 struct target_rt_sigframe *frame; 155 abi_ulong info_addr, uc_addr; 156 157 frame_addr = get_sigframe(ka, env, sizeof(*frame)); 158 trace_user_setup_rt_frame(env, frame_addr); 159 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { 160 goto give_sigsegv; 161 } 162 163 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info); 164 __put_user(info_addr, &frame->pinfo); 165 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc); 166 __put_user(uc_addr, &frame->puc); 167 168 if (ka->sa_flags & SA_SIGINFO) { 169 tswap_siginfo(&frame->info, info); 170 } 171 172 /*err |= __clear_user(&frame->uc, offsetof(ucontext_t, uc_mcontext));*/ 173 __put_user(0, &frame->uc.tuc_flags); 174 __put_user(0, &frame->uc.tuc_link); 175 target_save_altstack(&frame->uc.tuc_stack, env); 176 setup_sigcontext(&frame->sc, env, set->sig[0]); 177 178 /*err |= copy_to_user(frame->uc.tuc_sigmask, set, sizeof(*set));*/ 179 180 /* trampoline - the desired return ip is the retcode itself */ 181 return_ip = (unsigned long)&frame->retcode; 182 /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */ 183 __put_user(0xa960, (short *)(frame->retcode + 0)); 184 __put_user(TARGET_NR_rt_sigreturn, (short *)(frame->retcode + 2)); 185 __put_user(0x20000001, (unsigned long *)(frame->retcode + 4)); 186 __put_user(0x15000000, (unsigned long *)(frame->retcode + 8)); 187 188 if (err) { 189 goto give_sigsegv; 190 } 191 192 /* TODO what is the current->exec_domain stuff and invmap ? */ 193 194 /* Set up registers for signal handler */ 195 env->pc = (unsigned long)ka->_sa_handler; /* what we enter NOW */ 196 cpu_set_gpr(env, 9, (unsigned long)return_ip); /* what we enter LATER */ 197 cpu_set_gpr(env, 3, (unsigned long)sig); /* arg 1: signo */ 198 cpu_set_gpr(env, 4, (unsigned long)&frame->info); /* arg 2: (siginfo_t*) */ 199 cpu_set_gpr(env, 5, (unsigned long)&frame->uc); /* arg 3: ucontext */ 200 201 /* actually move the usp to reflect the stacked frame */ 202 cpu_set_gpr(env, 1, (unsigned long)frame); 203 204 return; 205 206 give_sigsegv: 207 unlock_user_struct(frame, frame_addr, 1); 208 force_sigsegv(sig); 209 } 210 211 long do_sigreturn(CPUOpenRISCState *env) 212 { 213 trace_user_do_sigreturn(env, 0); 214 fprintf(stderr, "do_sigreturn: not implemented\n"); 215 return -TARGET_ENOSYS; 216 } 217 218 long do_rt_sigreturn(CPUOpenRISCState *env) 219 { 220 trace_user_do_rt_sigreturn(env, 0); 221 fprintf(stderr, "do_rt_sigreturn: not implemented\n"); 222 return -TARGET_ENOSYS; 223 } 224