aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/signal_32.c
diff options
context:
space:
mode:
authorMichael Neuling <mikey@neuling.org>2008-07-02 00:06:37 -0400
committerPaul Mackerras <paulus@samba.org>2008-07-03 02:58:11 -0400
commit6a274c08f2f4dfac7167bbd849621f3a2b55d424 (patch)
tree1bad45a11c1e436ffbcb84107783da0e423925f9 /arch/powerpc/kernel/signal_32.c
parent2d1b2027626d5151fff8ef7c06ca8e7876a1a510 (diff)
powerpc: Clean up copy_to/from_user for vsx and fpr
This merges and cleans up some of the ugly copy/to from user code which is required for the new fpr and vsx layout in the thread_struct. Also fixes some hard coded buffer sizes and removes a redundant fpr_flush_to_thread. Signed-off-by: Michael Neuling <mikey@neuling.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/kernel/signal_32.c')
-rw-r--r--arch/powerpc/kernel/signal_32.c109
1 files changed, 75 insertions, 34 deletions
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 349d3487d920..9991e2a58bf4 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -328,6 +328,75 @@ struct rt_sigframe {
328 int abigap[56]; 328 int abigap[56];
329}; 329};
330 330
331#ifdef CONFIG_VSX
332unsigned long copy_fpr_to_user(void __user *to,
333 struct task_struct *task)
334{
335 double buf[ELF_NFPREG];
336 int i;
337
338 /* save FPR copy to local buffer then write to the thread_struct */
339 for (i = 0; i < (ELF_NFPREG - 1) ; i++)
340 buf[i] = task->thread.TS_FPR(i);
341 memcpy(&buf[i], &task->thread.fpscr, sizeof(double));
342 return __copy_to_user(to, buf, ELF_NFPREG * sizeof(double));
343}
344
345unsigned long copy_fpr_from_user(struct task_struct *task,
346 void __user *from)
347{
348 double buf[ELF_NFPREG];
349 int i;
350
351 if (__copy_from_user(buf, from, ELF_NFPREG * sizeof(double)))
352 return 1;
353 for (i = 0; i < (ELF_NFPREG - 1) ; i++)
354 task->thread.TS_FPR(i) = buf[i];
355 memcpy(&task->thread.fpscr, &buf[i], sizeof(double));
356
357 return 0;
358}
359
360unsigned long copy_vsx_to_user(void __user *to,
361 struct task_struct *task)
362{
363 double buf[ELF_NVSRHALFREG];
364 int i;
365
366 /* save FPR copy to local buffer then write to the thread_struct */
367 for (i = 0; i < ELF_NVSRHALFREG; i++)
368 buf[i] = task->thread.fpr[i][TS_VSRLOWOFFSET];
369 return __copy_to_user(to, buf, ELF_NVSRHALFREG * sizeof(double));
370}
371
372unsigned long copy_vsx_from_user(struct task_struct *task,
373 void __user *from)
374{
375 double buf[ELF_NVSRHALFREG];
376 int i;
377
378 if (__copy_from_user(buf, from, ELF_NVSRHALFREG * sizeof(double)))
379 return 1;
380 for (i = 0; i < ELF_NVSRHALFREG ; i++)
381 task->thread.fpr[i][TS_VSRLOWOFFSET] = buf[i];
382 return 0;
383}
384#else
385inline unsigned long copy_fpr_to_user(void __user *to,
386 struct task_struct *task)
387{
388 return __copy_to_user(to, task->thread.fpr,
389 ELF_NFPREG * sizeof(double));
390}
391
392inline unsigned long copy_fpr_from_user(struct task_struct *task,
393 void __user *from)
394{
395 return __copy_from_user(task->thread.fpr, from,
396 ELF_NFPREG * sizeof(double));
397}
398#endif
399
331/* 400/*
332 * Save the current user registers on the user stack. 401 * Save the current user registers on the user stack.
333 * We only save the altivec/spe registers if the process has used 402 * We only save the altivec/spe registers if the process has used
@@ -337,10 +406,6 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame,
337 int sigret) 406 int sigret)
338{ 407{
339 unsigned long msr = regs->msr; 408 unsigned long msr = regs->msr;
340#ifdef CONFIG_VSX
341 double buf[32];
342 int i;
343#endif
344 409
345 /* Make sure floating point registers are stored in regs */ 410 /* Make sure floating point registers are stored in regs */
346 flush_fp_to_thread(current); 411 flush_fp_to_thread(current);
@@ -370,14 +435,9 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame,
370 if (__put_user(current->thread.vrsave, (u32 __user *)&frame->mc_vregs[32])) 435 if (__put_user(current->thread.vrsave, (u32 __user *)&frame->mc_vregs[32]))
371 return 1; 436 return 1;
372#endif /* CONFIG_ALTIVEC */ 437#endif /* CONFIG_ALTIVEC */
373#ifdef CONFIG_VSX 438 if (copy_fpr_to_user(&frame->mc_fregs, current))
374 /* save FPR copy to local buffer then write to the thread_struct */
375 flush_fp_to_thread(current);
376 for (i = 0; i < 32 ; i++)
377 buf[i] = current->thread.TS_FPR(i);
378 memcpy(&buf[i], &current->thread.fpscr, sizeof(double));
379 if (__copy_to_user(&frame->mc_fregs, buf, ELF_NFPREG * sizeof(double)))
380 return 1; 439 return 1;
440#ifdef CONFIG_VSX
381 /* 441 /*
382 * Copy VSR 0-31 upper half from thread_struct to local 442 * Copy VSR 0-31 upper half from thread_struct to local
383 * buffer, then write that to userspace. Also set MSR_VSX in 443 * buffer, then write that to userspace. Also set MSR_VSX in
@@ -386,18 +446,10 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame,
386 */ 446 */
387 if (current->thread.used_vsr) { 447 if (current->thread.used_vsr) {
388 flush_vsx_to_thread(current); 448 flush_vsx_to_thread(current);
389 for (i = 0; i < 32 ; i++) 449 if (copy_vsx_to_user(&frame->mc_vsregs, current))
390 buf[i] = current->thread.fpr[i][TS_VSRLOWOFFSET];
391 if (__copy_to_user(&frame->mc_vsregs, buf,
392 ELF_NVSRHALFREG * sizeof(double)))
393 return 1; 450 return 1;
394 msr |= MSR_VSX; 451 msr |= MSR_VSX;
395 } 452 }
396#else
397 /* save floating-point registers */
398 if (__copy_to_user(&frame->mc_fregs, current->thread.fpr,
399 ELF_NFPREG * sizeof(double)))
400 return 1;
401#endif /* CONFIG_VSX */ 453#endif /* CONFIG_VSX */
402#ifdef CONFIG_SPE 454#ifdef CONFIG_SPE
403 /* save spe registers */ 455 /* save spe registers */
@@ -442,7 +494,6 @@ static long restore_user_regs(struct pt_regs *regs,
442 unsigned int save_r2 = 0; 494 unsigned int save_r2 = 0;
443 unsigned long msr; 495 unsigned long msr;
444#ifdef CONFIG_VSX 496#ifdef CONFIG_VSX
445 double buf[32];
446 int i; 497 int i;
447#endif 498#endif
448 499
@@ -490,13 +541,10 @@ static long restore_user_regs(struct pt_regs *regs,
490 if (__get_user(current->thread.vrsave, (u32 __user *)&sr->mc_vregs[32])) 541 if (__get_user(current->thread.vrsave, (u32 __user *)&sr->mc_vregs[32]))
491 return 1; 542 return 1;
492#endif /* CONFIG_ALTIVEC */ 543#endif /* CONFIG_ALTIVEC */
544 if (copy_fpr_from_user(current, &sr->mc_fregs))
545 return 1;
493 546
494#ifdef CONFIG_VSX 547#ifdef CONFIG_VSX
495 if (__copy_from_user(buf, &sr->mc_fregs,sizeof(sr->mc_fregs)))
496 return 1;
497 for (i = 0; i < 32 ; i++)
498 current->thread.TS_FPR(i) = buf[i];
499 memcpy(&current->thread.fpscr, &buf[i], sizeof(double));
500 /* 548 /*
501 * Force the process to reload the VSX registers from 549 * Force the process to reload the VSX registers from
502 * current->thread when it next does VSX instruction. 550 * current->thread when it next does VSX instruction.
@@ -507,18 +555,11 @@ static long restore_user_regs(struct pt_regs *regs,
507 * Restore altivec registers from the stack to a local 555 * Restore altivec registers from the stack to a local
508 * buffer, then write this out to the thread_struct 556 * buffer, then write this out to the thread_struct
509 */ 557 */
510 if (__copy_from_user(buf, &sr->mc_vsregs, 558 if (copy_vsx_from_user(current, &sr->mc_vsregs))
511 sizeof(sr->mc_vsregs)))
512 return 1; 559 return 1;
513 for (i = 0; i < 32 ; i++)
514 current->thread.fpr[i][TS_VSRLOWOFFSET] = buf[i];
515 } else if (current->thread.used_vsr) 560 } else if (current->thread.used_vsr)
516 for (i = 0; i < 32 ; i++) 561 for (i = 0; i < 32 ; i++)
517 current->thread.fpr[i][TS_VSRLOWOFFSET] = 0; 562 current->thread.fpr[i][TS_VSRLOWOFFSET] = 0;
518#else
519 if (__copy_from_user(current->thread.fpr, &sr->mc_fregs,
520 sizeof(sr->mc_fregs)))
521 return 1;
522#endif /* CONFIG_VSX */ 563#endif /* CONFIG_VSX */
523 /* 564 /*
524 * force the process to reload the FP registers from 565 * force the process to reload the FP registers from