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 25 struct 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. */ 32 struct 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 38 struct 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 46 static 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 69 static 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 92 static 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 100 void setup_frame(int sig, struct target_sigaction *ka, 101 target_sigset_t *set, CPUCRISState *env) 102 { 103 struct target_signal_frame *frame; 104 abi_ulong frame_addr; 105 int i; 106 107 frame_addr = get_sigframe(env, sizeof *frame); 108 trace_user_setup_frame(env, frame_addr); 109 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) 110 goto badframe; 111 112 /* 113 * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't 114 * use this trampoline anymore but it sets it up for GDB. 115 * In QEMU, using the trampoline simplifies things a bit so we use it. 116 * 117 * This is movu.w __NR_sigreturn, r9; break 13; 118 */ 119 __put_user(0x9c5f, frame->retcode+0); 120 __put_user(TARGET_NR_sigreturn, 121 frame->retcode + 1); 122 __put_user(0xe93d, frame->retcode + 2); 123 124 /* Save the mask. */ 125 __put_user(set->sig[0], &frame->sc.oldmask); 126 127 for(i = 1; i < TARGET_NSIG_WORDS; i++) { 128 __put_user(set->sig[i], &frame->extramask[i - 1]); 129 } 130 131 setup_sigcontext(&frame->sc, env); 132 133 /* Move the stack and setup the arguments for the handler. */ 134 env->regs[R_SP] = frame_addr; 135 env->regs[10] = sig; 136 env->pc = (unsigned long) ka->_sa_handler; 137 /* Link SRP so the guest returns through the trampoline. */ 138 env->pregs[PR_SRP] = frame_addr + offsetof(typeof(*frame), retcode); 139 140 unlock_user_struct(frame, frame_addr, 1); 141 return; 142 badframe: 143 force_sigsegv(sig); 144 } 145 146 void setup_rt_frame(int sig, struct target_sigaction *ka, 147 target_siginfo_t *info, 148 target_sigset_t *set, CPUCRISState *env) 149 { 150 qemu_log_mask(LOG_UNIMP, "setup_rt_frame: not implemented\n"); 151 } 152 153 long do_sigreturn(CPUCRISState *env) 154 { 155 struct target_signal_frame *frame; 156 abi_ulong frame_addr; 157 target_sigset_t target_set; 158 sigset_t set; 159 int i; 160 161 frame_addr = env->regs[R_SP]; 162 trace_user_do_sigreturn(env, frame_addr); 163 /* Make sure the guest isn't playing games. */ 164 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1)) { 165 goto badframe; 166 } 167 168 /* Restore blocked signals */ 169 __get_user(target_set.sig[0], &frame->sc.oldmask); 170 for(i = 1; i < TARGET_NSIG_WORDS; i++) { 171 __get_user(target_set.sig[i], &frame->extramask[i - 1]); 172 } 173 target_to_host_sigset_internal(&set, &target_set); 174 set_sigmask(&set); 175 176 restore_sigcontext(&frame->sc, env); 177 unlock_user_struct(frame, frame_addr, 0); 178 return -TARGET_QEMU_ESIGRETURN; 179 badframe: 180 force_sig(TARGET_SIGSEGV); 181 return -TARGET_QEMU_ESIGRETURN; 182 } 183 184 long do_rt_sigreturn(CPUCRISState *env) 185 { 186 trace_user_do_rt_sigreturn(env, 0); 187 qemu_log_mask(LOG_UNIMP, "do_rt_sigreturn: not implemented\n"); 188 return -TARGET_ENOSYS; 189 } 190