diff options
author | David S. Miller <davem@davemloft.net> | 2008-02-07 02:02:08 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-02-07 05:58:58 -0500 |
commit | d09c2a23ee4220a6341166a7dab5601258fef91f (patch) | |
tree | 634d362ec03f5d3bc03023e359ec3711b7cb5251 /arch | |
parent | ce22e1d39429c7de9f054ce8d03278dd2010b642 (diff) |
[SPARC64]: Add user regsets.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/sparc64/kernel/ptrace.c | 582 |
1 files changed, 581 insertions, 1 deletions
diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index 81111a12f0a8..668f569498b6 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* ptrace.c: Sparc process tracing support. | 1 | /* ptrace.c: Sparc process tracing support. |
2 | * | 2 | * |
3 | * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu) | 3 | * Copyright (C) 1996, 2008 David S. Miller (davem@davemloft.net) |
4 | * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | 4 | * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) |
5 | * | 5 | * |
6 | * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson, | 6 | * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson, |
@@ -22,6 +22,9 @@ | |||
22 | #include <linux/seccomp.h> | 22 | #include <linux/seccomp.h> |
23 | #include <linux/audit.h> | 23 | #include <linux/audit.h> |
24 | #include <linux/signal.h> | 24 | #include <linux/signal.h> |
25 | #include <linux/regset.h> | ||
26 | #include <linux/compat.h> | ||
27 | #include <linux/elf.h> | ||
25 | 28 | ||
26 | #include <asm/asi.h> | 29 | #include <asm/asi.h> |
27 | #include <asm/pgtable.h> | 30 | #include <asm/pgtable.h> |
@@ -167,6 +170,583 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page, | |||
167 | } | 170 | } |
168 | } | 171 | } |
169 | 172 | ||
173 | enum sparc_regset { | ||
174 | REGSET_GENERAL, | ||
175 | REGSET_FP, | ||
176 | }; | ||
177 | |||
178 | static int genregs64_get(struct task_struct *target, | ||
179 | const struct user_regset *regset, | ||
180 | unsigned int pos, unsigned int count, | ||
181 | void *kbuf, void __user *ubuf) | ||
182 | { | ||
183 | const struct pt_regs *regs = task_pt_regs(target); | ||
184 | int ret; | ||
185 | |||
186 | if (target == current) | ||
187 | flushw_user(); | ||
188 | |||
189 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
190 | regs->u_regs, | ||
191 | 0, 16 * sizeof(u64)); | ||
192 | if (!ret) { | ||
193 | unsigned long __user *reg_window = (unsigned long __user *) | ||
194 | (regs->u_regs[UREG_I6] + STACK_BIAS); | ||
195 | unsigned long window[16]; | ||
196 | |||
197 | if (copy_from_user(window, reg_window, sizeof(window))) | ||
198 | return -EFAULT; | ||
199 | |||
200 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
201 | window, | ||
202 | 16 * sizeof(u64), | ||
203 | 32 * sizeof(u64)); | ||
204 | } | ||
205 | |||
206 | if (!ret) { | ||
207 | /* TSTATE, TPC, TNPC */ | ||
208 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
209 | ®s->tstate, | ||
210 | 32 * sizeof(u64), | ||
211 | 35 * sizeof(u64)); | ||
212 | } | ||
213 | |||
214 | if (!ret) { | ||
215 | unsigned long y = regs->y; | ||
216 | |||
217 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
218 | &y, | ||
219 | 35 * sizeof(u64), | ||
220 | 36 * sizeof(u64)); | ||
221 | } | ||
222 | |||
223 | if (!ret) | ||
224 | ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, | ||
225 | 36 * sizeof(u64), -1); | ||
226 | |||
227 | return ret; | ||
228 | } | ||
229 | |||
230 | static int genregs64_set(struct task_struct *target, | ||
231 | const struct user_regset *regset, | ||
232 | unsigned int pos, unsigned int count, | ||
233 | const void *kbuf, const void __user *ubuf) | ||
234 | { | ||
235 | struct pt_regs *regs = task_pt_regs(target); | ||
236 | int ret; | ||
237 | |||
238 | if (target == current) | ||
239 | flushw_user(); | ||
240 | |||
241 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
242 | regs->u_regs, | ||
243 | 0, 16 * sizeof(u64)); | ||
244 | if (!ret && count > 0) { | ||
245 | unsigned long __user *reg_window = (unsigned long __user *) | ||
246 | (regs->u_regs[UREG_I6] + STACK_BIAS); | ||
247 | unsigned long window[16]; | ||
248 | |||
249 | if (copy_from_user(window, reg_window, sizeof(window))) | ||
250 | return -EFAULT; | ||
251 | |||
252 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
253 | window, | ||
254 | 16 * sizeof(u64), | ||
255 | 32 * sizeof(u64)); | ||
256 | if (!ret && | ||
257 | copy_to_user(reg_window, window, sizeof(window))) | ||
258 | return -EFAULT; | ||
259 | } | ||
260 | |||
261 | if (!ret && count > 0) { | ||
262 | unsigned long tstate; | ||
263 | |||
264 | /* TSTATE */ | ||
265 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
266 | &tstate, | ||
267 | 32 * sizeof(u64), | ||
268 | 33 * sizeof(u64)); | ||
269 | if (!ret) { | ||
270 | /* Only the condition codes can be modified | ||
271 | * in the %tstate register. | ||
272 | */ | ||
273 | tstate &= (TSTATE_ICC | TSTATE_XCC); | ||
274 | regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC); | ||
275 | regs->tstate |= tstate; | ||
276 | } | ||
277 | } | ||
278 | |||
279 | if (!ret) { | ||
280 | /* TPC, TNPC */ | ||
281 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
282 | ®s->tpc, | ||
283 | 33 * sizeof(u64), | ||
284 | 35 * sizeof(u64)); | ||
285 | } | ||
286 | |||
287 | if (!ret) { | ||
288 | unsigned long y; | ||
289 | |||
290 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
291 | &y, | ||
292 | 35 * sizeof(u64), | ||
293 | 36 * sizeof(u64)); | ||
294 | if (!ret) | ||
295 | regs->y = y; | ||
296 | } | ||
297 | |||
298 | if (!ret) | ||
299 | ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, | ||
300 | 36 * sizeof(u64), -1); | ||
301 | |||
302 | return ret; | ||
303 | } | ||
304 | |||
305 | static int fpregs64_get(struct task_struct *target, | ||
306 | const struct user_regset *regset, | ||
307 | unsigned int pos, unsigned int count, | ||
308 | void *kbuf, void __user *ubuf) | ||
309 | { | ||
310 | const unsigned long *fpregs = task_thread_info(target)->fpregs; | ||
311 | unsigned long fprs, fsr, gsr; | ||
312 | int ret; | ||
313 | |||
314 | if (target == current) | ||
315 | save_and_clear_fpu(); | ||
316 | |||
317 | fprs = task_thread_info(target)->fpsaved[0]; | ||
318 | |||
319 | if (fprs & FPRS_DL) | ||
320 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
321 | fpregs, | ||
322 | 0, 16 * sizeof(u64)); | ||
323 | else | ||
324 | ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, | ||
325 | 0, | ||
326 | 16 * sizeof(u64)); | ||
327 | |||
328 | if (!ret) { | ||
329 | if (fprs & FPRS_DU) | ||
330 | ret = user_regset_copyout(&pos, &count, | ||
331 | &kbuf, &ubuf, | ||
332 | fpregs + 16, | ||
333 | 16 * sizeof(u64), | ||
334 | 32 * sizeof(u64)); | ||
335 | else | ||
336 | ret = user_regset_copyout_zero(&pos, &count, | ||
337 | &kbuf, &ubuf, | ||
338 | 16 * sizeof(u64), | ||
339 | 32 * sizeof(u64)); | ||
340 | } | ||
341 | |||
342 | if (fprs & FPRS_FEF) { | ||
343 | fsr = task_thread_info(target)->xfsr[0]; | ||
344 | gsr = task_thread_info(target)->gsr[0]; | ||
345 | } else { | ||
346 | fsr = gsr = 0; | ||
347 | } | ||
348 | |||
349 | if (!ret) | ||
350 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
351 | &fsr, | ||
352 | 32 * sizeof(u64), | ||
353 | 33 * sizeof(u64)); | ||
354 | if (!ret) | ||
355 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
356 | &gsr, | ||
357 | 33 * sizeof(u64), | ||
358 | 34 * sizeof(u64)); | ||
359 | if (!ret) | ||
360 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
361 | &fprs, | ||
362 | 34 * sizeof(u64), | ||
363 | 35 * sizeof(u64)); | ||
364 | |||
365 | if (!ret) | ||
366 | ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, | ||
367 | 35 * sizeof(u64), -1); | ||
368 | |||
369 | return ret; | ||
370 | } | ||
371 | |||
372 | static int fpregs64_set(struct task_struct *target, | ||
373 | const struct user_regset *regset, | ||
374 | unsigned int pos, unsigned int count, | ||
375 | const void *kbuf, const void __user *ubuf) | ||
376 | { | ||
377 | unsigned long *fpregs = task_thread_info(target)->fpregs; | ||
378 | unsigned long fprs; | ||
379 | int ret; | ||
380 | |||
381 | if (target == current) | ||
382 | save_and_clear_fpu(); | ||
383 | |||
384 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
385 | fpregs, | ||
386 | 0, 32 * sizeof(u64)); | ||
387 | if (!ret) | ||
388 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
389 | task_thread_info(target)->xfsr, | ||
390 | 32 * sizeof(u64), | ||
391 | 33 * sizeof(u64)); | ||
392 | if (!ret) | ||
393 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
394 | task_thread_info(target)->gsr, | ||
395 | 33 * sizeof(u64), | ||
396 | 34 * sizeof(u64)); | ||
397 | |||
398 | fprs = task_thread_info(target)->fpsaved[0]; | ||
399 | if (!ret && count > 0) { | ||
400 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
401 | &fprs, | ||
402 | 34 * sizeof(u64), | ||
403 | 35 * sizeof(u64)); | ||
404 | } | ||
405 | |||
406 | fprs |= (FPRS_FEF | FPRS_DL | FPRS_DU); | ||
407 | task_thread_info(target)->fpsaved[0] = fprs; | ||
408 | |||
409 | if (!ret) | ||
410 | ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, | ||
411 | 35 * sizeof(u64), -1); | ||
412 | return ret; | ||
413 | } | ||
414 | |||
415 | static const struct user_regset sparc64_regsets[] = { | ||
416 | /* Format is: | ||
417 | * G0 --> G7 | ||
418 | * O0 --> O7 | ||
419 | * L0 --> L7 | ||
420 | * I0 --> I7 | ||
421 | * TSTATE, TPC, TNPC, Y | ||
422 | */ | ||
423 | [REGSET_GENERAL] = { | ||
424 | .core_note_type = NT_PRSTATUS, | ||
425 | .n = 36 * sizeof(u64), | ||
426 | .size = sizeof(u64), .align = sizeof(u64), | ||
427 | .get = genregs64_get, .set = genregs64_set | ||
428 | }, | ||
429 | /* Format is: | ||
430 | * F0 --> F63 | ||
431 | * FSR | ||
432 | * GSR | ||
433 | * FPRS | ||
434 | */ | ||
435 | [REGSET_FP] = { | ||
436 | .core_note_type = NT_PRFPREG, | ||
437 | .n = 35 * sizeof(u64), | ||
438 | .size = sizeof(u64), .align = sizeof(u64), | ||
439 | .get = fpregs64_get, .set = fpregs64_set | ||
440 | }, | ||
441 | }; | ||
442 | |||
443 | static const struct user_regset_view user_sparc64_view = { | ||
444 | .name = "sparc64", .e_machine = EM_SPARCV9, | ||
445 | .regsets = sparc64_regsets, .n = ARRAY_SIZE(sparc64_regsets) | ||
446 | }; | ||
447 | |||
448 | static int genregs32_get(struct task_struct *target, | ||
449 | const struct user_regset *regset, | ||
450 | unsigned int pos, unsigned int count, | ||
451 | void *kbuf, void __user *ubuf) | ||
452 | { | ||
453 | const struct pt_regs *regs = task_pt_regs(target); | ||
454 | compat_ulong_t __user *reg_window; | ||
455 | compat_ulong_t *k = kbuf; | ||
456 | compat_ulong_t __user *u = ubuf; | ||
457 | compat_ulong_t reg; | ||
458 | |||
459 | if (target == current) | ||
460 | flushw_user(); | ||
461 | |||
462 | pos /= sizeof(reg); | ||
463 | count /= sizeof(reg); | ||
464 | |||
465 | if (kbuf) { | ||
466 | for (; count > 0 && pos < 16; count--) | ||
467 | *k++ = regs->u_regs[pos++]; | ||
468 | |||
469 | reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6]; | ||
470 | for (; count > 0 && pos < 32; count--) { | ||
471 | if (get_user(*k++, ®_window[pos++])) | ||
472 | return -EFAULT; | ||
473 | } | ||
474 | } else { | ||
475 | for (; count > 0 && pos < 16; count--) { | ||
476 | if (put_user((compat_ulong_t) regs->u_regs[pos++], u++)) | ||
477 | return -EFAULT; | ||
478 | } | ||
479 | |||
480 | reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6]; | ||
481 | for (; count > 0 && pos < 32; count--) { | ||
482 | if (get_user(reg, ®_window[pos++]) || | ||
483 | put_user(reg, u++)) | ||
484 | return -EFAULT; | ||
485 | } | ||
486 | } | ||
487 | while (count > 0) { | ||
488 | switch (pos) { | ||
489 | case 32: /* PSR */ | ||
490 | reg = tstate_to_psr(regs->tstate); | ||
491 | break; | ||
492 | case 33: /* PC */ | ||
493 | reg = regs->tpc; | ||
494 | break; | ||
495 | case 34: /* NPC */ | ||
496 | reg = regs->tnpc; | ||
497 | break; | ||
498 | case 35: /* Y */ | ||
499 | reg = regs->y; | ||
500 | break; | ||
501 | case 36: /* WIM */ | ||
502 | case 37: /* TBR */ | ||
503 | reg = 0; | ||
504 | break; | ||
505 | default: | ||
506 | goto finish; | ||
507 | } | ||
508 | |||
509 | if (kbuf) | ||
510 | *k++ = reg; | ||
511 | else if (put_user(reg, u++)) | ||
512 | return -EFAULT; | ||
513 | pos++; | ||
514 | count--; | ||
515 | } | ||
516 | finish: | ||
517 | pos *= sizeof(reg); | ||
518 | count *= sizeof(reg); | ||
519 | |||
520 | return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, | ||
521 | 38 * sizeof(reg), -1); | ||
522 | } | ||
523 | |||
524 | static int genregs32_set(struct task_struct *target, | ||
525 | const struct user_regset *regset, | ||
526 | unsigned int pos, unsigned int count, | ||
527 | const void *kbuf, const void __user *ubuf) | ||
528 | { | ||
529 | struct pt_regs *regs = task_pt_regs(target); | ||
530 | compat_ulong_t __user *reg_window; | ||
531 | const compat_ulong_t *k = kbuf; | ||
532 | const compat_ulong_t __user *u = ubuf; | ||
533 | compat_ulong_t reg; | ||
534 | |||
535 | if (target == current) | ||
536 | flushw_user(); | ||
537 | |||
538 | pos /= sizeof(reg); | ||
539 | count /= sizeof(reg); | ||
540 | |||
541 | if (kbuf) { | ||
542 | for (; count > 0 && pos < 16; count--) | ||
543 | regs->u_regs[pos++] = *k++; | ||
544 | |||
545 | reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6]; | ||
546 | for (; count > 0 && pos < 32; count--) { | ||
547 | if (put_user(*k++, ®_window[pos++])) | ||
548 | return -EFAULT; | ||
549 | } | ||
550 | } else { | ||
551 | for (; count > 0 && pos < 16; count--) { | ||
552 | if (get_user(reg, u++)) | ||
553 | return -EFAULT; | ||
554 | regs->u_regs[pos++] = reg; | ||
555 | } | ||
556 | |||
557 | reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6]; | ||
558 | for (; count > 0 && pos < 32; count--) { | ||
559 | if (get_user(reg, u++) || | ||
560 | put_user(reg, ®_window[pos++])) | ||
561 | return -EFAULT; | ||
562 | } | ||
563 | } | ||
564 | while (count > 0) { | ||
565 | unsigned long tstate; | ||
566 | |||
567 | if (kbuf) | ||
568 | reg = *k++; | ||
569 | else if (get_user(reg, u++)) | ||
570 | return -EFAULT; | ||
571 | |||
572 | switch (pos) { | ||
573 | case 32: /* PSR */ | ||
574 | tstate = regs->tstate; | ||
575 | tstate &= ~(TSTATE_ICC | TSTATE_XCC); | ||
576 | tstate |= psr_to_tstate_icc(reg); | ||
577 | regs->tstate = tstate; | ||
578 | break; | ||
579 | case 33: /* PC */ | ||
580 | regs->tpc = reg; | ||
581 | break; | ||
582 | case 34: /* NPC */ | ||
583 | regs->tnpc = reg; | ||
584 | break; | ||
585 | case 35: /* Y */ | ||
586 | regs->y = reg; | ||
587 | break; | ||
588 | case 36: /* WIM */ | ||
589 | case 37: /* TBR */ | ||
590 | break; | ||
591 | default: | ||
592 | goto finish; | ||
593 | } | ||
594 | |||
595 | pos++; | ||
596 | count--; | ||
597 | } | ||
598 | finish: | ||
599 | pos *= sizeof(reg); | ||
600 | count *= sizeof(reg); | ||
601 | |||
602 | return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, | ||
603 | 38 * sizeof(reg), -1); | ||
604 | } | ||
605 | |||
606 | static int fpregs32_get(struct task_struct *target, | ||
607 | const struct user_regset *regset, | ||
608 | unsigned int pos, unsigned int count, | ||
609 | void *kbuf, void __user *ubuf) | ||
610 | { | ||
611 | const unsigned long *fpregs = task_thread_info(target)->fpregs; | ||
612 | compat_ulong_t enabled; | ||
613 | unsigned long fprs; | ||
614 | compat_ulong_t fsr; | ||
615 | int ret = 0; | ||
616 | |||
617 | if (target == current) | ||
618 | save_and_clear_fpu(); | ||
619 | |||
620 | fprs = task_thread_info(target)->fpsaved[0]; | ||
621 | if (fprs & FPRS_FEF) { | ||
622 | fsr = task_thread_info(target)->xfsr[0]; | ||
623 | enabled = 1; | ||
624 | } else { | ||
625 | fsr = 0; | ||
626 | enabled = 0; | ||
627 | } | ||
628 | |||
629 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
630 | fpregs, | ||
631 | 0, 32 * sizeof(u32)); | ||
632 | |||
633 | if (!ret) | ||
634 | ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, | ||
635 | 32 * sizeof(u32), | ||
636 | 33 * sizeof(u32)); | ||
637 | if (!ret) | ||
638 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
639 | &fsr, | ||
640 | 33 * sizeof(u32), | ||
641 | 34 * sizeof(u32)); | ||
642 | |||
643 | if (!ret) { | ||
644 | compat_ulong_t val; | ||
645 | |||
646 | val = (enabled << 8) | (8 << 16); | ||
647 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
648 | &val, | ||
649 | 34 * sizeof(u32), | ||
650 | 35 * sizeof(u32)); | ||
651 | } | ||
652 | |||
653 | if (!ret) | ||
654 | ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, | ||
655 | 35 * sizeof(u32), -1); | ||
656 | |||
657 | return ret; | ||
658 | } | ||
659 | |||
660 | static int fpregs32_set(struct task_struct *target, | ||
661 | const struct user_regset *regset, | ||
662 | unsigned int pos, unsigned int count, | ||
663 | const void *kbuf, const void __user *ubuf) | ||
664 | { | ||
665 | unsigned long *fpregs = task_thread_info(target)->fpregs; | ||
666 | unsigned long fprs; | ||
667 | int ret; | ||
668 | |||
669 | if (target == current) | ||
670 | save_and_clear_fpu(); | ||
671 | |||
672 | fprs = task_thread_info(target)->fpsaved[0]; | ||
673 | |||
674 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
675 | fpregs, | ||
676 | 0, 32 * sizeof(u32)); | ||
677 | if (!ret) | ||
678 | user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, | ||
679 | 32 * sizeof(u32), | ||
680 | 33 * sizeof(u32)); | ||
681 | if (!ret && count > 0) { | ||
682 | compat_ulong_t fsr; | ||
683 | unsigned long val; | ||
684 | |||
685 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
686 | &fsr, | ||
687 | 33 * sizeof(u32), | ||
688 | 34 * sizeof(u32)); | ||
689 | if (!ret) { | ||
690 | val = task_thread_info(target)->xfsr[0]; | ||
691 | val &= 0xffffffff00000000UL; | ||
692 | val |= fsr; | ||
693 | task_thread_info(target)->xfsr[0] = val; | ||
694 | } | ||
695 | } | ||
696 | |||
697 | fprs |= (FPRS_FEF | FPRS_DL); | ||
698 | task_thread_info(target)->fpsaved[0] = fprs; | ||
699 | |||
700 | if (!ret) | ||
701 | ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, | ||
702 | 34 * sizeof(u32), -1); | ||
703 | return ret; | ||
704 | } | ||
705 | |||
706 | static const struct user_regset sparc32_regsets[] = { | ||
707 | /* Format is: | ||
708 | * G0 --> G7 | ||
709 | * O0 --> O7 | ||
710 | * L0 --> L7 | ||
711 | * I0 --> I7 | ||
712 | * PSR, PC, nPC, Y, WIM, TBR | ||
713 | */ | ||
714 | [REGSET_GENERAL] = { | ||
715 | .core_note_type = NT_PRSTATUS, | ||
716 | .n = 38 * sizeof(u32), | ||
717 | .size = sizeof(u32), .align = sizeof(u32), | ||
718 | .get = genregs32_get, .set = genregs32_set | ||
719 | }, | ||
720 | /* Format is: | ||
721 | * F0 --> F31 | ||
722 | * empty 32-bit word | ||
723 | * FSR (32--bit word) | ||
724 | * FPU QUEUE COUNT (8-bit char) | ||
725 | * FPU QUEUE ENTRYSIZE (8-bit char) | ||
726 | * FPU ENABLED (8-bit char) | ||
727 | * empty 8-bit char | ||
728 | * FPU QUEUE (64 32-bit ints) | ||
729 | */ | ||
730 | [REGSET_FP] = { | ||
731 | .core_note_type = NT_PRFPREG, | ||
732 | .n = 99 * sizeof(u32), | ||
733 | .size = sizeof(u32), .align = sizeof(u32), | ||
734 | .get = fpregs32_get, .set = fpregs32_set | ||
735 | }, | ||
736 | }; | ||
737 | |||
738 | static const struct user_regset_view user_sparc32_view = { | ||
739 | .name = "sparc", .e_machine = EM_SPARC, | ||
740 | .regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets) | ||
741 | }; | ||
742 | |||
743 | const struct user_regset_view *task_user_regset_view(struct task_struct *task) | ||
744 | { | ||
745 | if (test_tsk_thread_flag(task, TIF_32BIT)) | ||
746 | return &user_sparc32_view; | ||
747 | return &user_sparc64_view; | ||
748 | } | ||
749 | |||
170 | asmlinkage void do_ptrace(struct pt_regs *regs) | 750 | asmlinkage void do_ptrace(struct pt_regs *regs) |
171 | { | 751 | { |
172 | int request = regs->u_regs[UREG_I0]; | 752 | int request = regs->u_regs[UREG_I0]; |