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