| .. | .. |
|---|
| 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: |
|---|