diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2008-07-14 03:58:54 -0400 |
---|---|---|
committer | Heiko Carstens <heiko.carstens@de.ibm.com> | 2008-07-14 04:02:09 -0400 |
commit | 63506c41986c4af9d4fd6f3490e98e335f3dc8f5 (patch) | |
tree | 6d817aedf37a004c12713a0b594387b9dadd59ea /arch/s390/kernel/ptrace.c | |
parent | ae437a452ed20f9d13c1f17b0356201d54394efa (diff) |
[S390] Introduce user_regset accessors for s390
Add the user_regset definitions for normal and compat processes, replace
the dump_regs core dump cruft with the generic CORE_DUMP_USER_REGSET and
replace binfmt_elf32.c with the generic compat_binfmt_elf.c implementation.
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel/ptrace.c')
-rw-r--r-- | arch/s390/kernel/ptrace.c | 363 |
1 files changed, 318 insertions, 45 deletions
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 35827b9bd4d1..2815bfe348a6 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c | |||
@@ -33,6 +33,8 @@ | |||
33 | #include <linux/security.h> | 33 | #include <linux/security.h> |
34 | #include <linux/audit.h> | 34 | #include <linux/audit.h> |
35 | #include <linux/signal.h> | 35 | #include <linux/signal.h> |
36 | #include <linux/elf.h> | ||
37 | #include <linux/regset.h> | ||
36 | 38 | ||
37 | #include <asm/segment.h> | 39 | #include <asm/segment.h> |
38 | #include <asm/page.h> | 40 | #include <asm/page.h> |
@@ -47,6 +49,11 @@ | |||
47 | #include "compat_ptrace.h" | 49 | #include "compat_ptrace.h" |
48 | #endif | 50 | #endif |
49 | 51 | ||
52 | enum s390_regset { | ||
53 | REGSET_GENERAL, | ||
54 | REGSET_FP, | ||
55 | }; | ||
56 | |||
50 | static void | 57 | static void |
51 | FixPerRegisters(struct task_struct *task) | 58 | FixPerRegisters(struct task_struct *task) |
52 | { | 59 | { |
@@ -126,24 +133,10 @@ ptrace_disable(struct task_struct *child) | |||
126 | * struct user contain pad bytes that should be read as zeroes. | 133 | * struct user contain pad bytes that should be read as zeroes. |
127 | * Lovely... | 134 | * Lovely... |
128 | */ | 135 | */ |
129 | static int | 136 | static unsigned long __peek_user(struct task_struct *child, addr_t addr) |
130 | peek_user(struct task_struct *child, addr_t addr, addr_t data) | ||
131 | { | 137 | { |
132 | struct user *dummy = NULL; | 138 | struct user *dummy = NULL; |
133 | addr_t offset, tmp, mask; | 139 | addr_t offset, tmp; |
134 | |||
135 | /* | ||
136 | * Stupid gdb peeks/pokes the access registers in 64 bit with | ||
137 | * an alignment of 4. Programmers from hell... | ||
138 | */ | ||
139 | mask = __ADDR_MASK; | ||
140 | #ifdef CONFIG_64BIT | ||
141 | if (addr >= (addr_t) &dummy->regs.acrs && | ||
142 | addr < (addr_t) &dummy->regs.orig_gpr2) | ||
143 | mask = 3; | ||
144 | #endif | ||
145 | if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK) | ||
146 | return -EIO; | ||
147 | 140 | ||
148 | if (addr < (addr_t) &dummy->regs.acrs) { | 141 | if (addr < (addr_t) &dummy->regs.acrs) { |
149 | /* | 142 | /* |
@@ -197,24 +190,18 @@ peek_user(struct task_struct *child, addr_t addr, addr_t data) | |||
197 | } else | 190 | } else |
198 | tmp = 0; | 191 | tmp = 0; |
199 | 192 | ||
200 | return put_user(tmp, (addr_t __user *) data); | 193 | return tmp; |
201 | } | 194 | } |
202 | 195 | ||
203 | /* | ||
204 | * Write a word to the user area of a process at location addr. This | ||
205 | * operation does have an additional problem compared to peek_user. | ||
206 | * Stores to the program status word and on the floating point | ||
207 | * control register needs to get checked for validity. | ||
208 | */ | ||
209 | static int | 196 | static int |
210 | poke_user(struct task_struct *child, addr_t addr, addr_t data) | 197 | peek_user(struct task_struct *child, addr_t addr, addr_t data) |
211 | { | 198 | { |
212 | struct user *dummy = NULL; | 199 | struct user *dummy = NULL; |
213 | addr_t offset, mask; | 200 | addr_t tmp, mask; |
214 | 201 | ||
215 | /* | 202 | /* |
216 | * Stupid gdb peeks/pokes the access registers in 64 bit with | 203 | * Stupid gdb peeks/pokes the access registers in 64 bit with |
217 | * an alignment of 4. Programmers from hell indeed... | 204 | * an alignment of 4. Programmers from hell... |
218 | */ | 205 | */ |
219 | mask = __ADDR_MASK; | 206 | mask = __ADDR_MASK; |
220 | #ifdef CONFIG_64BIT | 207 | #ifdef CONFIG_64BIT |
@@ -225,6 +212,21 @@ poke_user(struct task_struct *child, addr_t addr, addr_t data) | |||
225 | if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK) | 212 | if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK) |
226 | return -EIO; | 213 | return -EIO; |
227 | 214 | ||
215 | tmp = __peek_user(child, addr); | ||
216 | return put_user(tmp, (addr_t __user *) data); | ||
217 | } | ||
218 | |||
219 | /* | ||
220 | * Write a word to the user area of a process at location addr. This | ||
221 | * operation does have an additional problem compared to peek_user. | ||
222 | * Stores to the program status word and on the floating point | ||
223 | * control register needs to get checked for validity. | ||
224 | */ | ||
225 | static int __poke_user(struct task_struct *child, addr_t addr, addr_t data) | ||
226 | { | ||
227 | struct user *dummy = NULL; | ||
228 | addr_t offset; | ||
229 | |||
228 | if (addr < (addr_t) &dummy->regs.acrs) { | 230 | if (addr < (addr_t) &dummy->regs.acrs) { |
229 | /* | 231 | /* |
230 | * psw and gprs are stored on the stack | 232 | * psw and gprs are stored on the stack |
@@ -292,6 +294,28 @@ poke_user(struct task_struct *child, addr_t addr, addr_t data) | |||
292 | return 0; | 294 | return 0; |
293 | } | 295 | } |
294 | 296 | ||
297 | static int | ||
298 | poke_user(struct task_struct *child, addr_t addr, addr_t data) | ||
299 | { | ||
300 | struct user *dummy = NULL; | ||
301 | addr_t mask; | ||
302 | |||
303 | /* | ||
304 | * Stupid gdb peeks/pokes the access registers in 64 bit with | ||
305 | * an alignment of 4. Programmers from hell indeed... | ||
306 | */ | ||
307 | mask = __ADDR_MASK; | ||
308 | #ifdef CONFIG_64BIT | ||
309 | if (addr >= (addr_t) &dummy->regs.acrs && | ||
310 | addr < (addr_t) &dummy->regs.orig_gpr2) | ||
311 | mask = 3; | ||
312 | #endif | ||
313 | if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK) | ||
314 | return -EIO; | ||
315 | |||
316 | return __poke_user(child, addr, data); | ||
317 | } | ||
318 | |||
295 | long arch_ptrace(struct task_struct *child, long request, long addr, long data) | 319 | long arch_ptrace(struct task_struct *child, long request, long addr, long data) |
296 | { | 320 | { |
297 | ptrace_area parea; | 321 | ptrace_area parea; |
@@ -367,18 +391,13 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
367 | /* | 391 | /* |
368 | * Same as peek_user but for a 31 bit program. | 392 | * Same as peek_user but for a 31 bit program. |
369 | */ | 393 | */ |
370 | static int | 394 | static u32 __peek_user_compat(struct task_struct *child, addr_t addr) |
371 | peek_user_emu31(struct task_struct *child, addr_t addr, addr_t data) | ||
372 | { | 395 | { |
373 | struct user32 *dummy32 = NULL; | 396 | struct user32 *dummy32 = NULL; |
374 | per_struct32 *dummy_per32 = NULL; | 397 | per_struct32 *dummy_per32 = NULL; |
375 | addr_t offset; | 398 | addr_t offset; |
376 | __u32 tmp; | 399 | __u32 tmp; |
377 | 400 | ||
378 | if (!test_thread_flag(TIF_31BIT) || | ||
379 | (addr & 3) || addr > sizeof(struct user) - 3) | ||
380 | return -EIO; | ||
381 | |||
382 | if (addr < (addr_t) &dummy32->regs.acrs) { | 401 | if (addr < (addr_t) &dummy32->regs.acrs) { |
383 | /* | 402 | /* |
384 | * psw and gprs are stored on the stack | 403 | * psw and gprs are stored on the stack |
@@ -435,25 +454,32 @@ peek_user_emu31(struct task_struct *child, addr_t addr, addr_t data) | |||
435 | } else | 454 | } else |
436 | tmp = 0; | 455 | tmp = 0; |
437 | 456 | ||
457 | return tmp; | ||
458 | } | ||
459 | |||
460 | static int peek_user_compat(struct task_struct *child, | ||
461 | addr_t addr, addr_t data) | ||
462 | { | ||
463 | __u32 tmp; | ||
464 | |||
465 | if (!test_thread_flag(TIF_31BIT) || | ||
466 | (addr & 3) || addr > sizeof(struct user) - 3) | ||
467 | return -EIO; | ||
468 | |||
469 | tmp = __peek_user_compat(child, addr); | ||
438 | return put_user(tmp, (__u32 __user *) data); | 470 | return put_user(tmp, (__u32 __user *) data); |
439 | } | 471 | } |
440 | 472 | ||
441 | /* | 473 | /* |
442 | * Same as poke_user but for a 31 bit program. | 474 | * Same as poke_user but for a 31 bit program. |
443 | */ | 475 | */ |
444 | static int | 476 | static int __poke_user_compat(struct task_struct *child, |
445 | poke_user_emu31(struct task_struct *child, addr_t addr, addr_t data) | 477 | addr_t addr, addr_t data) |
446 | { | 478 | { |
447 | struct user32 *dummy32 = NULL; | 479 | struct user32 *dummy32 = NULL; |
448 | per_struct32 *dummy_per32 = NULL; | 480 | per_struct32 *dummy_per32 = NULL; |
481 | __u32 tmp = (__u32) data; | ||
449 | addr_t offset; | 482 | addr_t offset; |
450 | __u32 tmp; | ||
451 | |||
452 | if (!test_thread_flag(TIF_31BIT) || | ||
453 | (addr & 3) || addr > sizeof(struct user32) - 3) | ||
454 | return -EIO; | ||
455 | |||
456 | tmp = (__u32) data; | ||
457 | 483 | ||
458 | if (addr < (addr_t) &dummy32->regs.acrs) { | 484 | if (addr < (addr_t) &dummy32->regs.acrs) { |
459 | /* | 485 | /* |
@@ -528,6 +554,16 @@ poke_user_emu31(struct task_struct *child, addr_t addr, addr_t data) | |||
528 | return 0; | 554 | return 0; |
529 | } | 555 | } |
530 | 556 | ||
557 | static int poke_user_compat(struct task_struct *child, | ||
558 | addr_t addr, addr_t data) | ||
559 | { | ||
560 | if (!test_thread_flag(TIF_31BIT) || | ||
561 | (addr & 3) || addr > sizeof(struct user32) - 3) | ||
562 | return -EIO; | ||
563 | |||
564 | return __poke_user_compat(child, addr, data); | ||
565 | } | ||
566 | |||
531 | long compat_arch_ptrace(struct task_struct *child, compat_long_t request, | 567 | long compat_arch_ptrace(struct task_struct *child, compat_long_t request, |
532 | compat_ulong_t caddr, compat_ulong_t cdata) | 568 | compat_ulong_t caddr, compat_ulong_t cdata) |
533 | { | 569 | { |
@@ -539,11 +575,11 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, | |||
539 | switch (request) { | 575 | switch (request) { |
540 | case PTRACE_PEEKUSR: | 576 | case PTRACE_PEEKUSR: |
541 | /* read the word at location addr in the USER area. */ | 577 | /* read the word at location addr in the USER area. */ |
542 | return peek_user_emu31(child, addr, data); | 578 | return peek_user_compat(child, addr, data); |
543 | 579 | ||
544 | case PTRACE_POKEUSR: | 580 | case PTRACE_POKEUSR: |
545 | /* write the word at location addr in the USER area */ | 581 | /* write the word at location addr in the USER area */ |
546 | return poke_user_emu31(child, addr, data); | 582 | return poke_user_compat(child, addr, data); |
547 | 583 | ||
548 | case PTRACE_PEEKUSR_AREA: | 584 | case PTRACE_PEEKUSR_AREA: |
549 | case PTRACE_POKEUSR_AREA: | 585 | case PTRACE_POKEUSR_AREA: |
@@ -555,13 +591,13 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, | |||
555 | copied = 0; | 591 | copied = 0; |
556 | while (copied < parea.len) { | 592 | while (copied < parea.len) { |
557 | if (request == PTRACE_PEEKUSR_AREA) | 593 | if (request == PTRACE_PEEKUSR_AREA) |
558 | ret = peek_user_emu31(child, addr, data); | 594 | ret = peek_user_compat(child, addr, data); |
559 | else { | 595 | else { |
560 | __u32 utmp; | 596 | __u32 utmp; |
561 | if (get_user(utmp, | 597 | if (get_user(utmp, |
562 | (__u32 __force __user *) data)) | 598 | (__u32 __force __user *) data)) |
563 | return -EFAULT; | 599 | return -EFAULT; |
564 | ret = poke_user_emu31(child, addr, utmp); | 600 | ret = poke_user_compat(child, addr, utmp); |
565 | } | 601 | } |
566 | if (ret) | 602 | if (ret) |
567 | return ret; | 603 | return ret; |
@@ -610,3 +646,240 @@ syscall_trace(struct pt_regs *regs, int entryexit) | |||
610 | regs->gprs[2], regs->orig_gpr2, regs->gprs[3], | 646 | regs->gprs[2], regs->orig_gpr2, regs->gprs[3], |
611 | regs->gprs[4], regs->gprs[5]); | 647 | regs->gprs[4], regs->gprs[5]); |
612 | } | 648 | } |
649 | |||
650 | /* | ||
651 | * user_regset definitions. | ||
652 | */ | ||
653 | |||
654 | static int s390_regs_get(struct task_struct *target, | ||
655 | const struct user_regset *regset, | ||
656 | unsigned int pos, unsigned int count, | ||
657 | void *kbuf, void __user *ubuf) | ||
658 | { | ||
659 | if (target == current) | ||
660 | save_access_regs(target->thread.acrs); | ||
661 | |||
662 | if (kbuf) { | ||
663 | unsigned long *k = kbuf; | ||
664 | while (count > 0) { | ||
665 | *k++ = __peek_user(target, pos); | ||
666 | count -= sizeof(*k); | ||
667 | pos += sizeof(*k); | ||
668 | } | ||
669 | } else { | ||
670 | unsigned long __user *u = ubuf; | ||
671 | while (count > 0) { | ||
672 | if (__put_user(__peek_user(target, pos), u++)) | ||
673 | return -EFAULT; | ||
674 | count -= sizeof(*u); | ||
675 | pos += sizeof(*u); | ||
676 | } | ||
677 | } | ||
678 | return 0; | ||
679 | } | ||
680 | |||
681 | static int s390_regs_set(struct task_struct *target, | ||
682 | const struct user_regset *regset, | ||
683 | unsigned int pos, unsigned int count, | ||
684 | const void *kbuf, const void __user *ubuf) | ||
685 | { | ||
686 | int rc = 0; | ||
687 | |||
688 | if (target == current) | ||
689 | save_access_regs(target->thread.acrs); | ||
690 | |||
691 | if (kbuf) { | ||
692 | const unsigned long *k = kbuf; | ||
693 | while (count > 0 && !rc) { | ||
694 | rc = __poke_user(target, pos, *k++); | ||
695 | count -= sizeof(*k); | ||
696 | pos += sizeof(*k); | ||
697 | } | ||
698 | } else { | ||
699 | const unsigned long __user *u = ubuf; | ||
700 | while (count > 0 && !rc) { | ||
701 | unsigned long word; | ||
702 | rc = __get_user(word, u++); | ||
703 | if (rc) | ||
704 | break; | ||
705 | rc = __poke_user(target, pos, word); | ||
706 | count -= sizeof(*u); | ||
707 | pos += sizeof(*u); | ||
708 | } | ||
709 | } | ||
710 | |||
711 | if (rc == 0 && target == current) | ||
712 | restore_access_regs(target->thread.acrs); | ||
713 | |||
714 | return rc; | ||
715 | } | ||
716 | |||
717 | static int s390_fpregs_get(struct task_struct *target, | ||
718 | const struct user_regset *regset, unsigned int pos, | ||
719 | unsigned int count, void *kbuf, void __user *ubuf) | ||
720 | { | ||
721 | if (target == current) | ||
722 | save_fp_regs(&target->thread.fp_regs); | ||
723 | |||
724 | return user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
725 | &target->thread.fp_regs, 0, -1); | ||
726 | } | ||
727 | |||
728 | static int s390_fpregs_set(struct task_struct *target, | ||
729 | const struct user_regset *regset, unsigned int pos, | ||
730 | unsigned int count, const void *kbuf, | ||
731 | const void __user *ubuf) | ||
732 | { | ||
733 | int rc = 0; | ||
734 | |||
735 | if (target == current) | ||
736 | save_fp_regs(&target->thread.fp_regs); | ||
737 | |||
738 | /* If setting FPC, must validate it first. */ | ||
739 | if (count > 0 && pos < offsetof(s390_fp_regs, fprs)) { | ||
740 | u32 fpc[2] = { target->thread.fp_regs.fpc, 0 }; | ||
741 | rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &fpc, | ||
742 | 0, offsetof(s390_fp_regs, fprs)); | ||
743 | if (rc) | ||
744 | return rc; | ||
745 | if ((fpc[0] & ~FPC_VALID_MASK) != 0 || fpc[1] != 0) | ||
746 | return -EINVAL; | ||
747 | target->thread.fp_regs.fpc = fpc[0]; | ||
748 | } | ||
749 | |||
750 | if (rc == 0 && count > 0) | ||
751 | rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
752 | target->thread.fp_regs.fprs, | ||
753 | offsetof(s390_fp_regs, fprs), -1); | ||
754 | |||
755 | if (rc == 0 && target == current) | ||
756 | restore_fp_regs(&target->thread.fp_regs); | ||
757 | |||
758 | return rc; | ||
759 | } | ||
760 | |||
761 | static const struct user_regset s390_regsets[] = { | ||
762 | [REGSET_GENERAL] = { | ||
763 | .core_note_type = NT_PRSTATUS, | ||
764 | .n = sizeof(s390_regs) / sizeof(long), | ||
765 | .size = sizeof(long), | ||
766 | .align = sizeof(long), | ||
767 | .get = s390_regs_get, | ||
768 | .set = s390_regs_set, | ||
769 | }, | ||
770 | [REGSET_FP] = { | ||
771 | .core_note_type = NT_PRFPREG, | ||
772 | .n = sizeof(s390_fp_regs) / sizeof(long), | ||
773 | .size = sizeof(long), | ||
774 | .align = sizeof(long), | ||
775 | .get = s390_fpregs_get, | ||
776 | .set = s390_fpregs_set, | ||
777 | }, | ||
778 | }; | ||
779 | |||
780 | static const struct user_regset_view user_s390_view = { | ||
781 | .name = UTS_MACHINE, | ||
782 | .e_machine = EM_S390, | ||
783 | .regsets = s390_regsets, | ||
784 | .n = ARRAY_SIZE(s390_regsets) | ||
785 | }; | ||
786 | |||
787 | #ifdef CONFIG_COMPAT | ||
788 | static int s390_compat_regs_get(struct task_struct *target, | ||
789 | const struct user_regset *regset, | ||
790 | unsigned int pos, unsigned int count, | ||
791 | void *kbuf, void __user *ubuf) | ||
792 | { | ||
793 | if (target == current) | ||
794 | save_access_regs(target->thread.acrs); | ||
795 | |||
796 | if (kbuf) { | ||
797 | compat_ulong_t *k = kbuf; | ||
798 | while (count > 0) { | ||
799 | *k++ = __peek_user_compat(target, pos); | ||
800 | count -= sizeof(*k); | ||
801 | pos += sizeof(*k); | ||
802 | } | ||
803 | } else { | ||
804 | compat_ulong_t __user *u = ubuf; | ||
805 | while (count > 0) { | ||
806 | if (__put_user(__peek_user_compat(target, pos), u++)) | ||
807 | return -EFAULT; | ||
808 | count -= sizeof(*u); | ||
809 | pos += sizeof(*u); | ||
810 | } | ||
811 | } | ||
812 | return 0; | ||
813 | } | ||
814 | |||
815 | static int s390_compat_regs_set(struct task_struct *target, | ||
816 | const struct user_regset *regset, | ||
817 | unsigned int pos, unsigned int count, | ||
818 | const void *kbuf, const void __user *ubuf) | ||
819 | { | ||
820 | int rc = 0; | ||
821 | |||
822 | if (target == current) | ||
823 | save_access_regs(target->thread.acrs); | ||
824 | |||
825 | if (kbuf) { | ||
826 | const compat_ulong_t *k = kbuf; | ||
827 | while (count > 0 && !rc) { | ||
828 | rc = __poke_user_compat(target, pos, *k++); | ||
829 | count -= sizeof(*k); | ||
830 | pos += sizeof(*k); | ||
831 | } | ||
832 | } else { | ||
833 | const compat_ulong_t __user *u = ubuf; | ||
834 | while (count > 0 && !rc) { | ||
835 | compat_ulong_t word; | ||
836 | rc = __get_user(word, u++); | ||
837 | if (rc) | ||
838 | break; | ||
839 | rc = __poke_user_compat(target, pos, word); | ||
840 | count -= sizeof(*u); | ||
841 | pos += sizeof(*u); | ||
842 | } | ||
843 | } | ||
844 | |||
845 | if (rc == 0 && target == current) | ||
846 | restore_access_regs(target->thread.acrs); | ||
847 | |||
848 | return rc; | ||
849 | } | ||
850 | |||
851 | static const struct user_regset s390_compat_regsets[] = { | ||
852 | [REGSET_GENERAL] = { | ||
853 | .core_note_type = NT_PRSTATUS, | ||
854 | .n = sizeof(s390_compat_regs) / sizeof(compat_long_t), | ||
855 | .size = sizeof(compat_long_t), | ||
856 | .align = sizeof(compat_long_t), | ||
857 | .get = s390_compat_regs_get, | ||
858 | .set = s390_compat_regs_set, | ||
859 | }, | ||
860 | [REGSET_FP] = { | ||
861 | .core_note_type = NT_PRFPREG, | ||
862 | .n = sizeof(s390_fp_regs) / sizeof(compat_long_t), | ||
863 | .size = sizeof(compat_long_t), | ||
864 | .align = sizeof(compat_long_t), | ||
865 | .get = s390_fpregs_get, | ||
866 | .set = s390_fpregs_set, | ||
867 | }, | ||
868 | }; | ||
869 | |||
870 | static const struct user_regset_view user_s390_compat_view = { | ||
871 | .name = "s390", | ||
872 | .e_machine = EM_S390, | ||
873 | .regsets = s390_compat_regsets, | ||
874 | .n = ARRAY_SIZE(s390_compat_regsets) | ||
875 | }; | ||
876 | #endif | ||
877 | |||
878 | const struct user_regset_view *task_user_regset_view(struct task_struct *task) | ||
879 | { | ||
880 | #ifdef CONFIG_COMPAT | ||
881 | if (test_tsk_thread_flag(task, TIF_31BIT)) | ||
882 | return &user_s390_compat_view; | ||
883 | #endif | ||
884 | return &user_s390_view; | ||
885 | } | ||