diff options
Diffstat (limited to 'arch/mips/kernel/signal.c')
| -rw-r--r-- | arch/mips/kernel/signal.c | 52 |
1 files changed, 43 insertions, 9 deletions
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 8c3c5a5789b0..07d67309451a 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include <linux/ptrace.h> | 20 | #include <linux/ptrace.h> |
| 21 | #include <linux/unistd.h> | 21 | #include <linux/unistd.h> |
| 22 | #include <linux/compiler.h> | 22 | #include <linux/compiler.h> |
| 23 | #include <linux/uaccess.h> | ||
| 23 | 24 | ||
| 24 | #include <asm/abi.h> | 25 | #include <asm/abi.h> |
| 25 | #include <asm/asm.h> | 26 | #include <asm/asm.h> |
| @@ -27,7 +28,6 @@ | |||
| 27 | #include <asm/cacheflush.h> | 28 | #include <asm/cacheflush.h> |
| 28 | #include <asm/fpu.h> | 29 | #include <asm/fpu.h> |
| 29 | #include <asm/sim.h> | 30 | #include <asm/sim.h> |
| 30 | #include <asm/uaccess.h> | ||
| 31 | #include <asm/ucontext.h> | 31 | #include <asm/ucontext.h> |
| 32 | #include <asm/cpu-features.h> | 32 | #include <asm/cpu-features.h> |
| 33 | #include <asm/war.h> | 33 | #include <asm/war.h> |
| @@ -78,6 +78,46 @@ struct rt_sigframe { | |||
| 78 | /* | 78 | /* |
| 79 | * Helper routines | 79 | * Helper routines |
| 80 | */ | 80 | */ |
| 81 | static int protected_save_fp_context(struct sigcontext __user *sc) | ||
| 82 | { | ||
| 83 | int err; | ||
| 84 | while (1) { | ||
| 85 | lock_fpu_owner(); | ||
| 86 | own_fpu_inatomic(1); | ||
| 87 | err = save_fp_context(sc); /* this might fail */ | ||
| 88 | unlock_fpu_owner(); | ||
| 89 | if (likely(!err)) | ||
| 90 | break; | ||
| 91 | /* touch the sigcontext and try again */ | ||
| 92 | err = __put_user(0, &sc->sc_fpregs[0]) | | ||
| 93 | __put_user(0, &sc->sc_fpregs[31]) | | ||
| 94 | __put_user(0, &sc->sc_fpc_csr); | ||
| 95 | if (err) | ||
| 96 | break; /* really bad sigcontext */ | ||
| 97 | } | ||
| 98 | return err; | ||
| 99 | } | ||
| 100 | |||
| 101 | static int protected_restore_fp_context(struct sigcontext __user *sc) | ||
| 102 | { | ||
| 103 | int err, tmp; | ||
| 104 | while (1) { | ||
| 105 | lock_fpu_owner(); | ||
| 106 | own_fpu_inatomic(0); | ||
| 107 | err = restore_fp_context(sc); /* this might fail */ | ||
| 108 | unlock_fpu_owner(); | ||
| 109 | if (likely(!err)) | ||
| 110 | break; | ||
| 111 | /* touch the sigcontext and try again */ | ||
| 112 | err = __get_user(tmp, &sc->sc_fpregs[0]) | | ||
| 113 | __get_user(tmp, &sc->sc_fpregs[31]) | | ||
| 114 | __get_user(tmp, &sc->sc_fpc_csr); | ||
| 115 | if (err) | ||
| 116 | break; /* really bad sigcontext */ | ||
| 117 | } | ||
| 118 | return err; | ||
| 119 | } | ||
| 120 | |||
| 81 | int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) | 121 | int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) |
| 82 | { | 122 | { |
| 83 | int err = 0; | 123 | int err = 0; |
| @@ -113,10 +153,7 @@ int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) | |||
| 113 | * Save FPU state to signal context. Signal handler | 153 | * Save FPU state to signal context. Signal handler |
| 114 | * will "inherit" current FPU state. | 154 | * will "inherit" current FPU state. |
| 115 | */ | 155 | */ |
| 116 | own_fpu(1); | 156 | err |= protected_save_fp_context(sc); |
| 117 | enable_fp_in_kernel(); | ||
| 118 | err |= save_fp_context(sc); | ||
| 119 | disable_fp_in_kernel(); | ||
| 120 | } | 157 | } |
| 121 | return err; | 158 | return err; |
| 122 | } | 159 | } |
| @@ -148,7 +185,7 @@ check_and_restore_fp_context(struct sigcontext __user *sc) | |||
| 148 | err = sig = fpcsr_pending(&sc->sc_fpc_csr); | 185 | err = sig = fpcsr_pending(&sc->sc_fpc_csr); |
| 149 | if (err > 0) | 186 | if (err > 0) |
| 150 | err = 0; | 187 | err = 0; |
| 151 | err |= restore_fp_context(sc); | 188 | err |= protected_restore_fp_context(sc); |
| 152 | return err ?: sig; | 189 | return err ?: sig; |
| 153 | } | 190 | } |
| 154 | 191 | ||
| @@ -187,11 +224,8 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) | |||
| 187 | 224 | ||
| 188 | if (used_math) { | 225 | if (used_math) { |
| 189 | /* restore fpu context if we have used it before */ | 226 | /* restore fpu context if we have used it before */ |
| 190 | own_fpu(0); | ||
| 191 | enable_fp_in_kernel(); | ||
| 192 | if (!err) | 227 | if (!err) |
| 193 | err = check_and_restore_fp_context(sc); | 228 | err = check_and_restore_fp_context(sc); |
| 194 | disable_fp_in_kernel(); | ||
| 195 | } else { | 229 | } else { |
| 196 | /* signal handler may have used FPU. Give it up. */ | 230 | /* signal handler may have used FPU. Give it up. */ |
| 197 | lose_fpu(0); | 231 | lose_fpu(0); |
