| .. | .. |
|---|
| 12 | 12 | #include <asm/cacheflush.h> |
|---|
| 13 | 13 | #include <asm/ucontext.h> |
|---|
| 14 | 14 | #include <asm/unistd.h> |
|---|
| 15 | +#include <asm/fpu.h> |
|---|
| 15 | 16 | |
|---|
| 16 | 17 | #include <asm/ptrace.h> |
|---|
| 17 | 18 | #include <asm/vdso.h> |
|---|
| .. | .. |
|---|
| 20 | 21 | struct siginfo info; |
|---|
| 21 | 22 | struct ucontext uc; |
|---|
| 22 | 23 | }; |
|---|
| 24 | +#if IS_ENABLED(CONFIG_FPU) |
|---|
| 25 | +static inline int restore_sigcontext_fpu(struct pt_regs *regs, |
|---|
| 26 | + struct sigcontext __user *sc) |
|---|
| 27 | +{ |
|---|
| 28 | + struct task_struct *tsk = current; |
|---|
| 29 | + unsigned long used_math_flag; |
|---|
| 30 | + int ret = 0; |
|---|
| 31 | + |
|---|
| 32 | + clear_used_math(); |
|---|
| 33 | + __get_user_error(used_math_flag, &sc->used_math_flag, ret); |
|---|
| 34 | + |
|---|
| 35 | + if (!used_math_flag) |
|---|
| 36 | + return 0; |
|---|
| 37 | + set_used_math(); |
|---|
| 38 | + |
|---|
| 39 | +#if IS_ENABLED(CONFIG_LAZY_FPU) |
|---|
| 40 | + preempt_disable(); |
|---|
| 41 | + if (current == last_task_used_math) { |
|---|
| 42 | + last_task_used_math = NULL; |
|---|
| 43 | + disable_ptreg_fpu(regs); |
|---|
| 44 | + } |
|---|
| 45 | + preempt_enable(); |
|---|
| 46 | +#else |
|---|
| 47 | + clear_fpu(regs); |
|---|
| 48 | +#endif |
|---|
| 49 | + |
|---|
| 50 | + return __copy_from_user(&tsk->thread.fpu, &sc->fpu, |
|---|
| 51 | + sizeof(struct fpu_struct)); |
|---|
| 52 | +} |
|---|
| 53 | + |
|---|
| 54 | +static inline int setup_sigcontext_fpu(struct pt_regs *regs, |
|---|
| 55 | + struct sigcontext __user *sc) |
|---|
| 56 | +{ |
|---|
| 57 | + struct task_struct *tsk = current; |
|---|
| 58 | + int ret = 0; |
|---|
| 59 | + |
|---|
| 60 | + __put_user_error(used_math(), &sc->used_math_flag, ret); |
|---|
| 61 | + |
|---|
| 62 | + if (!used_math()) |
|---|
| 63 | + return ret; |
|---|
| 64 | + |
|---|
| 65 | + preempt_disable(); |
|---|
| 66 | +#if IS_ENABLED(CONFIG_LAZY_FPU) |
|---|
| 67 | + if (last_task_used_math == tsk) |
|---|
| 68 | + save_fpu(last_task_used_math); |
|---|
| 69 | +#else |
|---|
| 70 | + unlazy_fpu(tsk); |
|---|
| 71 | +#endif |
|---|
| 72 | + ret = __copy_to_user(&sc->fpu, &tsk->thread.fpu, |
|---|
| 73 | + sizeof(struct fpu_struct)); |
|---|
| 74 | + preempt_enable(); |
|---|
| 75 | + return ret; |
|---|
| 76 | +} |
|---|
| 77 | +#endif |
|---|
| 23 | 78 | |
|---|
| 24 | 79 | static int restore_sigframe(struct pt_regs *regs, |
|---|
| 25 | 80 | struct rt_sigframe __user * sf) |
|---|
| .. | .. |
|---|
| 69 | 124 | __get_user_error(regs->le, &sf->uc.uc_mcontext.zol.nds32_le, err); |
|---|
| 70 | 125 | __get_user_error(regs->lb, &sf->uc.uc_mcontext.zol.nds32_lb, err); |
|---|
| 71 | 126 | #endif |
|---|
| 72 | | - |
|---|
| 127 | +#if IS_ENABLED(CONFIG_FPU) |
|---|
| 128 | + err |= restore_sigcontext_fpu(regs, &sf->uc.uc_mcontext); |
|---|
| 129 | +#endif |
|---|
| 73 | 130 | /* |
|---|
| 74 | 131 | * Avoid sys_rt_sigreturn() restarting. |
|---|
| 75 | 132 | */ |
|---|
| .. | .. |
|---|
| 94 | 151 | |
|---|
| 95 | 152 | frame = (struct rt_sigframe __user *)regs->sp; |
|---|
| 96 | 153 | |
|---|
| 97 | | - if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
|---|
| 154 | + if (!access_ok(frame, sizeof(*frame))) |
|---|
| 98 | 155 | goto badframe; |
|---|
| 99 | 156 | |
|---|
| 100 | 157 | if (restore_sigframe(regs, frame)) |
|---|
| .. | .. |
|---|
| 106 | 163 | return regs->uregs[0]; |
|---|
| 107 | 164 | |
|---|
| 108 | 165 | badframe: |
|---|
| 109 | | - force_sig(SIGSEGV, current); |
|---|
| 166 | + force_sig(SIGSEGV); |
|---|
| 110 | 167 | return 0; |
|---|
| 111 | 168 | } |
|---|
| 112 | 169 | |
|---|
| .. | .. |
|---|
| 152 | 209 | __put_user_error(regs->lc, &sf->uc.uc_mcontext.zol.nds32_lc, err); |
|---|
| 153 | 210 | __put_user_error(regs->le, &sf->uc.uc_mcontext.zol.nds32_le, err); |
|---|
| 154 | 211 | __put_user_error(regs->lb, &sf->uc.uc_mcontext.zol.nds32_lb, err); |
|---|
| 212 | +#endif |
|---|
| 213 | +#if IS_ENABLED(CONFIG_FPU) |
|---|
| 214 | + err |= setup_sigcontext_fpu(regs, &sf->uc.uc_mcontext); |
|---|
| 155 | 215 | #endif |
|---|
| 156 | 216 | |
|---|
| 157 | 217 | __put_user_error(current->thread.trap_no, &sf->uc.uc_mcontext.trap_no, |
|---|
| .. | .. |
|---|
| 215 | 275 | get_sigframe(ksig, regs, sizeof(*frame)); |
|---|
| 216 | 276 | int err = 0; |
|---|
| 217 | 277 | |
|---|
| 218 | | - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
|---|
| 278 | + if (!access_ok(frame, sizeof(*frame))) |
|---|
| 219 | 279 | return -EFAULT; |
|---|
| 220 | 280 | |
|---|
| 221 | 281 | __put_user_error(0, &frame->uc.uc_flags, err); |
|---|
| .. | .. |
|---|
| 256 | 316 | regs->uregs[0] = -EINTR; |
|---|
| 257 | 317 | break; |
|---|
| 258 | 318 | } |
|---|
| 319 | + fallthrough; |
|---|
| 259 | 320 | case -ERESTARTNOINTR: |
|---|
| 260 | 321 | regs->uregs[0] = regs->orig_r0; |
|---|
| 261 | 322 | regs->ipc -= 4; |
|---|
| .. | .. |
|---|
| 300 | 361 | switch (regs->uregs[0]) { |
|---|
| 301 | 362 | case -ERESTART_RESTARTBLOCK: |
|---|
| 302 | 363 | regs->uregs[15] = __NR_restart_syscall; |
|---|
| 364 | + fallthrough; |
|---|
| 303 | 365 | case -ERESTARTNOHAND: |
|---|
| 304 | 366 | case -ERESTARTSYS: |
|---|
| 305 | 367 | case -ERESTARTNOINTR: |
|---|
| .. | .. |
|---|
| 314 | 376 | asmlinkage void |
|---|
| 315 | 377 | do_notify_resume(struct pt_regs *regs, unsigned int thread_flags) |
|---|
| 316 | 378 | { |
|---|
| 317 | | - if (thread_flags & _TIF_SIGPENDING) |
|---|
| 379 | + if (thread_flags & (_TIF_SIGPENDING | _TIF_NOTIFY_SIGNAL)) |
|---|
| 318 | 380 | do_signal(regs); |
|---|
| 319 | 381 | |
|---|
| 320 | | - if (thread_flags & _TIF_NOTIFY_RESUME) { |
|---|
| 321 | | - clear_thread_flag(TIF_NOTIFY_RESUME); |
|---|
| 382 | + if (thread_flags & _TIF_NOTIFY_RESUME) |
|---|
| 322 | 383 | tracehook_notify_resume(regs); |
|---|
| 323 | | - } |
|---|
| 324 | 384 | } |
|---|