Ley Foon Tan | b53e906 | 2014-11-06 15:19:59 +0800 | [diff] [blame] | 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; |
Chung-Ling Tang | 92d5dd8 | 2015-03-12 13:34:31 +0800 | [diff] [blame] | 42 | unsigned long *gregs = uc->uc_mcontext.gregs; |
Ley Foon Tan | b53e906 | 2014-11-06 15:19:59 +0800 | [diff] [blame] | 43 | int err; |
| 44 | |
| 45 | /* Always make any pending restarted system calls return -EINTR */ |
Ley Foon Tan | 7587d12 | 2015-04-08 13:44:18 +0800 | [diff] [blame] | 46 | current->restart_block.fn = do_no_restart_syscall; |
Ley Foon Tan | b53e906 | 2014-11-06 15:19:59 +0800 | [diff] [blame] | 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; |
Chung-Ling Tang | 92d5dd8 | 2015-03-12 13:34:31 +0800 | [diff] [blame] | 130 | unsigned long *gregs = uc->uc_mcontext.gregs; |
Ley Foon Tan | b53e906 | 2014-11-06 15:19:59 +0800 | [diff] [blame] | 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. */ |
Ley Foon Tan | d24c816 | 2015-01-22 17:05:16 +0800 | [diff] [blame] | 203 | regs->ra = (unsigned long) (0x1044); |
Ley Foon Tan | b53e906 | 2014-11-06 15:19:59 +0800 | [diff] [blame] | 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 | } |