diff options
author | Paul Burton <paul.burton@imgtec.com> | 2014-02-13 06:27:42 -0500 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2014-03-26 18:09:11 -0400 |
commit | eec43a224cf198c7e3538fca16f689e4d17d4471 (patch) | |
tree | 24d9236c0cd33dcf7862c09799910e8bbf5abde9 /arch/mips/kernel/signal32.c | |
parent | a8ad136789b4256fa372d59daaddb91b72aa0753 (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.c | 74 |
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); | |||
42 | extern asmlinkage int _save_fp_context32(struct sigcontext32 __user *sc); | 43 | extern asmlinkage int _save_fp_context32(struct sigcontext32 __user *sc); |
43 | extern asmlinkage int _restore_fp_context32(struct sigcontext32 __user *sc); | 44 | extern asmlinkage int _restore_fp_context32(struct sigcontext32 __user *sc); |
44 | 45 | ||
46 | extern asmlinkage int _save_msa_context32(struct sigcontext32 __user *sc); | ||
47 | extern 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 | */ | ||
121 | static 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(¤t->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 | |||
136 | static 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(¤t->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 | */ |
116 | static int protected_save_fp_context32(struct sigcontext32 __user *sc) | 154 | static 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 | ||
140 | static int protected_restore_fp_context32(struct sigcontext32 __user *sc) | 184 | static 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 | ||
202 | static int | 258 | static int |
203 | check_and_restore_fp_context32(struct sigcontext32 __user *sc) | 259 | check_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 | ||