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 #define __NUM_GPRS 16 25 #define __NUM_FPRS 16 26 #define __NUM_ACRS 16 27 28 #define __SIGNAL_FRAMESIZE 160 /* FIXME: 31-bit mode -> 96 */ 29 30 #define _SIGCONTEXT_NSIG 64 31 #define _SIGCONTEXT_NSIG_BPW 64 /* FIXME: 31-bit mode -> 32 */ 32 #define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW) 33 #define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS) 34 #define S390_SYSCALL_OPCODE ((uint16_t)0x0a00) 35 36 typedef struct { 37 target_psw_t psw; 38 abi_ulong gprs[__NUM_GPRS]; 39 abi_uint acrs[__NUM_ACRS]; 40 } target_s390_regs_common; 41 42 typedef struct { 43 uint32_t fpc; 44 uint32_t pad; 45 uint64_t fprs[__NUM_FPRS]; 46 } target_s390_fp_regs; 47 48 typedef struct { 49 target_s390_regs_common regs; 50 target_s390_fp_regs fpregs; 51 } target_sigregs; 52 53 typedef struct { 54 abi_ulong oldmask[_SIGCONTEXT_NSIG_WORDS]; 55 abi_ulong sregs; 56 } target_sigcontext; 57 58 typedef struct { 59 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE]; 60 target_sigcontext sc; 61 target_sigregs sregs; 62 int signo; 63 uint16_t retcode; 64 } sigframe; 65 66 struct target_ucontext { 67 abi_ulong tuc_flags; 68 abi_ulong tuc_link; 69 target_stack_t tuc_stack; 70 target_sigregs tuc_mcontext; 71 target_sigset_t tuc_sigmask; /* mask last for extensibility */ 72 }; 73 74 typedef struct { 75 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE]; 76 uint16_t retcode; 77 struct target_siginfo info; 78 struct target_ucontext uc; 79 } rt_sigframe; 80 81 static inline abi_ulong 82 get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size) 83 { 84 abi_ulong sp; 85 86 /* Default to using normal stack */ 87 sp = get_sp_from_cpustate(env); 88 89 /* This is the X/Open sanctioned signal stack switching. */ 90 if (ka->sa_flags & TARGET_SA_ONSTACK) { 91 sp = target_sigsp(sp, ka); 92 } 93 94 /* This is the legacy signal stack switching. */ 95 else if (/* FIXME !user_mode(regs) */ 0 && 96 !(ka->sa_flags & TARGET_SA_RESTORER) && 97 ka->sa_restorer) { 98 sp = (abi_ulong) ka->sa_restorer; 99 } 100 101 return (sp - frame_size) & -8ul; 102 } 103 104 static void save_sigregs(CPUS390XState *env, target_sigregs *sregs) 105 { 106 int i; 107 //save_access_regs(current->thread.acrs); FIXME 108 109 /* Copy a 'clean' PSW mask to the user to avoid leaking 110 information about whether PER is currently on. */ 111 __put_user(env->psw.mask, &sregs->regs.psw.mask); 112 __put_user(env->psw.addr, &sregs->regs.psw.addr); 113 for (i = 0; i < 16; i++) { 114 __put_user(env->regs[i], &sregs->regs.gprs[i]); 115 } 116 for (i = 0; i < 16; i++) { 117 __put_user(env->aregs[i], &sregs->regs.acrs[i]); 118 } 119 /* 120 * We have to store the fp registers to current->thread.fp_regs 121 * to merge them with the emulated registers. 122 */ 123 //save_fp_regs(¤t->thread.fp_regs); FIXME 124 for (i = 0; i < 16; i++) { 125 __put_user(*get_freg(env, i), &sregs->fpregs.fprs[i]); 126 } 127 } 128 129 void setup_frame(int sig, struct target_sigaction *ka, 130 target_sigset_t *set, CPUS390XState *env) 131 { 132 sigframe *frame; 133 abi_ulong frame_addr; 134 135 frame_addr = get_sigframe(ka, env, sizeof(*frame)); 136 trace_user_setup_frame(env, frame_addr); 137 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { 138 goto give_sigsegv; 139 } 140 141 __put_user(set->sig[0], &frame->sc.oldmask[0]); 142 143 save_sigregs(env, &frame->sregs); 144 145 __put_user((abi_ulong)(unsigned long)&frame->sregs, &frame->sc.sregs); 146 147 /* Set up to return from userspace. If provided, use a stub 148 already in userspace. */ 149 if (ka->sa_flags & TARGET_SA_RESTORER) { 150 env->regs[14] = ka->sa_restorer; 151 } else { 152 env->regs[14] = frame_addr + offsetof(sigframe, retcode); 153 __put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn, 154 &frame->retcode); 155 } 156 157 /* Set up backchain. */ 158 __put_user(env->regs[15], (abi_ulong *) frame); 159 160 /* Set up registers for signal handler */ 161 env->regs[15] = frame_addr; 162 env->psw.addr = ka->_sa_handler; 163 164 env->regs[2] = sig; //map_signal(sig); 165 env->regs[3] = frame_addr += offsetof(typeof(*frame), sc); 166 167 /* We forgot to include these in the sigcontext. 168 To avoid breaking binary compatibility, they are passed as args. */ 169 env->regs[4] = 0; // FIXME: no clue... current->thread.trap_no; 170 env->regs[5] = 0; // FIXME: no clue... current->thread.prot_addr; 171 172 /* Place signal number on stack to allow backtrace from handler. */ 173 __put_user(env->regs[2], &frame->signo); 174 unlock_user_struct(frame, frame_addr, 1); 175 return; 176 177 give_sigsegv: 178 force_sigsegv(sig); 179 } 180 181 void setup_rt_frame(int sig, struct target_sigaction *ka, 182 target_siginfo_t *info, 183 target_sigset_t *set, CPUS390XState *env) 184 { 185 int i; 186 rt_sigframe *frame; 187 abi_ulong frame_addr; 188 189 frame_addr = get_sigframe(ka, env, sizeof *frame); 190 trace_user_setup_rt_frame(env, frame_addr); 191 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { 192 goto give_sigsegv; 193 } 194 195 tswap_siginfo(&frame->info, info); 196 197 /* Create the ucontext. */ 198 __put_user(0, &frame->uc.tuc_flags); 199 __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link); 200 target_save_altstack(&frame->uc.tuc_stack, env); 201 save_sigregs(env, &frame->uc.tuc_mcontext); 202 for (i = 0; i < TARGET_NSIG_WORDS; i++) { 203 __put_user((abi_ulong)set->sig[i], 204 (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]); 205 } 206 207 /* Set up to return from userspace. If provided, use a stub 208 already in userspace. */ 209 if (ka->sa_flags & TARGET_SA_RESTORER) { 210 env->regs[14] = ka->sa_restorer; 211 } else { 212 env->regs[14] = frame_addr + offsetof(typeof(*frame), retcode); 213 __put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn, 214 &frame->retcode); 215 } 216 217 /* Set up backchain. */ 218 __put_user(env->regs[15], (abi_ulong *) frame); 219 220 /* Set up registers for signal handler */ 221 env->regs[15] = frame_addr; 222 env->psw.addr = ka->_sa_handler; 223 224 env->regs[2] = sig; //map_signal(sig); 225 env->regs[3] = frame_addr + offsetof(typeof(*frame), info); 226 env->regs[4] = frame_addr + offsetof(typeof(*frame), uc); 227 return; 228 229 give_sigsegv: 230 force_sigsegv(sig); 231 } 232 233 static void restore_sigregs(CPUS390XState *env, target_sigregs *sc) 234 { 235 target_ulong prev_addr; 236 int i; 237 238 for (i = 0; i < 16; i++) { 239 __get_user(env->regs[i], &sc->regs.gprs[i]); 240 } 241 242 prev_addr = env->psw.addr; 243 __get_user(env->psw.mask, &sc->regs.psw.mask); 244 __get_user(env->psw.addr, &sc->regs.psw.addr); 245 trace_user_s390x_restore_sigregs(env, env->psw.addr, prev_addr); 246 247 for (i = 0; i < 16; i++) { 248 __get_user(env->aregs[i], &sc->regs.acrs[i]); 249 } 250 for (i = 0; i < 16; i++) { 251 __get_user(*get_freg(env, i), &sc->fpregs.fprs[i]); 252 } 253 } 254 255 long do_sigreturn(CPUS390XState *env) 256 { 257 sigframe *frame; 258 abi_ulong frame_addr = env->regs[15]; 259 target_sigset_t target_set; 260 sigset_t set; 261 262 trace_user_do_sigreturn(env, frame_addr); 263 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { 264 goto badframe; 265 } 266 __get_user(target_set.sig[0], &frame->sc.oldmask[0]); 267 268 target_to_host_sigset_internal(&set, &target_set); 269 set_sigmask(&set); /* ~_BLOCKABLE? */ 270 271 restore_sigregs(env, &frame->sregs); 272 273 unlock_user_struct(frame, frame_addr, 0); 274 return -TARGET_QEMU_ESIGRETURN; 275 276 badframe: 277 force_sig(TARGET_SIGSEGV); 278 return -TARGET_QEMU_ESIGRETURN; 279 } 280 281 long do_rt_sigreturn(CPUS390XState *env) 282 { 283 rt_sigframe *frame; 284 abi_ulong frame_addr = env->regs[15]; 285 sigset_t set; 286 287 trace_user_do_rt_sigreturn(env, frame_addr); 288 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { 289 goto badframe; 290 } 291 target_to_host_sigset(&set, &frame->uc.tuc_sigmask); 292 293 set_sigmask(&set); /* ~_BLOCKABLE? */ 294 295 restore_sigregs(env, &frame->uc.tuc_mcontext); 296 297 target_restore_altstack(&frame->uc.tuc_stack, env); 298 299 unlock_user_struct(frame, frame_addr, 0); 300 return -TARGET_QEMU_ESIGRETURN; 301 302 badframe: 303 unlock_user_struct(frame, frame_addr, 0); 304 force_sig(TARGET_SIGSEGV); 305 return -TARGET_QEMU_ESIGRETURN; 306 } 307