summaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/signal_32.c
diff options
context:
space:
mode:
authorMichael Neuling <mikey@neuling.org>2008-06-25 14:07:18 +1000
committerPaul Mackerras <paulus@samba.org>2008-07-01 11:28:46 +1000
commitc6e6771b87d4e339d27f1383c8a808ae9b4ee5b8 (patch)
tree1900b7350ec685c3a31f2233fd88a57e34725b5c /arch/powerpc/kernel/signal_32.c
parent6f3d8e6947ec98e358514fc0f7b2e37fe88a21bb (diff)
powerpc: Introduce VSX thread_struct and CONFIG_VSX
The layout of the new VSR registers and how they overlap on top of the legacy FPR and VR registers is: VSR doubleword 0 VSR doubleword 1 ---------------------------------------------------------------- VSR[0] | FPR[0] | | ---------------------------------------------------------------- VSR[1] | FPR[1] | | ---------------------------------------------------------------- | ... | | | ... | | ---------------------------------------------------------------- VSR[30] | FPR[30] | | ---------------------------------------------------------------- VSR[31] | FPR[31] | | ---------------------------------------------------------------- VSR[32] | VR[0] | ---------------------------------------------------------------- VSR[33] | VR[1] | ---------------------------------------------------------------- | ... | | ... | ---------------------------------------------------------------- VSR[62] | VR[30] | ---------------------------------------------------------------- VSR[63] | VR[31] | ---------------------------------------------------------------- VSX has 64 128bit registers. The first 32 regs overlap with the FP registers and hence extend them with and additional 64 bits. The second 32 regs overlap with the VMX registers. This commit introduces the thread_struct changes required to reflect this register layout. Ptrace and signals code is updated so that the floating point registers are correctly accessed from the thread_struct when CONFIG_VSX is enabled. 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.c59
1 files changed, 45 insertions, 14 deletions
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index b057e6852a7..f7fa395b9fb 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -337,14 +337,16 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame,
int sigret)
{
unsigned long msr = regs->msr;
+#ifdef CONFIG_VSX
+ double buf[32];
+ int i;
+#endif
/* Make sure floating point registers are stored in regs */
flush_fp_to_thread(current);
- /* save general and floating-point registers */
- if (save_general_regs(regs, frame) ||
- __copy_to_user(&frame->mc_fregs, current->thread.fpr,
- ELF_NFPREG * sizeof(double)))
+ /* save general registers */
+ if (save_general_regs(regs, frame))
return 1;
#ifdef CONFIG_ALTIVEC
@@ -368,7 +370,20 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame,
if (__put_user(current->thread.vrsave, (u32 __user *)&frame->mc_vregs[32]))
return 1;
#endif /* CONFIG_ALTIVEC */
-
+#ifdef CONFIG_VSX
+ /* save FPR copy to local buffer then write to the thread_struct */
+ flush_fp_to_thread(current);
+ for (i = 0; i < 32 ; i++)
+ buf[i] = current->thread.TS_FPR(i);
+ memcpy(&buf[i], &current->thread.fpscr, sizeof(double));
+ if (__copy_to_user(&frame->mc_fregs, buf, ELF_NFPREG * sizeof(double)))
+ return 1;
+#else
+ /* save floating-point registers */
+ if (__copy_to_user(&frame->mc_fregs, current->thread.fpr,
+ ELF_NFPREG * sizeof(double)))
+ return 1;
+#endif /* CONFIG_VSX */
#ifdef CONFIG_SPE
/* save spe registers */
if (current->thread.used_spe) {
@@ -411,6 +426,10 @@ static long restore_user_regs(struct pt_regs *regs,
long err;
unsigned int save_r2 = 0;
unsigned long msr;
+#ifdef CONFIG_VSX
+ double buf[32];
+ int i;
+#endif
/*
* restore general registers but not including MSR or SOFTE. Also
@@ -438,16 +457,11 @@ static long restore_user_regs(struct pt_regs *regs,
*/
discard_lazy_cpu_state();
- /* force the process to reload the FP registers from
- current->thread when it next does FP instructions */
- regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1);
- if (__copy_from_user(current->thread.fpr, &sr->mc_fregs,
- sizeof(sr->mc_fregs)))
- return 1;
-
#ifdef CONFIG_ALTIVEC
- /* force the process to reload the altivec registers from
- current->thread when it next does altivec instructions */
+ /*
+ * Force the process to reload the altivec registers from
+ * current->thread when it next does altivec instructions
+ */
regs->msr &= ~MSR_VEC;
if (msr & MSR_VEC) {
/* restore altivec registers from the stack */
@@ -462,6 +476,23 @@ static long restore_user_regs(struct pt_regs *regs,
return 1;
#endif /* CONFIG_ALTIVEC */
+#ifdef CONFIG_VSX
+ if (__copy_from_user(buf, &sr->mc_fregs,sizeof(sr->mc_fregs)))
+ return 1;
+ for (i = 0; i < 32 ; i++)
+ current->thread.TS_FPR(i) = buf[i];
+ memcpy(&current->thread.fpscr, &buf[i], sizeof(double));
+#else
+ if (__copy_from_user(current->thread.fpr, &sr->mc_fregs,
+ sizeof(sr->mc_fregs)))
+ return 1;
+#endif /* CONFIG_VSX */
+ /*
+ * force the process to reload the FP registers from
+ * current->thread when it next does FP instructions
+ */
+ regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1);
+
#ifdef CONFIG_SPE
/* force the process to reload the spe registers from
current->thread when it next does spe instructions */