Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

MIPS: Save MSA extended context around signals

It is desirable for signal handlers to be allowed to make use of MSA,
particularly if auto vectorisation is used when compiling a program.
The MSA context must therefore be saved & restored before & after
invoking the signal handler. Make use of the extended context structs
defined in the preceding patch to save MSA context after the sigframe
when appropriate.

[ralf@linux-mips.org: Fixed conflicts.]

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: 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/10796/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

authored by

Paul Burton and committed by
Ralf Baechle
bf82cb30 f1fe2d21

+333 -15
+118
arch/mips/kernel/r4k_fpu.S
··· 238 238 239 239 #endif /* CONFIG_CPU_HAS_MSA */ 240 240 241 + #ifdef CONFIG_CPU_HAS_MSA 242 + 243 + .macro save_msa_upper wr, off, base 244 + .set push 245 + .set noat 246 + #ifdef CONFIG_64BIT 247 + copy_u_d \wr, 1 248 + EX sd $1, \off(\base) 249 + #elif defined(CONFIG_CPU_LITTLE_ENDIAN) 250 + copy_u_w \wr, 2 251 + EX sw $1, \off(\base) 252 + copy_u_w \wr, 3 253 + EX sw $1, (\off+4)(\base) 254 + #else /* CONFIG_CPU_BIG_ENDIAN */ 255 + copy_u_w \wr, 2 256 + EX sw $1, (\off+4)(\base) 257 + copy_u_w \wr, 3 258 + EX sw $1, \off(\base) 259 + #endif 260 + .set pop 261 + .endm 262 + 263 + LEAF(_save_msa_all_upper) 264 + save_msa_upper 0, 0x00, a0 265 + save_msa_upper 1, 0x08, a0 266 + save_msa_upper 2, 0x10, a0 267 + save_msa_upper 3, 0x18, a0 268 + save_msa_upper 4, 0x20, a0 269 + save_msa_upper 5, 0x28, a0 270 + save_msa_upper 6, 0x30, a0 271 + save_msa_upper 7, 0x38, a0 272 + save_msa_upper 8, 0x40, a0 273 + save_msa_upper 9, 0x48, a0 274 + save_msa_upper 10, 0x50, a0 275 + save_msa_upper 11, 0x58, a0 276 + save_msa_upper 12, 0x60, a0 277 + save_msa_upper 13, 0x68, a0 278 + save_msa_upper 14, 0x70, a0 279 + save_msa_upper 15, 0x78, a0 280 + save_msa_upper 16, 0x80, a0 281 + save_msa_upper 17, 0x88, a0 282 + save_msa_upper 18, 0x90, a0 283 + save_msa_upper 19, 0x98, a0 284 + save_msa_upper 20, 0xa0, a0 285 + save_msa_upper 21, 0xa8, a0 286 + save_msa_upper 22, 0xb0, a0 287 + save_msa_upper 23, 0xb8, a0 288 + save_msa_upper 24, 0xc0, a0 289 + save_msa_upper 25, 0xc8, a0 290 + save_msa_upper 26, 0xd0, a0 291 + save_msa_upper 27, 0xd8, a0 292 + save_msa_upper 28, 0xe0, a0 293 + save_msa_upper 29, 0xe8, a0 294 + save_msa_upper 30, 0xf0, a0 295 + save_msa_upper 31, 0xf8, a0 296 + jr ra 297 + li v0, 0 298 + END(_save_msa_all_upper) 299 + 300 + .macro restore_msa_upper wr, off, base 301 + .set push 302 + .set noat 303 + #ifdef CONFIG_64BIT 304 + EX ld $1, \off(\base) 305 + insert_d \wr, 1 306 + #elif defined(CONFIG_CPU_LITTLE_ENDIAN) 307 + EX lw $1, \off(\base) 308 + insert_w \wr, 2 309 + EX lw $1, (\off+4)(\base) 310 + insert_w \wr, 3 311 + #else /* CONFIG_CPU_BIG_ENDIAN */ 312 + EX lw $1, (\off+4)(\base) 313 + insert_w \wr, 2 314 + EX lw $1, \off(\base) 315 + insert_w \wr, 3 316 + #endif 317 + .set pop 318 + .endm 319 + 320 + LEAF(_restore_msa_all_upper) 321 + restore_msa_upper 0, 0x00, a0 322 + restore_msa_upper 1, 0x08, a0 323 + restore_msa_upper 2, 0x10, a0 324 + restore_msa_upper 3, 0x18, a0 325 + restore_msa_upper 4, 0x20, a0 326 + restore_msa_upper 5, 0x28, a0 327 + restore_msa_upper 6, 0x30, a0 328 + restore_msa_upper 7, 0x38, a0 329 + restore_msa_upper 8, 0x40, a0 330 + restore_msa_upper 9, 0x48, a0 331 + restore_msa_upper 10, 0x50, a0 332 + restore_msa_upper 11, 0x58, a0 333 + restore_msa_upper 12, 0x60, a0 334 + restore_msa_upper 13, 0x68, a0 335 + restore_msa_upper 14, 0x70, a0 336 + restore_msa_upper 15, 0x78, a0 337 + restore_msa_upper 16, 0x80, a0 338 + restore_msa_upper 17, 0x88, a0 339 + restore_msa_upper 18, 0x90, a0 340 + restore_msa_upper 19, 0x98, a0 341 + restore_msa_upper 20, 0xa0, a0 342 + restore_msa_upper 21, 0xa8, a0 343 + restore_msa_upper 22, 0xb0, a0 344 + restore_msa_upper 23, 0xb8, a0 345 + restore_msa_upper 24, 0xc0, a0 346 + restore_msa_upper 25, 0xc8, a0 347 + restore_msa_upper 26, 0xd0, a0 348 + restore_msa_upper 27, 0xd8, a0 349 + restore_msa_upper 28, 0xe0, a0 350 + restore_msa_upper 29, 0xe8, a0 351 + restore_msa_upper 30, 0xf0, a0 352 + restore_msa_upper 31, 0xf8, a0 353 + jr ra 354 + li v0, 0 355 + END(_restore_msa_all_upper) 356 + 357 + #endif /* CONFIG_CPU_HAS_MSA */ 358 + 241 359 .set reorder 242 360 243 361 .type fault@function
+3
arch/mips/kernel/signal-common.h
··· 37 37 extern asmlinkage int 38 38 _restore_fp_context(void __user *fpregs, void __user *csr); 39 39 40 + extern asmlinkage int _save_msa_all_upper(void __user *buf); 41 + extern asmlinkage int _restore_msa_all_upper(void __user *buf); 42 + 40 43 #endif /* __SIGNAL_COMMON_H */
+212 -15
arch/mips/kernel/signal.c
··· 38 38 #include <asm/vdso.h> 39 39 #include <asm/dsp.h> 40 40 #include <asm/inst.h> 41 + #include <asm/msa.h> 41 42 42 43 #include "signal-common.h" 43 44 ··· 126 125 } 127 126 128 127 /* 128 + * Extended context handling. 129 + */ 130 + 131 + static inline void __user *sc_to_extcontext(void __user *sc) 132 + { 133 + struct ucontext __user *uc; 134 + 135 + /* 136 + * We can just pretend the sigcontext is always embedded in a struct 137 + * ucontext here, because the offset from sigcontext to extended 138 + * context is the same in the struct sigframe case. 139 + */ 140 + uc = container_of(sc, struct ucontext, uc_mcontext); 141 + return &uc->uc_extcontext; 142 + } 143 + 144 + static int save_msa_extcontext(void __user *buf) 145 + { 146 + struct msa_extcontext __user *msa = buf; 147 + uint64_t val; 148 + int i, err; 149 + 150 + if (!thread_msa_context_live()) 151 + return 0; 152 + 153 + /* 154 + * Ensure that we can't lose the live MSA context between checking 155 + * for it & writing it to memory. 156 + */ 157 + preempt_disable(); 158 + 159 + if (is_msa_enabled()) { 160 + /* 161 + * There are no EVA versions of the vector register load/store 162 + * instructions, so MSA context has to be saved to kernel memory 163 + * and then copied to user memory. The save to kernel memory 164 + * should already have been done when handling scalar FP 165 + * context. 166 + */ 167 + BUG_ON(config_enabled(CONFIG_EVA)); 168 + 169 + err = __put_user(read_msa_csr(), &msa->csr); 170 + err |= _save_msa_all_upper(&msa->wr); 171 + 172 + preempt_enable(); 173 + } else { 174 + preempt_enable(); 175 + 176 + err = __put_user(current->thread.fpu.msacsr, &msa->csr); 177 + 178 + for (i = 0; i < NUM_FPU_REGS; i++) { 179 + val = get_fpr64(&current->thread.fpu.fpr[i], 1); 180 + err |= __put_user(val, &msa->wr[i]); 181 + } 182 + } 183 + 184 + err |= __put_user(MSA_EXTCONTEXT_MAGIC, &msa->ext.magic); 185 + err |= __put_user(sizeof(*msa), &msa->ext.size); 186 + 187 + return err ? -EFAULT : sizeof(*msa); 188 + } 189 + 190 + static int restore_msa_extcontext(void __user *buf, unsigned int size) 191 + { 192 + struct msa_extcontext __user *msa = buf; 193 + unsigned long long val; 194 + unsigned int csr; 195 + int i, err; 196 + 197 + if (size != sizeof(*msa)) 198 + return -EINVAL; 199 + 200 + err = get_user(csr, &msa->csr); 201 + if (err) 202 + return err; 203 + 204 + preempt_disable(); 205 + 206 + if (is_msa_enabled()) { 207 + /* 208 + * There are no EVA versions of the vector register load/store 209 + * instructions, so MSA context has to be copied to kernel 210 + * memory and later loaded to registers. The same is true of 211 + * scalar FP context, so FPU & MSA should have already been 212 + * disabled whilst handling scalar FP context. 213 + */ 214 + BUG_ON(config_enabled(CONFIG_EVA)); 215 + 216 + write_msa_csr(csr); 217 + err |= _restore_msa_all_upper(&msa->wr); 218 + preempt_enable(); 219 + } else { 220 + preempt_enable(); 221 + 222 + current->thread.fpu.msacsr = csr; 223 + 224 + for (i = 0; i < NUM_FPU_REGS; i++) { 225 + err |= __get_user(val, &msa->wr[i]); 226 + set_fpr64(&current->thread.fpu.fpr[i], 1, val); 227 + } 228 + } 229 + 230 + return err; 231 + } 232 + 233 + static int save_extcontext(void __user *buf) 234 + { 235 + int sz; 236 + 237 + sz = save_msa_extcontext(buf); 238 + if (sz < 0) 239 + return sz; 240 + buf += sz; 241 + 242 + /* If no context was saved then trivially return */ 243 + if (!sz) 244 + return 0; 245 + 246 + /* Write the end marker */ 247 + if (__put_user(END_EXTCONTEXT_MAGIC, (u32 *)buf)) 248 + return -EFAULT; 249 + 250 + sz += sizeof(((struct extcontext *)NULL)->magic); 251 + return sz; 252 + } 253 + 254 + static int restore_extcontext(void __user *buf) 255 + { 256 + struct extcontext ext; 257 + int err; 258 + 259 + while (1) { 260 + err = __get_user(ext.magic, (unsigned int *)buf); 261 + if (err) 262 + return err; 263 + 264 + if (ext.magic == END_EXTCONTEXT_MAGIC) 265 + return 0; 266 + 267 + err = __get_user(ext.size, (unsigned int *)(buf 268 + + offsetof(struct extcontext, size))); 269 + if (err) 270 + return err; 271 + 272 + switch (ext.magic) { 273 + case MSA_EXTCONTEXT_MAGIC: 274 + err = restore_msa_extcontext(buf, ext.size); 275 + break; 276 + 277 + default: 278 + err = -EINVAL; 279 + break; 280 + } 281 + 282 + if (err) 283 + return err; 284 + 285 + buf += ext.size; 286 + } 287 + } 288 + 289 + /* 129 290 * Helper routines 130 291 */ 131 292 int protected_save_fp_context(void __user *sc) ··· 296 133 uint64_t __user *fpregs = sc + abi->off_sc_fpregs; 297 134 uint32_t __user *csr = sc + abi->off_sc_fpc_csr; 298 135 uint32_t __user *used_math = sc + abi->off_sc_used_math; 299 - unsigned int used; 136 + unsigned int used, ext_sz; 300 137 int err; 301 138 302 139 used = used_math() ? USED_FP : 0; 303 - if (used) { 304 - if (!test_thread_flag(TIF_32BIT_FPREGS)) 305 - used |= USED_FR1; 306 - if (test_thread_flag(TIF_HYBRID_FPREGS)) 307 - used |= USED_HYBRID_FPRS; 308 - } 140 + if (!used) 141 + goto fp_done; 309 142 310 - err = __put_user(used, used_math); 311 - if (err || !(used & USED_FP)) 312 - return err; 143 + if (!test_thread_flag(TIF_32BIT_FPREGS)) 144 + used |= USED_FR1; 145 + if (test_thread_flag(TIF_HYBRID_FPREGS)) 146 + used |= USED_HYBRID_FPRS; 313 147 314 148 /* 315 149 * EVA does not have userland equivalents of ldc1 or sdc1, so ··· 331 171 __put_user(0, &fpregs[31]) | 332 172 __put_user(0, csr); 333 173 if (err) 334 - break; /* really bad sigcontext */ 174 + return err; /* really bad sigcontext */ 335 175 } 336 176 337 - return err; 177 + fp_done: 178 + ext_sz = err = save_extcontext(sc_to_extcontext(sc)); 179 + if (err < 0) 180 + return err; 181 + used |= ext_sz ? USED_EXTCONTEXT : 0; 182 + 183 + return __put_user(used, used_math); 338 184 } 339 185 340 186 int protected_restore_fp_context(void __user *sc) ··· 350 184 uint32_t __user *csr = sc + abi->off_sc_fpc_csr; 351 185 uint32_t __user *used_math = sc + abi->off_sc_used_math; 352 186 unsigned int used; 353 - int err, sig, tmp __maybe_unused; 187 + int err, sig = 0, tmp __maybe_unused; 354 188 355 189 err = __get_user(used, used_math); 356 190 conditional_used_math(used & USED_FP); ··· 359 193 * The signal handler may have used FPU; give it up if the program 360 194 * doesn't want it following sigreturn. 361 195 */ 362 - if (err || !(used & USED_FP)) { 196 + if (err || !(used & USED_FP)) 363 197 lose_fpu(0); 198 + if (err) 364 199 return err; 365 - } 200 + if (!(used & USED_FP)) 201 + goto fp_done; 366 202 367 203 err = sig = fpcsr_pending(csr); 368 204 if (err < 0) ··· 396 228 if (err) 397 229 break; /* really bad sigcontext */ 398 230 } 231 + 232 + fp_done: 233 + if (used & USED_EXTCONTEXT) 234 + err |= restore_extcontext(sc_to_extcontext(sc)); 399 235 400 236 return err ?: sig; 401 237 } ··· 438 266 err |= protected_save_fp_context(sc); 439 267 440 268 return err; 269 + } 270 + 271 + static size_t extcontext_max_size(void) 272 + { 273 + size_t sz = 0; 274 + 275 + /* 276 + * The assumption here is that between this point & the point at which 277 + * the extended context is saved the size of the context should only 278 + * ever be able to shrink (if the task is preempted), but never grow. 279 + * That is, what this function returns is an upper bound on the size of 280 + * the extended context for the current task at the current time. 281 + */ 282 + 283 + if (thread_msa_context_live()) 284 + sz += sizeof(struct msa_extcontext); 285 + 286 + /* If any context is saved then we'll append the end marker */ 287 + if (sz) 288 + sz += sizeof(((struct extcontext *)NULL)->magic); 289 + 290 + return sz; 441 291 } 442 292 443 293 int fpcsr_pending(unsigned int __user *fpcsr) ··· 517 323 size_t frame_size) 518 324 { 519 325 unsigned long sp; 326 + 327 + /* Leave space for potential extended context */ 328 + frame_size += extcontext_max_size(); 520 329 521 330 /* Default to using normal stack */ 522 331 sp = regs->regs[29];