signal.c (6400B)
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 25struct target_sigcontext { 26 struct target_pt_regs regs; /* needs to be first */ 27 uint32_t oldmask; 28 uint32_t usp; /* usp before stacking this gunk on it */ 29}; 30 31/* Signal frames. */ 32struct target_signal_frame { 33 struct target_sigcontext sc; 34 uint32_t extramask[TARGET_NSIG_WORDS - 1]; 35 uint16_t retcode[4]; /* Trampoline code. */ 36}; 37 38struct rt_signal_frame { 39 siginfo_t *pinfo; 40 void *puc; 41 siginfo_t info; 42 ucontext_t uc; 43 uint16_t retcode[4]; /* Trampoline code. */ 44}; 45 46static void setup_sigcontext(struct target_sigcontext *sc, CPUCRISState *env) 47{ 48 __put_user(env->regs[0], &sc->regs.r0); 49 __put_user(env->regs[1], &sc->regs.r1); 50 __put_user(env->regs[2], &sc->regs.r2); 51 __put_user(env->regs[3], &sc->regs.r3); 52 __put_user(env->regs[4], &sc->regs.r4); 53 __put_user(env->regs[5], &sc->regs.r5); 54 __put_user(env->regs[6], &sc->regs.r6); 55 __put_user(env->regs[7], &sc->regs.r7); 56 __put_user(env->regs[8], &sc->regs.r8); 57 __put_user(env->regs[9], &sc->regs.r9); 58 __put_user(env->regs[10], &sc->regs.r10); 59 __put_user(env->regs[11], &sc->regs.r11); 60 __put_user(env->regs[12], &sc->regs.r12); 61 __put_user(env->regs[13], &sc->regs.r13); 62 __put_user(env->regs[14], &sc->usp); 63 __put_user(env->regs[15], &sc->regs.acr); 64 __put_user(env->pregs[PR_MOF], &sc->regs.mof); 65 __put_user(env->pregs[PR_SRP], &sc->regs.srp); 66 __put_user(env->pc, &sc->regs.erp); 67} 68 69static void restore_sigcontext(struct target_sigcontext *sc, CPUCRISState *env) 70{ 71 __get_user(env->regs[0], &sc->regs.r0); 72 __get_user(env->regs[1], &sc->regs.r1); 73 __get_user(env->regs[2], &sc->regs.r2); 74 __get_user(env->regs[3], &sc->regs.r3); 75 __get_user(env->regs[4], &sc->regs.r4); 76 __get_user(env->regs[5], &sc->regs.r5); 77 __get_user(env->regs[6], &sc->regs.r6); 78 __get_user(env->regs[7], &sc->regs.r7); 79 __get_user(env->regs[8], &sc->regs.r8); 80 __get_user(env->regs[9], &sc->regs.r9); 81 __get_user(env->regs[10], &sc->regs.r10); 82 __get_user(env->regs[11], &sc->regs.r11); 83 __get_user(env->regs[12], &sc->regs.r12); 84 __get_user(env->regs[13], &sc->regs.r13); 85 __get_user(env->regs[14], &sc->usp); 86 __get_user(env->regs[15], &sc->regs.acr); 87 __get_user(env->pregs[PR_MOF], &sc->regs.mof); 88 __get_user(env->pregs[PR_SRP], &sc->regs.srp); 89 __get_user(env->pc, &sc->regs.erp); 90} 91 92static abi_ulong get_sigframe(CPUCRISState *env, int framesize) 93{ 94 abi_ulong sp; 95 /* Align the stack downwards to 4. */ 96 sp = (env->regs[R_SP] & ~3); 97 return sp - framesize; 98} 99 100static void setup_sigreturn(uint16_t *retcode) 101{ 102 /* This is movu.w __NR_sigreturn, r9; break 13; */ 103 __put_user(0x9c5f, retcode + 0); 104 __put_user(TARGET_NR_sigreturn, retcode + 1); 105 __put_user(0xe93d, retcode + 2); 106} 107 108void setup_frame(int sig, struct target_sigaction *ka, 109 target_sigset_t *set, CPUCRISState *env) 110{ 111 struct target_signal_frame *frame; 112 abi_ulong frame_addr; 113 int i; 114 115 frame_addr = get_sigframe(env, sizeof *frame); 116 trace_user_setup_frame(env, frame_addr); 117 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) 118 goto badframe; 119 120 /* 121 * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't 122 * use this trampoline anymore but it sets it up for GDB. 123 */ 124 setup_sigreturn(frame->retcode); 125 126 /* Save the mask. */ 127 __put_user(set->sig[0], &frame->sc.oldmask); 128 129 for(i = 1; i < TARGET_NSIG_WORDS; i++) { 130 __put_user(set->sig[i], &frame->extramask[i - 1]); 131 } 132 133 setup_sigcontext(&frame->sc, env); 134 135 /* Move the stack and setup the arguments for the handler. */ 136 env->regs[R_SP] = frame_addr; 137 env->regs[10] = sig; 138 env->pc = (unsigned long) ka->_sa_handler; 139 /* Link SRP so the guest returns through the trampoline. */ 140 env->pregs[PR_SRP] = default_sigreturn; 141 142 unlock_user_struct(frame, frame_addr, 1); 143 return; 144badframe: 145 force_sigsegv(sig); 146} 147 148void setup_rt_frame(int sig, struct target_sigaction *ka, 149 target_siginfo_t *info, 150 target_sigset_t *set, CPUCRISState *env) 151{ 152 qemu_log_mask(LOG_UNIMP, "setup_rt_frame: not implemented\n"); 153} 154 155long do_sigreturn(CPUCRISState *env) 156{ 157 struct target_signal_frame *frame; 158 abi_ulong frame_addr; 159 target_sigset_t target_set; 160 sigset_t set; 161 int i; 162 163 frame_addr = env->regs[R_SP]; 164 trace_user_do_sigreturn(env, frame_addr); 165 /* Make sure the guest isn't playing games. */ 166 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1)) { 167 goto badframe; 168 } 169 170 /* Restore blocked signals */ 171 __get_user(target_set.sig[0], &frame->sc.oldmask); 172 for(i = 1; i < TARGET_NSIG_WORDS; i++) { 173 __get_user(target_set.sig[i], &frame->extramask[i - 1]); 174 } 175 target_to_host_sigset_internal(&set, &target_set); 176 set_sigmask(&set); 177 178 restore_sigcontext(&frame->sc, env); 179 unlock_user_struct(frame, frame_addr, 0); 180 return -TARGET_QEMU_ESIGRETURN; 181badframe: 182 force_sig(TARGET_SIGSEGV); 183 return -TARGET_QEMU_ESIGRETURN; 184} 185 186long do_rt_sigreturn(CPUCRISState *env) 187{ 188 trace_user_do_rt_sigreturn(env, 0); 189 qemu_log_mask(LOG_UNIMP, "do_rt_sigreturn: not implemented\n"); 190 return -TARGET_ENOSYS; 191} 192 193void setup_sigtramp(abi_ulong sigtramp_page) 194{ 195 uint16_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 6, 0); 196 assert(tramp != NULL); 197 198 default_sigreturn = sigtramp_page; 199 setup_sigreturn(tramp); 200 201 unlock_user(tramp, sigtramp_page, 6); 202}