diff options
| -rw-r--r-- | arch/mips/kernel/signal-common.h | 9 | ||||
| -rw-r--r-- | arch/mips/kernel/signal.c | 52 | ||||
| -rw-r--r-- | arch/mips/kernel/signal32.c | 52 | ||||
| -rw-r--r-- | include/asm-mips/fpu.h | 9 |
4 files changed, 102 insertions, 20 deletions
diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h index 297dfcb97524..c0faabd52010 100644 --- a/arch/mips/kernel/signal-common.h +++ b/arch/mips/kernel/signal-common.h | |||
| @@ -34,4 +34,13 @@ extern int install_sigtramp(unsigned int __user *tramp, unsigned int syscall); | |||
| 34 | /* Check and clear pending FPU exceptions in saved CSR */ | 34 | /* Check and clear pending FPU exceptions in saved CSR */ |
| 35 | extern int fpcsr_pending(unsigned int __user *fpcsr); | 35 | extern int fpcsr_pending(unsigned int __user *fpcsr); |
| 36 | 36 | ||
| 37 | /* Make sure we will not lose FPU ownership */ | ||
| 38 | #ifdef CONFIG_PREEMPT | ||
| 39 | #define lock_fpu_owner() preempt_disable() | ||
| 40 | #define unlock_fpu_owner() preempt_enable() | ||
| 41 | #else | ||
| 42 | #define lock_fpu_owner() pagefault_disable() | ||
| 43 | #define unlock_fpu_owner() pagefault_enable() | ||
| 44 | #endif | ||
| 45 | |||
| 37 | #endif /* __SIGNAL_COMMON_H */ | 46 | #endif /* __SIGNAL_COMMON_H */ |
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index fa581192de21..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 | preempt_disable(); | 156 | err |= protected_save_fp_context(sc); |
| 117 | own_fpu(1); | ||
| 118 | err |= save_fp_context(sc); | ||
| 119 | preempt_enable(); | ||
| 120 | } | 157 | } |
| 121 | return err; | 158 | return err; |
| 122 | } | 159 | } |
| @@ -148,10 +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 | preempt_disable(); | 188 | err |= protected_restore_fp_context(sc); |
| 152 | own_fpu(0); | ||
| 153 | err |= restore_fp_context(sc); | ||
| 154 | preempt_enable(); | ||
| 155 | return err ?: sig; | 189 | return err ?: sig; |
| 156 | } | 190 | } |
| 157 | 191 | ||
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 53a337cfeb66..b9a014411f83 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | #include <linux/compat.h> | 22 | #include <linux/compat.h> |
| 23 | #include <linux/suspend.h> | 23 | #include <linux/suspend.h> |
| 24 | #include <linux/compiler.h> | 24 | #include <linux/compiler.h> |
| 25 | #include <linux/uaccess.h> | ||
| 25 | 26 | ||
| 26 | #include <asm/abi.h> | 27 | #include <asm/abi.h> |
| 27 | #include <asm/asm.h> | 28 | #include <asm/asm.h> |
| @@ -29,7 +30,6 @@ | |||
| 29 | #include <linux/bitops.h> | 30 | #include <linux/bitops.h> |
| 30 | #include <asm/cacheflush.h> | 31 | #include <asm/cacheflush.h> |
| 31 | #include <asm/sim.h> | 32 | #include <asm/sim.h> |
| 32 | #include <asm/uaccess.h> | ||
| 33 | #include <asm/ucontext.h> | 33 | #include <asm/ucontext.h> |
| 34 | #include <asm/system.h> | 34 | #include <asm/system.h> |
| 35 | #include <asm/fpu.h> | 35 | #include <asm/fpu.h> |
| @@ -176,6 +176,46 @@ struct rt_sigframe32 { | |||
| 176 | /* | 176 | /* |
| 177 | * sigcontext handlers | 177 | * sigcontext handlers |
| 178 | */ | 178 | */ |
| 179 | static int protected_save_fp_context32(struct sigcontext32 __user *sc) | ||
| 180 | { | ||
| 181 | int err; | ||
| 182 | while (1) { | ||
| 183 | lock_fpu_owner(); | ||
| 184 | own_fpu_inatomic(1); | ||
| 185 | err = save_fp_context32(sc); /* this might fail */ | ||
| 186 | unlock_fpu_owner(); | ||
| 187 | if (likely(!err)) | ||
| 188 | break; | ||
| 189 | /* touch the sigcontext and try again */ | ||
| 190 | err = __put_user(0, &sc->sc_fpregs[0]) | | ||
| 191 | __put_user(0, &sc->sc_fpregs[31]) | | ||
| 192 | __put_user(0, &sc->sc_fpc_csr); | ||
| 193 | if (err) | ||
| 194 | break; /* really bad sigcontext */ | ||
| 195 | } | ||
| 196 | return err; | ||
| 197 | } | ||
| 198 | |||
| 199 | static int protected_restore_fp_context32(struct sigcontext32 __user *sc) | ||
| 200 | { | ||
| 201 | int err, tmp; | ||
| 202 | while (1) { | ||
| 203 | lock_fpu_owner(); | ||
| 204 | own_fpu_inatomic(0); | ||
| 205 | err = restore_fp_context32(sc); /* this might fail */ | ||
| 206 | unlock_fpu_owner(); | ||
| 207 | if (likely(!err)) | ||
| 208 | break; | ||
| 209 | /* touch the sigcontext and try again */ | ||
| 210 | err = __get_user(tmp, &sc->sc_fpregs[0]) | | ||
| 211 | __get_user(tmp, &sc->sc_fpregs[31]) | | ||
| 212 | __get_user(tmp, &sc->sc_fpc_csr); | ||
| 213 | if (err) | ||
| 214 | break; /* really bad sigcontext */ | ||
| 215 | } | ||
| 216 | return err; | ||
| 217 | } | ||
| 218 | |||
| 179 | static int setup_sigcontext32(struct pt_regs *regs, | 219 | static int setup_sigcontext32(struct pt_regs *regs, |
| 180 | struct sigcontext32 __user *sc) | 220 | struct sigcontext32 __user *sc) |
| 181 | { | 221 | { |
| @@ -209,10 +249,7 @@ static int setup_sigcontext32(struct pt_regs *regs, | |||
| 209 | * Save FPU state to signal context. Signal handler | 249 | * Save FPU state to signal context. Signal handler |
| 210 | * will "inherit" current FPU state. | 250 | * will "inherit" current FPU state. |
| 211 | */ | 251 | */ |
| 212 | preempt_disable(); | 252 | err |= protected_save_fp_context32(sc); |
| 213 | own_fpu(1); | ||
| 214 | err |= save_fp_context32(sc); | ||
| 215 | preempt_enable(); | ||
| 216 | } | 253 | } |
| 217 | return err; | 254 | return err; |
| 218 | } | 255 | } |
| @@ -225,10 +262,7 @@ check_and_restore_fp_context32(struct sigcontext32 __user *sc) | |||
| 225 | err = sig = fpcsr_pending(&sc->sc_fpc_csr); | 262 | err = sig = fpcsr_pending(&sc->sc_fpc_csr); |
| 226 | if (err > 0) | 263 | if (err > 0) |
| 227 | err = 0; | 264 | err = 0; |
| 228 | preempt_disable(); | 265 | err |= protected_restore_fp_context32(sc); |
| 229 | own_fpu(0); | ||
| 230 | err |= restore_fp_context32(sc); | ||
| 231 | preempt_enable(); | ||
| 232 | return err ?: sig; | 266 | return err ?: sig; |
| 233 | } | 267 | } |
| 234 | 268 | ||
diff --git a/include/asm-mips/fpu.h b/include/asm-mips/fpu.h index 71436f90203f..b414a7d9db43 100644 --- a/include/asm-mips/fpu.h +++ b/include/asm-mips/fpu.h | |||
| @@ -100,14 +100,19 @@ static inline void __own_fpu(void) | |||
| 100 | set_thread_flag(TIF_USEDFPU); | 100 | set_thread_flag(TIF_USEDFPU); |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | static inline void own_fpu(int restore) | 103 | static inline void own_fpu_inatomic(int restore) |
| 104 | { | 104 | { |
| 105 | preempt_disable(); | ||
| 106 | if (cpu_has_fpu && !__is_fpu_owner()) { | 105 | if (cpu_has_fpu && !__is_fpu_owner()) { |
| 107 | __own_fpu(); | 106 | __own_fpu(); |
| 108 | if (restore) | 107 | if (restore) |
| 109 | _restore_fp(current); | 108 | _restore_fp(current); |
| 110 | } | 109 | } |
| 110 | } | ||
| 111 | |||
| 112 | static inline void own_fpu(int restore) | ||
| 113 | { | ||
| 114 | preempt_disable(); | ||
| 115 | own_fpu_inatomic(restore); | ||
| 111 | preempt_enable(); | 116 | preempt_enable(); |
| 112 | } | 117 | } |
| 113 | 118 | ||
