aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/signal32.c
diff options
context:
space:
mode:
authorPaul Burton <paul.burton@imgtec.com>2014-02-13 06:27:42 -0500
committerRalf Baechle <ralf@linux-mips.org>2014-03-26 18:09:11 -0400
commiteec43a224cf198c7e3538fca16f689e4d17d4471 (patch)
tree24d9236c0cd33dcf7862c09799910e8bbf5abde9 /arch/mips/kernel/signal32.c
parenta8ad136789b4256fa372d59daaddb91b72aa0753 (diff)
MIPS: Save/restore MSA context around signals
This patch extends sigcontext in order to hold the most significant 64 bits of each vector register in addition to the MSA control & status register. The least significant 64 bits are already saved as the scalar FP context. This makes things a little awkward since the least & most significant 64 bits of each vector register are not contiguous in memory. Thus the copy_u & insert instructions are used to transfer the values of the most significant 64 bits via GP registers. Signed-off-by: Paul Burton <paul.burton@imgtec.com> Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/6533/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/kernel/signal32.c')
-rw-r--r--arch/mips/kernel/signal32.c74
1 files changed, 66 insertions, 8 deletions
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index bae2e6ee2109..299f956e4db3 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -30,6 +30,7 @@
30#include <asm/sim.h> 30#include <asm/sim.h>
31#include <asm/ucontext.h> 31#include <asm/ucontext.h>
32#include <asm/fpu.h> 32#include <asm/fpu.h>
33#include <asm/msa.h>
33#include <asm/war.h> 34#include <asm/war.h>
34#include <asm/vdso.h> 35#include <asm/vdso.h>
35#include <asm/dsp.h> 36#include <asm/dsp.h>
@@ -42,6 +43,9 @@ static int (*restore_fp_context32)(struct sigcontext32 __user *sc);
42extern asmlinkage int _save_fp_context32(struct sigcontext32 __user *sc); 43extern asmlinkage int _save_fp_context32(struct sigcontext32 __user *sc);
43extern asmlinkage int _restore_fp_context32(struct sigcontext32 __user *sc); 44extern asmlinkage int _restore_fp_context32(struct sigcontext32 __user *sc);
44 45
46extern asmlinkage int _save_msa_context32(struct sigcontext32 __user *sc);
47extern asmlinkage int _restore_msa_context32(struct sigcontext32 __user *sc);
48
45/* 49/*
46 * Including <asm/unistd.h> would give use the 64-bit syscall numbers ... 50 * Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
47 */ 51 */
@@ -111,19 +115,59 @@ static int copy_fp_from_sigcontext32(struct sigcontext32 __user *sc)
111} 115}
112 116
113/* 117/*
118 * These functions will save only the upper 64 bits of the vector registers,
119 * since the lower 64 bits have already been saved as the scalar FP context.
120 */
121static int copy_msa_to_sigcontext32(struct sigcontext32 __user *sc)
122{
123 int i;
124 int err = 0;
125
126 for (i = 0; i < NUM_FPU_REGS; i++) {
127 err |=
128 __put_user(get_fpr64(&current->thread.fpu.fpr[i], 1),
129 &sc->sc_msaregs[i]);
130 }
131 err |= __put_user(current->thread.fpu.msacsr, &sc->sc_msa_csr);
132
133 return err;
134}
135
136static int copy_msa_from_sigcontext32(struct sigcontext32 __user *sc)
137{
138 int i;
139 int err = 0;
140 u64 val;
141
142 for (i = 0; i < NUM_FPU_REGS; i++) {
143 err |= __get_user(val, &sc->sc_msaregs[i]);
144 set_fpr64(&current->thread.fpu.fpr[i], 1, val);
145 }
146 err |= __get_user(current->thread.fpu.msacsr, &sc->sc_msa_csr);
147
148 return err;
149}
150
151/*
114 * sigcontext handlers 152 * sigcontext handlers
115 */ 153 */
116static int protected_save_fp_context32(struct sigcontext32 __user *sc) 154static int protected_save_fp_context32(struct sigcontext32 __user *sc,
155 unsigned used_math)
117{ 156{
118 int err; 157 int err;
158 bool save_msa = cpu_has_msa && (used_math & USEDMATH_MSA);
119 while (1) { 159 while (1) {
120 lock_fpu_owner(); 160 lock_fpu_owner();
121 if (is_fpu_owner()) { 161 if (is_fpu_owner()) {
122 err = save_fp_context32(sc); 162 err = save_fp_context32(sc);
163 if (save_msa && !err)
164 err = _save_msa_context32(sc);
123 unlock_fpu_owner(); 165 unlock_fpu_owner();
124 } else { 166 } else {
125 unlock_fpu_owner(); 167 unlock_fpu_owner();
126 err = copy_fp_to_sigcontext32(sc); 168 err = copy_fp_to_sigcontext32(sc);
169 if (save_msa && !err)
170 err = copy_msa_to_sigcontext32(sc);
127 } 171 }
128 if (likely(!err)) 172 if (likely(!err))
129 break; 173 break;
@@ -137,17 +181,28 @@ static int protected_save_fp_context32(struct sigcontext32 __user *sc)
137 return err; 181 return err;
138} 182}
139 183
140static int protected_restore_fp_context32(struct sigcontext32 __user *sc) 184static int protected_restore_fp_context32(struct sigcontext32 __user *sc,
185 unsigned used_math)
141{ 186{
142 int err, tmp __maybe_unused; 187 int err, tmp __maybe_unused;
188 bool restore_msa = cpu_has_msa && (used_math & USEDMATH_MSA);
143 while (1) { 189 while (1) {
144 lock_fpu_owner(); 190 lock_fpu_owner();
145 if (is_fpu_owner()) { 191 if (is_fpu_owner()) {
146 err = restore_fp_context32(sc); 192 err = restore_fp_context32(sc);
193 if (restore_msa && !err) {
194 enable_msa();
195 err = _restore_msa_context32(sc);
196 } else {
197 /* signal handler may have used MSA */
198 disable_msa();
199 }
147 unlock_fpu_owner(); 200 unlock_fpu_owner();
148 } else { 201 } else {
149 unlock_fpu_owner(); 202 unlock_fpu_owner();
150 err = copy_fp_from_sigcontext32(sc); 203 err = copy_fp_from_sigcontext32(sc);
204 if (restore_msa && !err)
205 err = copy_msa_from_sigcontext32(sc);
151 } 206 }
152 if (likely(!err)) 207 if (likely(!err))
153 break; 208 break;
@@ -186,7 +241,8 @@ static int setup_sigcontext32(struct pt_regs *regs,
186 err |= __put_user(mflo3(), &sc->sc_lo3); 241 err |= __put_user(mflo3(), &sc->sc_lo3);
187 } 242 }
188 243
189 used_math = !!used_math(); 244 used_math = used_math() ? USEDMATH_FP : 0;
245 used_math |= thread_msa_context_live() ? USEDMATH_MSA : 0;
190 err |= __put_user(used_math, &sc->sc_used_math); 246 err |= __put_user(used_math, &sc->sc_used_math);
191 247
192 if (used_math) { 248 if (used_math) {
@@ -194,20 +250,21 @@ static int setup_sigcontext32(struct pt_regs *regs,
194 * Save FPU state to signal context. Signal handler 250 * Save FPU state to signal context. Signal handler
195 * will "inherit" current FPU state. 251 * will "inherit" current FPU state.
196 */ 252 */
197 err |= protected_save_fp_context32(sc); 253 err |= protected_save_fp_context32(sc, used_math);
198 } 254 }
199 return err; 255 return err;
200} 256}
201 257
202static int 258static int
203check_and_restore_fp_context32(struct sigcontext32 __user *sc) 259check_and_restore_fp_context32(struct sigcontext32 __user *sc,
260 unsigned used_math)
204{ 261{
205 int err, sig; 262 int err, sig;
206 263
207 err = sig = fpcsr_pending(&sc->sc_fpc_csr); 264 err = sig = fpcsr_pending(&sc->sc_fpc_csr);
208 if (err > 0) 265 if (err > 0)
209 err = 0; 266 err = 0;
210 err |= protected_restore_fp_context32(sc); 267 err |= protected_restore_fp_context32(sc, used_math);
211 return err ?: sig; 268 return err ?: sig;
212} 269}
213 270
@@ -244,9 +301,10 @@ static int restore_sigcontext32(struct pt_regs *regs,
244 if (used_math) { 301 if (used_math) {
245 /* restore fpu context if we have used it before */ 302 /* restore fpu context if we have used it before */
246 if (!err) 303 if (!err)
247 err = check_and_restore_fp_context32(sc); 304 err = check_and_restore_fp_context32(sc, used_math);
248 } else { 305 } else {
249 /* signal handler may have used FPU. Give it up. */ 306 /* signal handler may have used FPU or MSA. Disable them. */
307 disable_msa();
250 lose_fpu(0); 308 lose_fpu(0);
251 } 309 }
252 310