aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 8655c7670350..92768d3006f7 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 59ff08704e94..70fbde84b83f 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 b057e6852a7d..f7fa395b9fb5 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 da7c058e3731..a587b33cd6b9 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 a23da6356e06..e93e72df4bca 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 */