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 static void setup_sigcontext(struct target_sigcontext *sc, CPUCRISState *env) 39 { 40 __put_user(env->regs[0], &sc->regs.r0); 41 __put_user(env->regs[1], &sc->regs.r1); 42 __put_user(env->regs[2], &sc->regs.r2); 43 __put_user(env->regs[3], &sc->regs.r3); 44 __put_user(env->regs[4], &sc->regs.r4); 45 __put_user(env->regs[5], &sc->regs.r5); 46 __put_user(env->regs[6], &sc->regs.r6); 47 __put_user(env->regs[7], &sc->regs.r7); 48 __put_user(env->regs[8], &sc->regs.r8); 49 __put_user(env->regs[9], &sc->regs.r9); 50 __put_user(env->regs[10], &sc->regs.r10); 51 __put_user(env->regs[11], &sc->regs.r11); 52 __put_user(env->regs[12], &sc->regs.r12); 53 __put_user(env->regs[13], &sc->regs.r13); 54 __put_user(env->regs[14], &sc->usp); 55 __put_user(env->regs[15], &sc->regs.acr); 56 __put_user(env->pregs[PR_MOF], &sc->regs.mof); 57 __put_user(env->pregs[PR_SRP], &sc->regs.srp); 58 __put_user(env->pc, &sc->regs.erp); 59 } 60 61 static void restore_sigcontext(struct target_sigcontext *sc, CPUCRISState *env) 62 { 63 __get_user(env->regs[0], &sc->regs.r0); 64 __get_user(env->regs[1], &sc->regs.r1); 65 __get_user(env->regs[2], &sc->regs.r2); 66 __get_user(env->regs[3], &sc->regs.r3); 67 __get_user(env->regs[4], &sc->regs.r4); 68 __get_user(env->regs[5], &sc->regs.r5); 69 __get_user(env->regs[6], &sc->regs.r6); 70 __get_user(env->regs[7], &sc->regs.r7); 71 __get_user(env->regs[8], &sc->regs.r8); 72 __get_user(env->regs[9], &sc->regs.r9); 73 __get_user(env->regs[10], &sc->regs.r10); 74 __get_user(env->regs[11], &sc->regs.r11); 75 __get_user(env->regs[12], &sc->regs.r12); 76 __get_user(env->regs[13], &sc->regs.r13); 77 __get_user(env->regs[14], &sc->usp); 78 __get_user(env->regs[15], &sc->regs.acr); 79 __get_user(env->pregs[PR_MOF], &sc->regs.mof); 80 __get_user(env->pregs[PR_SRP], &sc->regs.srp); 81 __get_user(env->pc, &sc->regs.erp); 82 } 83 84 static abi_ulong get_sigframe(CPUCRISState *env, int framesize) 85 { 86 abi_ulong sp; 87 /* Align the stack downwards to 4. */ 88 sp = (env->regs[R_SP] & ~3); 89 return sp - framesize; 90 } 91 92 static void setup_sigreturn(uint16_t *retcode) 93 { 94 /* This is movu.w __NR_sigreturn, r9; break 13; */ 95 __put_user(0x9c5f, retcode + 0); 96 __put_user(TARGET_NR_sigreturn, retcode + 1); 97 __put_user(0xe93d, retcode + 2); 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 */ 116 setup_sigreturn(frame->retcode); 117 118 /* Save the mask. */ 119 __put_user(set->sig[0], &frame->sc.oldmask); 120 121 for(i = 1; i < TARGET_NSIG_WORDS; i++) { 122 __put_user(set->sig[i], &frame->extramask[i - 1]); 123 } 124 125 setup_sigcontext(&frame->sc, env); 126 127 /* Move the stack and setup the arguments for the handler. */ 128 env->regs[R_SP] = frame_addr; 129 env->regs[10] = sig; 130 env->pc = (unsigned long) ka->_sa_handler; 131 /* Link SRP so the guest returns through the trampoline. */ 132 env->pregs[PR_SRP] = default_sigreturn; 133 134 unlock_user_struct(frame, frame_addr, 1); 135 return; 136 badframe: 137 force_sigsegv(sig); 138 } 139 140 void setup_rt_frame(int sig, struct target_sigaction *ka, 141 target_siginfo_t *info, 142 target_sigset_t *set, CPUCRISState *env) 143 { 144 qemu_log_mask(LOG_UNIMP, "setup_rt_frame: not implemented\n"); 145 } 146 147 long do_sigreturn(CPUCRISState *env) 148 { 149 struct target_signal_frame *frame; 150 abi_ulong frame_addr; 151 target_sigset_t target_set; 152 sigset_t set; 153 int i; 154 155 frame_addr = env->regs[R_SP]; 156 trace_user_do_sigreturn(env, frame_addr); 157 /* Make sure the guest isn't playing games. */ 158 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1)) { 159 goto badframe; 160 } 161 162 /* Restore blocked signals */ 163 __get_user(target_set.sig[0], &frame->sc.oldmask); 164 for(i = 1; i < TARGET_NSIG_WORDS; i++) { 165 __get_user(target_set.sig[i], &frame->extramask[i - 1]); 166 } 167 target_to_host_sigset_internal(&set, &target_set); 168 set_sigmask(&set); 169 170 restore_sigcontext(&frame->sc, env); 171 unlock_user_struct(frame, frame_addr, 0); 172 return -QEMU_ESIGRETURN; 173 badframe: 174 force_sig(TARGET_SIGSEGV); 175 return -QEMU_ESIGRETURN; 176 } 177 178 long do_rt_sigreturn(CPUCRISState *env) 179 { 180 trace_user_do_rt_sigreturn(env, 0); 181 qemu_log_mask(LOG_UNIMP, "do_rt_sigreturn: not implemented\n"); 182 return -TARGET_ENOSYS; 183 } 184 185 void setup_sigtramp(abi_ulong sigtramp_page) 186 { 187 uint16_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 6, 0); 188 assert(tramp != NULL); 189 190 default_sigreturn = sigtramp_page; 191 setup_sigreturn(tramp); 192 193 unlock_user(tramp, sigtramp_page, 6); 194 } 195