162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright IBM Corp. 1999, 2006 462306a36Sopenharmony_ci * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Based on Intel version 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Copyright (C) 1991, 1992 Linus Torvalds 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/sched.h> 1462306a36Sopenharmony_ci#include <linux/sched/task_stack.h> 1562306a36Sopenharmony_ci#include <linux/mm.h> 1662306a36Sopenharmony_ci#include <linux/smp.h> 1762306a36Sopenharmony_ci#include <linux/kernel.h> 1862306a36Sopenharmony_ci#include <linux/signal.h> 1962306a36Sopenharmony_ci#include <linux/entry-common.h> 2062306a36Sopenharmony_ci#include <linux/errno.h> 2162306a36Sopenharmony_ci#include <linux/wait.h> 2262306a36Sopenharmony_ci#include <linux/ptrace.h> 2362306a36Sopenharmony_ci#include <linux/unistd.h> 2462306a36Sopenharmony_ci#include <linux/stddef.h> 2562306a36Sopenharmony_ci#include <linux/tty.h> 2662306a36Sopenharmony_ci#include <linux/personality.h> 2762306a36Sopenharmony_ci#include <linux/binfmts.h> 2862306a36Sopenharmony_ci#include <linux/syscalls.h> 2962306a36Sopenharmony_ci#include <linux/compat.h> 3062306a36Sopenharmony_ci#include <asm/ucontext.h> 3162306a36Sopenharmony_ci#include <linux/uaccess.h> 3262306a36Sopenharmony_ci#include <asm/lowcore.h> 3362306a36Sopenharmony_ci#include <asm/switch_to.h> 3462306a36Sopenharmony_ci#include <asm/vdso.h> 3562306a36Sopenharmony_ci#include "entry.h" 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* 3862306a36Sopenharmony_ci * Layout of an old-style signal-frame: 3962306a36Sopenharmony_ci * ----------------------------------------- 4062306a36Sopenharmony_ci * | save area (_SIGNAL_FRAMESIZE) | 4162306a36Sopenharmony_ci * ----------------------------------------- 4262306a36Sopenharmony_ci * | struct sigcontext | 4362306a36Sopenharmony_ci * | oldmask | 4462306a36Sopenharmony_ci * | _sigregs * | 4562306a36Sopenharmony_ci * ----------------------------------------- 4662306a36Sopenharmony_ci * | _sigregs with | 4762306a36Sopenharmony_ci * | _s390_regs_common | 4862306a36Sopenharmony_ci * | _s390_fp_regs | 4962306a36Sopenharmony_ci * ----------------------------------------- 5062306a36Sopenharmony_ci * | int signo | 5162306a36Sopenharmony_ci * ----------------------------------------- 5262306a36Sopenharmony_ci * | _sigregs_ext with | 5362306a36Sopenharmony_ci * | gprs_high 64 byte (opt) | 5462306a36Sopenharmony_ci * | vxrs_low 128 byte (opt) | 5562306a36Sopenharmony_ci * | vxrs_high 256 byte (opt) | 5662306a36Sopenharmony_ci * | reserved 128 byte (opt) | 5762306a36Sopenharmony_ci * ----------------------------------------- 5862306a36Sopenharmony_ci * | __u16 svc_insn | 5962306a36Sopenharmony_ci * ----------------------------------------- 6062306a36Sopenharmony_ci * The svc_insn entry with the sigreturn system call opcode does not 6162306a36Sopenharmony_ci * have a fixed position and moves if gprs_high or vxrs exist. 6262306a36Sopenharmony_ci * Future extensions will be added to _sigregs_ext. 6362306a36Sopenharmony_ci */ 6462306a36Sopenharmony_cistruct sigframe 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci __u8 callee_used_stack[__SIGNAL_FRAMESIZE]; 6762306a36Sopenharmony_ci struct sigcontext sc; 6862306a36Sopenharmony_ci _sigregs sregs; 6962306a36Sopenharmony_ci int signo; 7062306a36Sopenharmony_ci _sigregs_ext sregs_ext; 7162306a36Sopenharmony_ci __u16 svc_insn; /* Offset of svc_insn is NOT fixed! */ 7262306a36Sopenharmony_ci}; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/* 7562306a36Sopenharmony_ci * Layout of an rt signal-frame: 7662306a36Sopenharmony_ci * ----------------------------------------- 7762306a36Sopenharmony_ci * | save area (_SIGNAL_FRAMESIZE) | 7862306a36Sopenharmony_ci * ----------------------------------------- 7962306a36Sopenharmony_ci * | svc __NR_rt_sigreturn 2 byte | 8062306a36Sopenharmony_ci * ----------------------------------------- 8162306a36Sopenharmony_ci * | struct siginfo | 8262306a36Sopenharmony_ci * ----------------------------------------- 8362306a36Sopenharmony_ci * | struct ucontext_extended with | 8462306a36Sopenharmony_ci * | unsigned long uc_flags | 8562306a36Sopenharmony_ci * | struct ucontext *uc_link | 8662306a36Sopenharmony_ci * | stack_t uc_stack | 8762306a36Sopenharmony_ci * | _sigregs uc_mcontext with | 8862306a36Sopenharmony_ci * | _s390_regs_common | 8962306a36Sopenharmony_ci * | _s390_fp_regs | 9062306a36Sopenharmony_ci * | sigset_t uc_sigmask | 9162306a36Sopenharmony_ci * | _sigregs_ext uc_mcontext_ext | 9262306a36Sopenharmony_ci * | gprs_high 64 byte (opt) | 9362306a36Sopenharmony_ci * | vxrs_low 128 byte (opt) | 9462306a36Sopenharmony_ci * | vxrs_high 256 byte (opt)| 9562306a36Sopenharmony_ci * | reserved 128 byte (opt) | 9662306a36Sopenharmony_ci * ----------------------------------------- 9762306a36Sopenharmony_ci * Future extensions will be added to _sigregs_ext. 9862306a36Sopenharmony_ci */ 9962306a36Sopenharmony_cistruct rt_sigframe 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci __u8 callee_used_stack[__SIGNAL_FRAMESIZE]; 10262306a36Sopenharmony_ci __u16 svc_insn; 10362306a36Sopenharmony_ci struct siginfo info; 10462306a36Sopenharmony_ci struct ucontext_extended uc; 10562306a36Sopenharmony_ci}; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci/* Store registers needed to create the signal frame */ 10862306a36Sopenharmony_cistatic void store_sigregs(void) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci save_access_regs(current->thread.acrs); 11162306a36Sopenharmony_ci save_fpu_regs(); 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci/* Load registers after signal return */ 11562306a36Sopenharmony_cistatic void load_sigregs(void) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci restore_access_regs(current->thread.acrs); 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci/* Returns non-zero on fault. */ 12162306a36Sopenharmony_cistatic int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci _sigregs user_sregs; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci /* Copy a 'clean' PSW mask to the user to avoid leaking 12662306a36Sopenharmony_ci information about whether PER is currently on. */ 12762306a36Sopenharmony_ci user_sregs.regs.psw.mask = PSW_USER_BITS | 12862306a36Sopenharmony_ci (regs->psw.mask & (PSW_MASK_USER | PSW_MASK_RI)); 12962306a36Sopenharmony_ci user_sregs.regs.psw.addr = regs->psw.addr; 13062306a36Sopenharmony_ci memcpy(&user_sregs.regs.gprs, ®s->gprs, sizeof(sregs->regs.gprs)); 13162306a36Sopenharmony_ci memcpy(&user_sregs.regs.acrs, current->thread.acrs, 13262306a36Sopenharmony_ci sizeof(user_sregs.regs.acrs)); 13362306a36Sopenharmony_ci fpregs_store(&user_sregs.fpregs, ¤t->thread.fpu); 13462306a36Sopenharmony_ci if (__copy_to_user(sregs, &user_sregs, sizeof(_sigregs))) 13562306a36Sopenharmony_ci return -EFAULT; 13662306a36Sopenharmony_ci return 0; 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci _sigregs user_sregs; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci /* Always make any pending restarted system call return -EINTR */ 14462306a36Sopenharmony_ci current->restart_block.fn = do_no_restart_syscall; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if (__copy_from_user(&user_sregs, sregs, sizeof(user_sregs))) 14762306a36Sopenharmony_ci return -EFAULT; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci if (!is_ri_task(current) && (user_sregs.regs.psw.mask & PSW_MASK_RI)) 15062306a36Sopenharmony_ci return -EINVAL; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci /* Test the floating-point-control word. */ 15362306a36Sopenharmony_ci if (test_fp_ctl(user_sregs.fpregs.fpc)) 15462306a36Sopenharmony_ci return -EINVAL; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci /* Use regs->psw.mask instead of PSW_USER_BITS to preserve PER bit. */ 15762306a36Sopenharmony_ci regs->psw.mask = (regs->psw.mask & ~(PSW_MASK_USER | PSW_MASK_RI)) | 15862306a36Sopenharmony_ci (user_sregs.regs.psw.mask & (PSW_MASK_USER | PSW_MASK_RI)); 15962306a36Sopenharmony_ci /* Check for invalid user address space control. */ 16062306a36Sopenharmony_ci if ((regs->psw.mask & PSW_MASK_ASC) == PSW_ASC_HOME) 16162306a36Sopenharmony_ci regs->psw.mask = PSW_ASC_PRIMARY | 16262306a36Sopenharmony_ci (regs->psw.mask & ~PSW_MASK_ASC); 16362306a36Sopenharmony_ci /* Check for invalid amode */ 16462306a36Sopenharmony_ci if (regs->psw.mask & PSW_MASK_EA) 16562306a36Sopenharmony_ci regs->psw.mask |= PSW_MASK_BA; 16662306a36Sopenharmony_ci regs->psw.addr = user_sregs.regs.psw.addr; 16762306a36Sopenharmony_ci memcpy(®s->gprs, &user_sregs.regs.gprs, sizeof(sregs->regs.gprs)); 16862306a36Sopenharmony_ci memcpy(¤t->thread.acrs, &user_sregs.regs.acrs, 16962306a36Sopenharmony_ci sizeof(current->thread.acrs)); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci fpregs_load(&user_sregs.fpregs, ¤t->thread.fpu); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci clear_pt_regs_flag(regs, PIF_SYSCALL); /* No longer in a system call */ 17462306a36Sopenharmony_ci return 0; 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci/* Returns non-zero on fault. */ 17862306a36Sopenharmony_cistatic int save_sigregs_ext(struct pt_regs *regs, 17962306a36Sopenharmony_ci _sigregs_ext __user *sregs_ext) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci __u64 vxrs[__NUM_VXRS_LOW]; 18262306a36Sopenharmony_ci int i; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci /* Save vector registers to signal stack */ 18562306a36Sopenharmony_ci if (MACHINE_HAS_VX) { 18662306a36Sopenharmony_ci for (i = 0; i < __NUM_VXRS_LOW; i++) 18762306a36Sopenharmony_ci vxrs[i] = current->thread.fpu.vxrs[i].low; 18862306a36Sopenharmony_ci if (__copy_to_user(&sregs_ext->vxrs_low, vxrs, 18962306a36Sopenharmony_ci sizeof(sregs_ext->vxrs_low)) || 19062306a36Sopenharmony_ci __copy_to_user(&sregs_ext->vxrs_high, 19162306a36Sopenharmony_ci current->thread.fpu.vxrs + __NUM_VXRS_LOW, 19262306a36Sopenharmony_ci sizeof(sregs_ext->vxrs_high))) 19362306a36Sopenharmony_ci return -EFAULT; 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci return 0; 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic int restore_sigregs_ext(struct pt_regs *regs, 19962306a36Sopenharmony_ci _sigregs_ext __user *sregs_ext) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci __u64 vxrs[__NUM_VXRS_LOW]; 20262306a36Sopenharmony_ci int i; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci /* Restore vector registers from signal stack */ 20562306a36Sopenharmony_ci if (MACHINE_HAS_VX) { 20662306a36Sopenharmony_ci if (__copy_from_user(vxrs, &sregs_ext->vxrs_low, 20762306a36Sopenharmony_ci sizeof(sregs_ext->vxrs_low)) || 20862306a36Sopenharmony_ci __copy_from_user(current->thread.fpu.vxrs + __NUM_VXRS_LOW, 20962306a36Sopenharmony_ci &sregs_ext->vxrs_high, 21062306a36Sopenharmony_ci sizeof(sregs_ext->vxrs_high))) 21162306a36Sopenharmony_ci return -EFAULT; 21262306a36Sopenharmony_ci for (i = 0; i < __NUM_VXRS_LOW; i++) 21362306a36Sopenharmony_ci current->thread.fpu.vxrs[i].low = vxrs[i]; 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci return 0; 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ciSYSCALL_DEFINE0(sigreturn) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci struct pt_regs *regs = task_pt_regs(current); 22162306a36Sopenharmony_ci struct sigframe __user *frame = 22262306a36Sopenharmony_ci (struct sigframe __user *) regs->gprs[15]; 22362306a36Sopenharmony_ci sigset_t set; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE)) 22662306a36Sopenharmony_ci goto badframe; 22762306a36Sopenharmony_ci set_current_blocked(&set); 22862306a36Sopenharmony_ci save_fpu_regs(); 22962306a36Sopenharmony_ci if (restore_sigregs(regs, &frame->sregs)) 23062306a36Sopenharmony_ci goto badframe; 23162306a36Sopenharmony_ci if (restore_sigregs_ext(regs, &frame->sregs_ext)) 23262306a36Sopenharmony_ci goto badframe; 23362306a36Sopenharmony_ci load_sigregs(); 23462306a36Sopenharmony_ci return regs->gprs[2]; 23562306a36Sopenharmony_cibadframe: 23662306a36Sopenharmony_ci force_sig(SIGSEGV); 23762306a36Sopenharmony_ci return 0; 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ciSYSCALL_DEFINE0(rt_sigreturn) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci struct pt_regs *regs = task_pt_regs(current); 24362306a36Sopenharmony_ci struct rt_sigframe __user *frame = 24462306a36Sopenharmony_ci (struct rt_sigframe __user *)regs->gprs[15]; 24562306a36Sopenharmony_ci sigset_t set; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci if (__copy_from_user(&set.sig, &frame->uc.uc_sigmask, sizeof(set))) 24862306a36Sopenharmony_ci goto badframe; 24962306a36Sopenharmony_ci set_current_blocked(&set); 25062306a36Sopenharmony_ci if (restore_altstack(&frame->uc.uc_stack)) 25162306a36Sopenharmony_ci goto badframe; 25262306a36Sopenharmony_ci save_fpu_regs(); 25362306a36Sopenharmony_ci if (restore_sigregs(regs, &frame->uc.uc_mcontext)) 25462306a36Sopenharmony_ci goto badframe; 25562306a36Sopenharmony_ci if (restore_sigregs_ext(regs, &frame->uc.uc_mcontext_ext)) 25662306a36Sopenharmony_ci goto badframe; 25762306a36Sopenharmony_ci load_sigregs(); 25862306a36Sopenharmony_ci return regs->gprs[2]; 25962306a36Sopenharmony_cibadframe: 26062306a36Sopenharmony_ci force_sig(SIGSEGV); 26162306a36Sopenharmony_ci return 0; 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci/* 26562306a36Sopenharmony_ci * Determine which stack to use.. 26662306a36Sopenharmony_ci */ 26762306a36Sopenharmony_cistatic inline void __user * 26862306a36Sopenharmony_ciget_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci unsigned long sp; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* Default to using normal stack */ 27362306a36Sopenharmony_ci sp = regs->gprs[15]; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci /* Overflow on alternate signal stack gives SIGSEGV. */ 27662306a36Sopenharmony_ci if (on_sig_stack(sp) && !on_sig_stack((sp - frame_size) & -8UL)) 27762306a36Sopenharmony_ci return (void __user *) -1UL; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci /* This is the X/Open sanctioned signal stack switching. */ 28062306a36Sopenharmony_ci if (ka->sa.sa_flags & SA_ONSTACK) { 28162306a36Sopenharmony_ci if (! sas_ss_flags(sp)) 28262306a36Sopenharmony_ci sp = current->sas_ss_sp + current->sas_ss_size; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci return (void __user *)((sp - frame_size) & -8ul); 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic int setup_frame(int sig, struct k_sigaction *ka, 28962306a36Sopenharmony_ci sigset_t *set, struct pt_regs * regs) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci struct sigframe __user *frame; 29262306a36Sopenharmony_ci struct sigcontext sc; 29362306a36Sopenharmony_ci unsigned long restorer; 29462306a36Sopenharmony_ci size_t frame_size; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci /* 29762306a36Sopenharmony_ci * gprs_high are only present for a 31-bit task running on 29862306a36Sopenharmony_ci * a 64-bit kernel (see compat_signal.c) but the space for 29962306a36Sopenharmony_ci * gprs_high need to be allocated if vector registers are 30062306a36Sopenharmony_ci * included in the signal frame on a 31-bit system. 30162306a36Sopenharmony_ci */ 30262306a36Sopenharmony_ci frame_size = sizeof(*frame) - sizeof(frame->sregs_ext); 30362306a36Sopenharmony_ci if (MACHINE_HAS_VX) 30462306a36Sopenharmony_ci frame_size += sizeof(frame->sregs_ext); 30562306a36Sopenharmony_ci frame = get_sigframe(ka, regs, frame_size); 30662306a36Sopenharmony_ci if (frame == (void __user *) -1UL) 30762306a36Sopenharmony_ci return -EFAULT; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci /* Set up backchain. */ 31062306a36Sopenharmony_ci if (__put_user(regs->gprs[15], (addr_t __user *) frame)) 31162306a36Sopenharmony_ci return -EFAULT; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci /* Create struct sigcontext on the signal stack */ 31462306a36Sopenharmony_ci memcpy(&sc.oldmask, &set->sig, _SIGMASK_COPY_SIZE); 31562306a36Sopenharmony_ci sc.sregs = (_sigregs __user __force *) &frame->sregs; 31662306a36Sopenharmony_ci if (__copy_to_user(&frame->sc, &sc, sizeof(frame->sc))) 31762306a36Sopenharmony_ci return -EFAULT; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci /* Store registers needed to create the signal frame */ 32062306a36Sopenharmony_ci store_sigregs(); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci /* Create _sigregs on the signal stack */ 32362306a36Sopenharmony_ci if (save_sigregs(regs, &frame->sregs)) 32462306a36Sopenharmony_ci return -EFAULT; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci /* Place signal number on stack to allow backtrace from handler. */ 32762306a36Sopenharmony_ci if (__put_user(regs->gprs[2], (int __user *) &frame->signo)) 32862306a36Sopenharmony_ci return -EFAULT; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci /* Create _sigregs_ext on the signal stack */ 33162306a36Sopenharmony_ci if (save_sigregs_ext(regs, &frame->sregs_ext)) 33262306a36Sopenharmony_ci return -EFAULT; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci /* Set up to return from userspace. If provided, use a stub 33562306a36Sopenharmony_ci already in userspace. */ 33662306a36Sopenharmony_ci if (ka->sa.sa_flags & SA_RESTORER) 33762306a36Sopenharmony_ci restorer = (unsigned long) ka->sa.sa_restorer; 33862306a36Sopenharmony_ci else 33962306a36Sopenharmony_ci restorer = VDSO64_SYMBOL(current, sigreturn); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci /* Set up registers for signal handler */ 34262306a36Sopenharmony_ci regs->gprs[14] = restorer; 34362306a36Sopenharmony_ci regs->gprs[15] = (unsigned long) frame; 34462306a36Sopenharmony_ci /* Force default amode and default user address space control. */ 34562306a36Sopenharmony_ci regs->psw.mask = PSW_MASK_EA | PSW_MASK_BA | 34662306a36Sopenharmony_ci (PSW_USER_BITS & PSW_MASK_ASC) | 34762306a36Sopenharmony_ci (regs->psw.mask & ~PSW_MASK_ASC); 34862306a36Sopenharmony_ci regs->psw.addr = (unsigned long) ka->sa.sa_handler; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci regs->gprs[2] = sig; 35162306a36Sopenharmony_ci regs->gprs[3] = (unsigned long) &frame->sc; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci /* We forgot to include these in the sigcontext. 35462306a36Sopenharmony_ci To avoid breaking binary compatibility, they are passed as args. */ 35562306a36Sopenharmony_ci if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL || 35662306a36Sopenharmony_ci sig == SIGTRAP || sig == SIGFPE) { 35762306a36Sopenharmony_ci /* set extra registers only for synchronous signals */ 35862306a36Sopenharmony_ci regs->gprs[4] = regs->int_code & 127; 35962306a36Sopenharmony_ci regs->gprs[5] = regs->int_parm_long; 36062306a36Sopenharmony_ci regs->gprs[6] = current->thread.last_break; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci return 0; 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cistatic int setup_rt_frame(struct ksignal *ksig, sigset_t *set, 36662306a36Sopenharmony_ci struct pt_regs *regs) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci struct rt_sigframe __user *frame; 36962306a36Sopenharmony_ci unsigned long uc_flags, restorer; 37062306a36Sopenharmony_ci size_t frame_size; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci frame_size = sizeof(struct rt_sigframe) - sizeof(_sigregs_ext); 37362306a36Sopenharmony_ci /* 37462306a36Sopenharmony_ci * gprs_high are only present for a 31-bit task running on 37562306a36Sopenharmony_ci * a 64-bit kernel (see compat_signal.c) but the space for 37662306a36Sopenharmony_ci * gprs_high need to be allocated if vector registers are 37762306a36Sopenharmony_ci * included in the signal frame on a 31-bit system. 37862306a36Sopenharmony_ci */ 37962306a36Sopenharmony_ci uc_flags = 0; 38062306a36Sopenharmony_ci if (MACHINE_HAS_VX) { 38162306a36Sopenharmony_ci frame_size += sizeof(_sigregs_ext); 38262306a36Sopenharmony_ci uc_flags |= UC_VXRS; 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci frame = get_sigframe(&ksig->ka, regs, frame_size); 38562306a36Sopenharmony_ci if (frame == (void __user *) -1UL) 38662306a36Sopenharmony_ci return -EFAULT; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci /* Set up backchain. */ 38962306a36Sopenharmony_ci if (__put_user(regs->gprs[15], (addr_t __user *) frame)) 39062306a36Sopenharmony_ci return -EFAULT; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci /* Set up to return from userspace. If provided, use a stub 39362306a36Sopenharmony_ci already in userspace. */ 39462306a36Sopenharmony_ci if (ksig->ka.sa.sa_flags & SA_RESTORER) 39562306a36Sopenharmony_ci restorer = (unsigned long) ksig->ka.sa.sa_restorer; 39662306a36Sopenharmony_ci else 39762306a36Sopenharmony_ci restorer = VDSO64_SYMBOL(current, rt_sigreturn); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci /* Create siginfo on the signal stack */ 40062306a36Sopenharmony_ci if (copy_siginfo_to_user(&frame->info, &ksig->info)) 40162306a36Sopenharmony_ci return -EFAULT; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci /* Store registers needed to create the signal frame */ 40462306a36Sopenharmony_ci store_sigregs(); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci /* Create ucontext on the signal stack. */ 40762306a36Sopenharmony_ci if (__put_user(uc_flags, &frame->uc.uc_flags) || 40862306a36Sopenharmony_ci __put_user(NULL, &frame->uc.uc_link) || 40962306a36Sopenharmony_ci __save_altstack(&frame->uc.uc_stack, regs->gprs[15]) || 41062306a36Sopenharmony_ci save_sigregs(regs, &frame->uc.uc_mcontext) || 41162306a36Sopenharmony_ci __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)) || 41262306a36Sopenharmony_ci save_sigregs_ext(regs, &frame->uc.uc_mcontext_ext)) 41362306a36Sopenharmony_ci return -EFAULT; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci /* Set up registers for signal handler */ 41662306a36Sopenharmony_ci regs->gprs[14] = restorer; 41762306a36Sopenharmony_ci regs->gprs[15] = (unsigned long) frame; 41862306a36Sopenharmony_ci /* Force default amode and default user address space control. */ 41962306a36Sopenharmony_ci regs->psw.mask = PSW_MASK_EA | PSW_MASK_BA | 42062306a36Sopenharmony_ci (PSW_USER_BITS & PSW_MASK_ASC) | 42162306a36Sopenharmony_ci (regs->psw.mask & ~PSW_MASK_ASC); 42262306a36Sopenharmony_ci regs->psw.addr = (unsigned long) ksig->ka.sa.sa_handler; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci regs->gprs[2] = ksig->sig; 42562306a36Sopenharmony_ci regs->gprs[3] = (unsigned long) &frame->info; 42662306a36Sopenharmony_ci regs->gprs[4] = (unsigned long) &frame->uc; 42762306a36Sopenharmony_ci regs->gprs[5] = current->thread.last_break; 42862306a36Sopenharmony_ci return 0; 42962306a36Sopenharmony_ci} 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cistatic void handle_signal(struct ksignal *ksig, sigset_t *oldset, 43262306a36Sopenharmony_ci struct pt_regs *regs) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci int ret; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci /* Set up the stack frame */ 43762306a36Sopenharmony_ci if (ksig->ka.sa.sa_flags & SA_SIGINFO) 43862306a36Sopenharmony_ci ret = setup_rt_frame(ksig, oldset, regs); 43962306a36Sopenharmony_ci else 44062306a36Sopenharmony_ci ret = setup_frame(ksig->sig, &ksig->ka, oldset, regs); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci signal_setup_done(ret, ksig, test_thread_flag(TIF_SINGLE_STEP)); 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci/* 44662306a36Sopenharmony_ci * Note that 'init' is a special process: it doesn't get signals it doesn't 44762306a36Sopenharmony_ci * want to handle. Thus you cannot kill init even with a SIGKILL even by 44862306a36Sopenharmony_ci * mistake. 44962306a36Sopenharmony_ci * 45062306a36Sopenharmony_ci * Note that we go through the signals twice: once to check the signals that 45162306a36Sopenharmony_ci * the kernel can handle, and then we build all the user-level signal handling 45262306a36Sopenharmony_ci * stack-frames in one go after that. 45362306a36Sopenharmony_ci */ 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_civoid arch_do_signal_or_restart(struct pt_regs *regs) 45662306a36Sopenharmony_ci{ 45762306a36Sopenharmony_ci struct ksignal ksig; 45862306a36Sopenharmony_ci sigset_t *oldset = sigmask_to_save(); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci /* 46162306a36Sopenharmony_ci * Get signal to deliver. When running under ptrace, at this point 46262306a36Sopenharmony_ci * the debugger may change all our registers, including the system 46362306a36Sopenharmony_ci * call information. 46462306a36Sopenharmony_ci */ 46562306a36Sopenharmony_ci current->thread.system_call = 46662306a36Sopenharmony_ci test_pt_regs_flag(regs, PIF_SYSCALL) ? regs->int_code : 0; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci if (get_signal(&ksig)) { 46962306a36Sopenharmony_ci /* Whee! Actually deliver the signal. */ 47062306a36Sopenharmony_ci if (current->thread.system_call) { 47162306a36Sopenharmony_ci regs->int_code = current->thread.system_call; 47262306a36Sopenharmony_ci /* Check for system call restarting. */ 47362306a36Sopenharmony_ci switch (regs->gprs[2]) { 47462306a36Sopenharmony_ci case -ERESTART_RESTARTBLOCK: 47562306a36Sopenharmony_ci case -ERESTARTNOHAND: 47662306a36Sopenharmony_ci regs->gprs[2] = -EINTR; 47762306a36Sopenharmony_ci break; 47862306a36Sopenharmony_ci case -ERESTARTSYS: 47962306a36Sopenharmony_ci if (!(ksig.ka.sa.sa_flags & SA_RESTART)) { 48062306a36Sopenharmony_ci regs->gprs[2] = -EINTR; 48162306a36Sopenharmony_ci break; 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci fallthrough; 48462306a36Sopenharmony_ci case -ERESTARTNOINTR: 48562306a36Sopenharmony_ci regs->gprs[2] = regs->orig_gpr2; 48662306a36Sopenharmony_ci regs->psw.addr = 48762306a36Sopenharmony_ci __rewind_psw(regs->psw, 48862306a36Sopenharmony_ci regs->int_code >> 16); 48962306a36Sopenharmony_ci break; 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci /* No longer in a system call */ 49362306a36Sopenharmony_ci clear_pt_regs_flag(regs, PIF_SYSCALL); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci rseq_signal_deliver(&ksig, regs); 49662306a36Sopenharmony_ci if (is_compat_task()) 49762306a36Sopenharmony_ci handle_signal32(&ksig, oldset, regs); 49862306a36Sopenharmony_ci else 49962306a36Sopenharmony_ci handle_signal(&ksig, oldset, regs); 50062306a36Sopenharmony_ci return; 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci /* No handlers present - check for system call restart */ 50462306a36Sopenharmony_ci clear_pt_regs_flag(regs, PIF_SYSCALL); 50562306a36Sopenharmony_ci if (current->thread.system_call) { 50662306a36Sopenharmony_ci regs->int_code = current->thread.system_call; 50762306a36Sopenharmony_ci switch (regs->gprs[2]) { 50862306a36Sopenharmony_ci case -ERESTART_RESTARTBLOCK: 50962306a36Sopenharmony_ci /* Restart with sys_restart_syscall */ 51062306a36Sopenharmony_ci regs->gprs[2] = regs->orig_gpr2; 51162306a36Sopenharmony_ci current->restart_block.arch_data = regs->psw.addr; 51262306a36Sopenharmony_ci if (is_compat_task()) 51362306a36Sopenharmony_ci regs->psw.addr = VDSO32_SYMBOL(current, restart_syscall); 51462306a36Sopenharmony_ci else 51562306a36Sopenharmony_ci regs->psw.addr = VDSO64_SYMBOL(current, restart_syscall); 51662306a36Sopenharmony_ci if (test_thread_flag(TIF_SINGLE_STEP)) 51762306a36Sopenharmony_ci clear_thread_flag(TIF_PER_TRAP); 51862306a36Sopenharmony_ci break; 51962306a36Sopenharmony_ci case -ERESTARTNOHAND: 52062306a36Sopenharmony_ci case -ERESTARTSYS: 52162306a36Sopenharmony_ci case -ERESTARTNOINTR: 52262306a36Sopenharmony_ci regs->gprs[2] = regs->orig_gpr2; 52362306a36Sopenharmony_ci regs->psw.addr = __rewind_psw(regs->psw, regs->int_code >> 16); 52462306a36Sopenharmony_ci if (test_thread_flag(TIF_SINGLE_STEP)) 52562306a36Sopenharmony_ci clear_thread_flag(TIF_PER_TRAP); 52662306a36Sopenharmony_ci break; 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci } 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci /* 53162306a36Sopenharmony_ci * If there's no signal to deliver, we just put the saved sigmask back. 53262306a36Sopenharmony_ci */ 53362306a36Sopenharmony_ci restore_saved_sigmask(); 53462306a36Sopenharmony_ci} 535