1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * linux/arch/parisc/kernel/signal.c: Architecture-specific signal 41da177e4SLinus Torvalds * handling support. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Copyright (C) 2000 David Huggins-Daines <dhd@debian.org> 71da177e4SLinus Torvalds * Copyright (C) 2000 Linuxcare, Inc. 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * Based on the ia64, i386, and alpha versions. 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds * Like the IA-64, we are a recent enough port (we are *starting* 121da177e4SLinus Torvalds * with glibc2.2) that we do not need to support the old non-realtime 13c78c2b7eSHelge Deller * Linux signals. Therefore we don't. 141da177e4SLinus Torvalds */ 151da177e4SLinus Torvalds 161da177e4SLinus Torvalds #include <linux/sched.h> 17b17b0153SIngo Molnar #include <linux/sched/debug.h> 181da177e4SLinus Torvalds #include <linux/mm.h> 191da177e4SLinus Torvalds #include <linux/smp.h> 201da177e4SLinus Torvalds #include <linux/kernel.h> 211da177e4SLinus Torvalds #include <linux/signal.h> 221da177e4SLinus Torvalds #include <linux/errno.h> 231da177e4SLinus Torvalds #include <linux/wait.h> 241da177e4SLinus Torvalds #include <linux/ptrace.h> 25ecf02de5SKyle McMartin #include <linux/tracehook.h> 261da177e4SLinus Torvalds #include <linux/unistd.h> 271da177e4SLinus Torvalds #include <linux/stddef.h> 281da177e4SLinus Torvalds #include <linux/compat.h> 291da177e4SLinus Torvalds #include <linux/elf.h> 301da177e4SLinus Torvalds #include <asm/ucontext.h> 311da177e4SLinus Torvalds #include <asm/rt_sigframe.h> 327c0f6ba6SLinus Torvalds #include <linux/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 "signal32.h" 391da177e4SLinus Torvalds #endif 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds #define DEBUG_SIG 0 421da177e4SLinus Torvalds #define DEBUG_SIG_LEVEL 2 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds #if DEBUG_SIG 451da177e4SLinus Torvalds #define DBG(LEVEL, ...) \ 461da177e4SLinus Torvalds ((DEBUG_SIG_LEVEL >= LEVEL) \ 471da177e4SLinus Torvalds ? printk(__VA_ARGS__) : (void) 0) 481da177e4SLinus Torvalds #else 491da177e4SLinus Torvalds #define DBG(LEVEL, ...) 501da177e4SLinus Torvalds #endif 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds /* gcc will complain if a pointer is cast to an integer of different 531da177e4SLinus Torvalds * size. If you really need to do this (and we do for an ELF32 user 541da177e4SLinus Torvalds * application in an ELF64 kernel) then you have to do a cast to an 551da177e4SLinus Torvalds * integer of the same size first. The A() macro accomplishes 561da177e4SLinus Torvalds * this. */ 571da177e4SLinus Torvalds #define A(__x) ((unsigned long)(__x)) 581da177e4SLinus Torvalds 591da177e4SLinus Torvalds /* 601da177e4SLinus Torvalds * Do a signal return - restore sigcontext. 611da177e4SLinus Torvalds */ 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds /* Trampoline for calling rt_sigreturn() */ 641da177e4SLinus Torvalds #define INSN_LDI_R25_0 0x34190000 /* ldi 0,%r25 (in_syscall=0) */ 651da177e4SLinus Torvalds #define INSN_LDI_R25_1 0x34190002 /* ldi 1,%r25 (in_syscall=1) */ 661da177e4SLinus Torvalds #define INSN_LDI_R20 0x3414015a /* ldi __NR_rt_sigreturn,%r20 */ 671da177e4SLinus Torvalds #define INSN_BLE_SR2_R0 0xe4008200 /* be,l 0x100(%sr2,%r0),%sr0,%r31 */ 681da177e4SLinus Torvalds /* For debugging */ 691da177e4SLinus Torvalds #define INSN_DIE_HORRIBLY 0x68000ccc /* stw %r0,0x666(%sr0,%r0) */ 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds static long 721da177e4SLinus Torvalds restore_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs) 731da177e4SLinus Torvalds { 741da177e4SLinus Torvalds long err = 0; 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds err |= __copy_from_user(regs->gr, sc->sc_gr, sizeof(regs->gr)); 771da177e4SLinus Torvalds err |= __copy_from_user(regs->fr, sc->sc_fr, sizeof(regs->fr)); 781da177e4SLinus Torvalds err |= __copy_from_user(regs->iaoq, sc->sc_iaoq, sizeof(regs->iaoq)); 791da177e4SLinus Torvalds err |= __copy_from_user(regs->iasq, sc->sc_iasq, sizeof(regs->iasq)); 801da177e4SLinus Torvalds err |= __get_user(regs->sar, &sc->sc_sar); 818e33a52fSJoe Perches DBG(2,"restore_sigcontext: iaoq is %#lx / %#lx\n", 821da177e4SLinus Torvalds regs->iaoq[0],regs->iaoq[1]); 831da177e4SLinus Torvalds DBG(2,"restore_sigcontext: r28 is %ld\n", regs->gr[28]); 841da177e4SLinus Torvalds return err; 851da177e4SLinus Torvalds } 861da177e4SLinus Torvalds 871da177e4SLinus Torvalds void 881da177e4SLinus Torvalds sys_rt_sigreturn(struct pt_regs *regs, int in_syscall) 891da177e4SLinus Torvalds { 901da177e4SLinus Torvalds struct rt_sigframe __user *frame; 911da177e4SLinus Torvalds sigset_t set; 921da177e4SLinus Torvalds unsigned long usp = (regs->gr[30] & ~(0x01UL)); 931da177e4SLinus Torvalds unsigned long sigframe_size = PARISC_RT_SIGFRAME_SIZE; 94a8f44e38SHelge Deller #ifdef CONFIG_64BIT 951da177e4SLinus Torvalds struct compat_rt_sigframe __user * compat_frame; 961da177e4SLinus Torvalds 97a3ea84faSKyle McMartin if (is_compat_task()) 981da177e4SLinus Torvalds sigframe_size = PARISC_RT_SIGFRAME_SIZE32; 991da177e4SLinus Torvalds #endif 1001da177e4SLinus Torvalds 101f56141e3SAndy Lutomirski current->restart_block.fn = do_no_restart_syscall; 1021da177e4SLinus Torvalds 1031da177e4SLinus Torvalds /* Unwind the user stack to get the rt_sigframe structure. */ 1041da177e4SLinus Torvalds frame = (struct rt_sigframe __user *) 1051da177e4SLinus Torvalds (usp - sigframe_size); 1061da177e4SLinus Torvalds DBG(2,"sys_rt_sigreturn: frame is %p\n", frame); 1071da177e4SLinus Torvalds 10800df111eSAl Viro regs->orig_r28 = 1; /* no restarts for sigreturn */ 10900df111eSAl Viro 110a8f44e38SHelge Deller #ifdef CONFIG_64BIT 1111da177e4SLinus Torvalds compat_frame = (struct compat_rt_sigframe __user *)frame; 1121da177e4SLinus Torvalds 113a3ea84faSKyle McMartin if (is_compat_task()) { 1141da177e4SLinus Torvalds DBG(2,"sys_rt_sigreturn: ELF32 process.\n"); 115d74f0f47SAl Viro if (get_compat_sigset(&set, &compat_frame->uc.uc_sigmask)) 1161da177e4SLinus Torvalds goto give_sigsegv; 1171da177e4SLinus Torvalds } else 1181da177e4SLinus Torvalds #endif 1191da177e4SLinus Torvalds { 1201da177e4SLinus Torvalds if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) 1211da177e4SLinus Torvalds goto give_sigsegv; 1221da177e4SLinus Torvalds } 1231da177e4SLinus Torvalds 124ade7728bSMatt Fleming set_current_blocked(&set); 1251da177e4SLinus Torvalds 1261da177e4SLinus Torvalds /* Good thing we saved the old gr[30], eh? */ 127a8f44e38SHelge Deller #ifdef CONFIG_64BIT 128a3ea84faSKyle McMartin if (is_compat_task()) { 1291da177e4SLinus Torvalds DBG(1,"sys_rt_sigreturn: compat_frame->uc.uc_mcontext 0x%p\n", 1301da177e4SLinus Torvalds &compat_frame->uc.uc_mcontext); 1311da177e4SLinus Torvalds // FIXME: Load upper half from register file 1321da177e4SLinus Torvalds if (restore_sigcontext32(&compat_frame->uc.uc_mcontext, 1331da177e4SLinus Torvalds &compat_frame->regs, regs)) 1341da177e4SLinus Torvalds goto give_sigsegv; 1351da177e4SLinus Torvalds DBG(1,"sys_rt_sigreturn: usp %#08lx stack 0x%p\n", 1361da177e4SLinus Torvalds usp, &compat_frame->uc.uc_stack); 1376e26aab9SAl Viro if (compat_restore_altstack(&compat_frame->uc.uc_stack)) 1381da177e4SLinus Torvalds goto give_sigsegv; 1391da177e4SLinus Torvalds } else 1401da177e4SLinus Torvalds #endif 1411da177e4SLinus Torvalds { 1421da177e4SLinus Torvalds DBG(1,"sys_rt_sigreturn: frame->uc.uc_mcontext 0x%p\n", 1431da177e4SLinus Torvalds &frame->uc.uc_mcontext); 1441da177e4SLinus Torvalds if (restore_sigcontext(&frame->uc.uc_mcontext, regs)) 1451da177e4SLinus Torvalds goto give_sigsegv; 1461da177e4SLinus Torvalds DBG(1,"sys_rt_sigreturn: usp %#08lx stack 0x%p\n", 1471da177e4SLinus Torvalds usp, &frame->uc.uc_stack); 1486e26aab9SAl Viro if (restore_altstack(&frame->uc.uc_stack)) 1491da177e4SLinus Torvalds goto give_sigsegv; 1501da177e4SLinus Torvalds } 1511da177e4SLinus Torvalds 1521da177e4SLinus Torvalds 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds /* If we are on the syscall path IAOQ will not be restored, and 1551da177e4SLinus Torvalds * if we are on the interrupt path we must not corrupt gr31. 1561da177e4SLinus Torvalds */ 1571da177e4SLinus Torvalds if (in_syscall) 1581da177e4SLinus Torvalds regs->gr[31] = regs->iaoq[0]; 1591da177e4SLinus Torvalds #if DEBUG_SIG 1601da177e4SLinus Torvalds DBG(1,"sys_rt_sigreturn: returning to %#lx, DUMPING REGS:\n", regs->iaoq[0]); 1611da177e4SLinus Torvalds show_regs(regs); 1621da177e4SLinus Torvalds #endif 1631da177e4SLinus Torvalds return; 1641da177e4SLinus Torvalds 1651da177e4SLinus Torvalds give_sigsegv: 1661da177e4SLinus Torvalds DBG(1,"sys_rt_sigreturn: Sending SIGSEGV\n"); 167*3cf5d076SEric W. Biederman force_sig(SIGSEGV); 1681da177e4SLinus Torvalds return; 1691da177e4SLinus Torvalds } 1701da177e4SLinus Torvalds 1711da177e4SLinus Torvalds /* 1721da177e4SLinus Torvalds * Set up a signal frame. 1731da177e4SLinus Torvalds */ 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds static inline void __user * 1761da177e4SLinus Torvalds get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) 1771da177e4SLinus Torvalds { 1781da177e4SLinus Torvalds /*FIXME: ELF32 vs. ELF64 has different frame_size, but since we 1791da177e4SLinus Torvalds don't use the parameter it doesn't matter */ 1801da177e4SLinus Torvalds 1811da177e4SLinus Torvalds DBG(1,"get_sigframe: ka = %#lx, sp = %#lx, frame_size = %#lx\n", 1821da177e4SLinus Torvalds (unsigned long)ka, sp, frame_size); 1831da177e4SLinus Torvalds 184ad30f3ffSJohn David Anglin /* Align alternate stack and reserve 64 bytes for the signal 185ad30f3ffSJohn David Anglin handler's frame marker. */ 186d09042daSLaurent MEYER if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! sas_ss_flags(sp)) 187ad30f3ffSJohn David Anglin sp = (current->sas_ss_sp + 0x7f) & ~0x3f; /* Stacks grow up! */ 1881da177e4SLinus Torvalds 1891da177e4SLinus Torvalds DBG(1,"get_sigframe: Returning sp = %#lx\n", (unsigned long)sp); 1901da177e4SLinus Torvalds return (void __user *) sp; /* Stacks grow up. Fun. */ 1911da177e4SLinus Torvalds } 1921da177e4SLinus Torvalds 1931da177e4SLinus Torvalds static long 1941da177e4SLinus Torvalds setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, int in_syscall) 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds { 1971da177e4SLinus Torvalds unsigned long flags = 0; 1981da177e4SLinus Torvalds long err = 0; 1991da177e4SLinus Torvalds 2001da177e4SLinus Torvalds if (on_sig_stack((unsigned long) sc)) 2011da177e4SLinus Torvalds flags |= PARISC_SC_FLAG_ONSTACK; 2021da177e4SLinus Torvalds if (in_syscall) { 2031da177e4SLinus Torvalds flags |= PARISC_SC_FLAG_IN_SYSCALL; 2041da177e4SLinus Torvalds /* regs->iaoq is undefined in the syscall return path */ 2051da177e4SLinus Torvalds err |= __put_user(regs->gr[31], &sc->sc_iaoq[0]); 2061da177e4SLinus Torvalds err |= __put_user(regs->gr[31]+4, &sc->sc_iaoq[1]); 2071da177e4SLinus Torvalds err |= __put_user(regs->sr[3], &sc->sc_iasq[0]); 2081da177e4SLinus Torvalds err |= __put_user(regs->sr[3], &sc->sc_iasq[1]); 2091da177e4SLinus Torvalds DBG(1,"setup_sigcontext: iaoq %#lx / %#lx (in syscall)\n", 2101da177e4SLinus Torvalds regs->gr[31], regs->gr[31]+4); 2111da177e4SLinus Torvalds } else { 2121da177e4SLinus Torvalds err |= __copy_to_user(sc->sc_iaoq, regs->iaoq, sizeof(regs->iaoq)); 2131da177e4SLinus Torvalds err |= __copy_to_user(sc->sc_iasq, regs->iasq, sizeof(regs->iasq)); 2141da177e4SLinus Torvalds DBG(1,"setup_sigcontext: iaoq %#lx / %#lx (not in syscall)\n", 2151da177e4SLinus Torvalds regs->iaoq[0], regs->iaoq[1]); 2161da177e4SLinus Torvalds } 2171da177e4SLinus Torvalds 2181da177e4SLinus Torvalds err |= __put_user(flags, &sc->sc_flags); 2191da177e4SLinus Torvalds err |= __copy_to_user(sc->sc_gr, regs->gr, sizeof(regs->gr)); 2201da177e4SLinus Torvalds err |= __copy_to_user(sc->sc_fr, regs->fr, sizeof(regs->fr)); 2211da177e4SLinus Torvalds err |= __put_user(regs->sar, &sc->sc_sar); 2221da177e4SLinus Torvalds DBG(1,"setup_sigcontext: r28 is %ld\n", regs->gr[28]); 2231da177e4SLinus Torvalds 2241da177e4SLinus Torvalds return err; 2251da177e4SLinus Torvalds } 2261da177e4SLinus Torvalds 2271da177e4SLinus Torvalds static long 228e4dc894bSRichard Weinberger setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs, 229e4dc894bSRichard Weinberger int in_syscall) 2301da177e4SLinus Torvalds { 2311da177e4SLinus Torvalds struct rt_sigframe __user *frame; 2321da177e4SLinus Torvalds unsigned long rp, usp; 2331da177e4SLinus Torvalds unsigned long haddr, sigframe_size; 234ef470a60SJohn David Anglin unsigned long start, end; 2351da177e4SLinus Torvalds int err = 0; 236a8f44e38SHelge Deller #ifdef CONFIG_64BIT 2371da177e4SLinus Torvalds struct compat_rt_sigframe __user * compat_frame; 2381da177e4SLinus Torvalds #endif 2391da177e4SLinus Torvalds 2401da177e4SLinus Torvalds usp = (regs->gr[30] & ~(0x01UL)); 2411da177e4SLinus Torvalds /*FIXME: frame_size parameter is unused, remove it. */ 242e4dc894bSRichard Weinberger frame = get_sigframe(&ksig->ka, usp, sizeof(*frame)); 2431da177e4SLinus Torvalds 2441da177e4SLinus Torvalds DBG(1,"SETUP_RT_FRAME: START\n"); 245e4dc894bSRichard Weinberger DBG(1,"setup_rt_frame: frame %p info %p\n", frame, ksig->info); 2461da177e4SLinus Torvalds 2471da177e4SLinus Torvalds 248a8f44e38SHelge Deller #ifdef CONFIG_64BIT 2491da177e4SLinus Torvalds 2501da177e4SLinus Torvalds compat_frame = (struct compat_rt_sigframe __user *)frame; 2511da177e4SLinus Torvalds 252a3ea84faSKyle McMartin if (is_compat_task()) { 2531da177e4SLinus Torvalds DBG(1,"setup_rt_frame: frame->info = 0x%p\n", &compat_frame->info); 254e4dc894bSRichard Weinberger err |= copy_siginfo_to_user32(&compat_frame->info, &ksig->info); 2556e26aab9SAl Viro err |= __compat_save_altstack( &compat_frame->uc.uc_stack, regs->gr[30]); 2561da177e4SLinus Torvalds DBG(1,"setup_rt_frame: frame->uc = 0x%p\n", &compat_frame->uc); 2571da177e4SLinus Torvalds DBG(1,"setup_rt_frame: frame->uc.uc_mcontext = 0x%p\n", &compat_frame->uc.uc_mcontext); 2581da177e4SLinus Torvalds err |= setup_sigcontext32(&compat_frame->uc.uc_mcontext, 2591da177e4SLinus Torvalds &compat_frame->regs, regs, in_syscall); 260d74f0f47SAl Viro err |= put_compat_sigset(&compat_frame->uc.uc_sigmask, set, 261d74f0f47SAl Viro sizeof(compat_sigset_t)); 2621da177e4SLinus Torvalds } else 2631da177e4SLinus Torvalds #endif 2641da177e4SLinus Torvalds { 2651da177e4SLinus Torvalds DBG(1,"setup_rt_frame: frame->info = 0x%p\n", &frame->info); 266e4dc894bSRichard Weinberger err |= copy_siginfo_to_user(&frame->info, &ksig->info); 2676e26aab9SAl Viro err |= __save_altstack(&frame->uc.uc_stack, regs->gr[30]); 2681da177e4SLinus Torvalds DBG(1,"setup_rt_frame: frame->uc = 0x%p\n", &frame->uc); 2691da177e4SLinus Torvalds DBG(1,"setup_rt_frame: frame->uc.uc_mcontext = 0x%p\n", &frame->uc.uc_mcontext); 2701da177e4SLinus Torvalds err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, in_syscall); 2711da177e4SLinus Torvalds /* FIXME: Should probably be converted as well for the compat case */ 2721da177e4SLinus Torvalds err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); 2731da177e4SLinus Torvalds } 2741da177e4SLinus Torvalds 2751da177e4SLinus Torvalds if (err) 276e4dc894bSRichard Weinberger return -EFAULT; 2771da177e4SLinus Torvalds 2781da177e4SLinus Torvalds /* Set up to return from userspace. If provided, use a stub 2791da177e4SLinus Torvalds already in userspace. The first words of tramp are used to 2801da177e4SLinus Torvalds save the previous sigrestartblock trampoline that might be 2811da177e4SLinus Torvalds on the stack. We start the sigreturn trampoline at 2821da177e4SLinus Torvalds SIGRESTARTBLOCK_TRAMP+X. */ 2831da177e4SLinus Torvalds err |= __put_user(in_syscall ? INSN_LDI_R25_1 : INSN_LDI_R25_0, 2841da177e4SLinus Torvalds &frame->tramp[SIGRESTARTBLOCK_TRAMP+0]); 2851da177e4SLinus Torvalds err |= __put_user(INSN_LDI_R20, 2861da177e4SLinus Torvalds &frame->tramp[SIGRESTARTBLOCK_TRAMP+1]); 2871da177e4SLinus Torvalds err |= __put_user(INSN_BLE_SR2_R0, 2881da177e4SLinus Torvalds &frame->tramp[SIGRESTARTBLOCK_TRAMP+2]); 2891da177e4SLinus Torvalds err |= __put_user(INSN_NOP, &frame->tramp[SIGRESTARTBLOCK_TRAMP+3]); 2901da177e4SLinus Torvalds 2911da177e4SLinus Torvalds #if DEBUG_SIG 2921da177e4SLinus Torvalds /* Assert that we're flushing in the correct space... */ 2931da177e4SLinus Torvalds { 29445b6eff2SJohn David Anglin unsigned long sid; 2951da177e4SLinus Torvalds asm ("mfsp %%sr3,%0" : "=r" (sid)); 2961da177e4SLinus Torvalds DBG(1,"setup_rt_frame: Flushing 64 bytes at space %#x offset %p\n", 2971da177e4SLinus Torvalds sid, frame->tramp); 2981da177e4SLinus Torvalds } 2991da177e4SLinus Torvalds #endif 3001da177e4SLinus Torvalds 301ef470a60SJohn David Anglin start = (unsigned long) &frame->tramp[0]; 302ef470a60SJohn David Anglin end = (unsigned long) &frame->tramp[TRAMP_SIZE]; 303ef470a60SJohn David Anglin flush_user_dcache_range_asm(start, end); 304ef470a60SJohn David Anglin flush_user_icache_range_asm(start, end); 3051da177e4SLinus Torvalds 306efad798bSPaulius Zaleckas /* TRAMP Words 0-4, Length 5 = SIGRESTARTBLOCK_TRAMP 3071da177e4SLinus Torvalds * TRAMP Words 5-9, Length 4 = SIGRETURN_TRAMP 3081da177e4SLinus Torvalds * So the SIGRETURN_TRAMP is at the end of SIGRESTARTBLOCK_TRAMP 3091da177e4SLinus Torvalds */ 3101da177e4SLinus Torvalds rp = (unsigned long) &frame->tramp[SIGRESTARTBLOCK_TRAMP]; 3111da177e4SLinus Torvalds 3121da177e4SLinus Torvalds if (err) 313e4dc894bSRichard Weinberger return -EFAULT; 3141da177e4SLinus Torvalds 315e4dc894bSRichard Weinberger haddr = A(ksig->ka.sa.sa_handler); 3161da177e4SLinus Torvalds /* The sa_handler may be a pointer to a function descriptor */ 317a8f44e38SHelge Deller #ifdef CONFIG_64BIT 318a3ea84faSKyle McMartin if (is_compat_task()) { 3191da177e4SLinus Torvalds #endif 3201da177e4SLinus Torvalds if (haddr & PA_PLABEL_FDESC) { 3211da177e4SLinus Torvalds Elf32_Fdesc fdesc; 3221da177e4SLinus Torvalds Elf32_Fdesc __user *ufdesc = (Elf32_Fdesc __user *)A(haddr & ~3); 3231da177e4SLinus Torvalds 3241da177e4SLinus Torvalds err = __copy_from_user(&fdesc, ufdesc, sizeof(fdesc)); 3251da177e4SLinus Torvalds 3261da177e4SLinus Torvalds if (err) 327e4dc894bSRichard Weinberger return -EFAULT; 3281da177e4SLinus Torvalds 3291da177e4SLinus Torvalds haddr = fdesc.addr; 3301da177e4SLinus Torvalds regs->gr[19] = fdesc.gp; 3311da177e4SLinus Torvalds } 332a8f44e38SHelge Deller #ifdef CONFIG_64BIT 3331da177e4SLinus Torvalds } else { 3341da177e4SLinus Torvalds Elf64_Fdesc fdesc; 3351da177e4SLinus Torvalds Elf64_Fdesc __user *ufdesc = (Elf64_Fdesc __user *)A(haddr & ~3); 3361da177e4SLinus Torvalds 3371da177e4SLinus Torvalds err = __copy_from_user(&fdesc, ufdesc, sizeof(fdesc)); 3381da177e4SLinus Torvalds 3391da177e4SLinus Torvalds if (err) 340e4dc894bSRichard Weinberger return -EFAULT; 3411da177e4SLinus Torvalds 3421da177e4SLinus Torvalds haddr = fdesc.addr; 3431da177e4SLinus Torvalds regs->gr[19] = fdesc.gp; 3441da177e4SLinus Torvalds DBG(1,"setup_rt_frame: 64 bit signal, exe=%#lx, r19=%#lx, in_syscall=%d\n", 3451da177e4SLinus Torvalds haddr, regs->gr[19], in_syscall); 3461da177e4SLinus Torvalds } 3471da177e4SLinus Torvalds #endif 3481da177e4SLinus Torvalds 3491da177e4SLinus Torvalds /* The syscall return path will create IAOQ values from r31. 3501da177e4SLinus Torvalds */ 3511da177e4SLinus Torvalds sigframe_size = PARISC_RT_SIGFRAME_SIZE; 352a8f44e38SHelge Deller #ifdef CONFIG_64BIT 353a3ea84faSKyle McMartin if (is_compat_task()) 3541da177e4SLinus Torvalds sigframe_size = PARISC_RT_SIGFRAME_SIZE32; 3551da177e4SLinus Torvalds #endif 3561da177e4SLinus Torvalds if (in_syscall) { 3571da177e4SLinus Torvalds regs->gr[31] = haddr; 358a8f44e38SHelge Deller #ifdef CONFIG_64BIT 359df570b9cSKyle McMartin if (!test_thread_flag(TIF_32BIT)) 3601da177e4SLinus Torvalds sigframe_size |= 1; 3611da177e4SLinus Torvalds #endif 3621da177e4SLinus Torvalds } else { 3631da177e4SLinus Torvalds unsigned long psw = USER_PSW; 364a8f44e38SHelge Deller #ifdef CONFIG_64BIT 365df570b9cSKyle McMartin if (!test_thread_flag(TIF_32BIT)) 3661da177e4SLinus Torvalds psw |= PSW_W; 3671da177e4SLinus Torvalds #endif 3681da177e4SLinus Torvalds 3691da177e4SLinus Torvalds /* If we are singlestepping, arrange a trap to be delivered 3701da177e4SLinus Torvalds when we return to userspace. Note the semantics -- we 3711da177e4SLinus Torvalds should trap before the first insn in the handler is 3721da177e4SLinus Torvalds executed. Ref: 3731da177e4SLinus Torvalds http://sources.redhat.com/ml/gdb/2004-11/msg00245.html 3741da177e4SLinus Torvalds */ 3751da177e4SLinus Torvalds if (pa_psw(current)->r) { 3761da177e4SLinus Torvalds pa_psw(current)->r = 0; 3771da177e4SLinus Torvalds psw |= PSW_R; 3781da177e4SLinus Torvalds mtctl(-1, 0); 3791da177e4SLinus Torvalds } 3801da177e4SLinus Torvalds 3811da177e4SLinus Torvalds regs->gr[0] = psw; 3821da177e4SLinus Torvalds regs->iaoq[0] = haddr | 3; 3831da177e4SLinus Torvalds regs->iaoq[1] = regs->iaoq[0] + 4; 3841da177e4SLinus Torvalds } 3851da177e4SLinus Torvalds 3861da177e4SLinus Torvalds regs->gr[2] = rp; /* userland return pointer */ 387e4dc894bSRichard Weinberger regs->gr[26] = ksig->sig; /* signal number */ 3881da177e4SLinus Torvalds 389a8f44e38SHelge Deller #ifdef CONFIG_64BIT 390a3ea84faSKyle McMartin if (is_compat_task()) { 3911da177e4SLinus Torvalds regs->gr[25] = A(&compat_frame->info); /* siginfo pointer */ 3921da177e4SLinus Torvalds regs->gr[24] = A(&compat_frame->uc); /* ucontext pointer */ 3931da177e4SLinus Torvalds } else 3941da177e4SLinus Torvalds #endif 3951da177e4SLinus Torvalds { 3961da177e4SLinus Torvalds regs->gr[25] = A(&frame->info); /* siginfo pointer */ 3971da177e4SLinus Torvalds regs->gr[24] = A(&frame->uc); /* ucontext pointer */ 3981da177e4SLinus Torvalds } 3991da177e4SLinus Torvalds 4001da177e4SLinus Torvalds DBG(1,"setup_rt_frame: making sigreturn frame: %#lx + %#lx = %#lx\n", 4011da177e4SLinus Torvalds regs->gr[30], sigframe_size, 4021da177e4SLinus Torvalds regs->gr[30] + sigframe_size); 4031da177e4SLinus Torvalds /* Raise the user stack pointer to make a proper call frame. */ 4041da177e4SLinus Torvalds regs->gr[30] = (A(frame) + sigframe_size); 4051da177e4SLinus Torvalds 4061da177e4SLinus Torvalds 4071da177e4SLinus Torvalds DBG(1,"setup_rt_frame: sig deliver (%s,%d) frame=0x%p sp=%#lx iaoq=%#lx/%#lx rp=%#lx\n", 4081da177e4SLinus Torvalds current->comm, current->pid, frame, regs->gr[30], 4091da177e4SLinus Torvalds regs->iaoq[0], regs->iaoq[1], rp); 4101da177e4SLinus Torvalds 4111da177e4SLinus Torvalds return 0; 4121da177e4SLinus Torvalds } 4131da177e4SLinus Torvalds 4141da177e4SLinus Torvalds /* 4151da177e4SLinus Torvalds * OK, we're invoking a handler. 4161da177e4SLinus Torvalds */ 4171da177e4SLinus Torvalds 418e3b880c6SAl Viro static void 419e4dc894bSRichard Weinberger handle_signal(struct ksignal *ksig, struct pt_regs *regs, int in_syscall) 4201da177e4SLinus Torvalds { 421e4dc894bSRichard Weinberger int ret; 422b7f9a11aSAl Viro sigset_t *oldset = sigmask_to_save(); 423e4dc894bSRichard Weinberger 4241da177e4SLinus Torvalds DBG(1,"handle_signal: sig=%ld, ka=%p, info=%p, oldset=%p, regs=%p\n", 425e4dc894bSRichard Weinberger ksig->sig, ksig->ka, ksig->info, oldset, regs); 4261da177e4SLinus Torvalds 4271da177e4SLinus Torvalds /* Set up the stack frame */ 428e4dc894bSRichard Weinberger ret = setup_rt_frame(ksig, oldset, regs, in_syscall); 4291da177e4SLinus Torvalds 430e4dc894bSRichard Weinberger signal_setup_done(ret, ksig, test_thread_flag(TIF_SINGLESTEP) || 43122a8cdd6SKyle McMartin test_thread_flag(TIF_BLOCKSTEP)); 432ecf02de5SKyle McMartin 433a610d6e6SAl Viro DBG(1,KERN_DEBUG "do_signal: Exit (success), regs->gr[28] = %ld\n", 434a610d6e6SAl Viro regs->gr[28]); 4351da177e4SLinus Torvalds } 4361da177e4SLinus Torvalds 43771a71fb5SHelge Deller /* 43871a71fb5SHelge Deller * Check how the syscall number gets loaded into %r20 within 43971a71fb5SHelge Deller * the delay branch in userspace and adjust as needed. 44071a71fb5SHelge Deller */ 44171a71fb5SHelge Deller 44271a71fb5SHelge Deller static void check_syscallno_in_delay_branch(struct pt_regs *regs) 44371a71fb5SHelge Deller { 44471a71fb5SHelge Deller u32 opcode, source_reg; 44571a71fb5SHelge Deller u32 __user *uaddr; 44671a71fb5SHelge Deller int err; 44771a71fb5SHelge Deller 44871a71fb5SHelge Deller /* Usually we don't have to restore %r20 (the system call number) 44971a71fb5SHelge Deller * because it gets loaded in the delay slot of the branch external 45071a71fb5SHelge Deller * instruction via the ldi instruction. 45171a71fb5SHelge Deller * In some cases a register-to-register copy instruction might have 45271a71fb5SHelge Deller * been used instead, in which case we need to copy the syscall 45371a71fb5SHelge Deller * number into the source register before returning to userspace. 45471a71fb5SHelge Deller */ 45571a71fb5SHelge Deller 45671a71fb5SHelge Deller /* A syscall is just a branch, so all we have to do is fiddle the 45771a71fb5SHelge Deller * return pointer so that the ble instruction gets executed again. 45871a71fb5SHelge Deller */ 45971a71fb5SHelge Deller regs->gr[31] -= 8; /* delayed branching */ 46071a71fb5SHelge Deller 46171a71fb5SHelge Deller /* Get assembler opcode of code in delay branch */ 46271a71fb5SHelge Deller uaddr = (unsigned int *) ((regs->gr[31] & ~3) + 4); 46371a71fb5SHelge Deller err = get_user(opcode, uaddr); 46471a71fb5SHelge Deller if (err) 46571a71fb5SHelge Deller return; 46671a71fb5SHelge Deller 46771a71fb5SHelge Deller /* Check if delay branch uses "ldi int,%r20" */ 46871a71fb5SHelge Deller if ((opcode & 0xffff0000) == 0x34140000) 46971a71fb5SHelge Deller return; /* everything ok, just return */ 47071a71fb5SHelge Deller 47171a71fb5SHelge Deller /* Check if delay branch uses "nop" */ 47271a71fb5SHelge Deller if (opcode == INSN_NOP) 47371a71fb5SHelge Deller return; 47471a71fb5SHelge Deller 47571a71fb5SHelge Deller /* Check if delay branch uses "copy %rX,%r20" */ 47671a71fb5SHelge Deller if ((opcode & 0xffe0ffff) == 0x08000254) { 47771a71fb5SHelge Deller source_reg = (opcode >> 16) & 31; 47871a71fb5SHelge Deller regs->gr[source_reg] = regs->gr[20]; 47971a71fb5SHelge Deller return; 48071a71fb5SHelge Deller } 48171a71fb5SHelge Deller 48271a71fb5SHelge Deller pr_warn("syscall restart: %s (pid %d): unexpected opcode 0x%08x\n", 48371a71fb5SHelge Deller current->comm, task_pid_nr(current), opcode); 48471a71fb5SHelge Deller } 48571a71fb5SHelge Deller 4862b163b71SKyle McMartin static inline void 4872b163b71SKyle McMartin syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) 4882b163b71SKyle McMartin { 48900df111eSAl Viro if (regs->orig_r28) 49000df111eSAl Viro return; 49100df111eSAl Viro regs->orig_r28 = 1; /* no more restarts */ 4922b163b71SKyle McMartin /* Check the return code */ 4932b163b71SKyle McMartin switch (regs->gr[28]) { 4942b163b71SKyle McMartin case -ERESTART_RESTARTBLOCK: 4952b163b71SKyle McMartin case -ERESTARTNOHAND: 4962b163b71SKyle McMartin DBG(1,"ERESTARTNOHAND: returning -EINTR\n"); 4972b163b71SKyle McMartin regs->gr[28] = -EINTR; 4982b163b71SKyle McMartin break; 4992b163b71SKyle McMartin 5002b163b71SKyle McMartin case -ERESTARTSYS: 5012b163b71SKyle McMartin if (!(ka->sa.sa_flags & SA_RESTART)) { 5022b163b71SKyle McMartin DBG(1,"ERESTARTSYS: putting -EINTR\n"); 5032b163b71SKyle McMartin regs->gr[28] = -EINTR; 5042b163b71SKyle McMartin break; 5052b163b71SKyle McMartin } 5062b163b71SKyle McMartin /* fallthrough */ 5072b163b71SKyle McMartin case -ERESTARTNOINTR: 50871a71fb5SHelge Deller check_syscallno_in_delay_branch(regs); 5092b163b71SKyle McMartin break; 5102b163b71SKyle McMartin } 5112b163b71SKyle McMartin } 5122b163b71SKyle McMartin 5132b163b71SKyle McMartin static inline void 5142b163b71SKyle McMartin insert_restart_trampoline(struct pt_regs *regs) 5152b163b71SKyle McMartin { 51600df111eSAl Viro if (regs->orig_r28) 51700df111eSAl Viro return; 51800df111eSAl Viro regs->orig_r28 = 1; /* no more restarts */ 5192b163b71SKyle McMartin switch(regs->gr[28]) { 5202b163b71SKyle McMartin case -ERESTART_RESTARTBLOCK: { 5212b163b71SKyle McMartin /* Restart the system call - no handlers present */ 5222b163b71SKyle McMartin unsigned int *usp = (unsigned int *)regs->gr[30]; 5230bd1e94bSHelge Deller unsigned long start = (unsigned long) &usp[2]; 5240bd1e94bSHelge Deller unsigned long end = (unsigned long) &usp[5]; 5250bd1e94bSHelge Deller long err = 0; 5262b163b71SKyle McMartin 5272b163b71SKyle McMartin /* Setup a trampoline to restart the syscall 5282b163b71SKyle McMartin * with __NR_restart_syscall 5292b163b71SKyle McMartin * 5302b163b71SKyle McMartin * 0: <return address (orig r31)> 5312b163b71SKyle McMartin * 4: <2nd half for 64-bit> 5322b163b71SKyle McMartin * 8: ldw 0(%sp), %r31 5332b163b71SKyle McMartin * 12: be 0x100(%sr2, %r0) 5342b163b71SKyle McMartin * 16: ldi __NR_restart_syscall, %r20 5352b163b71SKyle McMartin */ 5362b163b71SKyle McMartin #ifdef CONFIG_64BIT 5370bd1e94bSHelge Deller err |= put_user(regs->gr[31] >> 32, &usp[0]); 5380bd1e94bSHelge Deller err |= put_user(regs->gr[31] & 0xffffffff, &usp[1]); 5390bd1e94bSHelge Deller err |= put_user(0x0fc010df, &usp[2]); 5402b163b71SKyle McMartin #else 5410bd1e94bSHelge Deller err |= put_user(regs->gr[31], &usp[0]); 5420bd1e94bSHelge Deller err |= put_user(0x0fc0109f, &usp[2]); 5432b163b71SKyle McMartin #endif 5440bd1e94bSHelge Deller err |= put_user(0xe0008200, &usp[3]); 5450bd1e94bSHelge Deller err |= put_user(0x34140000, &usp[4]); 5462b163b71SKyle McMartin 5470bd1e94bSHelge Deller WARN_ON(err); 5480bd1e94bSHelge Deller 5490bd1e94bSHelge Deller /* flush data/instruction cache for new insns */ 550ef470a60SJohn David Anglin flush_user_dcache_range_asm(start, end); 551ef470a60SJohn David Anglin flush_user_icache_range_asm(start, end); 5522b163b71SKyle McMartin 5532b163b71SKyle McMartin regs->gr[31] = regs->gr[30] + 8; 5542b163b71SKyle McMartin return; 5552b163b71SKyle McMartin } 5562b163b71SKyle McMartin case -ERESTARTNOHAND: 5572b163b71SKyle McMartin case -ERESTARTSYS: 55871a71fb5SHelge Deller case -ERESTARTNOINTR: 55971a71fb5SHelge Deller check_syscallno_in_delay_branch(regs); 5602b163b71SKyle McMartin return; 5612b163b71SKyle McMartin default: 5622b163b71SKyle McMartin break; 5632b163b71SKyle McMartin } 5642b163b71SKyle McMartin } 5652b163b71SKyle McMartin 5661da177e4SLinus Torvalds /* 5671da177e4SLinus Torvalds * Note that 'init' is a special process: it doesn't get signals it doesn't 5681da177e4SLinus Torvalds * want to handle. Thus you cannot kill init even with a SIGKILL even by 5691da177e4SLinus Torvalds * mistake. 5701da177e4SLinus Torvalds * 5711da177e4SLinus Torvalds * We need to be able to restore the syscall arguments (r21-r26) to 5721da177e4SLinus Torvalds * restart syscalls. Thus, the syscall path should save them in the 5731da177e4SLinus Torvalds * pt_regs structure (it's okay to do so since they are caller-save 5741da177e4SLinus Torvalds * registers). As noted below, the syscall number gets restored for 5751da177e4SLinus Torvalds * us due to the magic of delayed branching. 5761da177e4SLinus Torvalds */ 5774650f0a5SKyle McMartin asmlinkage void 5784650f0a5SKyle McMartin do_signal(struct pt_regs *regs, long in_syscall) 5791da177e4SLinus Torvalds { 580e4dc894bSRichard Weinberger struct ksignal ksig; 5811da177e4SLinus Torvalds 582b7f9a11aSAl Viro DBG(1,"\ndo_signal: regs=0x%p, sr7 %#lx, in_syscall=%d\n", 583b7f9a11aSAl Viro regs, regs->sr[7], in_syscall); 5841da177e4SLinus Torvalds 585e4dc894bSRichard Weinberger if (get_signal(&ksig)) { 5861da177e4SLinus Torvalds DBG(3,"do_signal: signr = %d, regs->gr[28] = %ld\n", signr, regs->gr[28]); 5871da177e4SLinus Torvalds /* Restart a system call if necessary. */ 5882b163b71SKyle McMartin if (in_syscall) 589e4dc894bSRichard Weinberger syscall_restart(regs, &ksig.ka); 5901da177e4SLinus Torvalds 591e4dc894bSRichard Weinberger handle_signal(&ksig, regs, in_syscall); 5924650f0a5SKyle McMartin return; 5931da177e4SLinus Torvalds } 5941da177e4SLinus Torvalds 5951da177e4SLinus Torvalds /* Did we come from a system call? */ 5962b163b71SKyle McMartin if (in_syscall) 5972b163b71SKyle McMartin insert_restart_trampoline(regs); 5981da177e4SLinus Torvalds 5991da177e4SLinus Torvalds DBG(1,"do_signal: Exit (not delivered), regs->gr[28] = %ld\n", 6001da177e4SLinus Torvalds regs->gr[28]); 6011da177e4SLinus Torvalds 60251a7b448SAl Viro restore_saved_sigmask(); 6034650f0a5SKyle McMartin } 6044650f0a5SKyle McMartin 6054650f0a5SKyle McMartin void do_notify_resume(struct pt_regs *regs, long in_syscall) 6064650f0a5SKyle McMartin { 6076fd84c08SAl Viro if (test_thread_flag(TIF_SIGPENDING)) 6084650f0a5SKyle McMartin do_signal(regs, in_syscall); 609d0420c83SDavid Howells 610d0420c83SDavid Howells if (test_thread_flag(TIF_NOTIFY_RESUME)) { 611d0420c83SDavid Howells clear_thread_flag(TIF_NOTIFY_RESUME); 612d0420c83SDavid Howells tracehook_notify_resume(regs); 613d0420c83SDavid Howells } 6141da177e4SLinus Torvalds } 615