.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* ptrace.c: Sparc process tracing support. |
---|
2 | 3 | * |
---|
3 | 4 | * Copyright (C) 1996, 2008 David S. Miller (davem@davemloft.net) |
---|
.. | .. |
---|
31 | 32 | #include <linux/context_tracking.h> |
---|
32 | 33 | |
---|
33 | 34 | #include <asm/asi.h> |
---|
34 | | -#include <asm/pgtable.h> |
---|
35 | 35 | #include <linux/uaccess.h> |
---|
36 | 36 | #include <asm/psrcompat.h> |
---|
37 | 37 | #include <asm/visasm.h> |
---|
.. | .. |
---|
246 | 246 | |
---|
247 | 247 | static int genregs64_get(struct task_struct *target, |
---|
248 | 248 | const struct user_regset *regset, |
---|
249 | | - unsigned int pos, unsigned int count, |
---|
250 | | - void *kbuf, void __user *ubuf) |
---|
| 249 | + struct membuf to) |
---|
251 | 250 | { |
---|
252 | 251 | const struct pt_regs *regs = task_pt_regs(target); |
---|
253 | | - int ret; |
---|
| 252 | + struct reg_window window; |
---|
254 | 253 | |
---|
255 | 254 | if (target == current) |
---|
256 | 255 | flushw_user(); |
---|
257 | 256 | |
---|
258 | | - ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, |
---|
259 | | - regs->u_regs, |
---|
260 | | - 0, 16 * sizeof(u64)); |
---|
261 | | - if (!ret && count && pos < (32 * sizeof(u64))) { |
---|
262 | | - struct reg_window window; |
---|
263 | | - |
---|
264 | | - if (regwindow64_get(target, regs, &window)) |
---|
265 | | - return -EFAULT; |
---|
266 | | - ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, |
---|
267 | | - &window, |
---|
268 | | - 16 * sizeof(u64), |
---|
269 | | - 32 * sizeof(u64)); |
---|
270 | | - } |
---|
271 | | - |
---|
272 | | - if (!ret) { |
---|
273 | | - /* TSTATE, TPC, TNPC */ |
---|
274 | | - ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, |
---|
275 | | - ®s->tstate, |
---|
276 | | - 32 * sizeof(u64), |
---|
277 | | - 35 * sizeof(u64)); |
---|
278 | | - } |
---|
279 | | - |
---|
280 | | - if (!ret) { |
---|
281 | | - unsigned long y = regs->y; |
---|
282 | | - |
---|
283 | | - ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, |
---|
284 | | - &y, |
---|
285 | | - 35 * sizeof(u64), |
---|
286 | | - 36 * sizeof(u64)); |
---|
287 | | - } |
---|
288 | | - |
---|
289 | | - if (!ret) { |
---|
290 | | - ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, |
---|
291 | | - 36 * sizeof(u64), -1); |
---|
292 | | - |
---|
293 | | - } |
---|
294 | | - return ret; |
---|
| 257 | + membuf_write(&to, regs->u_regs, 16 * sizeof(u64)); |
---|
| 258 | + if (!to.left) |
---|
| 259 | + return 0; |
---|
| 260 | + if (regwindow64_get(target, regs, &window)) |
---|
| 261 | + return -EFAULT; |
---|
| 262 | + membuf_write(&to, &window, 16 * sizeof(u64)); |
---|
| 263 | + /* TSTATE, TPC, TNPC */ |
---|
| 264 | + membuf_write(&to, ®s->tstate, 3 * sizeof(u64)); |
---|
| 265 | + return membuf_store(&to, (u64)regs->y); |
---|
295 | 266 | } |
---|
296 | 267 | |
---|
297 | 268 | static int genregs64_set(struct task_struct *target, |
---|
.. | .. |
---|
370 | 341 | |
---|
371 | 342 | static int fpregs64_get(struct task_struct *target, |
---|
372 | 343 | const struct user_regset *regset, |
---|
373 | | - unsigned int pos, unsigned int count, |
---|
374 | | - void *kbuf, void __user *ubuf) |
---|
| 344 | + struct membuf to) |
---|
375 | 345 | { |
---|
376 | | - const unsigned long *fpregs = task_thread_info(target)->fpregs; |
---|
377 | | - unsigned long fprs, fsr, gsr; |
---|
378 | | - int ret; |
---|
| 346 | + struct thread_info *t = task_thread_info(target); |
---|
| 347 | + unsigned long fprs; |
---|
379 | 348 | |
---|
380 | 349 | if (target == current) |
---|
381 | 350 | save_and_clear_fpu(); |
---|
382 | 351 | |
---|
383 | | - fprs = task_thread_info(target)->fpsaved[0]; |
---|
| 352 | + fprs = t->fpsaved[0]; |
---|
384 | 353 | |
---|
385 | 354 | if (fprs & FPRS_DL) |
---|
386 | | - ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, |
---|
387 | | - fpregs, |
---|
388 | | - 0, 16 * sizeof(u64)); |
---|
| 355 | + membuf_write(&to, t->fpregs, 16 * sizeof(u64)); |
---|
389 | 356 | else |
---|
390 | | - ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, |
---|
391 | | - 0, |
---|
392 | | - 16 * sizeof(u64)); |
---|
| 357 | + membuf_zero(&to, 16 * sizeof(u64)); |
---|
393 | 358 | |
---|
394 | | - if (!ret) { |
---|
395 | | - if (fprs & FPRS_DU) |
---|
396 | | - ret = user_regset_copyout(&pos, &count, |
---|
397 | | - &kbuf, &ubuf, |
---|
398 | | - fpregs + 16, |
---|
399 | | - 16 * sizeof(u64), |
---|
400 | | - 32 * sizeof(u64)); |
---|
401 | | - else |
---|
402 | | - ret = user_regset_copyout_zero(&pos, &count, |
---|
403 | | - &kbuf, &ubuf, |
---|
404 | | - 16 * sizeof(u64), |
---|
405 | | - 32 * sizeof(u64)); |
---|
406 | | - } |
---|
407 | | - |
---|
| 359 | + if (fprs & FPRS_DU) |
---|
| 360 | + membuf_write(&to, t->fpregs + 16, 16 * sizeof(u64)); |
---|
| 361 | + else |
---|
| 362 | + membuf_zero(&to, 16 * sizeof(u64)); |
---|
408 | 363 | if (fprs & FPRS_FEF) { |
---|
409 | | - fsr = task_thread_info(target)->xfsr[0]; |
---|
410 | | - gsr = task_thread_info(target)->gsr[0]; |
---|
| 364 | + membuf_store(&to, t->xfsr[0]); |
---|
| 365 | + membuf_store(&to, t->gsr[0]); |
---|
411 | 366 | } else { |
---|
412 | | - fsr = gsr = 0; |
---|
| 367 | + membuf_zero(&to, 2 * sizeof(u64)); |
---|
413 | 368 | } |
---|
414 | | - |
---|
415 | | - if (!ret) |
---|
416 | | - ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, |
---|
417 | | - &fsr, |
---|
418 | | - 32 * sizeof(u64), |
---|
419 | | - 33 * sizeof(u64)); |
---|
420 | | - if (!ret) |
---|
421 | | - ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, |
---|
422 | | - &gsr, |
---|
423 | | - 33 * sizeof(u64), |
---|
424 | | - 34 * sizeof(u64)); |
---|
425 | | - if (!ret) |
---|
426 | | - ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, |
---|
427 | | - &fprs, |
---|
428 | | - 34 * sizeof(u64), |
---|
429 | | - 35 * sizeof(u64)); |
---|
430 | | - |
---|
431 | | - if (!ret) |
---|
432 | | - ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, |
---|
433 | | - 35 * sizeof(u64), -1); |
---|
434 | | - |
---|
435 | | - return ret; |
---|
| 369 | + return membuf_store(&to, fprs); |
---|
436 | 370 | } |
---|
437 | 371 | |
---|
438 | 372 | static int fpregs64_set(struct task_struct *target, |
---|
.. | .. |
---|
490 | 424 | .core_note_type = NT_PRSTATUS, |
---|
491 | 425 | .n = 36, |
---|
492 | 426 | .size = sizeof(u64), .align = sizeof(u64), |
---|
493 | | - .get = genregs64_get, .set = genregs64_set |
---|
| 427 | + .regset_get = genregs64_get, .set = genregs64_set |
---|
494 | 428 | }, |
---|
495 | 429 | /* Format is: |
---|
496 | 430 | * F0 --> F63 |
---|
.. | .. |
---|
502 | 436 | .core_note_type = NT_PRFPREG, |
---|
503 | 437 | .n = 35, |
---|
504 | 438 | .size = sizeof(u64), .align = sizeof(u64), |
---|
505 | | - .get = fpregs64_get, .set = fpregs64_set |
---|
| 439 | + .regset_get = fpregs64_get, .set = fpregs64_set |
---|
506 | 440 | }, |
---|
| 441 | +}; |
---|
| 442 | + |
---|
| 443 | +static int getregs64_get(struct task_struct *target, |
---|
| 444 | + const struct user_regset *regset, |
---|
| 445 | + struct membuf to) |
---|
| 446 | +{ |
---|
| 447 | + const struct pt_regs *regs = task_pt_regs(target); |
---|
| 448 | + |
---|
| 449 | + if (target == current) |
---|
| 450 | + flushw_user(); |
---|
| 451 | + |
---|
| 452 | + membuf_write(&to, regs->u_regs + 1, 15 * sizeof(u64)); |
---|
| 453 | + membuf_store(&to, (u64)0); |
---|
| 454 | + membuf_write(&to, ®s->tstate, 3 * sizeof(u64)); |
---|
| 455 | + return membuf_store(&to, (u64)regs->y); |
---|
| 456 | +} |
---|
| 457 | + |
---|
| 458 | +static int setregs64_set(struct task_struct *target, |
---|
| 459 | + const struct user_regset *regset, |
---|
| 460 | + unsigned int pos, unsigned int count, |
---|
| 461 | + const void *kbuf, const void __user *ubuf) |
---|
| 462 | +{ |
---|
| 463 | + struct pt_regs *regs = task_pt_regs(target); |
---|
| 464 | + unsigned long y = regs->y; |
---|
| 465 | + unsigned long tstate; |
---|
| 466 | + int ret; |
---|
| 467 | + |
---|
| 468 | + if (target == current) |
---|
| 469 | + flushw_user(); |
---|
| 470 | + |
---|
| 471 | + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, |
---|
| 472 | + regs->u_regs + 1, |
---|
| 473 | + 0 * sizeof(u64), |
---|
| 474 | + 15 * sizeof(u64)); |
---|
| 475 | + if (ret) |
---|
| 476 | + return ret; |
---|
| 477 | + ret =user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, |
---|
| 478 | + 15 * sizeof(u64), 16 * sizeof(u64)); |
---|
| 479 | + if (ret) |
---|
| 480 | + return ret; |
---|
| 481 | + /* TSTATE */ |
---|
| 482 | + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, |
---|
| 483 | + &tstate, |
---|
| 484 | + 16 * sizeof(u64), |
---|
| 485 | + 17 * sizeof(u64)); |
---|
| 486 | + if (ret) |
---|
| 487 | + return ret; |
---|
| 488 | + /* Only the condition codes and the "in syscall" |
---|
| 489 | + * state can be modified in the %tstate register. |
---|
| 490 | + */ |
---|
| 491 | + tstate &= (TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL); |
---|
| 492 | + regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL); |
---|
| 493 | + regs->tstate |= tstate; |
---|
| 494 | + |
---|
| 495 | + /* TPC, TNPC */ |
---|
| 496 | + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, |
---|
| 497 | + ®s->tpc, |
---|
| 498 | + 17 * sizeof(u64), |
---|
| 499 | + 19 * sizeof(u64)); |
---|
| 500 | + if (ret) |
---|
| 501 | + return ret; |
---|
| 502 | + /* Y */ |
---|
| 503 | + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, |
---|
| 504 | + &y, |
---|
| 505 | + 19 * sizeof(u64), |
---|
| 506 | + 20 * sizeof(u64)); |
---|
| 507 | + if (!ret) |
---|
| 508 | + regs->y = y; |
---|
| 509 | + return ret; |
---|
| 510 | +} |
---|
| 511 | + |
---|
| 512 | +static const struct user_regset ptrace64_regsets[] = { |
---|
| 513 | + /* Format is: |
---|
| 514 | + * G1 --> G7 |
---|
| 515 | + * O0 --> O7 |
---|
| 516 | + * 0 |
---|
| 517 | + * TSTATE, TPC, TNPC, Y |
---|
| 518 | + */ |
---|
| 519 | + [REGSET_GENERAL] = { |
---|
| 520 | + .n = 20, .size = sizeof(u64), |
---|
| 521 | + .regset_get = getregs64_get, .set = setregs64_set, |
---|
| 522 | + }, |
---|
| 523 | +}; |
---|
| 524 | + |
---|
| 525 | +static const struct user_regset_view ptrace64_view = { |
---|
| 526 | + .regsets = ptrace64_regsets, .n = ARRAY_SIZE(ptrace64_regsets) |
---|
507 | 527 | }; |
---|
508 | 528 | |
---|
509 | 529 | static const struct user_regset_view user_sparc64_view = { |
---|
.. | .. |
---|
514 | 534 | #ifdef CONFIG_COMPAT |
---|
515 | 535 | static int genregs32_get(struct task_struct *target, |
---|
516 | 536 | const struct user_regset *regset, |
---|
517 | | - unsigned int pos, unsigned int count, |
---|
518 | | - void *kbuf, void __user *ubuf) |
---|
| 537 | + struct membuf to) |
---|
519 | 538 | { |
---|
520 | 539 | const struct pt_regs *regs = task_pt_regs(target); |
---|
521 | | - compat_ulong_t __user *reg_window; |
---|
522 | | - compat_ulong_t *k = kbuf; |
---|
523 | | - compat_ulong_t __user *u = ubuf; |
---|
524 | | - compat_ulong_t reg; |
---|
| 540 | + u32 uregs[16]; |
---|
| 541 | + int i; |
---|
525 | 542 | |
---|
526 | 543 | if (target == current) |
---|
527 | 544 | flushw_user(); |
---|
528 | 545 | |
---|
529 | | - pos /= sizeof(reg); |
---|
530 | | - count /= sizeof(reg); |
---|
531 | | - |
---|
532 | | - if (kbuf) { |
---|
533 | | - for (; count > 0 && pos < 16; count--) |
---|
534 | | - *k++ = regs->u_regs[pos++]; |
---|
535 | | - |
---|
536 | | - reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6]; |
---|
537 | | - reg_window -= 16; |
---|
538 | | - if (target == current) { |
---|
539 | | - for (; count > 0 && pos < 32; count--) { |
---|
540 | | - if (get_user(*k++, ®_window[pos++])) |
---|
541 | | - return -EFAULT; |
---|
542 | | - } |
---|
543 | | - } else { |
---|
544 | | - for (; count > 0 && pos < 32; count--) { |
---|
545 | | - if (access_process_vm(target, |
---|
546 | | - (unsigned long) |
---|
547 | | - ®_window[pos], |
---|
548 | | - k, sizeof(*k), |
---|
549 | | - FOLL_FORCE) |
---|
550 | | - != sizeof(*k)) |
---|
551 | | - return -EFAULT; |
---|
552 | | - k++; |
---|
553 | | - pos++; |
---|
554 | | - } |
---|
555 | | - } |
---|
556 | | - } else { |
---|
557 | | - for (; count > 0 && pos < 16; count--) { |
---|
558 | | - if (put_user((compat_ulong_t) regs->u_regs[pos++], u++)) |
---|
559 | | - return -EFAULT; |
---|
560 | | - } |
---|
561 | | - |
---|
562 | | - reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6]; |
---|
563 | | - reg_window -= 16; |
---|
564 | | - if (target == current) { |
---|
565 | | - for (; count > 0 && pos < 32; count--) { |
---|
566 | | - if (get_user(reg, ®_window[pos++]) || |
---|
567 | | - put_user(reg, u++)) |
---|
568 | | - return -EFAULT; |
---|
569 | | - } |
---|
570 | | - } else { |
---|
571 | | - for (; count > 0 && pos < 32; count--) { |
---|
572 | | - if (access_process_vm(target, |
---|
573 | | - (unsigned long) |
---|
574 | | - ®_window[pos++], |
---|
575 | | - ®, sizeof(reg), |
---|
576 | | - FOLL_FORCE) |
---|
577 | | - != sizeof(reg)) |
---|
578 | | - return -EFAULT; |
---|
579 | | - if (put_user(reg, u++)) |
---|
580 | | - return -EFAULT; |
---|
581 | | - } |
---|
582 | | - } |
---|
583 | | - } |
---|
584 | | - while (count > 0) { |
---|
585 | | - switch (pos) { |
---|
586 | | - case 32: /* PSR */ |
---|
587 | | - reg = tstate_to_psr(regs->tstate); |
---|
588 | | - break; |
---|
589 | | - case 33: /* PC */ |
---|
590 | | - reg = regs->tpc; |
---|
591 | | - break; |
---|
592 | | - case 34: /* NPC */ |
---|
593 | | - reg = regs->tnpc; |
---|
594 | | - break; |
---|
595 | | - case 35: /* Y */ |
---|
596 | | - reg = regs->y; |
---|
597 | | - break; |
---|
598 | | - case 36: /* WIM */ |
---|
599 | | - case 37: /* TBR */ |
---|
600 | | - reg = 0; |
---|
601 | | - break; |
---|
602 | | - default: |
---|
603 | | - goto finish; |
---|
604 | | - } |
---|
605 | | - |
---|
606 | | - if (kbuf) |
---|
607 | | - *k++ = reg; |
---|
608 | | - else if (put_user(reg, u++)) |
---|
609 | | - return -EFAULT; |
---|
610 | | - pos++; |
---|
611 | | - count--; |
---|
612 | | - } |
---|
613 | | -finish: |
---|
614 | | - pos *= sizeof(reg); |
---|
615 | | - count *= sizeof(reg); |
---|
616 | | - |
---|
617 | | - return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, |
---|
618 | | - 38 * sizeof(reg), -1); |
---|
| 546 | + for (i = 0; i < 16; i++) |
---|
| 547 | + membuf_store(&to, (u32)regs->u_regs[i]); |
---|
| 548 | + if (!to.left) |
---|
| 549 | + return 0; |
---|
| 550 | + if (get_from_target(target, regs->u_regs[UREG_I6], |
---|
| 551 | + uregs, sizeof(uregs))) |
---|
| 552 | + return -EFAULT; |
---|
| 553 | + membuf_write(&to, uregs, 16 * sizeof(u32)); |
---|
| 554 | + membuf_store(&to, (u32)tstate_to_psr(regs->tstate)); |
---|
| 555 | + membuf_store(&to, (u32)(regs->tpc)); |
---|
| 556 | + membuf_store(&to, (u32)(regs->tnpc)); |
---|
| 557 | + membuf_store(&to, (u32)(regs->y)); |
---|
| 558 | + return membuf_zero(&to, 2 * sizeof(u32)); |
---|
619 | 559 | } |
---|
620 | 560 | |
---|
621 | 561 | static int genregs32_set(struct task_struct *target, |
---|
.. | .. |
---|
737 | 677 | |
---|
738 | 678 | static int fpregs32_get(struct task_struct *target, |
---|
739 | 679 | const struct user_regset *regset, |
---|
740 | | - unsigned int pos, unsigned int count, |
---|
741 | | - void *kbuf, void __user *ubuf) |
---|
| 680 | + struct membuf to) |
---|
742 | 681 | { |
---|
743 | | - const unsigned long *fpregs = task_thread_info(target)->fpregs; |
---|
744 | | - compat_ulong_t enabled; |
---|
745 | | - unsigned long fprs; |
---|
746 | | - compat_ulong_t fsr; |
---|
747 | | - int ret = 0; |
---|
| 682 | + struct thread_info *t = task_thread_info(target); |
---|
| 683 | + bool enabled; |
---|
748 | 684 | |
---|
749 | 685 | if (target == current) |
---|
750 | 686 | save_and_clear_fpu(); |
---|
751 | 687 | |
---|
752 | | - fprs = task_thread_info(target)->fpsaved[0]; |
---|
753 | | - if (fprs & FPRS_FEF) { |
---|
754 | | - fsr = task_thread_info(target)->xfsr[0]; |
---|
755 | | - enabled = 1; |
---|
756 | | - } else { |
---|
757 | | - fsr = 0; |
---|
758 | | - enabled = 0; |
---|
759 | | - } |
---|
| 688 | + enabled = t->fpsaved[0] & FPRS_FEF; |
---|
760 | 689 | |
---|
761 | | - ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, |
---|
762 | | - fpregs, |
---|
763 | | - 0, 32 * sizeof(u32)); |
---|
764 | | - |
---|
765 | | - if (!ret) |
---|
766 | | - ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, |
---|
767 | | - 32 * sizeof(u32), |
---|
768 | | - 33 * sizeof(u32)); |
---|
769 | | - if (!ret) |
---|
770 | | - ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, |
---|
771 | | - &fsr, |
---|
772 | | - 33 * sizeof(u32), |
---|
773 | | - 34 * sizeof(u32)); |
---|
774 | | - |
---|
775 | | - if (!ret) { |
---|
776 | | - compat_ulong_t val; |
---|
777 | | - |
---|
778 | | - val = (enabled << 8) | (8 << 16); |
---|
779 | | - ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, |
---|
780 | | - &val, |
---|
781 | | - 34 * sizeof(u32), |
---|
782 | | - 35 * sizeof(u32)); |
---|
783 | | - } |
---|
784 | | - |
---|
785 | | - if (!ret) |
---|
786 | | - ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, |
---|
787 | | - 35 * sizeof(u32), -1); |
---|
788 | | - |
---|
789 | | - return ret; |
---|
| 690 | + membuf_write(&to, t->fpregs, 32 * sizeof(u32)); |
---|
| 691 | + membuf_zero(&to, sizeof(u32)); |
---|
| 692 | + if (enabled) |
---|
| 693 | + membuf_store(&to, (u32)t->xfsr[0]); |
---|
| 694 | + else |
---|
| 695 | + membuf_zero(&to, sizeof(u32)); |
---|
| 696 | + membuf_store(&to, (u32)((enabled << 8) | (8 << 16))); |
---|
| 697 | + return membuf_zero(&to, 64 * sizeof(u32)); |
---|
790 | 698 | } |
---|
791 | 699 | |
---|
792 | 700 | static int fpregs32_set(struct task_struct *target, |
---|
.. | .. |
---|
847 | 755 | .core_note_type = NT_PRSTATUS, |
---|
848 | 756 | .n = 38, |
---|
849 | 757 | .size = sizeof(u32), .align = sizeof(u32), |
---|
850 | | - .get = genregs32_get, .set = genregs32_set |
---|
| 758 | + .regset_get = genregs32_get, .set = genregs32_set |
---|
851 | 759 | }, |
---|
852 | 760 | /* Format is: |
---|
853 | 761 | * F0 --> F31 |
---|
.. | .. |
---|
863 | 771 | .core_note_type = NT_PRFPREG, |
---|
864 | 772 | .n = 99, |
---|
865 | 773 | .size = sizeof(u32), .align = sizeof(u32), |
---|
866 | | - .get = fpregs32_get, .set = fpregs32_set |
---|
| 774 | + .regset_get = fpregs32_get, .set = fpregs32_set |
---|
867 | 775 | }, |
---|
| 776 | +}; |
---|
| 777 | + |
---|
| 778 | +static int getregs_get(struct task_struct *target, |
---|
| 779 | + const struct user_regset *regset, |
---|
| 780 | + struct membuf to) |
---|
| 781 | +{ |
---|
| 782 | + const struct pt_regs *regs = task_pt_regs(target); |
---|
| 783 | + int i; |
---|
| 784 | + |
---|
| 785 | + if (target == current) |
---|
| 786 | + flushw_user(); |
---|
| 787 | + |
---|
| 788 | + membuf_store(&to, (u32)tstate_to_psr(regs->tstate)); |
---|
| 789 | + membuf_store(&to, (u32)(regs->tpc)); |
---|
| 790 | + membuf_store(&to, (u32)(regs->tnpc)); |
---|
| 791 | + membuf_store(&to, (u32)(regs->y)); |
---|
| 792 | + for (i = 1; i < 16; i++) |
---|
| 793 | + membuf_store(&to, (u32)regs->u_regs[i]); |
---|
| 794 | + return to.left; |
---|
| 795 | +} |
---|
| 796 | + |
---|
| 797 | +static int setregs_set(struct task_struct *target, |
---|
| 798 | + const struct user_regset *regset, |
---|
| 799 | + unsigned int pos, unsigned int count, |
---|
| 800 | + const void *kbuf, const void __user *ubuf) |
---|
| 801 | +{ |
---|
| 802 | + struct pt_regs *regs = task_pt_regs(target); |
---|
| 803 | + unsigned long tstate; |
---|
| 804 | + u32 uregs[19]; |
---|
| 805 | + int i, ret; |
---|
| 806 | + |
---|
| 807 | + if (target == current) |
---|
| 808 | + flushw_user(); |
---|
| 809 | + |
---|
| 810 | + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, |
---|
| 811 | + uregs, |
---|
| 812 | + 0, 19 * sizeof(u32)); |
---|
| 813 | + if (ret) |
---|
| 814 | + return ret; |
---|
| 815 | + |
---|
| 816 | + tstate = regs->tstate; |
---|
| 817 | + tstate &= ~(TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL); |
---|
| 818 | + tstate |= psr_to_tstate_icc(uregs[0]); |
---|
| 819 | + if (uregs[0] & PSR_SYSCALL) |
---|
| 820 | + tstate |= TSTATE_SYSCALL; |
---|
| 821 | + regs->tstate = tstate; |
---|
| 822 | + regs->tpc = uregs[1]; |
---|
| 823 | + regs->tnpc = uregs[2]; |
---|
| 824 | + regs->y = uregs[3]; |
---|
| 825 | + |
---|
| 826 | + for (i = 1; i < 15; i++) |
---|
| 827 | + regs->u_regs[i] = uregs[3 + i]; |
---|
| 828 | + return 0; |
---|
| 829 | +} |
---|
| 830 | + |
---|
| 831 | +static int getfpregs_get(struct task_struct *target, |
---|
| 832 | + const struct user_regset *regset, |
---|
| 833 | + struct membuf to) |
---|
| 834 | +{ |
---|
| 835 | + struct thread_info *t = task_thread_info(target); |
---|
| 836 | + |
---|
| 837 | + if (target == current) |
---|
| 838 | + save_and_clear_fpu(); |
---|
| 839 | + |
---|
| 840 | + membuf_write(&to, t->fpregs, 32 * sizeof(u32)); |
---|
| 841 | + if (t->fpsaved[0] & FPRS_FEF) |
---|
| 842 | + membuf_store(&to, (u32)t->xfsr[0]); |
---|
| 843 | + else |
---|
| 844 | + membuf_zero(&to, sizeof(u32)); |
---|
| 845 | + return membuf_zero(&to, 35 * sizeof(u32)); |
---|
| 846 | +} |
---|
| 847 | + |
---|
| 848 | +static int setfpregs_set(struct task_struct *target, |
---|
| 849 | + const struct user_regset *regset, |
---|
| 850 | + unsigned int pos, unsigned int count, |
---|
| 851 | + const void *kbuf, const void __user *ubuf) |
---|
| 852 | +{ |
---|
| 853 | + unsigned long *fpregs = task_thread_info(target)->fpregs; |
---|
| 854 | + unsigned long fprs; |
---|
| 855 | + int ret; |
---|
| 856 | + |
---|
| 857 | + if (target == current) |
---|
| 858 | + save_and_clear_fpu(); |
---|
| 859 | + |
---|
| 860 | + fprs = task_thread_info(target)->fpsaved[0]; |
---|
| 861 | + |
---|
| 862 | + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, |
---|
| 863 | + fpregs, |
---|
| 864 | + 0, 32 * sizeof(u32)); |
---|
| 865 | + if (!ret) { |
---|
| 866 | + compat_ulong_t fsr; |
---|
| 867 | + unsigned long val; |
---|
| 868 | + |
---|
| 869 | + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, |
---|
| 870 | + &fsr, |
---|
| 871 | + 32 * sizeof(u32), |
---|
| 872 | + 33 * sizeof(u32)); |
---|
| 873 | + if (!ret) { |
---|
| 874 | + val = task_thread_info(target)->xfsr[0]; |
---|
| 875 | + val &= 0xffffffff00000000UL; |
---|
| 876 | + val |= fsr; |
---|
| 877 | + task_thread_info(target)->xfsr[0] = val; |
---|
| 878 | + } |
---|
| 879 | + } |
---|
| 880 | + |
---|
| 881 | + fprs |= (FPRS_FEF | FPRS_DL); |
---|
| 882 | + task_thread_info(target)->fpsaved[0] = fprs; |
---|
| 883 | + return ret; |
---|
| 884 | +} |
---|
| 885 | + |
---|
| 886 | +static const struct user_regset ptrace32_regsets[] = { |
---|
| 887 | + [REGSET_GENERAL] = { |
---|
| 888 | + .n = 19, .size = sizeof(u32), |
---|
| 889 | + .regset_get = getregs_get, .set = setregs_set, |
---|
| 890 | + }, |
---|
| 891 | + [REGSET_FP] = { |
---|
| 892 | + .n = 68, .size = sizeof(u32), |
---|
| 893 | + .regset_get = getfpregs_get, .set = setfpregs_set, |
---|
| 894 | + }, |
---|
| 895 | +}; |
---|
| 896 | + |
---|
| 897 | +static const struct user_regset_view ptrace32_view = { |
---|
| 898 | + .regsets = ptrace32_regsets, .n = ARRAY_SIZE(ptrace32_regsets) |
---|
868 | 899 | }; |
---|
869 | 900 | |
---|
870 | 901 | static const struct user_regset_view user_sparc32_view = { |
---|
.. | .. |
---|
898 | 929 | long compat_arch_ptrace(struct task_struct *child, compat_long_t request, |
---|
899 | 930 | compat_ulong_t caddr, compat_ulong_t cdata) |
---|
900 | 931 | { |
---|
901 | | - const struct user_regset_view *view = task_user_regset_view(current); |
---|
902 | 932 | compat_ulong_t caddr2 = task_pt_regs(current)->u_regs[UREG_I4]; |
---|
903 | 933 | struct pt_regs32 __user *pregs; |
---|
904 | 934 | struct compat_fps __user *fps; |
---|
.. | .. |
---|
916 | 946 | break; |
---|
917 | 947 | |
---|
918 | 948 | case PTRACE_GETREGS: |
---|
919 | | - ret = copy_regset_to_user(child, view, REGSET_GENERAL, |
---|
920 | | - 32 * sizeof(u32), |
---|
921 | | - 4 * sizeof(u32), |
---|
922 | | - &pregs->psr); |
---|
923 | | - if (!ret) |
---|
924 | | - ret = copy_regset_to_user(child, view, REGSET_GENERAL, |
---|
925 | | - 1 * sizeof(u32), |
---|
926 | | - 15 * sizeof(u32), |
---|
927 | | - &pregs->u_regs[0]); |
---|
| 949 | + ret = copy_regset_to_user(child, &ptrace32_view, |
---|
| 950 | + REGSET_GENERAL, 0, |
---|
| 951 | + 19 * sizeof(u32), |
---|
| 952 | + pregs); |
---|
928 | 953 | break; |
---|
929 | 954 | |
---|
930 | 955 | case PTRACE_SETREGS: |
---|
931 | | - ret = copy_regset_from_user(child, view, REGSET_GENERAL, |
---|
932 | | - 32 * sizeof(u32), |
---|
933 | | - 4 * sizeof(u32), |
---|
934 | | - &pregs->psr); |
---|
935 | | - if (!ret) |
---|
936 | | - ret = copy_regset_from_user(child, view, REGSET_GENERAL, |
---|
937 | | - 1 * sizeof(u32), |
---|
938 | | - 15 * sizeof(u32), |
---|
939 | | - &pregs->u_regs[0]); |
---|
| 956 | + ret = copy_regset_from_user(child, &ptrace32_view, |
---|
| 957 | + REGSET_GENERAL, 0, |
---|
| 958 | + 19 * sizeof(u32), |
---|
| 959 | + pregs); |
---|
940 | 960 | break; |
---|
941 | 961 | |
---|
942 | 962 | case PTRACE_GETFPREGS: |
---|
943 | | - ret = copy_regset_to_user(child, view, REGSET_FP, |
---|
944 | | - 0 * sizeof(u32), |
---|
945 | | - 32 * sizeof(u32), |
---|
946 | | - &fps->regs[0]); |
---|
947 | | - if (!ret) |
---|
948 | | - ret = copy_regset_to_user(child, view, REGSET_FP, |
---|
949 | | - 33 * sizeof(u32), |
---|
950 | | - 1 * sizeof(u32), |
---|
951 | | - &fps->fsr); |
---|
952 | | - if (!ret) { |
---|
953 | | - if (__put_user(0, &fps->flags) || |
---|
954 | | - __put_user(0, &fps->extra) || |
---|
955 | | - __put_user(0, &fps->fpqd) || |
---|
956 | | - clear_user(&fps->fpq[0], 32 * sizeof(unsigned int))) |
---|
957 | | - ret = -EFAULT; |
---|
958 | | - } |
---|
| 963 | + ret = copy_regset_to_user(child, &ptrace32_view, |
---|
| 964 | + REGSET_FP, 0, |
---|
| 965 | + 68 * sizeof(u32), |
---|
| 966 | + fps); |
---|
959 | 967 | break; |
---|
960 | 968 | |
---|
961 | 969 | case PTRACE_SETFPREGS: |
---|
962 | | - ret = copy_regset_from_user(child, view, REGSET_FP, |
---|
963 | | - 0 * sizeof(u32), |
---|
964 | | - 32 * sizeof(u32), |
---|
965 | | - &fps->regs[0]); |
---|
966 | | - if (!ret) |
---|
967 | | - ret = copy_regset_from_user(child, view, REGSET_FP, |
---|
968 | | - 33 * sizeof(u32), |
---|
969 | | - 1 * sizeof(u32), |
---|
970 | | - &fps->fsr); |
---|
| 970 | + ret = copy_regset_from_user(child, &ptrace32_view, |
---|
| 971 | + REGSET_FP, 0, |
---|
| 972 | + 33 * sizeof(u32), |
---|
| 973 | + fps); |
---|
971 | 974 | break; |
---|
972 | 975 | |
---|
973 | 976 | case PTRACE_READTEXT: |
---|
.. | .. |
---|
1026 | 1029 | break; |
---|
1027 | 1030 | |
---|
1028 | 1031 | case PTRACE_GETREGS64: |
---|
1029 | | - ret = copy_regset_to_user(child, view, REGSET_GENERAL, |
---|
1030 | | - 1 * sizeof(u64), |
---|
1031 | | - 15 * sizeof(u64), |
---|
1032 | | - &pregs->u_regs[0]); |
---|
1033 | | - if (!ret) { |
---|
1034 | | - /* XXX doesn't handle 'y' register correctly XXX */ |
---|
1035 | | - ret = copy_regset_to_user(child, view, REGSET_GENERAL, |
---|
1036 | | - 32 * sizeof(u64), |
---|
1037 | | - 4 * sizeof(u64), |
---|
1038 | | - &pregs->tstate); |
---|
1039 | | - } |
---|
| 1032 | + ret = copy_regset_to_user(child, &ptrace64_view, |
---|
| 1033 | + REGSET_GENERAL, 0, |
---|
| 1034 | + 19 * sizeof(u64), |
---|
| 1035 | + pregs); |
---|
1040 | 1036 | break; |
---|
1041 | 1037 | |
---|
1042 | 1038 | case PTRACE_SETREGS64: |
---|
1043 | | - ret = copy_regset_from_user(child, view, REGSET_GENERAL, |
---|
1044 | | - 1 * sizeof(u64), |
---|
1045 | | - 15 * sizeof(u64), |
---|
1046 | | - &pregs->u_regs[0]); |
---|
1047 | | - if (!ret) { |
---|
1048 | | - /* XXX doesn't handle 'y' register correctly XXX */ |
---|
1049 | | - ret = copy_regset_from_user(child, view, REGSET_GENERAL, |
---|
1050 | | - 32 * sizeof(u64), |
---|
1051 | | - 4 * sizeof(u64), |
---|
1052 | | - &pregs->tstate); |
---|
1053 | | - } |
---|
| 1039 | + ret = copy_regset_from_user(child, &ptrace64_view, |
---|
| 1040 | + REGSET_GENERAL, 0, |
---|
| 1041 | + 19 * sizeof(u64), |
---|
| 1042 | + pregs); |
---|
1054 | 1043 | break; |
---|
1055 | 1044 | |
---|
1056 | 1045 | case PTRACE_GETFPREGS64: |
---|