aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/signal32.c
diff options
context:
space:
mode:
authorPaul Burton <paul.burton@imgtec.com>2015-07-27 15:58:18 -0400
committerRalf Baechle <ralf@linux-mips.org>2015-09-03 06:07:56 -0400
commitd02a40aff6e043bae1cd6e6416e9048990928b1d (patch)
treec915c841990f1a18d5173e7e526dd3f56aae6e17 /arch/mips/kernel/signal32.c
parent6f0aba63bfb3eb33b68cf746c44b6ab302599180 (diff)
MIPS: Use common FP sigcontext code for O32 compat
Make use of the common FP sigcontext code for O32 binaries running on MIPS64 kernels now that it is taking appropriate offsets into struct sigcontext(32) from struct mips_abi. [ralf@linux-mips.org: Fixed reject.] Signed-off-by: Paul Burton <paul.burton@imgtec.com> Cc: linux-mips@linux-mips.org Cc: Guenter Roeck <linux@roeck-us.net> Cc: Matthew Fortune <matthew.fortune@imgtec.com> Cc: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com> Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: linux-kernel@vger.kernel.org Cc: Richard Weinberger <richard@nod.at> Cc: James Hogan <james.hogan@imgtec.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Andy Lutomirski <luto@amacapital.net> Cc: Markos Chandras <markos.chandras@imgtec.com> Cc: Manuel Lauss <manuel.lauss@gmail.com> Cc: Maciej W. Rozycki <macro@codesourcery.com> Patchwork: https://patchwork.linux-mips.org/patch/10792/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/kernel/signal32.c')
-rw-r--r--arch/mips/kernel/signal32.c150
1 files changed, 6 insertions, 144 deletions
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index da70ea5cf6ec..7c45cb3e075a 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -36,12 +36,6 @@
36 36
37#include "signal-common.h" 37#include "signal-common.h"
38 38
39static int (*save_fp_context32)(struct sigcontext32 __user *sc);
40static int (*restore_fp_context32)(struct sigcontext32 __user *sc);
41
42extern asmlinkage int _save_fp_context32(struct sigcontext32 __user *sc);
43extern asmlinkage int _restore_fp_context32(struct sigcontext32 __user *sc);
44
45/* 39/*
46 * Including <asm/unistd.h> would give use the 64-bit syscall numbers ... 40 * Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
47 */ 41 */
@@ -74,99 +68,11 @@ struct rt_sigframe32 {
74 struct ucontext32 rs_uc; 68 struct ucontext32 rs_uc;
75}; 69};
76 70
77/*
78 * Thread saved context copy to/from a signal context presumed to be on the
79 * user stack, and therefore accessed with appropriate macros from uaccess.h.
80 */
81static int copy_fp_to_sigcontext32(struct sigcontext32 __user *sc)
82{
83 int i;
84 int err = 0;
85 int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1;
86
87 for (i = 0; i < NUM_FPU_REGS; i += inc) {
88 err |=
89 __put_user(get_fpr64(&current->thread.fpu.fpr[i], 0),
90 &sc->sc_fpregs[i]);
91 }
92 err |= __put_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr);
93
94 return err;
95}
96
97static int copy_fp_from_sigcontext32(struct sigcontext32 __user *sc)
98{
99 int i;
100 int err = 0;
101 int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1;
102 u64 fpr_val;
103
104 for (i = 0; i < NUM_FPU_REGS; i += inc) {
105 err |= __get_user(fpr_val, &sc->sc_fpregs[i]);
106 set_fpr64(&current->thread.fpu.fpr[i], 0, fpr_val);
107 }
108 err |= __get_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr);
109
110 return err;
111}
112
113/*
114 * sigcontext handlers
115 */
116static int protected_save_fp_context32(struct sigcontext32 __user *sc)
117{
118 int err;
119 while (1) {
120 lock_fpu_owner();
121 if (is_fpu_owner()) {
122 err = save_fp_context32(sc);
123 unlock_fpu_owner();
124 } else {
125 unlock_fpu_owner();
126 err = copy_fp_to_sigcontext32(sc);
127 }
128 if (likely(!err))
129 break;
130 /* touch the sigcontext and try again */
131 err = __put_user(0, &sc->sc_fpregs[0]) |
132 __put_user(0, &sc->sc_fpregs[31]) |
133 __put_user(0, &sc->sc_fpc_csr);
134 if (err)
135 break; /* really bad sigcontext */
136 }
137 return err;
138}
139
140static int protected_restore_fp_context32(struct sigcontext32 __user *sc)
141{
142 int err, tmp __maybe_unused;
143 while (1) {
144 lock_fpu_owner();
145 if (is_fpu_owner()) {
146 err = restore_fp_context32(sc);
147 unlock_fpu_owner();
148 } else {
149 unlock_fpu_owner();
150 err = copy_fp_from_sigcontext32(sc);
151 }
152 if (likely(!err))
153 break;
154 /* touch the sigcontext and try again */
155 err = __get_user(tmp, &sc->sc_fpregs[0]) |
156 __get_user(tmp, &sc->sc_fpregs[31]) |
157 __get_user(tmp, &sc->sc_fpc_csr);
158 if (err)
159 break; /* really bad sigcontext */
160 }
161 return err;
162}
163
164static int setup_sigcontext32(struct pt_regs *regs, 71static int setup_sigcontext32(struct pt_regs *regs,
165 struct sigcontext32 __user *sc) 72 struct sigcontext32 __user *sc)
166{ 73{
167 int err = 0; 74 int err = 0;
168 int i; 75 int i;
169 u32 used_math;
170 76
171 err |= __put_user(regs->cp0_epc, &sc->sc_pc); 77 err |= __put_user(regs->cp0_epc, &sc->sc_pc);
172 78
@@ -186,35 +92,18 @@ static int setup_sigcontext32(struct pt_regs *regs,
186 err |= __put_user(mflo3(), &sc->sc_lo3); 92 err |= __put_user(mflo3(), &sc->sc_lo3);
187 } 93 }
188 94
189 used_math = !!used_math(); 95 /*
190 err |= __put_user(used_math, &sc->sc_used_math); 96 * Save FPU state to signal context. Signal handler
97 * will "inherit" current FPU state.
98 */
99 err |= protected_save_fp_context(sc);
191 100
192 if (used_math) {
193 /*
194 * Save FPU state to signal context. Signal handler
195 * will "inherit" current FPU state.
196 */
197 err |= protected_save_fp_context32(sc);
198 }
199 return err; 101 return err;
200} 102}
201 103
202static int
203check_and_restore_fp_context32(struct sigcontext32 __user *sc)
204{
205 int err, sig;
206
207 err = sig = fpcsr_pending(&sc->sc_fpc_csr);
208 if (err > 0)
209 err = 0;
210 err |= protected_restore_fp_context32(sc);
211 return err ?: sig;
212}
213
214static int restore_sigcontext32(struct pt_regs *regs, 104static int restore_sigcontext32(struct pt_regs *regs,
215 struct sigcontext32 __user *sc) 105 struct sigcontext32 __user *sc)
216{ 106{
217 u32 used_math;
218 int err = 0; 107 int err = 0;
219 s32 treg; 108 s32 treg;
220 int i; 109 int i;
@@ -238,19 +127,7 @@ static int restore_sigcontext32(struct pt_regs *regs,
238 for (i = 1; i < 32; i++) 127 for (i = 1; i < 32; i++)
239 err |= __get_user(regs->regs[i], &sc->sc_regs[i]); 128 err |= __get_user(regs->regs[i], &sc->sc_regs[i]);
240 129
241 err |= __get_user(used_math, &sc->sc_used_math); 130 return err ?: protected_restore_fp_context(sc);
242 conditional_used_math(used_math);
243
244 if (used_math) {
245 /* restore fpu context if we have used it before */
246 if (!err)
247 err = check_and_restore_fp_context32(sc);
248 } else {
249 /* signal handler may have used FPU. Give it up. */
250 lose_fpu(0);
251 }
252
253 return err;
254} 131}
255 132
256/* 133/*
@@ -591,18 +468,3 @@ struct mips_abi mips_abi_32 = {
591 .off_sc_fpc_csr = offsetof(struct sigcontext32, sc_fpc_csr), 468 .off_sc_fpc_csr = offsetof(struct sigcontext32, sc_fpc_csr),
592 .off_sc_used_math = offsetof(struct sigcontext32, sc_used_math), 469 .off_sc_used_math = offsetof(struct sigcontext32, sc_used_math),
593}; 470};
594
595static int signal32_init(void)
596{
597 if (cpu_has_fpu) {
598 save_fp_context32 = _save_fp_context32;
599 restore_fp_context32 = _restore_fp_context32;
600 } else {
601 save_fp_context32 = copy_fp_to_sigcontext32;
602 restore_fp_context32 = copy_fp_from_sigcontext32;
603 }
604
605 return 0;
606}
607
608arch_initcall(signal32_init);