diff options
author | Michael Neuling <mikey@neuling.org> | 2008-07-02 00:06:37 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2008-07-03 02:58:11 -0400 |
commit | 6a274c08f2f4dfac7167bbd849621f3a2b55d424 (patch) | |
tree | 1bad45a11c1e436ffbcb84107783da0e423925f9 /arch/powerpc/kernel/signal_32.c | |
parent | 2d1b2027626d5151fff8ef7c06ca8e7876a1a510 (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.c | 109 |
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 | ||
332 | unsigned 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 | |||
345 | unsigned 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 | |||
360 | unsigned 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 | |||
372 | unsigned 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 | ||
385 | inline 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 | |||
392 | inline 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], ¤t->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(¤t->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 |