aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--arch/powerpc/kernel/signal.h10
-rw-r--r--arch/powerpc/kernel/signal_32.c109
-rw-r--r--arch/powerpc/kernel/signal_64.c43
3 files changed, 96 insertions, 66 deletions
diff --git a/arch/powerpc/kernel/signal.h b/arch/powerpc/kernel/signal.h
index 77efb3d5465a..28f4b9f5fe5e 100644
--- a/arch/powerpc/kernel/signal.h
+++ b/arch/powerpc/kernel/signal.h
@@ -24,6 +24,16 @@ extern int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
24 siginfo_t *info, sigset_t *oldset, 24 siginfo_t *info, sigset_t *oldset,
25 struct pt_regs *regs); 25 struct pt_regs *regs);
26 26
27extern unsigned long copy_fpr_to_user(void __user *to,
28 struct task_struct *task);
29extern unsigned long copy_fpr_from_user(struct task_struct *task,
30 void __user *from);
31#ifdef CONFIG_VSX
32extern unsigned long copy_vsx_to_user(void __user *to,
33 struct task_struct *task);
34extern unsigned long copy_vsx_from_user(struct task_struct *task,
35 void __user *from);
36#endif
27 37
28#ifdef CONFIG_PPC64 38#ifdef CONFIG_PPC64
29 39
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
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index 8214e57aab67..93ebfb6944b6 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -89,10 +89,6 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
89#endif 89#endif
90 unsigned long msr = regs->msr; 90 unsigned long msr = regs->msr;
91 long err = 0; 91 long err = 0;
92#ifdef CONFIG_VSX
93 double buf[FP_REGS_SIZE];
94 int i;
95#endif
96 92
97 flush_fp_to_thread(current); 93 flush_fp_to_thread(current);
98 94
@@ -117,12 +113,9 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
117 err |= __put_user(0, &sc->v_regs); 113 err |= __put_user(0, &sc->v_regs);
118#endif /* CONFIG_ALTIVEC */ 114#endif /* CONFIG_ALTIVEC */
119 flush_fp_to_thread(current); 115 flush_fp_to_thread(current);
116 /* copy fpr regs and fpscr */
117 err |= copy_fpr_to_user(&sc->fp_regs, current);
120#ifdef CONFIG_VSX 118#ifdef CONFIG_VSX
121 /* Copy FP to local buffer then write that out */
122 for (i = 0; i < 32 ; i++)
123 buf[i] = current->thread.TS_FPR(i);
124 memcpy(&buf[i], &current->thread.fpscr, sizeof(double));
125 err |= __copy_to_user(&sc->fp_regs, buf, FP_REGS_SIZE);
126 /* 119 /*
127 * Copy VSX low doubleword to local buffer for formatting, 120 * Copy VSX low doubleword to local buffer for formatting,
128 * then out to userspace. Update v_regs to point after the 121 * then out to userspace. Update v_regs to point after the
@@ -131,17 +124,12 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
131 if (current->thread.used_vsr) { 124 if (current->thread.used_vsr) {
132 flush_vsx_to_thread(current); 125 flush_vsx_to_thread(current);
133 v_regs += ELF_NVRREG; 126 v_regs += ELF_NVRREG;
134 for (i = 0; i < 32 ; i++) 127 err |= copy_vsx_to_user(v_regs, current);
135 buf[i] = current->thread.fpr[i][TS_VSRLOWOFFSET];
136 err |= __copy_to_user(v_regs, buf, 32 * sizeof(double));
137 /* set MSR_VSX in the MSR value in the frame to 128 /* set MSR_VSX in the MSR value in the frame to
138 * indicate that sc->vs_reg) contains valid data. 129 * indicate that sc->vs_reg) contains valid data.
139 */ 130 */
140 msr |= MSR_VSX; 131 msr |= MSR_VSX;
141 } 132 }
142#else /* CONFIG_VSX */
143 /* copy fpr regs and fpscr */
144 err |= __copy_to_user(&sc->fp_regs, &current->thread.fpr, FP_REGS_SIZE);
145#endif /* CONFIG_VSX */ 133#endif /* CONFIG_VSX */
146 err |= __put_user(&sc->gp_regs, &sc->regs); 134 err |= __put_user(&sc->gp_regs, &sc->regs);
147 WARN_ON(!FULL_REGS(regs)); 135 WARN_ON(!FULL_REGS(regs));
@@ -165,13 +153,12 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig,
165#ifdef CONFIG_ALTIVEC 153#ifdef CONFIG_ALTIVEC
166 elf_vrreg_t __user *v_regs; 154 elf_vrreg_t __user *v_regs;
167#endif 155#endif
168#ifdef CONFIG_VSX
169 double buf[FP_REGS_SIZE];
170 int i;
171#endif
172 unsigned long err = 0; 156 unsigned long err = 0;
173 unsigned long save_r13 = 0; 157 unsigned long save_r13 = 0;
174 unsigned long msr; 158 unsigned long msr;
159#ifdef CONFIG_VSX
160 int i;
161#endif
175 162
176 /* If this is not a signal return, we preserve the TLS in r13 */ 163 /* If this is not a signal return, we preserve the TLS in r13 */
177 if (!sig) 164 if (!sig)
@@ -234,15 +221,9 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig,
234 else 221 else
235 current->thread.vrsave = 0; 222 current->thread.vrsave = 0;
236#endif /* CONFIG_ALTIVEC */ 223#endif /* CONFIG_ALTIVEC */
237#ifdef CONFIG_VSX
238 /* restore floating point */ 224 /* restore floating point */
239 err |= __copy_from_user(buf, &sc->fp_regs, FP_REGS_SIZE); 225 err |= copy_fpr_from_user(current, &sc->fp_regs);
240 if (err) 226#ifdef CONFIG_VSX
241 return err;
242 for (i = 0; i < 32 ; i++)
243 current->thread.TS_FPR(i) = buf[i];
244 memcpy(&current->thread.fpscr, &buf[i], sizeof(double));
245
246 /* 227 /*
247 * Get additional VSX data. Update v_regs to point after the 228 * Get additional VSX data. Update v_regs to point after the
248 * VMX data. Copy VSX low doubleword from userspace to local 229 * VMX data. Copy VSX low doubleword from userspace to local
@@ -250,14 +231,12 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig,
250 */ 231 */
251 v_regs += ELF_NVRREG; 232 v_regs += ELF_NVRREG;
252 if ((msr & MSR_VSX) != 0) 233 if ((msr & MSR_VSX) != 0)
253 err |= __copy_from_user(buf, v_regs, 32 * sizeof(double)); 234 err |= copy_vsx_from_user(current, v_regs);
254 else 235 else
255 memset(buf, 0, 32 * sizeof(double)); 236 for (i = 0; i < 32 ; i++)
237 current->thread.fpr[i][TS_VSRLOWOFFSET] = 0;
256 238
257 for (i = 0; i < 32 ; i++)
258 current->thread.fpr[i][TS_VSRLOWOFFSET] = buf[i];
259#else 239#else
260 err |= __copy_from_user(&current->thread.fpr, &sc->fp_regs, FP_REGS_SIZE);
261#endif 240#endif
262 return err; 241 return err;
263} 242}