11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/arch/parisc/kernel/signal.c: Architecture-specific signal 31da177e4SLinus Torvalds * handling support. 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Copyright (C) 2000 David Huggins-Daines <dhd@debian.org> 61da177e4SLinus Torvalds * Copyright (C) 2000 Linuxcare, Inc. 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * Based on the ia64, i386, and alpha versions. 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds * Like the IA-64, we are a recent enough port (we are *starting* 111da177e4SLinus Torvalds * with glibc2.2) that we do not need to support the old non-realtime 121da177e4SLinus Torvalds * Linux signals. Therefore we don't. HP/UX signals will go in 131da177e4SLinus Torvalds * arch/parisc/hpux/signal.c when we figure out how to do them. 141da177e4SLinus Torvalds */ 151da177e4SLinus Torvalds 161da177e4SLinus Torvalds #include <linux/sched.h> 171da177e4SLinus Torvalds #include <linux/mm.h> 181da177e4SLinus Torvalds #include <linux/smp.h> 191da177e4SLinus Torvalds #include <linux/kernel.h> 201da177e4SLinus Torvalds #include <linux/signal.h> 211da177e4SLinus Torvalds #include <linux/errno.h> 221da177e4SLinus Torvalds #include <linux/wait.h> 231da177e4SLinus Torvalds #include <linux/ptrace.h> 24*ecf02de5SKyle McMartin #include <linux/tracehook.h> 251da177e4SLinus Torvalds #include <linux/unistd.h> 261da177e4SLinus Torvalds #include <linux/stddef.h> 271da177e4SLinus Torvalds #include <linux/compat.h> 281da177e4SLinus Torvalds #include <linux/elf.h> 29733e5e4bSDavid Howells #include <linux/tracehook.h> 301da177e4SLinus Torvalds #include <asm/ucontext.h> 311da177e4SLinus Torvalds #include <asm/rt_sigframe.h> 321da177e4SLinus Torvalds #include <asm/uaccess.h> 331da177e4SLinus Torvalds #include <asm/pgalloc.h> 341da177e4SLinus Torvalds #include <asm/cacheflush.h> 350013a854SSam Ravnborg #include <asm/asm-offsets.h> 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds #ifdef CONFIG_COMPAT 381da177e4SLinus Torvalds #include <linux/compat.h> 391da177e4SLinus Torvalds #include "signal32.h" 401da177e4SLinus Torvalds #endif 411da177e4SLinus Torvalds 421da177e4SLinus Torvalds #define DEBUG_SIG 0 431da177e4SLinus Torvalds #define DEBUG_SIG_LEVEL 2 441da177e4SLinus Torvalds 451da177e4SLinus Torvalds #if DEBUG_SIG 461da177e4SLinus Torvalds #define DBG(LEVEL, ...) \ 471da177e4SLinus Torvalds ((DEBUG_SIG_LEVEL >= LEVEL) \ 481da177e4SLinus Torvalds ? printk(__VA_ARGS__) : (void) 0) 491da177e4SLinus Torvalds #else 501da177e4SLinus Torvalds #define DBG(LEVEL, ...) 511da177e4SLinus Torvalds #endif 521da177e4SLinus Torvalds 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds /* gcc will complain if a pointer is cast to an integer of different 571da177e4SLinus Torvalds * size. If you really need to do this (and we do for an ELF32 user 581da177e4SLinus Torvalds * application in an ELF64 kernel) then you have to do a cast to an 591da177e4SLinus Torvalds * integer of the same size first. The A() macro accomplishes 601da177e4SLinus Torvalds * this. */ 611da177e4SLinus Torvalds #define A(__x) ((unsigned long)(__x)) 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds /* 641da177e4SLinus Torvalds * Atomically swap in the new signal mask, and wait for a signal. 651da177e4SLinus Torvalds */ 66a8f44e38SHelge Deller #ifdef CONFIG_64BIT 671da177e4SLinus Torvalds #include "sys32.h" 681da177e4SLinus Torvalds #endif 691da177e4SLinus Torvalds 701da177e4SLinus Torvalds /* 711da177e4SLinus Torvalds * Do a signal return - restore sigcontext. 721da177e4SLinus Torvalds */ 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds /* Trampoline for calling rt_sigreturn() */ 751da177e4SLinus Torvalds #define INSN_LDI_R25_0 0x34190000 /* ldi 0,%r25 (in_syscall=0) */ 761da177e4SLinus Torvalds #define INSN_LDI_R25_1 0x34190002 /* ldi 1,%r25 (in_syscall=1) */ 771da177e4SLinus Torvalds #define INSN_LDI_R20 0x3414015a /* ldi __NR_rt_sigreturn,%r20 */ 781da177e4SLinus Torvalds #define INSN_BLE_SR2_R0 0xe4008200 /* be,l 0x100(%sr2,%r0),%sr0,%r31 */ 791da177e4SLinus Torvalds #define INSN_NOP 0x08000240 /* nop */ 801da177e4SLinus Torvalds /* For debugging */ 811da177e4SLinus Torvalds #define INSN_DIE_HORRIBLY 0x68000ccc /* stw %r0,0x666(%sr0,%r0) */ 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds static long 841da177e4SLinus Torvalds restore_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs) 851da177e4SLinus Torvalds { 861da177e4SLinus Torvalds long err = 0; 871da177e4SLinus Torvalds 881da177e4SLinus Torvalds err |= __copy_from_user(regs->gr, sc->sc_gr, sizeof(regs->gr)); 891da177e4SLinus Torvalds err |= __copy_from_user(regs->fr, sc->sc_fr, sizeof(regs->fr)); 901da177e4SLinus Torvalds err |= __copy_from_user(regs->iaoq, sc->sc_iaoq, sizeof(regs->iaoq)); 911da177e4SLinus Torvalds err |= __copy_from_user(regs->iasq, sc->sc_iasq, sizeof(regs->iasq)); 921da177e4SLinus Torvalds err |= __get_user(regs->sar, &sc->sc_sar); 931da177e4SLinus Torvalds DBG(2,"restore_sigcontext: iaoq is 0x%#lx / 0x%#lx\n", 941da177e4SLinus Torvalds regs->iaoq[0],regs->iaoq[1]); 951da177e4SLinus Torvalds DBG(2,"restore_sigcontext: r28 is %ld\n", regs->gr[28]); 961da177e4SLinus Torvalds return err; 971da177e4SLinus Torvalds } 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds void 1001da177e4SLinus Torvalds sys_rt_sigreturn(struct pt_regs *regs, int in_syscall) 1011da177e4SLinus Torvalds { 1021da177e4SLinus Torvalds struct rt_sigframe __user *frame; 1031da177e4SLinus Torvalds struct siginfo si; 1041da177e4SLinus Torvalds sigset_t set; 1051da177e4SLinus Torvalds unsigned long usp = (regs->gr[30] & ~(0x01UL)); 1061da177e4SLinus Torvalds unsigned long sigframe_size = PARISC_RT_SIGFRAME_SIZE; 107a8f44e38SHelge Deller #ifdef CONFIG_64BIT 1081da177e4SLinus Torvalds compat_sigset_t compat_set; 1091da177e4SLinus Torvalds struct compat_rt_sigframe __user * compat_frame; 1101da177e4SLinus Torvalds 111a3ea84faSKyle McMartin if (is_compat_task()) 1121da177e4SLinus Torvalds sigframe_size = PARISC_RT_SIGFRAME_SIZE32; 1131da177e4SLinus Torvalds #endif 1141da177e4SLinus Torvalds 1151da177e4SLinus Torvalds 1161da177e4SLinus Torvalds /* Unwind the user stack to get the rt_sigframe structure. */ 1171da177e4SLinus Torvalds frame = (struct rt_sigframe __user *) 1181da177e4SLinus Torvalds (usp - sigframe_size); 1191da177e4SLinus Torvalds DBG(2,"sys_rt_sigreturn: frame is %p\n", frame); 1201da177e4SLinus Torvalds 121a8f44e38SHelge Deller #ifdef CONFIG_64BIT 1221da177e4SLinus Torvalds compat_frame = (struct compat_rt_sigframe __user *)frame; 1231da177e4SLinus Torvalds 124a3ea84faSKyle McMartin if (is_compat_task()) { 1251da177e4SLinus Torvalds DBG(2,"sys_rt_sigreturn: ELF32 process.\n"); 1261da177e4SLinus Torvalds if (__copy_from_user(&compat_set, &compat_frame->uc.uc_sigmask, sizeof(compat_set))) 1271da177e4SLinus Torvalds goto give_sigsegv; 1281da177e4SLinus Torvalds sigset_32to64(&set,&compat_set); 1291da177e4SLinus Torvalds } else 1301da177e4SLinus Torvalds #endif 1311da177e4SLinus Torvalds { 1321da177e4SLinus Torvalds if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) 1331da177e4SLinus Torvalds goto give_sigsegv; 1341da177e4SLinus Torvalds } 1351da177e4SLinus Torvalds 1361da177e4SLinus Torvalds sigdelsetmask(&set, ~_BLOCKABLE); 1371da177e4SLinus Torvalds spin_lock_irq(¤t->sighand->siglock); 1381da177e4SLinus Torvalds current->blocked = set; 1391da177e4SLinus Torvalds recalc_sigpending(); 1401da177e4SLinus Torvalds spin_unlock_irq(¤t->sighand->siglock); 1411da177e4SLinus Torvalds 1421da177e4SLinus Torvalds /* Good thing we saved the old gr[30], eh? */ 143a8f44e38SHelge Deller #ifdef CONFIG_64BIT 144a3ea84faSKyle McMartin if (is_compat_task()) { 1451da177e4SLinus Torvalds DBG(1,"sys_rt_sigreturn: compat_frame->uc.uc_mcontext 0x%p\n", 1461da177e4SLinus Torvalds &compat_frame->uc.uc_mcontext); 1471da177e4SLinus Torvalds // FIXME: Load upper half from register file 1481da177e4SLinus Torvalds if (restore_sigcontext32(&compat_frame->uc.uc_mcontext, 1491da177e4SLinus Torvalds &compat_frame->regs, regs)) 1501da177e4SLinus Torvalds goto give_sigsegv; 1511da177e4SLinus Torvalds DBG(1,"sys_rt_sigreturn: usp %#08lx stack 0x%p\n", 1521da177e4SLinus Torvalds usp, &compat_frame->uc.uc_stack); 1531da177e4SLinus Torvalds if (do_sigaltstack32(&compat_frame->uc.uc_stack, NULL, usp) == -EFAULT) 1541da177e4SLinus Torvalds goto give_sigsegv; 1551da177e4SLinus Torvalds } else 1561da177e4SLinus Torvalds #endif 1571da177e4SLinus Torvalds { 1581da177e4SLinus Torvalds DBG(1,"sys_rt_sigreturn: frame->uc.uc_mcontext 0x%p\n", 1591da177e4SLinus Torvalds &frame->uc.uc_mcontext); 1601da177e4SLinus Torvalds if (restore_sigcontext(&frame->uc.uc_mcontext, regs)) 1611da177e4SLinus Torvalds goto give_sigsegv; 1621da177e4SLinus Torvalds DBG(1,"sys_rt_sigreturn: usp %#08lx stack 0x%p\n", 1631da177e4SLinus Torvalds usp, &frame->uc.uc_stack); 1641da177e4SLinus Torvalds if (do_sigaltstack(&frame->uc.uc_stack, NULL, usp) == -EFAULT) 1651da177e4SLinus Torvalds goto give_sigsegv; 1661da177e4SLinus Torvalds } 1671da177e4SLinus Torvalds 1681da177e4SLinus Torvalds 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds /* If we are on the syscall path IAOQ will not be restored, and 1711da177e4SLinus Torvalds * if we are on the interrupt path we must not corrupt gr31. 1721da177e4SLinus Torvalds */ 1731da177e4SLinus Torvalds if (in_syscall) 1741da177e4SLinus Torvalds regs->gr[31] = regs->iaoq[0]; 1751da177e4SLinus Torvalds #if DEBUG_SIG 1761da177e4SLinus Torvalds DBG(1,"sys_rt_sigreturn: returning to %#lx, DUMPING REGS:\n", regs->iaoq[0]); 1771da177e4SLinus Torvalds show_regs(regs); 1781da177e4SLinus Torvalds #endif 1791da177e4SLinus Torvalds return; 1801da177e4SLinus Torvalds 1811da177e4SLinus Torvalds give_sigsegv: 1821da177e4SLinus Torvalds DBG(1,"sys_rt_sigreturn: Sending SIGSEGV\n"); 1831da177e4SLinus Torvalds si.si_signo = SIGSEGV; 1841da177e4SLinus Torvalds si.si_errno = 0; 1851da177e4SLinus Torvalds si.si_code = SI_KERNEL; 186b488893aSPavel Emelyanov si.si_pid = task_pid_vnr(current); 18725e15731SDavid Howells si.si_uid = current_uid(); 1881da177e4SLinus Torvalds si.si_addr = &frame->uc; 1891da177e4SLinus Torvalds force_sig_info(SIGSEGV, &si, current); 1901da177e4SLinus Torvalds return; 1911da177e4SLinus Torvalds } 1921da177e4SLinus Torvalds 1931da177e4SLinus Torvalds /* 1941da177e4SLinus Torvalds * Set up a signal frame. 1951da177e4SLinus Torvalds */ 1961da177e4SLinus Torvalds 1971da177e4SLinus Torvalds static inline void __user * 1981da177e4SLinus Torvalds get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) 1991da177e4SLinus Torvalds { 2001da177e4SLinus Torvalds /*FIXME: ELF32 vs. ELF64 has different frame_size, but since we 2011da177e4SLinus Torvalds don't use the parameter it doesn't matter */ 2021da177e4SLinus Torvalds 2031da177e4SLinus Torvalds DBG(1,"get_sigframe: ka = %#lx, sp = %#lx, frame_size = %#lx\n", 2041da177e4SLinus Torvalds (unsigned long)ka, sp, frame_size); 2051da177e4SLinus Torvalds 206d09042daSLaurent MEYER if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! sas_ss_flags(sp)) 2071da177e4SLinus Torvalds sp = current->sas_ss_sp; /* Stacks grow up! */ 2081da177e4SLinus Torvalds 2091da177e4SLinus Torvalds DBG(1,"get_sigframe: Returning sp = %#lx\n", (unsigned long)sp); 2101da177e4SLinus Torvalds return (void __user *) sp; /* Stacks grow up. Fun. */ 2111da177e4SLinus Torvalds } 2121da177e4SLinus Torvalds 2131da177e4SLinus Torvalds static long 2141da177e4SLinus Torvalds setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, int in_syscall) 2151da177e4SLinus Torvalds 2161da177e4SLinus Torvalds { 2171da177e4SLinus Torvalds unsigned long flags = 0; 2181da177e4SLinus Torvalds long err = 0; 2191da177e4SLinus Torvalds 2201da177e4SLinus Torvalds if (on_sig_stack((unsigned long) sc)) 2211da177e4SLinus Torvalds flags |= PARISC_SC_FLAG_ONSTACK; 2221da177e4SLinus Torvalds if (in_syscall) { 2231da177e4SLinus Torvalds flags |= PARISC_SC_FLAG_IN_SYSCALL; 2241da177e4SLinus Torvalds /* regs->iaoq is undefined in the syscall return path */ 2251da177e4SLinus Torvalds err |= __put_user(regs->gr[31], &sc->sc_iaoq[0]); 2261da177e4SLinus Torvalds err |= __put_user(regs->gr[31]+4, &sc->sc_iaoq[1]); 2271da177e4SLinus Torvalds err |= __put_user(regs->sr[3], &sc->sc_iasq[0]); 2281da177e4SLinus Torvalds err |= __put_user(regs->sr[3], &sc->sc_iasq[1]); 2291da177e4SLinus Torvalds DBG(1,"setup_sigcontext: iaoq %#lx / %#lx (in syscall)\n", 2301da177e4SLinus Torvalds regs->gr[31], regs->gr[31]+4); 2311da177e4SLinus Torvalds } else { 2321da177e4SLinus Torvalds err |= __copy_to_user(sc->sc_iaoq, regs->iaoq, sizeof(regs->iaoq)); 2331da177e4SLinus Torvalds err |= __copy_to_user(sc->sc_iasq, regs->iasq, sizeof(regs->iasq)); 2341da177e4SLinus Torvalds DBG(1,"setup_sigcontext: iaoq %#lx / %#lx (not in syscall)\n", 2351da177e4SLinus Torvalds regs->iaoq[0], regs->iaoq[1]); 2361da177e4SLinus Torvalds } 2371da177e4SLinus Torvalds 2381da177e4SLinus Torvalds err |= __put_user(flags, &sc->sc_flags); 2391da177e4SLinus Torvalds err |= __copy_to_user(sc->sc_gr, regs->gr, sizeof(regs->gr)); 2401da177e4SLinus Torvalds err |= __copy_to_user(sc->sc_fr, regs->fr, sizeof(regs->fr)); 2411da177e4SLinus Torvalds err |= __put_user(regs->sar, &sc->sc_sar); 2421da177e4SLinus Torvalds DBG(1,"setup_sigcontext: r28 is %ld\n", regs->gr[28]); 2431da177e4SLinus Torvalds 2441da177e4SLinus Torvalds return err; 2451da177e4SLinus Torvalds } 2461da177e4SLinus Torvalds 2471da177e4SLinus Torvalds static long 2481da177e4SLinus Torvalds setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, 2491da177e4SLinus Torvalds sigset_t *set, struct pt_regs *regs, int in_syscall) 2501da177e4SLinus Torvalds { 2511da177e4SLinus Torvalds struct rt_sigframe __user *frame; 2521da177e4SLinus Torvalds unsigned long rp, usp; 2531da177e4SLinus Torvalds unsigned long haddr, sigframe_size; 2541da177e4SLinus Torvalds int err = 0; 255a8f44e38SHelge Deller #ifdef CONFIG_64BIT 2561da177e4SLinus Torvalds compat_int_t compat_val; 2571da177e4SLinus Torvalds struct compat_rt_sigframe __user * compat_frame; 2581da177e4SLinus Torvalds compat_sigset_t compat_set; 2591da177e4SLinus Torvalds #endif 2601da177e4SLinus Torvalds 2611da177e4SLinus Torvalds usp = (regs->gr[30] & ~(0x01UL)); 2621da177e4SLinus Torvalds /*FIXME: frame_size parameter is unused, remove it. */ 2631da177e4SLinus Torvalds frame = get_sigframe(ka, usp, sizeof(*frame)); 2641da177e4SLinus Torvalds 2651da177e4SLinus Torvalds DBG(1,"SETUP_RT_FRAME: START\n"); 2661da177e4SLinus Torvalds DBG(1,"setup_rt_frame: frame %p info %p\n", frame, info); 2671da177e4SLinus Torvalds 2681da177e4SLinus Torvalds 269a8f44e38SHelge Deller #ifdef CONFIG_64BIT 2701da177e4SLinus Torvalds 2711da177e4SLinus Torvalds compat_frame = (struct compat_rt_sigframe __user *)frame; 2721da177e4SLinus Torvalds 273a3ea84faSKyle McMartin if (is_compat_task()) { 2741da177e4SLinus Torvalds DBG(1,"setup_rt_frame: frame->info = 0x%p\n", &compat_frame->info); 275f671c45dSKyle McMartin err |= copy_siginfo_to_user32(&compat_frame->info, info); 2761da177e4SLinus Torvalds DBG(1,"SETUP_RT_FRAME: 1\n"); 2771da177e4SLinus Torvalds compat_val = (compat_int_t)current->sas_ss_sp; 2781da177e4SLinus Torvalds err |= __put_user(compat_val, &compat_frame->uc.uc_stack.ss_sp); 2791da177e4SLinus Torvalds DBG(1,"SETUP_RT_FRAME: 2\n"); 2801da177e4SLinus Torvalds compat_val = (compat_int_t)current->sas_ss_size; 2811da177e4SLinus Torvalds err |= __put_user(compat_val, &compat_frame->uc.uc_stack.ss_size); 2821da177e4SLinus Torvalds DBG(1,"SETUP_RT_FRAME: 3\n"); 2831da177e4SLinus Torvalds compat_val = sas_ss_flags(regs->gr[30]); 2841da177e4SLinus Torvalds err |= __put_user(compat_val, &compat_frame->uc.uc_stack.ss_flags); 2851da177e4SLinus Torvalds DBG(1,"setup_rt_frame: frame->uc = 0x%p\n", &compat_frame->uc); 2861da177e4SLinus Torvalds DBG(1,"setup_rt_frame: frame->uc.uc_mcontext = 0x%p\n", &compat_frame->uc.uc_mcontext); 2871da177e4SLinus Torvalds err |= setup_sigcontext32(&compat_frame->uc.uc_mcontext, 2881da177e4SLinus Torvalds &compat_frame->regs, regs, in_syscall); 2891da177e4SLinus Torvalds sigset_64to32(&compat_set,set); 2901da177e4SLinus Torvalds err |= __copy_to_user(&compat_frame->uc.uc_sigmask, &compat_set, sizeof(compat_set)); 2911da177e4SLinus Torvalds } else 2921da177e4SLinus Torvalds #endif 2931da177e4SLinus Torvalds { 2941da177e4SLinus Torvalds DBG(1,"setup_rt_frame: frame->info = 0x%p\n", &frame->info); 2951da177e4SLinus Torvalds err |= copy_siginfo_to_user(&frame->info, info); 2961da177e4SLinus Torvalds err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); 2971da177e4SLinus Torvalds err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); 2981da177e4SLinus Torvalds err |= __put_user(sas_ss_flags(regs->gr[30]), 2991da177e4SLinus Torvalds &frame->uc.uc_stack.ss_flags); 3001da177e4SLinus Torvalds DBG(1,"setup_rt_frame: frame->uc = 0x%p\n", &frame->uc); 3011da177e4SLinus Torvalds DBG(1,"setup_rt_frame: frame->uc.uc_mcontext = 0x%p\n", &frame->uc.uc_mcontext); 3021da177e4SLinus Torvalds err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, in_syscall); 3031da177e4SLinus Torvalds /* FIXME: Should probably be converted aswell for the compat case */ 3041da177e4SLinus Torvalds err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); 3051da177e4SLinus Torvalds } 3061da177e4SLinus Torvalds 3071da177e4SLinus Torvalds if (err) 3081da177e4SLinus Torvalds goto give_sigsegv; 3091da177e4SLinus Torvalds 3101da177e4SLinus Torvalds /* Set up to return from userspace. If provided, use a stub 3111da177e4SLinus Torvalds already in userspace. The first words of tramp are used to 3121da177e4SLinus Torvalds save the previous sigrestartblock trampoline that might be 3131da177e4SLinus Torvalds on the stack. We start the sigreturn trampoline at 3141da177e4SLinus Torvalds SIGRESTARTBLOCK_TRAMP+X. */ 3151da177e4SLinus Torvalds err |= __put_user(in_syscall ? INSN_LDI_R25_1 : INSN_LDI_R25_0, 3161da177e4SLinus Torvalds &frame->tramp[SIGRESTARTBLOCK_TRAMP+0]); 3171da177e4SLinus Torvalds err |= __put_user(INSN_LDI_R20, 3181da177e4SLinus Torvalds &frame->tramp[SIGRESTARTBLOCK_TRAMP+1]); 3191da177e4SLinus Torvalds err |= __put_user(INSN_BLE_SR2_R0, 3201da177e4SLinus Torvalds &frame->tramp[SIGRESTARTBLOCK_TRAMP+2]); 3211da177e4SLinus Torvalds err |= __put_user(INSN_NOP, &frame->tramp[SIGRESTARTBLOCK_TRAMP+3]); 3221da177e4SLinus Torvalds 3231da177e4SLinus Torvalds #if DEBUG_SIG 3241da177e4SLinus Torvalds /* Assert that we're flushing in the correct space... */ 3251da177e4SLinus Torvalds { 3261da177e4SLinus Torvalds int sid; 3271da177e4SLinus Torvalds asm ("mfsp %%sr3,%0" : "=r" (sid)); 3281da177e4SLinus Torvalds DBG(1,"setup_rt_frame: Flushing 64 bytes at space %#x offset %p\n", 3291da177e4SLinus Torvalds sid, frame->tramp); 3301da177e4SLinus Torvalds } 3311da177e4SLinus Torvalds #endif 3321da177e4SLinus Torvalds 3331da177e4SLinus Torvalds flush_user_dcache_range((unsigned long) &frame->tramp[0], 3341da177e4SLinus Torvalds (unsigned long) &frame->tramp[TRAMP_SIZE]); 3351da177e4SLinus Torvalds flush_user_icache_range((unsigned long) &frame->tramp[0], 3361da177e4SLinus Torvalds (unsigned long) &frame->tramp[TRAMP_SIZE]); 3371da177e4SLinus Torvalds 338efad798bSPaulius Zaleckas /* TRAMP Words 0-4, Length 5 = SIGRESTARTBLOCK_TRAMP 3391da177e4SLinus Torvalds * TRAMP Words 5-9, Length 4 = SIGRETURN_TRAMP 3401da177e4SLinus Torvalds * So the SIGRETURN_TRAMP is at the end of SIGRESTARTBLOCK_TRAMP 3411da177e4SLinus Torvalds */ 3421da177e4SLinus Torvalds rp = (unsigned long) &frame->tramp[SIGRESTARTBLOCK_TRAMP]; 3431da177e4SLinus Torvalds 3441da177e4SLinus Torvalds if (err) 3451da177e4SLinus Torvalds goto give_sigsegv; 3461da177e4SLinus Torvalds 3471da177e4SLinus Torvalds haddr = A(ka->sa.sa_handler); 3481da177e4SLinus Torvalds /* The sa_handler may be a pointer to a function descriptor */ 349a8f44e38SHelge Deller #ifdef CONFIG_64BIT 350a3ea84faSKyle McMartin if (is_compat_task()) { 3511da177e4SLinus Torvalds #endif 3521da177e4SLinus Torvalds if (haddr & PA_PLABEL_FDESC) { 3531da177e4SLinus Torvalds Elf32_Fdesc fdesc; 3541da177e4SLinus Torvalds Elf32_Fdesc __user *ufdesc = (Elf32_Fdesc __user *)A(haddr & ~3); 3551da177e4SLinus Torvalds 3561da177e4SLinus Torvalds err = __copy_from_user(&fdesc, ufdesc, sizeof(fdesc)); 3571da177e4SLinus Torvalds 3581da177e4SLinus Torvalds if (err) 3591da177e4SLinus Torvalds goto give_sigsegv; 3601da177e4SLinus Torvalds 3611da177e4SLinus Torvalds haddr = fdesc.addr; 3621da177e4SLinus Torvalds regs->gr[19] = fdesc.gp; 3631da177e4SLinus Torvalds } 364a8f44e38SHelge Deller #ifdef CONFIG_64BIT 3651da177e4SLinus Torvalds } else { 3661da177e4SLinus Torvalds Elf64_Fdesc fdesc; 3671da177e4SLinus Torvalds Elf64_Fdesc __user *ufdesc = (Elf64_Fdesc __user *)A(haddr & ~3); 3681da177e4SLinus Torvalds 3691da177e4SLinus Torvalds err = __copy_from_user(&fdesc, ufdesc, sizeof(fdesc)); 3701da177e4SLinus Torvalds 3711da177e4SLinus Torvalds if (err) 3721da177e4SLinus Torvalds goto give_sigsegv; 3731da177e4SLinus Torvalds 3741da177e4SLinus Torvalds haddr = fdesc.addr; 3751da177e4SLinus Torvalds regs->gr[19] = fdesc.gp; 3761da177e4SLinus Torvalds DBG(1,"setup_rt_frame: 64 bit signal, exe=%#lx, r19=%#lx, in_syscall=%d\n", 3771da177e4SLinus Torvalds haddr, regs->gr[19], in_syscall); 3781da177e4SLinus Torvalds } 3791da177e4SLinus Torvalds #endif 3801da177e4SLinus Torvalds 3811da177e4SLinus Torvalds /* The syscall return path will create IAOQ values from r31. 3821da177e4SLinus Torvalds */ 3831da177e4SLinus Torvalds sigframe_size = PARISC_RT_SIGFRAME_SIZE; 384a8f44e38SHelge Deller #ifdef CONFIG_64BIT 385a3ea84faSKyle McMartin if (is_compat_task()) 3861da177e4SLinus Torvalds sigframe_size = PARISC_RT_SIGFRAME_SIZE32; 3871da177e4SLinus Torvalds #endif 3881da177e4SLinus Torvalds if (in_syscall) { 3891da177e4SLinus Torvalds regs->gr[31] = haddr; 390a8f44e38SHelge Deller #ifdef CONFIG_64BIT 391df570b9cSKyle McMartin if (!test_thread_flag(TIF_32BIT)) 3921da177e4SLinus Torvalds sigframe_size |= 1; 3931da177e4SLinus Torvalds #endif 3941da177e4SLinus Torvalds } else { 3951da177e4SLinus Torvalds unsigned long psw = USER_PSW; 396a8f44e38SHelge Deller #ifdef CONFIG_64BIT 397df570b9cSKyle McMartin if (!test_thread_flag(TIF_32BIT)) 3981da177e4SLinus Torvalds psw |= PSW_W; 3991da177e4SLinus Torvalds #endif 4001da177e4SLinus Torvalds 4011da177e4SLinus Torvalds /* If we are singlestepping, arrange a trap to be delivered 4021da177e4SLinus Torvalds when we return to userspace. Note the semantics -- we 4031da177e4SLinus Torvalds should trap before the first insn in the handler is 4041da177e4SLinus Torvalds executed. Ref: 4051da177e4SLinus Torvalds http://sources.redhat.com/ml/gdb/2004-11/msg00245.html 4061da177e4SLinus Torvalds */ 4071da177e4SLinus Torvalds if (pa_psw(current)->r) { 4081da177e4SLinus Torvalds pa_psw(current)->r = 0; 4091da177e4SLinus Torvalds psw |= PSW_R; 4101da177e4SLinus Torvalds mtctl(-1, 0); 4111da177e4SLinus Torvalds } 4121da177e4SLinus Torvalds 4131da177e4SLinus Torvalds regs->gr[0] = psw; 4141da177e4SLinus Torvalds regs->iaoq[0] = haddr | 3; 4151da177e4SLinus Torvalds regs->iaoq[1] = regs->iaoq[0] + 4; 4161da177e4SLinus Torvalds } 4171da177e4SLinus Torvalds 4181da177e4SLinus Torvalds regs->gr[2] = rp; /* userland return pointer */ 4191da177e4SLinus Torvalds regs->gr[26] = sig; /* signal number */ 4201da177e4SLinus Torvalds 421a8f44e38SHelge Deller #ifdef CONFIG_64BIT 422a3ea84faSKyle McMartin if (is_compat_task()) { 4231da177e4SLinus Torvalds regs->gr[25] = A(&compat_frame->info); /* siginfo pointer */ 4241da177e4SLinus Torvalds regs->gr[24] = A(&compat_frame->uc); /* ucontext pointer */ 4251da177e4SLinus Torvalds } else 4261da177e4SLinus Torvalds #endif 4271da177e4SLinus Torvalds { 4281da177e4SLinus Torvalds regs->gr[25] = A(&frame->info); /* siginfo pointer */ 4291da177e4SLinus Torvalds regs->gr[24] = A(&frame->uc); /* ucontext pointer */ 4301da177e4SLinus Torvalds } 4311da177e4SLinus Torvalds 4321da177e4SLinus Torvalds DBG(1,"setup_rt_frame: making sigreturn frame: %#lx + %#lx = %#lx\n", 4331da177e4SLinus Torvalds regs->gr[30], sigframe_size, 4341da177e4SLinus Torvalds regs->gr[30] + sigframe_size); 4351da177e4SLinus Torvalds /* Raise the user stack pointer to make a proper call frame. */ 4361da177e4SLinus Torvalds regs->gr[30] = (A(frame) + sigframe_size); 4371da177e4SLinus Torvalds 4381da177e4SLinus Torvalds 4391da177e4SLinus Torvalds DBG(1,"setup_rt_frame: sig deliver (%s,%d) frame=0x%p sp=%#lx iaoq=%#lx/%#lx rp=%#lx\n", 4401da177e4SLinus Torvalds current->comm, current->pid, frame, regs->gr[30], 4411da177e4SLinus Torvalds regs->iaoq[0], regs->iaoq[1], rp); 4421da177e4SLinus Torvalds 4431da177e4SLinus Torvalds return 1; 4441da177e4SLinus Torvalds 4451da177e4SLinus Torvalds give_sigsegv: 4461da177e4SLinus Torvalds DBG(1,"setup_rt_frame: sending SIGSEGV\n"); 44740c72f20SRandolph Chung force_sigsegv(sig, current); 4481da177e4SLinus Torvalds return 0; 4491da177e4SLinus Torvalds } 4501da177e4SLinus Torvalds 4511da177e4SLinus Torvalds /* 4521da177e4SLinus Torvalds * OK, we're invoking a handler. 4531da177e4SLinus Torvalds */ 4541da177e4SLinus Torvalds 4551da177e4SLinus Torvalds static long 4561da177e4SLinus Torvalds handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, 4571da177e4SLinus Torvalds sigset_t *oldset, struct pt_regs *regs, int in_syscall) 4581da177e4SLinus Torvalds { 4591da177e4SLinus Torvalds DBG(1,"handle_signal: sig=%ld, ka=%p, info=%p, oldset=%p, regs=%p\n", 4601da177e4SLinus Torvalds sig, ka, info, oldset, regs); 4611da177e4SLinus Torvalds 4621da177e4SLinus Torvalds /* Set up the stack frame */ 4631da177e4SLinus Torvalds if (!setup_rt_frame(sig, ka, info, oldset, regs, in_syscall)) 4641da177e4SLinus Torvalds return 0; 4651da177e4SLinus Torvalds 4661da177e4SLinus Torvalds spin_lock_irq(¤t->sighand->siglock); 4671da177e4SLinus Torvalds sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); 46869be8f18SSteven Rostedt if (!(ka->sa.sa_flags & SA_NODEFER)) 4691da177e4SLinus Torvalds sigaddset(¤t->blocked,sig); 4701da177e4SLinus Torvalds recalc_sigpending(); 4711da177e4SLinus Torvalds spin_unlock_irq(¤t->sighand->siglock); 472*ecf02de5SKyle McMartin 473*ecf02de5SKyle McMartin tracehook_signal_handler(sig, info, ka, regs, 0); 474*ecf02de5SKyle McMartin 4751da177e4SLinus Torvalds return 1; 4761da177e4SLinus Torvalds } 4771da177e4SLinus Torvalds 4782b163b71SKyle McMartin static inline void 4792b163b71SKyle McMartin syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) 4802b163b71SKyle McMartin { 4812b163b71SKyle McMartin /* Check the return code */ 4822b163b71SKyle McMartin switch (regs->gr[28]) { 4832b163b71SKyle McMartin case -ERESTART_RESTARTBLOCK: 4842b163b71SKyle McMartin current_thread_info()->restart_block.fn = 4852b163b71SKyle McMartin do_no_restart_syscall; 4862b163b71SKyle McMartin case -ERESTARTNOHAND: 4872b163b71SKyle McMartin DBG(1,"ERESTARTNOHAND: returning -EINTR\n"); 4882b163b71SKyle McMartin regs->gr[28] = -EINTR; 4892b163b71SKyle McMartin break; 4902b163b71SKyle McMartin 4912b163b71SKyle McMartin case -ERESTARTSYS: 4922b163b71SKyle McMartin if (!(ka->sa.sa_flags & SA_RESTART)) { 4932b163b71SKyle McMartin DBG(1,"ERESTARTSYS: putting -EINTR\n"); 4942b163b71SKyle McMartin regs->gr[28] = -EINTR; 4952b163b71SKyle McMartin break; 4962b163b71SKyle McMartin } 4972b163b71SKyle McMartin /* fallthrough */ 4982b163b71SKyle McMartin case -ERESTARTNOINTR: 4992b163b71SKyle McMartin /* A syscall is just a branch, so all 5002b163b71SKyle McMartin * we have to do is fiddle the return pointer. 5012b163b71SKyle McMartin */ 5022b163b71SKyle McMartin regs->gr[31] -= 8; /* delayed branching */ 5032b163b71SKyle McMartin /* Preserve original r28. */ 5042b163b71SKyle McMartin regs->gr[28] = regs->orig_r28; 5052b163b71SKyle McMartin break; 5062b163b71SKyle McMartin } 5072b163b71SKyle McMartin } 5082b163b71SKyle McMartin 5092b163b71SKyle McMartin static inline void 5102b163b71SKyle McMartin insert_restart_trampoline(struct pt_regs *regs) 5112b163b71SKyle McMartin { 5122b163b71SKyle McMartin switch(regs->gr[28]) { 5132b163b71SKyle McMartin case -ERESTART_RESTARTBLOCK: { 5142b163b71SKyle McMartin /* Restart the system call - no handlers present */ 5152b163b71SKyle McMartin unsigned int *usp = (unsigned int *)regs->gr[30]; 5162b163b71SKyle McMartin 5172b163b71SKyle McMartin /* Setup a trampoline to restart the syscall 5182b163b71SKyle McMartin * with __NR_restart_syscall 5192b163b71SKyle McMartin * 5202b163b71SKyle McMartin * 0: <return address (orig r31)> 5212b163b71SKyle McMartin * 4: <2nd half for 64-bit> 5222b163b71SKyle McMartin * 8: ldw 0(%sp), %r31 5232b163b71SKyle McMartin * 12: be 0x100(%sr2, %r0) 5242b163b71SKyle McMartin * 16: ldi __NR_restart_syscall, %r20 5252b163b71SKyle McMartin */ 5262b163b71SKyle McMartin #ifdef CONFIG_64BIT 5272b163b71SKyle McMartin put_user(regs->gr[31] >> 32, &usp[0]); 5282b163b71SKyle McMartin put_user(regs->gr[31] & 0xffffffff, &usp[1]); 5292b163b71SKyle McMartin put_user(0x0fc010df, &usp[2]); 5302b163b71SKyle McMartin #else 5312b163b71SKyle McMartin put_user(regs->gr[31], &usp[0]); 5322b163b71SKyle McMartin put_user(0x0fc0109f, &usp[2]); 5332b163b71SKyle McMartin #endif 5342b163b71SKyle McMartin put_user(0xe0008200, &usp[3]); 5352b163b71SKyle McMartin put_user(0x34140000, &usp[4]); 5362b163b71SKyle McMartin 5372b163b71SKyle McMartin /* Stack is 64-byte aligned, and we only need 5382b163b71SKyle McMartin * to flush 1 cache line. 5392b163b71SKyle McMartin * Flushing one cacheline is cheap. 5402b163b71SKyle McMartin * "sync" on bigger (> 4 way) boxes is not. 5412b163b71SKyle McMartin */ 542cf39cc3bSKyle McMartin flush_user_dcache_range(regs->gr[30], regs->gr[30] + 4); 543cf39cc3bSKyle McMartin flush_user_icache_range(regs->gr[30], regs->gr[30] + 4); 5442b163b71SKyle McMartin 5452b163b71SKyle McMartin regs->gr[31] = regs->gr[30] + 8; 5462b163b71SKyle McMartin /* Preserve original r28. */ 5472b163b71SKyle McMartin regs->gr[28] = regs->orig_r28; 5482b163b71SKyle McMartin 5492b163b71SKyle McMartin return; 5502b163b71SKyle McMartin } 5512b163b71SKyle McMartin case -ERESTARTNOHAND: 5522b163b71SKyle McMartin case -ERESTARTSYS: 5532b163b71SKyle McMartin case -ERESTARTNOINTR: { 5542b163b71SKyle McMartin /* Hooray for delayed branching. We don't 5552b163b71SKyle McMartin * have to restore %r20 (the system call 5562b163b71SKyle McMartin * number) because it gets loaded in the delay 5572b163b71SKyle McMartin * slot of the branch external instruction. 5582b163b71SKyle McMartin */ 5592b163b71SKyle McMartin regs->gr[31] -= 8; 5602b163b71SKyle McMartin /* Preserve original r28. */ 5612b163b71SKyle McMartin regs->gr[28] = regs->orig_r28; 5622b163b71SKyle McMartin 5632b163b71SKyle McMartin return; 5642b163b71SKyle McMartin } 5652b163b71SKyle McMartin default: 5662b163b71SKyle McMartin break; 5672b163b71SKyle McMartin } 5682b163b71SKyle McMartin } 5692b163b71SKyle McMartin 5701da177e4SLinus Torvalds /* 5711da177e4SLinus Torvalds * Note that 'init' is a special process: it doesn't get signals it doesn't 5721da177e4SLinus Torvalds * want to handle. Thus you cannot kill init even with a SIGKILL even by 5731da177e4SLinus Torvalds * mistake. 5741da177e4SLinus Torvalds * 5751da177e4SLinus Torvalds * We need to be able to restore the syscall arguments (r21-r26) to 5761da177e4SLinus Torvalds * restart syscalls. Thus, the syscall path should save them in the 5771da177e4SLinus Torvalds * pt_regs structure (it's okay to do so since they are caller-save 5781da177e4SLinus Torvalds * registers). As noted below, the syscall number gets restored for 5791da177e4SLinus Torvalds * us due to the magic of delayed branching. 5801da177e4SLinus Torvalds */ 5814650f0a5SKyle McMartin asmlinkage void 5824650f0a5SKyle McMartin do_signal(struct pt_regs *regs, long in_syscall) 5831da177e4SLinus Torvalds { 5841da177e4SLinus Torvalds siginfo_t info; 5851da177e4SLinus Torvalds struct k_sigaction ka; 5861da177e4SLinus Torvalds int signr; 5874650f0a5SKyle McMartin sigset_t *oldset; 5881da177e4SLinus Torvalds 5891da177e4SLinus Torvalds DBG(1,"\ndo_signal: oldset=0x%p, regs=0x%p, sr7 %#lx, in_syscall=%d\n", 5901da177e4SLinus Torvalds oldset, regs, regs->sr[7], in_syscall); 5911da177e4SLinus Torvalds 5921da177e4SLinus Torvalds /* Everyone else checks to see if they are in kernel mode at 5931da177e4SLinus Torvalds this point and exits if that's the case. I'm not sure why 5941da177e4SLinus Torvalds we would be called in that case, but for some reason we 5951da177e4SLinus Torvalds are. */ 5961da177e4SLinus Torvalds 5974650f0a5SKyle McMartin if (test_thread_flag(TIF_RESTORE_SIGMASK)) 5984650f0a5SKyle McMartin oldset = ¤t->saved_sigmask; 5994650f0a5SKyle McMartin else 6001da177e4SLinus Torvalds oldset = ¤t->blocked; 6011da177e4SLinus Torvalds 6021da177e4SLinus Torvalds DBG(1,"do_signal: oldset %08lx / %08lx\n", 6031da177e4SLinus Torvalds oldset->sig[0], oldset->sig[1]); 6041da177e4SLinus Torvalds 6051da177e4SLinus Torvalds 6061da177e4SLinus Torvalds /* May need to force signal if handle_signal failed to deliver */ 6071da177e4SLinus Torvalds while (1) { 6081da177e4SLinus Torvalds 6091da177e4SLinus Torvalds signr = get_signal_to_deliver(&info, &ka, regs, NULL); 6101da177e4SLinus Torvalds DBG(3,"do_signal: signr = %d, regs->gr[28] = %ld\n", signr, regs->gr[28]); 6111da177e4SLinus Torvalds 6121da177e4SLinus Torvalds if (signr <= 0) 6131da177e4SLinus Torvalds break; 6141da177e4SLinus Torvalds 6151da177e4SLinus Torvalds /* Restart a system call if necessary. */ 6162b163b71SKyle McMartin if (in_syscall) 6172b163b71SKyle McMartin syscall_restart(regs, &ka); 6181da177e4SLinus Torvalds 6191da177e4SLinus Torvalds /* Whee! Actually deliver the signal. If the 6201da177e4SLinus Torvalds delivery failed, we need to continue to iterate in 6211da177e4SLinus Torvalds this loop so we can deliver the SIGSEGV... */ 6222b163b71SKyle McMartin if (handle_signal(signr, &info, &ka, oldset, 6232b163b71SKyle McMartin regs, in_syscall)) { 6241da177e4SLinus Torvalds DBG(1,KERN_DEBUG "do_signal: Exit (success), regs->gr[28] = %ld\n", 6251da177e4SLinus Torvalds regs->gr[28]); 6264650f0a5SKyle McMartin if (test_thread_flag(TIF_RESTORE_SIGMASK)) 6274650f0a5SKyle McMartin clear_thread_flag(TIF_RESTORE_SIGMASK); 6284650f0a5SKyle McMartin return; 6291da177e4SLinus Torvalds } 6301da177e4SLinus Torvalds } 6311da177e4SLinus Torvalds /* end of while(1) looping forever if we can't force a signal */ 6321da177e4SLinus Torvalds 6331da177e4SLinus Torvalds /* Did we come from a system call? */ 6342b163b71SKyle McMartin if (in_syscall) 6352b163b71SKyle McMartin insert_restart_trampoline(regs); 6361da177e4SLinus Torvalds 6371da177e4SLinus Torvalds DBG(1,"do_signal: Exit (not delivered), regs->gr[28] = %ld\n", 6381da177e4SLinus Torvalds regs->gr[28]); 6391da177e4SLinus Torvalds 6404650f0a5SKyle McMartin if (test_thread_flag(TIF_RESTORE_SIGMASK)) { 6414650f0a5SKyle McMartin clear_thread_flag(TIF_RESTORE_SIGMASK); 6424650f0a5SKyle McMartin sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); 6434650f0a5SKyle McMartin } 6444650f0a5SKyle McMartin 6454650f0a5SKyle McMartin return; 6464650f0a5SKyle McMartin } 6474650f0a5SKyle McMartin 6484650f0a5SKyle McMartin void do_notify_resume(struct pt_regs *regs, long in_syscall) 6494650f0a5SKyle McMartin { 6504650f0a5SKyle McMartin if (test_thread_flag(TIF_SIGPENDING) || 6514650f0a5SKyle McMartin test_thread_flag(TIF_RESTORE_SIGMASK)) 6524650f0a5SKyle McMartin do_signal(regs, in_syscall); 653d0420c83SDavid Howells 654d0420c83SDavid Howells if (test_thread_flag(TIF_NOTIFY_RESUME)) { 655d0420c83SDavid Howells clear_thread_flag(TIF_NOTIFY_RESUME); 656d0420c83SDavid Howells tracehook_notify_resume(regs); 657ee18d64cSDavid Howells if (current->replacement_session_keyring) 658ee18d64cSDavid Howells key_replace_session_keyring(); 659d0420c83SDavid Howells } 6601da177e4SLinus Torvalds } 661