16bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin/* 26bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * arch/score/kernel/signal.c 36bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * 46bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * Score Processor version. 56bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * 66bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * Copyright (C) 2009 Sunplus Core Technology Co., Ltd. 76bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * Chen Liqin <liqin.chen@sunplusct.com> 86bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * Lennox Wu <lennox.wu@sunplusct.com> 96bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * 106bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * This program is free software; you can redistribute it and/or modify 116bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * it under the terms of the GNU General Public License as published by 126bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * the Free Software Foundation; either version 2 of the License, or 136bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * (at your option) any later version. 146bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * 156bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * This program is distributed in the hope that it will be useful, 166bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * but WITHOUT ANY WARRANTY; without even the implied warranty of 176bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 186bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * GNU General Public License for more details. 196bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * 206bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * You should have received a copy of the GNU General Public License 216bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * along with this program; if not, see the file COPYING, or write 226bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * to the Free Software Foundation, Inc., 236bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 246bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin */ 256bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 266bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin#include <linux/errno.h> 276bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin#include <linux/signal.h> 28d8aa899bb27ad7879ab9e621365e04ada2745a65Chen Liqin#include <linux/ptrace.h> 296bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin#include <linux/unistd.h> 306bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin#include <linux/uaccess.h> 319fb24cc50045ec8d13d0a6c3d4d454750b466d61Arnd Bergmann 32d8aa899bb27ad7879ab9e621365e04ada2745a65Chen Liqin#include <asm/cacheflush.h> 339fb24cc50045ec8d13d0a6c3d4d454750b466d61Arnd Bergmann#include <asm/syscalls.h> 349fb24cc50045ec8d13d0a6c3d4d454750b466d61Arnd Bergmann#include <asm/ucontext.h> 356bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 366bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) 376bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 386bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqinstruct rt_sigframe { 396bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin u32 rs_ass[4]; /* argument save space */ 406bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin u32 rs_code[2]; /* signal trampoline */ 416bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin struct siginfo rs_info; 426bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin struct ucontext rs_uc; 436bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin}; 446bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 45bddc605955bca2d914ca621a7ef4ca6c271f55d8Arnd Bergmannstatic int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) 466bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin{ 476bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin int err = 0; 486bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin unsigned long reg; 496bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 506bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin reg = regs->cp0_epc; err |= __put_user(reg, &sc->sc_pc); 516bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin err |= __put_user(regs->cp0_psr, &sc->sc_psr); 526bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin err |= __put_user(regs->cp0_condition, &sc->sc_condition); 536bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 546bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 556bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin#define save_gp_reg(i) { \ 566bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin reg = regs->regs[i]; \ 576bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin err |= __put_user(reg, &sc->sc_regs[i]); \ 586bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin} while (0) 596bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin save_gp_reg(0); save_gp_reg(1); save_gp_reg(2); 606bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); 616bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin save_gp_reg(6); save_gp_reg(7); save_gp_reg(8); 626bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin save_gp_reg(9); save_gp_reg(10); save_gp_reg(11); 636bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin save_gp_reg(12); save_gp_reg(13); save_gp_reg(14); 646bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); 656bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin save_gp_reg(18); save_gp_reg(19); save_gp_reg(20); 666bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin save_gp_reg(21); save_gp_reg(22); save_gp_reg(23); 676bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin save_gp_reg(24); save_gp_reg(25); save_gp_reg(26); 686bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); 696bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin#undef save_gp_reg 706bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 716bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin reg = regs->ceh; err |= __put_user(reg, &sc->sc_mdceh); 726bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin reg = regs->cel; err |= __put_user(reg, &sc->sc_mdcel); 736bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin err |= __put_user(regs->cp0_ecr, &sc->sc_ecr); 746bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin err |= __put_user(regs->cp0_ema, &sc->sc_ema); 756bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 766bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin return err; 776bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin} 786bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 79bddc605955bca2d914ca621a7ef4ca6c271f55d8Arnd Bergmannstatic int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) 806bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin{ 816bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin int err = 0; 826bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin u32 reg; 836bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 846bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin err |= __get_user(regs->cp0_epc, &sc->sc_pc); 856bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin err |= __get_user(regs->cp0_condition, &sc->sc_condition); 866bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 876bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin err |= __get_user(reg, &sc->sc_mdceh); 886bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin regs->ceh = (int) reg; 896bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin err |= __get_user(reg, &sc->sc_mdcel); 906bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin regs->cel = (int) reg; 916bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 926bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin err |= __get_user(reg, &sc->sc_psr); 936bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin regs->cp0_psr = (int) reg; 946bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin err |= __get_user(reg, &sc->sc_ecr); 956bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin regs->cp0_ecr = (int) reg; 966bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin err |= __get_user(reg, &sc->sc_ema); 976bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin regs->cp0_ema = (int) reg; 986bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 996bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin#define restore_gp_reg(i) do { \ 1006bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin err |= __get_user(reg, &sc->sc_regs[i]); \ 1016bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin regs->regs[i] = reg; \ 1026bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin} while (0) 1036bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin restore_gp_reg(0); restore_gp_reg(1); restore_gp_reg(2); 1046bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin restore_gp_reg(3); restore_gp_reg(4); restore_gp_reg(5); 1056bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin restore_gp_reg(6); restore_gp_reg(7); restore_gp_reg(8); 1066bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin restore_gp_reg(9); restore_gp_reg(10); restore_gp_reg(11); 1076bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin restore_gp_reg(12); restore_gp_reg(13); restore_gp_reg(14); 1086bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin restore_gp_reg(15); restore_gp_reg(16); restore_gp_reg(17); 1096bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin restore_gp_reg(18); restore_gp_reg(19); restore_gp_reg(20); 1106bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin restore_gp_reg(21); restore_gp_reg(22); restore_gp_reg(23); 1116bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin restore_gp_reg(24); restore_gp_reg(25); restore_gp_reg(26); 1126bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin restore_gp_reg(27); restore_gp_reg(28); restore_gp_reg(29); 1136bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin#undef restore_gp_reg 1146bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 1156bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin return err; 1166bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin} 1176bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 1186bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin/* 1196bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * Determine which stack to use.. 1206bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin */ 121bddc605955bca2d914ca621a7ef4ca6c271f55d8Arnd Bergmannstatic void __user *get_sigframe(struct k_sigaction *ka, 122bddc605955bca2d914ca621a7ef4ca6c271f55d8Arnd Bergmann struct pt_regs *regs, size_t frame_size) 1236bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin{ 1246bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin unsigned long sp; 1256bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 1266bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin /* Default to using normal stack */ 1276bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin sp = regs->regs[0]; 1286bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin sp -= 32; 1296bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 1306bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin /* This is the X/Open sanctioned signal stack switching. */ 1316bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin if ((ka->sa.sa_flags & SA_ONSTACK) && (!on_sig_stack(sp))) 1326bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin sp = current->sas_ss_sp + current->sas_ss_size; 1336bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 134a1f8213b9518d0e9124a48a34bdd58b4bc2650e5Arnd Bergmann return (void __user*)((sp - frame_size) & ~7); 1356bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin} 1366bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 137bddc605955bca2d914ca621a7ef4ca6c271f55d8Arnd Bergmannasmlinkage long 138bddc605955bca2d914ca621a7ef4ca6c271f55d8Arnd Bergmannscore_sigaltstack(struct pt_regs *regs) 1396bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin{ 140a1f8213b9518d0e9124a48a34bdd58b4bc2650e5Arnd Bergmann const stack_t __user *uss = (const stack_t __user *) regs->regs[4]; 141a1f8213b9518d0e9124a48a34bdd58b4bc2650e5Arnd Bergmann stack_t __user *uoss = (stack_t __user *) regs->regs[5]; 1426bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin unsigned long usp = regs->regs[0]; 1436bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 1446bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin return do_sigaltstack(uss, uoss, usp); 1456bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin} 1466bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 147bddc605955bca2d914ca621a7ef4ca6c271f55d8Arnd Bergmannasmlinkage long 148bddc605955bca2d914ca621a7ef4ca6c271f55d8Arnd Bergmannscore_rt_sigreturn(struct pt_regs *regs) 1496bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin{ 1506bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin struct rt_sigframe __user *frame; 1516bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin sigset_t set; 1526bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin stack_t st; 1536bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin int sig; 1546bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 1556bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin frame = (struct rt_sigframe __user *) regs->regs[0]; 1566bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) 1576bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin goto badframe; 1586bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set))) 1596bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin goto badframe; 1606bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 1616bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin sigdelsetmask(&set, ~_BLOCKABLE); 1626bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin spin_lock_irq(¤t->sighand->siglock); 1636bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin current->blocked = set; 1646bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin recalc_sigpending(); 1656bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin spin_unlock_irq(¤t->sighand->siglock); 1666bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 1676bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin sig = restore_sigcontext(regs, &frame->rs_uc.uc_mcontext); 1686bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin if (sig < 0) 1696bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin goto badframe; 1706bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin else if (sig) 1716bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin force_sig(sig, current); 1726bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 1736bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin if (__copy_from_user(&st, &frame->rs_uc.uc_stack, sizeof(st))) 1746bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin goto badframe; 1756bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 1766bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin /* It is more difficult to avoid calling this function than to 1776bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin call it and ignore errors. */ 1786bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin do_sigaltstack((stack_t __user *)&st, NULL, regs->regs[0]); 1796bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 1806bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin __asm__ __volatile__( 1816bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin "mv\tr0, %0\n\t" 1826bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin "la\tr8, syscall_exit\n\t" 1836bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin "br\tr8\n\t" 1846bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin : : "r" (regs) : "r8"); 1856bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 1866bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqinbadframe: 1876bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin force_sig(SIGSEGV, current); 188bddc605955bca2d914ca621a7ef4ca6c271f55d8Arnd Bergmann 189bddc605955bca2d914ca621a7ef4ca6c271f55d8Arnd Bergmann return 0; 1906bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin} 1916bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 192bddc605955bca2d914ca621a7ef4ca6c271f55d8Arnd Bergmannstatic int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, 1936bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin int signr, sigset_t *set, siginfo_t *info) 1946bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin{ 195a1f8213b9518d0e9124a48a34bdd58b4bc2650e5Arnd Bergmann struct rt_sigframe __user *frame; 1966bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin int err = 0; 1976bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 1986bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin frame = get_sigframe(ka, regs, sizeof(*frame)); 1996bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) 2006bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin goto give_sigsegv; 2016bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 2026bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin /* 2036bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * Set up the return code ... 2046bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * 2056bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * li v0, __NR_rt_sigreturn 2066bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * syscall 2076bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin */ 2086bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin err |= __put_user(0x87788000 + __NR_rt_sigreturn*2, 2096bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin frame->rs_code + 0); 2106bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin err |= __put_user(0x80008002, frame->rs_code + 1); 2116bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin flush_cache_sigtramp((unsigned long) frame->rs_code); 2126bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 2136bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin err |= copy_siginfo_to_user(&frame->rs_info, info); 2146bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin err |= __put_user(0, &frame->rs_uc.uc_flags); 215c6067472252c1d6155c7c01c93e0d580342cdb29Arnd Bergmann err |= __put_user(NULL, &frame->rs_uc.uc_link); 216a1f8213b9518d0e9124a48a34bdd58b4bc2650e5Arnd Bergmann err |= __put_user((void __user *)current->sas_ss_sp, 2176bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin &frame->rs_uc.uc_stack.ss_sp); 2186bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin err |= __put_user(sas_ss_flags(regs->regs[0]), 2196bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin &frame->rs_uc.uc_stack.ss_flags); 2206bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin err |= __put_user(current->sas_ss_size, 2216bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin &frame->rs_uc.uc_stack.ss_size); 2226bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext); 2236bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set)); 2246bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 2256bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin if (err) 2266bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin goto give_sigsegv; 2276bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 2286bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin regs->regs[0] = (unsigned long) frame; 2296bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin regs->regs[3] = (unsigned long) frame->rs_code; 2306bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin regs->regs[4] = signr; 2316bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin regs->regs[5] = (unsigned long) &frame->rs_info; 2326bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin regs->regs[6] = (unsigned long) &frame->rs_uc; 2336bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin regs->regs[29] = (unsigned long) ka->sa.sa_handler; 2346bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin regs->cp0_epc = (unsigned long) ka->sa.sa_handler; 2356bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 2366bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin return 0; 2376bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 2386bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqingive_sigsegv: 2396bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin if (signr == SIGSEGV) 2406bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin ka->sa.sa_handler = SIG_DFL; 2416bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin force_sig(SIGSEGV, current); 2426bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin return -EFAULT; 2436bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin} 2446bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 245bddc605955bca2d914ca621a7ef4ca6c271f55d8Arnd Bergmannstatic int handle_signal(unsigned long sig, siginfo_t *info, 2466bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin struct k_sigaction *ka, sigset_t *oldset, struct pt_regs *regs) 2476bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin{ 2486bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin int ret; 2496bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 2506bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin if (regs->is_syscall) { 2516bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin switch (regs->regs[4]) { 2526bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin case ERESTART_RESTARTBLOCK: 2536bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin case ERESTARTNOHAND: 2546bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin regs->regs[4] = EINTR; 2556bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin break; 2566bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin case ERESTARTSYS: 2576bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin if (!(ka->sa.sa_flags & SA_RESTART)) { 2586bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin regs->regs[4] = EINTR; 2596bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin break; 2606bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin } 2616bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin case ERESTARTNOINTR: 2626bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin regs->regs[4] = regs->orig_r4; 2636bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin regs->regs[7] = regs->orig_r7; 2646bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin regs->cp0_epc -= 8; 2656bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin } 2666bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 2676bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin regs->is_syscall = 0; 2686bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin } 2696bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 2706bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin /* 2716bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * Set up the stack frame 2726bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin */ 2736bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin ret = setup_rt_frame(ka, regs, sig, oldset, info); 2746bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 2756bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin spin_lock_irq(¤t->sighand->siglock); 2766bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); 2776bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin if (!(ka->sa.sa_flags & SA_NODEFER)) 2786bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin sigaddset(¤t->blocked, sig); 2796bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin recalc_sigpending(); 2806bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin spin_unlock_irq(¤t->sighand->siglock); 2816bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 2826bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin return ret; 2836bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin} 2846bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 285bddc605955bca2d914ca621a7ef4ca6c271f55d8Arnd Bergmannstatic void do_signal(struct pt_regs *regs) 2866bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin{ 2876bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin struct k_sigaction ka; 2886bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin sigset_t *oldset; 2896bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin siginfo_t info; 2906bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin int signr; 2916bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 2926bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin /* 2936bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * We want the common case to go fast, which is why we may in certain 2946bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * cases get here from kernel mode. Just return without doing anything 2956bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * if so. 2966bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin */ 2976bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin if (!user_mode(regs)) 2986bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin return; 2996bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 3006bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin if (test_thread_flag(TIF_RESTORE_SIGMASK)) 3016bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin oldset = ¤t->saved_sigmask; 3026bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin else 3036bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin oldset = ¤t->blocked; 3046bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 3056bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin signr = get_signal_to_deliver(&info, &ka, regs, NULL); 3066bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin if (signr > 0) { 3076bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin /* Actually deliver the signal. */ 3086bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin if (handle_signal(signr, &info, &ka, oldset, regs) == 0) { 3096bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin /* 3106bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * A signal was successfully delivered; the saved 3116bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * sigmask will have been stored in the signal frame, 3126bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * and will be restored by sigreturn, so we can simply 3136bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * clear the TIF_RESTORE_SIGMASK flag. 3146bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin */ 3156bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin if (test_thread_flag(TIF_RESTORE_SIGMASK)) 3166bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin clear_thread_flag(TIF_RESTORE_SIGMASK); 3176bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin } 3186bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 3196bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin return; 3206bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin } 3216bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 3226bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin if (regs->is_syscall) { 3236bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin if (regs->regs[4] == ERESTARTNOHAND || 3246bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin regs->regs[4] == ERESTARTSYS || 3256bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin regs->regs[4] == ERESTARTNOINTR) { 3266bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin regs->regs[4] = regs->orig_r4; 3276bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin regs->regs[7] = regs->orig_r7; 3286bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin regs->cp0_epc -= 8; 3296bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin } 3306bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 3316bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin if (regs->regs[4] == ERESTART_RESTARTBLOCK) { 3326bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin regs->regs[27] = __NR_restart_syscall; 3336bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin regs->regs[4] = regs->orig_r4; 3346bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin regs->regs[7] = regs->orig_r7; 3356bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin regs->cp0_epc -= 8; 3366bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin } 3376bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 3386bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin regs->is_syscall = 0; /* Don't deal with this again. */ 3396bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin } 3406bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 3416bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin /* 3426bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * If there's no signal to deliver, we just put the saved sigmask 3436bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * back 3446bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin */ 3456bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin if (test_thread_flag(TIF_RESTORE_SIGMASK)) { 3466bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin clear_thread_flag(TIF_RESTORE_SIGMASK); 3476bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); 3486bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin } 3496bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin} 3506bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin 3516bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin/* 3526bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * notification of userspace execution resumption 3536bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin * - triggered by the TIF_WORK_MASK flags 3546bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin */ 3556bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqinasmlinkage void do_notify_resume(struct pt_regs *regs, void *unused, 3566bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin __u32 thread_info_flags) 3576bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin{ 3586bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin /* deal with pending signal delivery */ 3596bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) 3606bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin do_signal(regs); 3616bc9a3966f0395419b09b2ec90f89f7f00341b37Chen Liqin} 362