aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Neuling <mikey@neuling.org>2008-06-25 00:07:18 -0400
committerPaul Mackerras <paulus@samba.org>2008-06-30 21:28:46 -0400
commitc6e6771b87d4e339d27f1383c8a808ae9b4ee5b8 (patch)
tree1900b7350ec685c3a31f2233fd88a57e34725b5c
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>
-rw-r--r--arch/powerpc/kernel/asm-offsets.c4
-rw-r--r--arch/powerpc/kernel/ptrace.c29
-rw-r--r--arch/powerpc/kernel/signal_32.c59
-rw-r--r--arch/powerpc/kernel/signal_64.c32
-rw-r--r--include/asm-powerpc/processor.h18
5 files changed, 121 insertions, 21 deletions
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 8655c767035..92768d3006f 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -78,6 +78,10 @@ int main(void)
78 DEFINE(THREAD_VSCR, offsetof(struct thread_struct, vscr)); 78 DEFINE(THREAD_VSCR, offsetof(struct thread_struct, vscr));
79 DEFINE(THREAD_USED_VR, offsetof(struct thread_struct, used_vr)); 79 DEFINE(THREAD_USED_VR, offsetof(struct thread_struct, used_vr));
80#endif /* CONFIG_ALTIVEC */ 80#endif /* CONFIG_ALTIVEC */
81#ifdef CONFIG_VSX
82 DEFINE(THREAD_VSR0, offsetof(struct thread_struct, fpr));
83 DEFINE(THREAD_USED_VSR, offsetof(struct thread_struct, used_vsr));
84#endif /* CONFIG_VSX */
81#ifdef CONFIG_PPC64 85#ifdef CONFIG_PPC64
82 DEFINE(KSP_VSID, offsetof(struct thread_struct, ksp_vsid)); 86 DEFINE(KSP_VSID, offsetof(struct thread_struct, ksp_vsid));
83#else /* CONFIG_PPC64 */ 87#else /* CONFIG_PPC64 */
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 59ff08704e9..70fbde84b83 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -215,29 +215,56 @@ static int fpr_get(struct task_struct *target, const struct user_regset *regset,
215 unsigned int pos, unsigned int count, 215 unsigned int pos, unsigned int count,
216 void *kbuf, void __user *ubuf) 216 void *kbuf, void __user *ubuf)
217{ 217{
218#ifdef CONFIG_VSX
219 double buf[33];
220 int i;
221#endif
218 flush_fp_to_thread(target); 222 flush_fp_to_thread(target);
219 223
224#ifdef CONFIG_VSX
225 /* copy to local buffer then write that out */
226 for (i = 0; i < 32 ; i++)
227 buf[i] = target->thread.TS_FPR(i);
228 memcpy(&buf[32], &target->thread.fpscr, sizeof(double));
229 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, buf, 0, -1);
230
231#else
220 BUILD_BUG_ON(offsetof(struct thread_struct, fpscr) != 232 BUILD_BUG_ON(offsetof(struct thread_struct, fpscr) !=
221 offsetof(struct thread_struct, TS_FPR(32))); 233 offsetof(struct thread_struct, TS_FPR(32)));
222 234
223 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, 235 return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
224 &target->thread.fpr, 0, -1); 236 &target->thread.fpr, 0, -1);
237#endif
225} 238}
226 239
227static int fpr_set(struct task_struct *target, const struct user_regset *regset, 240static int fpr_set(struct task_struct *target, const struct user_regset *regset,
228 unsigned int pos, unsigned int count, 241 unsigned int pos, unsigned int count,
229 const void *kbuf, const void __user *ubuf) 242 const void *kbuf, const void __user *ubuf)
230{ 243{
244#ifdef CONFIG_VSX
245 double buf[33];
246 int i;
247#endif
231 flush_fp_to_thread(target); 248 flush_fp_to_thread(target);
232 249
250#ifdef CONFIG_VSX
251 /* copy to local buffer then write that out */
252 i = user_regset_copyin(&pos, &count, &kbuf, &ubuf, buf, 0, -1);
253 if (i)
254 return i;
255 for (i = 0; i < 32 ; i++)
256 target->thread.TS_FPR(i) = buf[i];
257 memcpy(&target->thread.fpscr, &buf[32], sizeof(double));
258 return 0;
259#else
233 BUILD_BUG_ON(offsetof(struct thread_struct, fpscr) != 260 BUILD_BUG_ON(offsetof(struct thread_struct, fpscr) !=
234 offsetof(struct thread_struct, TS_FPR(32))); 261 offsetof(struct thread_struct, TS_FPR(32)));
235 262
236 return user_regset_copyin(&pos, &count, &kbuf, &ubuf, 263 return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
237 &target->thread.fpr, 0, -1); 264 &target->thread.fpr, 0, -1);
265#endif
238} 266}
239 267
240
241#ifdef CONFIG_ALTIVEC 268#ifdef CONFIG_ALTIVEC
242/* 269/*
243 * Get/set all the altivec registers vr0..vr31, vscr, vrsave, in one go. 270 * Get/set all the altivec registers vr0..vr31, vscr, vrsave, in one go.
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,
337 int sigret) 337 int sigret)
338{ 338{
339 unsigned long msr = regs->msr; 339 unsigned long msr = regs->msr;
340#ifdef CONFIG_VSX
341 double buf[32];
342 int i;
343#endif
340 344
341 /* Make sure floating point registers are stored in regs */ 345 /* Make sure floating point registers are stored in regs */
342 flush_fp_to_thread(current); 346 flush_fp_to_thread(current);
343 347
344 /* save general and floating-point registers */ 348 /* save general registers */
345 if (save_general_regs(regs, frame) || 349 if (save_general_regs(regs, frame))
346 __copy_to_user(&frame->mc_fregs, current->thread.fpr,
347 ELF_NFPREG * sizeof(double)))
348 return 1; 350 return 1;
349 351
350#ifdef CONFIG_ALTIVEC 352#ifdef CONFIG_ALTIVEC
@@ -368,7 +370,20 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame,
368 if (__put_user(current->thread.vrsave, (u32 __user *)&frame->mc_vregs[32])) 370 if (__put_user(current->thread.vrsave, (u32 __user *)&frame->mc_vregs[32]))
369 return 1; 371 return 1;
370#endif /* CONFIG_ALTIVEC */ 372#endif /* CONFIG_ALTIVEC */
371 373#ifdef CONFIG_VSX
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;
381#else
382 /* save floating-point registers */
383 if (__copy_to_user(&frame->mc_fregs, current->thread.fpr,
384 ELF_NFPREG * sizeof(double)))
385 return 1;
386#endif /* CONFIG_VSX */
372#ifdef CONFIG_SPE 387#ifdef CONFIG_SPE
373 /* save spe registers */ 388 /* save spe registers */
374 if (current->thread.used_spe) { 389 if (current->thread.used_spe) {
@@ -411,6 +426,10 @@ static long restore_user_regs(struct pt_regs *regs,
411 long err; 426 long err;
412 unsigned int save_r2 = 0; 427 unsigned int save_r2 = 0;
413 unsigned long msr; 428 unsigned long msr;
429#ifdef CONFIG_VSX
430 double buf[32];
431 int i;
432#endif
414 433
415 /* 434 /*
416 * restore general registers but not including MSR or SOFTE. Also 435 * restore general registers but not including MSR or SOFTE. Also
@@ -438,16 +457,11 @@ static long restore_user_regs(struct pt_regs *regs,
438 */ 457 */
439 discard_lazy_cpu_state(); 458 discard_lazy_cpu_state();
440 459
441 /* force the process to reload the FP registers from
442 current->thread when it next does FP instructions */
443 regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1);
444 if (__copy_from_user(current->thread.fpr, &sr->mc_fregs,
445 sizeof(sr->mc_fregs)))
446 return 1;
447
448#ifdef CONFIG_ALTIVEC 460#ifdef CONFIG_ALTIVEC
449 /* force the process to reload the altivec registers from 461 /*
450 current->thread when it next does altivec instructions */ 462 * Force the process to reload the altivec registers from
463 * current->thread when it next does altivec instructions
464 */
451 regs->msr &= ~MSR_VEC; 465 regs->msr &= ~MSR_VEC;
452 if (msr & MSR_VEC) { 466 if (msr & MSR_VEC) {
453 /* restore altivec registers from the stack */ 467 /* restore altivec registers from the stack */
@@ -462,6 +476,23 @@ static long restore_user_regs(struct pt_regs *regs,
462 return 1; 476 return 1;
463#endif /* CONFIG_ALTIVEC */ 477#endif /* CONFIG_ALTIVEC */
464 478
479#ifdef CONFIG_VSX
480 if (__copy_from_user(buf, &sr->mc_fregs,sizeof(sr->mc_fregs)))
481 return 1;
482 for (i = 0; i < 32 ; i++)
483 current->thread.TS_FPR(i) = buf[i];
484 memcpy(&current->thread.fpscr, &buf[i], sizeof(double));
485#else
486 if (__copy_from_user(current->thread.fpr, &sr->mc_fregs,
487 sizeof(sr->mc_fregs)))
488 return 1;
489#endif /* CONFIG_VSX */
490 /*
491 * force the process to reload the FP registers from
492 * current->thread when it next does FP instructions
493 */
494 regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1);
495
465#ifdef CONFIG_SPE 496#ifdef CONFIG_SPE
466 /* force the process to reload the spe registers from 497 /* force the process to reload the spe registers from
467 current->thread when it next does spe instructions */ 498 current->thread when it next does spe instructions */
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index da7c058e373..a587b33cd6b 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -89,6 +89,10 @@ 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
92 96
93 flush_fp_to_thread(current); 97 flush_fp_to_thread(current);
94 98
@@ -112,11 +116,21 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
112#else /* CONFIG_ALTIVEC */ 116#else /* CONFIG_ALTIVEC */
113 err |= __put_user(0, &sc->v_regs); 117 err |= __put_user(0, &sc->v_regs);
114#endif /* CONFIG_ALTIVEC */ 118#endif /* CONFIG_ALTIVEC */
119 flush_fp_to_thread(current);
120#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#else /* CONFIG_VSX */
127 /* copy fpr regs and fpscr */
128 err |= __copy_to_user(&sc->fp_regs, &current->thread.fpr, FP_REGS_SIZE);
129#endif /* CONFIG_VSX */
115 err |= __put_user(&sc->gp_regs, &sc->regs); 130 err |= __put_user(&sc->gp_regs, &sc->regs);
116 WARN_ON(!FULL_REGS(regs)); 131 WARN_ON(!FULL_REGS(regs));
117 err |= __copy_to_user(&sc->gp_regs, regs, GP_REGS_SIZE); 132 err |= __copy_to_user(&sc->gp_regs, regs, GP_REGS_SIZE);
118 err |= __put_user(msr, &sc->gp_regs[PT_MSR]); 133 err |= __put_user(msr, &sc->gp_regs[PT_MSR]);
119 err |= __copy_to_user(&sc->fp_regs, &current->thread.fpr, FP_REGS_SIZE);
120 err |= __put_user(signr, &sc->signal); 134 err |= __put_user(signr, &sc->signal);
121 err |= __put_user(handler, &sc->handler); 135 err |= __put_user(handler, &sc->handler);
122 if (set != NULL) 136 if (set != NULL)
@@ -135,6 +149,9 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig,
135#ifdef CONFIG_ALTIVEC 149#ifdef CONFIG_ALTIVEC
136 elf_vrreg_t __user *v_regs; 150 elf_vrreg_t __user *v_regs;
137#endif 151#endif
152#ifdef CONFIG_VSX
153 double buf[FP_REGS_SIZE];
154#endif
138 unsigned long err = 0; 155 unsigned long err = 0;
139 unsigned long save_r13 = 0; 156 unsigned long save_r13 = 0;
140 elf_greg_t *gregs = (elf_greg_t *)regs; 157 elf_greg_t *gregs = (elf_greg_t *)regs;
@@ -182,8 +199,6 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig,
182 */ 199 */
183 regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1 | MSR_VEC); 200 regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1 | MSR_VEC);
184 201
185 err |= __copy_from_user(&current->thread.fpr, &sc->fp_regs, FP_REGS_SIZE);
186
187#ifdef CONFIG_ALTIVEC 202#ifdef CONFIG_ALTIVEC
188 err |= __get_user(v_regs, &sc->v_regs); 203 err |= __get_user(v_regs, &sc->v_regs);
189 if (err) 204 if (err)
@@ -202,7 +217,18 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig,
202 else 217 else
203 current->thread.vrsave = 0; 218 current->thread.vrsave = 0;
204#endif /* CONFIG_ALTIVEC */ 219#endif /* CONFIG_ALTIVEC */
220#ifdef CONFIG_VSX
221 /* restore floating point */
222 err |= __copy_from_user(buf, &sc->fp_regs, FP_REGS_SIZE);
223 if (err)
224 return err;
225 for (i = 0; i < 32 ; i++)
226 current->thread.TS_FPR(i) = buf[i];
227 memcpy(&current->thread.fpscr, &buf[i], sizeof(double));
205 228
229#else
230 err |= __copy_from_user(&current->thread.fpr, &sc->fp_regs, FP_REGS_SIZE);
231#endif
206 return err; 232 return err;
207} 233}
208 234
diff --git a/include/asm-powerpc/processor.h b/include/asm-powerpc/processor.h
index a23da6356e0..e93e72df4bc 100644
--- a/include/asm-powerpc/processor.h
+++ b/include/asm-powerpc/processor.h
@@ -12,7 +12,11 @@
12 12
13#include <asm/reg.h> 13#include <asm/reg.h>
14 14
15#ifdef CONFIG_VSX
16#define TS_FPRWIDTH 2
17#else
15#define TS_FPRWIDTH 1 18#define TS_FPRWIDTH 1
19#endif
16 20
17#ifndef __ASSEMBLY__ 21#ifndef __ASSEMBLY__
18#include <linux/compiler.h> 22#include <linux/compiler.h>
@@ -80,6 +84,7 @@ extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
80/* Lazy FPU handling on uni-processor */ 84/* Lazy FPU handling on uni-processor */
81extern struct task_struct *last_task_used_math; 85extern struct task_struct *last_task_used_math;
82extern struct task_struct *last_task_used_altivec; 86extern struct task_struct *last_task_used_altivec;
87extern struct task_struct *last_task_used_vsx;
83extern struct task_struct *last_task_used_spe; 88extern struct task_struct *last_task_used_spe;
84 89
85#ifdef CONFIG_PPC32 90#ifdef CONFIG_PPC32
@@ -142,7 +147,9 @@ typedef struct {
142 unsigned long seg; 147 unsigned long seg;
143} mm_segment_t; 148} mm_segment_t;
144 149
145#define TS_FPR(i) fpr[i] 150#define TS_FPROFFSET 0
151#define TS_VSRLOWOFFSET 1
152#define TS_FPR(i) fpr[i][TS_FPROFFSET]
146 153
147struct thread_struct { 154struct thread_struct {
148 unsigned long ksp; /* Kernel stack pointer */ 155 unsigned long ksp; /* Kernel stack pointer */
@@ -160,8 +167,9 @@ struct thread_struct {
160 unsigned long dbcr0; /* debug control register values */ 167 unsigned long dbcr0; /* debug control register values */
161 unsigned long dbcr1; 168 unsigned long dbcr1;
162#endif 169#endif
163 double fpr[32]; /* Complete floating point set */ 170 /* FP and VSX 0-31 register set */
164 struct { /* fpr ... fpscr must be contiguous */ 171 double fpr[32][TS_FPRWIDTH];
172 struct {
165 173
166 unsigned int pad; 174 unsigned int pad;
167 unsigned int val; /* Floating point status */ 175 unsigned int val; /* Floating point status */
@@ -181,6 +189,10 @@ struct thread_struct {
181 unsigned long vrsave; 189 unsigned long vrsave;
182 int used_vr; /* set if process has used altivec */ 190 int used_vr; /* set if process has used altivec */
183#endif /* CONFIG_ALTIVEC */ 191#endif /* CONFIG_ALTIVEC */
192#ifdef CONFIG_VSX
193 /* VSR status */
194 int used_vsr; /* set if process has used altivec */
195#endif /* CONFIG_VSX */
184#ifdef CONFIG_SPE 196#ifdef CONFIG_SPE
185 unsigned long evr[32]; /* upper 32-bits of SPE regs */ 197 unsigned long evr[32]; /* upper 32-bits of SPE regs */
186 u64 acc; /* Accumulator */ 198 u64 acc; /* Accumulator */