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