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 "target_signal.h" 22 #include "signal-common.h" 23 #include "linux-user/trace.h" 24 25 #define __NUM_GPRS 16 26 #define __NUM_FPRS 16 27 #define __NUM_ACRS 16 28 29 #define S390_SYSCALL_SIZE 2 30 #define __SIGNAL_FRAMESIZE 160 /* FIXME: 31-bit mode -> 96 */ 31 32 #define _SIGCONTEXT_NSIG 64 33 #define _SIGCONTEXT_NSIG_BPW 64 /* FIXME: 31-bit mode -> 32 */ 34 #define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW) 35 #define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS) 36 #define PSW_ADDR_AMODE 0x0000000000000000UL /* 0x80000000UL for 31-bit */ 37 #define S390_SYSCALL_OPCODE ((uint16_t)0x0a00) 38 39 typedef struct { 40 target_psw_t psw; 41 target_ulong gprs[__NUM_GPRS]; 42 unsigned int acrs[__NUM_ACRS]; 43 } target_s390_regs_common; 44 45 typedef struct { 46 unsigned int fpc; 47 double fprs[__NUM_FPRS]; 48 } target_s390_fp_regs; 49 50 typedef struct { 51 target_s390_regs_common regs; 52 target_s390_fp_regs fpregs; 53 } target_sigregs; 54 55 struct target_sigcontext { 56 target_ulong oldmask[_SIGCONTEXT_NSIG_WORDS]; 57 target_sigregs *sregs; 58 }; 59 60 typedef struct { 61 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE]; 62 struct target_sigcontext sc; 63 target_sigregs sregs; 64 int signo; 65 uint8_t retcode[S390_SYSCALL_SIZE]; 66 } sigframe; 67 68 struct target_ucontext { 69 target_ulong tuc_flags; 70 struct target_ucontext *tuc_link; 71 target_stack_t tuc_stack; 72 target_sigregs tuc_mcontext; 73 target_sigset_t tuc_sigmask; /* mask last for extensibility */ 74 }; 75 76 typedef struct { 77 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE]; 78 uint8_t retcode[S390_SYSCALL_SIZE]; 79 struct target_siginfo info; 80 struct target_ucontext uc; 81 } rt_sigframe; 82 83 static inline abi_ulong 84 get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size) 85 { 86 abi_ulong sp; 87 88 /* Default to using normal stack */ 89 sp = get_sp_from_cpustate(env); 90 91 /* This is the X/Open sanctioned signal stack switching. */ 92 if (ka->sa_flags & TARGET_SA_ONSTACK) { 93 sp = target_sigsp(sp, ka); 94 } 95 96 /* This is the legacy signal stack switching. */ 97 else if (/* FIXME !user_mode(regs) */ 0 && 98 !(ka->sa_flags & TARGET_SA_RESTORER) && 99 ka->sa_restorer) { 100 sp = (abi_ulong) ka->sa_restorer; 101 } 102 103 return (sp - frame_size) & -8ul; 104 } 105 106 static void save_sigregs(CPUS390XState *env, target_sigregs *sregs) 107 { 108 int i; 109 //save_access_regs(current->thread.acrs); FIXME 110 111 /* Copy a 'clean' PSW mask to the user to avoid leaking 112 information about whether PER is currently on. */ 113 __put_user(env->psw.mask, &sregs->regs.psw.mask); 114 __put_user(env->psw.addr, &sregs->regs.psw.addr); 115 for (i = 0; i < 16; i++) { 116 __put_user(env->regs[i], &sregs->regs.gprs[i]); 117 } 118 for (i = 0; i < 16; i++) { 119 __put_user(env->aregs[i], &sregs->regs.acrs[i]); 120 } 121 /* 122 * We have to store the fp registers to current->thread.fp_regs 123 * to merge them with the emulated registers. 124 */ 125 //save_fp_regs(¤t->thread.fp_regs); FIXME 126 for (i = 0; i < 16; i++) { 127 __put_user(get_freg(env, i)->ll, &sregs->fpregs.fprs[i]); 128 } 129 } 130 131 void setup_frame(int sig, struct target_sigaction *ka, 132 target_sigset_t *set, CPUS390XState *env) 133 { 134 sigframe *frame; 135 abi_ulong frame_addr; 136 137 frame_addr = get_sigframe(ka, env, sizeof(*frame)); 138 trace_user_setup_frame(env, frame_addr); 139 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { 140 goto give_sigsegv; 141 } 142 143 __put_user(set->sig[0], &frame->sc.oldmask[0]); 144 145 save_sigregs(env, &frame->sregs); 146 147 __put_user((abi_ulong)(unsigned long)&frame->sregs, 148 (abi_ulong *)&frame->sc.sregs); 149 150 /* Set up to return from userspace. If provided, use a stub 151 already in userspace. */ 152 if (ka->sa_flags & TARGET_SA_RESTORER) { 153 env->regs[14] = (unsigned long) 154 ka->sa_restorer | PSW_ADDR_AMODE; 155 } else { 156 env->regs[14] = (frame_addr + offsetof(sigframe, retcode)) 157 | PSW_ADDR_AMODE; 158 __put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn, 159 (uint16_t *)(frame->retcode)); 160 } 161 162 /* Set up backchain. */ 163 __put_user(env->regs[15], (abi_ulong *) frame); 164 165 /* Set up registers for signal handler */ 166 env->regs[15] = frame_addr; 167 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE; 168 169 env->regs[2] = sig; //map_signal(sig); 170 env->regs[3] = frame_addr += offsetof(typeof(*frame), sc); 171 172 /* We forgot to include these in the sigcontext. 173 To avoid breaking binary compatibility, they are passed as args. */ 174 env->regs[4] = 0; // FIXME: no clue... current->thread.trap_no; 175 env->regs[5] = 0; // FIXME: no clue... current->thread.prot_addr; 176 177 /* Place signal number on stack to allow backtrace from handler. */ 178 __put_user(env->regs[2], &frame->signo); 179 unlock_user_struct(frame, frame_addr, 1); 180 return; 181 182 give_sigsegv: 183 force_sigsegv(sig); 184 } 185 186 void setup_rt_frame(int sig, struct target_sigaction *ka, 187 target_siginfo_t *info, 188 target_sigset_t *set, CPUS390XState *env) 189 { 190 int i; 191 rt_sigframe *frame; 192 abi_ulong frame_addr; 193 194 frame_addr = get_sigframe(ka, env, sizeof *frame); 195 trace_user_setup_rt_frame(env, frame_addr); 196 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { 197 goto give_sigsegv; 198 } 199 200 tswap_siginfo(&frame->info, info); 201 202 /* Create the ucontext. */ 203 __put_user(0, &frame->uc.tuc_flags); 204 __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link); 205 target_save_altstack(&frame->uc.tuc_stack, env); 206 save_sigregs(env, &frame->uc.tuc_mcontext); 207 for (i = 0; i < TARGET_NSIG_WORDS; i++) { 208 __put_user((abi_ulong)set->sig[i], 209 (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]); 210 } 211 212 /* Set up to return from userspace. If provided, use a stub 213 already in userspace. */ 214 if (ka->sa_flags & TARGET_SA_RESTORER) { 215 env->regs[14] = (unsigned long) ka->sa_restorer | PSW_ADDR_AMODE; 216 } else { 217 env->regs[14] = (unsigned long) frame->retcode | 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)->ll, &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