Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

nios2: Signal handling support

This patch adds support for signal handling.

Signed-off-by: Ley Foon Tan <lftan@altera.com>

+428
+22
arch/nios2/include/asm/signal.h
··· 1 + /* 2 + * Copyright Altera Corporation (C) 2013. All rights reserved 3 + * 4 + * This program is free software; you can redistribute it and/or modify it 5 + * under the terms and conditions of the GNU General Public License, 6 + * version 2, as published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope it will be useful, but WITHOUT 9 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 + * more details. 12 + * 13 + * You should have received a copy of the GNU General Public License along with 14 + * this program. If not, see <http://www.gnu.org/licenses/>. 15 + * 16 + */ 17 + #ifndef _NIOS2_SIGNAL_H 18 + #define _NIOS2_SIGNAL_H 19 + 20 + #include <uapi/asm/signal.h> 21 + 22 + #endif /* _NIOS2_SIGNAL_H */
+32
arch/nios2/include/asm/ucontext.h
··· 1 + /* 2 + * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> 3 + * Copyright (C) 2004 Microtronix Datacom Ltd 4 + * 5 + * This file is subject to the terms and conditions of the GNU General Public 6 + * License. See the file "COPYING" in the main directory of this archive 7 + * for more details. 8 + */ 9 + 10 + #ifndef _ASM_NIOS2_UCONTEXT_H 11 + #define _ASM_NIOS2_UCONTEXT_H 12 + 13 + typedef int greg_t; 14 + #define NGREG 32 15 + typedef greg_t gregset_t[NGREG]; 16 + 17 + struct mcontext { 18 + int version; 19 + gregset_t gregs; 20 + }; 21 + 22 + #define MCONTEXT_VERSION 2 23 + 24 + struct ucontext { 25 + unsigned long uc_flags; 26 + struct ucontext *uc_link; 27 + stack_t uc_stack; 28 + struct mcontext uc_mcontext; 29 + sigset_t uc_sigmask; /* mask last for extensibility */ 30 + }; 31 + 32 + #endif
+28
arch/nios2/include/uapi/asm/sigcontext.h
··· 1 + /* 2 + * Copyright (C) 2004, Microtronix Datacom Ltd. 3 + * 4 + * All rights reserved. 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + * 11 + * This program is distributed in the hope that it will be useful, but 12 + * WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 14 + * NON INFRINGEMENT. See the GNU General Public License for more 15 + * details. 16 + */ 17 + 18 + #ifndef _ASM_NIOS2_SIGCONTEXT_H 19 + #define _ASM_NIOS2_SIGCONTEXT_H 20 + 21 + #include <asm/ptrace.h> 22 + 23 + struct sigcontext { 24 + struct pt_regs regs; 25 + unsigned long sc_mask; /* old sigmask */ 26 + }; 27 + 28 + #endif
+23
arch/nios2/include/uapi/asm/signal.h
··· 1 + /* 2 + * Copyright Altera Corporation (C) 2013. All rights reserved 3 + * 4 + * This program is free software; you can redistribute it and/or modify it 5 + * under the terms and conditions of the GNU General Public License, 6 + * version 2, as published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope it will be useful, but WITHOUT 9 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 + * more details. 12 + * 13 + * You should have received a copy of the GNU General Public License along with 14 + * this program. If not, see <http://www.gnu.org/licenses/>. 15 + * 16 + */ 17 + #ifndef _ASM_NIOS2_SIGNAL_H 18 + #define _ASM_NIOS2_SIGNAL_H 19 + 20 + #define SA_RESTORER 0x04000000 21 + #include <asm-generic/signal.h> 22 + 23 + #endif /* _ASM_NIOS2_SIGNAL_H */
+323
arch/nios2/kernel/signal.c
··· 1 + /* 2 + * Copyright (C) 2013-2014 Altera Corporation 3 + * Copyright (C) 2011-2012 Tobias Klauser <tklauser@distanz.ch> 4 + * Copyright (C) 2004 Microtronix Datacom Ltd 5 + * Copyright (C) 1991, 1992 Linus Torvalds 6 + * 7 + * This file is subject to the terms and conditions of the GNU General Public 8 + * License. See the file COPYING in the main directory of this archive 9 + * for more details. 10 + */ 11 + 12 + #include <linux/signal.h> 13 + #include <linux/errno.h> 14 + #include <linux/ptrace.h> 15 + #include <linux/uaccess.h> 16 + #include <linux/unistd.h> 17 + #include <linux/personality.h> 18 + #include <linux/tracehook.h> 19 + 20 + #include <asm/ucontext.h> 21 + #include <asm/cacheflush.h> 22 + 23 + #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) 24 + 25 + /* 26 + * Do a signal return; undo the signal stack. 27 + * 28 + * Keep the return code on the stack quadword aligned! 29 + * That makes the cache flush below easier. 30 + */ 31 + 32 + struct rt_sigframe { 33 + struct siginfo info; 34 + struct ucontext uc; 35 + }; 36 + 37 + static inline int rt_restore_ucontext(struct pt_regs *regs, 38 + struct switch_stack *sw, 39 + struct ucontext *uc, int *pr2) 40 + { 41 + int temp; 42 + greg_t *gregs = uc->uc_mcontext.gregs; 43 + int err; 44 + 45 + /* Always make any pending restarted system calls return -EINTR */ 46 + current_thread_info()->restart_block.fn = do_no_restart_syscall; 47 + 48 + err = __get_user(temp, &uc->uc_mcontext.version); 49 + if (temp != MCONTEXT_VERSION) 50 + goto badframe; 51 + /* restore passed registers */ 52 + err |= __get_user(regs->r1, &gregs[0]); 53 + err |= __get_user(regs->r2, &gregs[1]); 54 + err |= __get_user(regs->r3, &gregs[2]); 55 + err |= __get_user(regs->r4, &gregs[3]); 56 + err |= __get_user(regs->r5, &gregs[4]); 57 + err |= __get_user(regs->r6, &gregs[5]); 58 + err |= __get_user(regs->r7, &gregs[6]); 59 + err |= __get_user(regs->r8, &gregs[7]); 60 + err |= __get_user(regs->r9, &gregs[8]); 61 + err |= __get_user(regs->r10, &gregs[9]); 62 + err |= __get_user(regs->r11, &gregs[10]); 63 + err |= __get_user(regs->r12, &gregs[11]); 64 + err |= __get_user(regs->r13, &gregs[12]); 65 + err |= __get_user(regs->r14, &gregs[13]); 66 + err |= __get_user(regs->r15, &gregs[14]); 67 + err |= __get_user(sw->r16, &gregs[15]); 68 + err |= __get_user(sw->r17, &gregs[16]); 69 + err |= __get_user(sw->r18, &gregs[17]); 70 + err |= __get_user(sw->r19, &gregs[18]); 71 + err |= __get_user(sw->r20, &gregs[19]); 72 + err |= __get_user(sw->r21, &gregs[20]); 73 + err |= __get_user(sw->r22, &gregs[21]); 74 + err |= __get_user(sw->r23, &gregs[22]); 75 + /* gregs[23] is handled below */ 76 + err |= __get_user(sw->fp, &gregs[24]); /* Verify, should this be 77 + settable */ 78 + err |= __get_user(sw->gp, &gregs[25]); /* Verify, should this be 79 + settable */ 80 + 81 + err |= __get_user(temp, &gregs[26]); /* Not really necessary no user 82 + settable bits */ 83 + err |= __get_user(regs->ea, &gregs[27]); 84 + 85 + err |= __get_user(regs->ra, &gregs[23]); 86 + err |= __get_user(regs->sp, &gregs[28]); 87 + 88 + regs->orig_r2 = -1; /* disable syscall checks */ 89 + 90 + err |= restore_altstack(&uc->uc_stack); 91 + if (err) 92 + goto badframe; 93 + 94 + *pr2 = regs->r2; 95 + return err; 96 + 97 + badframe: 98 + return 1; 99 + } 100 + 101 + asmlinkage int do_rt_sigreturn(struct switch_stack *sw) 102 + { 103 + struct pt_regs *regs = (struct pt_regs *)(sw + 1); 104 + /* Verify, can we follow the stack back */ 105 + struct rt_sigframe *frame = (struct rt_sigframe *) regs->sp; 106 + sigset_t set; 107 + int rval; 108 + 109 + if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) 110 + goto badframe; 111 + 112 + if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) 113 + goto badframe; 114 + 115 + set_current_blocked(&set); 116 + 117 + if (rt_restore_ucontext(regs, sw, &frame->uc, &rval)) 118 + goto badframe; 119 + 120 + return rval; 121 + 122 + badframe: 123 + force_sig(SIGSEGV, current); 124 + return 0; 125 + } 126 + 127 + static inline int rt_setup_ucontext(struct ucontext *uc, struct pt_regs *regs) 128 + { 129 + struct switch_stack *sw = (struct switch_stack *)regs - 1; 130 + greg_t *gregs = uc->uc_mcontext.gregs; 131 + int err = 0; 132 + 133 + err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version); 134 + err |= __put_user(regs->r1, &gregs[0]); 135 + err |= __put_user(regs->r2, &gregs[1]); 136 + err |= __put_user(regs->r3, &gregs[2]); 137 + err |= __put_user(regs->r4, &gregs[3]); 138 + err |= __put_user(regs->r5, &gregs[4]); 139 + err |= __put_user(regs->r6, &gregs[5]); 140 + err |= __put_user(regs->r7, &gregs[6]); 141 + err |= __put_user(regs->r8, &gregs[7]); 142 + err |= __put_user(regs->r9, &gregs[8]); 143 + err |= __put_user(regs->r10, &gregs[9]); 144 + err |= __put_user(regs->r11, &gregs[10]); 145 + err |= __put_user(regs->r12, &gregs[11]); 146 + err |= __put_user(regs->r13, &gregs[12]); 147 + err |= __put_user(regs->r14, &gregs[13]); 148 + err |= __put_user(regs->r15, &gregs[14]); 149 + err |= __put_user(sw->r16, &gregs[15]); 150 + err |= __put_user(sw->r17, &gregs[16]); 151 + err |= __put_user(sw->r18, &gregs[17]); 152 + err |= __put_user(sw->r19, &gregs[18]); 153 + err |= __put_user(sw->r20, &gregs[19]); 154 + err |= __put_user(sw->r21, &gregs[20]); 155 + err |= __put_user(sw->r22, &gregs[21]); 156 + err |= __put_user(sw->r23, &gregs[22]); 157 + err |= __put_user(regs->ra, &gregs[23]); 158 + err |= __put_user(sw->fp, &gregs[24]); 159 + err |= __put_user(sw->gp, &gregs[25]); 160 + err |= __put_user(regs->ea, &gregs[27]); 161 + err |= __put_user(regs->sp, &gregs[28]); 162 + return err; 163 + } 164 + 165 + static inline void *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, 166 + size_t frame_size) 167 + { 168 + unsigned long usp; 169 + 170 + /* Default to using normal stack. */ 171 + usp = regs->sp; 172 + 173 + /* This is the X/Open sanctioned signal stack switching. */ 174 + usp = sigsp(usp, ksig); 175 + 176 + /* Verify, is it 32 or 64 bit aligned */ 177 + return (void *)((usp - frame_size) & -8UL); 178 + } 179 + 180 + static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, 181 + struct pt_regs *regs) 182 + { 183 + struct rt_sigframe *frame; 184 + int err = 0; 185 + 186 + frame = get_sigframe(ksig, regs, sizeof(*frame)); 187 + 188 + if (ksig->ka.sa.sa_flags & SA_SIGINFO) 189 + err |= copy_siginfo_to_user(&frame->info, &ksig->info); 190 + 191 + /* Create the ucontext. */ 192 + err |= __put_user(0, &frame->uc.uc_flags); 193 + err |= __put_user(0, &frame->uc.uc_link); 194 + err |= __save_altstack(&frame->uc.uc_stack, regs->sp); 195 + err |= rt_setup_ucontext(&frame->uc, regs); 196 + err |= copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); 197 + 198 + if (err) 199 + goto give_sigsegv; 200 + 201 + /* Set up to return from userspace; jump to fixed address sigreturn 202 + trampoline on kuser page. */ 203 + regs->ra = (unsigned long) (0x1040); 204 + 205 + /* Set up registers for signal handler */ 206 + regs->sp = (unsigned long) frame; 207 + regs->r4 = (unsigned long) ksig->sig; 208 + regs->r5 = (unsigned long) &frame->info; 209 + regs->r6 = (unsigned long) &frame->uc; 210 + regs->ea = (unsigned long) ksig->ka.sa.sa_handler; 211 + return 0; 212 + 213 + give_sigsegv: 214 + force_sigsegv(ksig->sig, current); 215 + return -EFAULT; 216 + } 217 + 218 + /* 219 + * OK, we're invoking a handler 220 + */ 221 + static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) 222 + { 223 + int ret; 224 + sigset_t *oldset = sigmask_to_save(); 225 + 226 + /* set up the stack frame */ 227 + ret = setup_rt_frame(ksig, oldset, regs); 228 + 229 + signal_setup_done(ret, ksig, 0); 230 + } 231 + 232 + static int do_signal(struct pt_regs *regs) 233 + { 234 + unsigned int retval = 0, continue_addr = 0, restart_addr = 0; 235 + int restart = 0; 236 + struct ksignal ksig; 237 + 238 + current->thread.kregs = regs; 239 + 240 + /* 241 + * If we were from a system call, check for system call restarting... 242 + */ 243 + if (regs->orig_r2 >= 0) { 244 + continue_addr = regs->ea; 245 + restart_addr = continue_addr - 4; 246 + retval = regs->r2; 247 + 248 + /* 249 + * Prepare for system call restart. We do this here so that a 250 + * debugger will see the already changed PC. 251 + */ 252 + switch (retval) { 253 + case ERESTART_RESTARTBLOCK: 254 + restart = -2; 255 + case ERESTARTNOHAND: 256 + case ERESTARTSYS: 257 + case ERESTARTNOINTR: 258 + restart++; 259 + regs->r2 = regs->orig_r2; 260 + regs->r7 = regs->orig_r7; 261 + regs->ea = restart_addr; 262 + break; 263 + } 264 + } 265 + 266 + if (get_signal(&ksig)) { 267 + /* handler */ 268 + if (unlikely(restart && regs->ea == restart_addr)) { 269 + if (retval == ERESTARTNOHAND || 270 + retval == ERESTART_RESTARTBLOCK || 271 + (retval == ERESTARTSYS 272 + && !(ksig.ka.sa.sa_flags & SA_RESTART))) { 273 + regs->r2 = EINTR; 274 + regs->r7 = 1; 275 + regs->ea = continue_addr; 276 + } 277 + } 278 + handle_signal(&ksig, regs); 279 + return 0; 280 + } 281 + 282 + /* 283 + * No handler present 284 + */ 285 + if (unlikely(restart) && regs->ea == restart_addr) { 286 + regs->ea = continue_addr; 287 + regs->r2 = __NR_restart_syscall; 288 + } 289 + 290 + /* 291 + * If there's no signal to deliver, we just put the saved sigmask back. 292 + */ 293 + restore_saved_sigmask(); 294 + 295 + return restart; 296 + } 297 + 298 + asmlinkage int do_notify_resume(struct pt_regs *regs) 299 + { 300 + /* 301 + * We want the common case to go fast, which is why we may in certain 302 + * cases get here from kernel mode. Just return without doing anything 303 + * if so. 304 + */ 305 + if (!user_mode(regs)) 306 + return 0; 307 + 308 + if (test_thread_flag(TIF_SIGPENDING)) { 309 + int restart = do_signal(regs); 310 + 311 + if (unlikely(restart)) { 312 + /* 313 + * Restart without handlers. 314 + * Deal with it without leaving 315 + * the kernel space. 316 + */ 317 + return restart; 318 + } 319 + } else if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) 320 + tracehook_notify_resume(regs); 321 + 322 + return 0; 323 + }