diff options
-rw-r--r-- | arch/powerpc/kernel/asm-offsets.c | 4 | ||||
-rw-r--r-- | arch/powerpc/kernel/ptrace.c | 29 | ||||
-rw-r--r-- | arch/powerpc/kernel/signal_32.c | 59 | ||||
-rw-r--r-- | arch/powerpc/kernel/signal_64.c | 32 | ||||
-rw-r--r-- | include/asm-powerpc/processor.h | 18 |
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 | ||
227 | static int fpr_set(struct task_struct *target, const struct user_regset *regset, | 240 | static 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], ¤t->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(¤t->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], ¤t->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, ¤t->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, ¤t->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(¤t->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(¤t->thread.fpscr, &buf[i], sizeof(double)); | ||
205 | 228 | ||
229 | #else | ||
230 | err |= __copy_from_user(¤t->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 */ |
81 | extern struct task_struct *last_task_used_math; | 85 | extern struct task_struct *last_task_used_math; |
82 | extern struct task_struct *last_task_used_altivec; | 86 | extern struct task_struct *last_task_used_altivec; |
87 | extern struct task_struct *last_task_used_vsx; | ||
83 | extern struct task_struct *last_task_used_spe; | 88 | extern 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 | ||
147 | struct thread_struct { | 154 | struct 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 */ |