diff options
Diffstat (limited to 'arch/s390/kernel/ptrace.c')
-rw-r--r-- | arch/s390/kernel/ptrace.c | 70 |
1 files changed, 42 insertions, 28 deletions
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 9556905bd3ce..e65c91c591e8 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c | |||
@@ -198,9 +198,11 @@ static unsigned long __peek_user(struct task_struct *child, addr_t addr) | |||
198 | * psw and gprs are stored on the stack | 198 | * psw and gprs are stored on the stack |
199 | */ | 199 | */ |
200 | tmp = *(addr_t *)((addr_t) &task_pt_regs(child)->psw + addr); | 200 | tmp = *(addr_t *)((addr_t) &task_pt_regs(child)->psw + addr); |
201 | if (addr == (addr_t) &dummy->regs.psw.mask) | 201 | if (addr == (addr_t) &dummy->regs.psw.mask) { |
202 | /* Return a clean psw mask. */ | 202 | /* Return a clean psw mask. */ |
203 | tmp = psw_user_bits | (tmp & PSW_MASK_USER); | 203 | tmp &= PSW_MASK_USER | PSW_MASK_RI; |
204 | tmp |= PSW_USER_BITS; | ||
205 | } | ||
204 | 206 | ||
205 | } else if (addr < (addr_t) &dummy->regs.orig_gpr2) { | 207 | } else if (addr < (addr_t) &dummy->regs.orig_gpr2) { |
206 | /* | 208 | /* |
@@ -239,8 +241,7 @@ static unsigned long __peek_user(struct task_struct *child, addr_t addr) | |||
239 | offset = addr - (addr_t) &dummy->regs.fp_regs; | 241 | offset = addr - (addr_t) &dummy->regs.fp_regs; |
240 | tmp = *(addr_t *)((addr_t) &child->thread.fp_regs + offset); | 242 | tmp = *(addr_t *)((addr_t) &child->thread.fp_regs + offset); |
241 | if (addr == (addr_t) &dummy->regs.fp_regs.fpc) | 243 | if (addr == (addr_t) &dummy->regs.fp_regs.fpc) |
242 | tmp &= (unsigned long) FPC_VALID_MASK | 244 | tmp <<= BITS_PER_LONG - 32; |
243 | << (BITS_PER_LONG - 32); | ||
244 | 245 | ||
245 | } else if (addr < (addr_t) (&dummy->regs.per_info + 1)) { | 246 | } else if (addr < (addr_t) (&dummy->regs.per_info + 1)) { |
246 | /* | 247 | /* |
@@ -321,11 +322,15 @@ static int __poke_user(struct task_struct *child, addr_t addr, addr_t data) | |||
321 | /* | 322 | /* |
322 | * psw and gprs are stored on the stack | 323 | * psw and gprs are stored on the stack |
323 | */ | 324 | */ |
324 | if (addr == (addr_t) &dummy->regs.psw.mask && | 325 | if (addr == (addr_t) &dummy->regs.psw.mask) { |
325 | ((data & ~PSW_MASK_USER) != psw_user_bits || | 326 | unsigned long mask = PSW_MASK_USER; |
326 | ((data & PSW_MASK_EA) && !(data & PSW_MASK_BA)))) | 327 | |
327 | /* Invalid psw mask. */ | 328 | mask |= is_ri_task(child) ? PSW_MASK_RI : 0; |
328 | return -EINVAL; | 329 | if ((data & ~mask) != PSW_USER_BITS) |
330 | return -EINVAL; | ||
331 | if ((data & PSW_MASK_EA) && !(data & PSW_MASK_BA)) | ||
332 | return -EINVAL; | ||
333 | } | ||
329 | *(addr_t *)((addr_t) &task_pt_regs(child)->psw + addr) = data; | 334 | *(addr_t *)((addr_t) &task_pt_regs(child)->psw + addr) = data; |
330 | 335 | ||
331 | } else if (addr < (addr_t) (&dummy->regs.orig_gpr2)) { | 336 | } else if (addr < (addr_t) (&dummy->regs.orig_gpr2)) { |
@@ -363,10 +368,10 @@ static int __poke_user(struct task_struct *child, addr_t addr, addr_t data) | |||
363 | /* | 368 | /* |
364 | * floating point regs. are stored in the thread structure | 369 | * floating point regs. are stored in the thread structure |
365 | */ | 370 | */ |
366 | if (addr == (addr_t) &dummy->regs.fp_regs.fpc && | 371 | if (addr == (addr_t) &dummy->regs.fp_regs.fpc) |
367 | (data & ~((unsigned long) FPC_VALID_MASK | 372 | if ((unsigned int) data != 0 || |
368 | << (BITS_PER_LONG - 32))) != 0) | 373 | test_fp_ctl(data >> (BITS_PER_LONG - 32))) |
369 | return -EINVAL; | 374 | return -EINVAL; |
370 | offset = addr - (addr_t) &dummy->regs.fp_regs; | 375 | offset = addr - (addr_t) &dummy->regs.fp_regs; |
371 | *(addr_t *)((addr_t) &child->thread.fp_regs + offset) = data; | 376 | *(addr_t *)((addr_t) &child->thread.fp_regs + offset) = data; |
372 | 377 | ||
@@ -557,7 +562,8 @@ static u32 __peek_user_compat(struct task_struct *child, addr_t addr) | |||
557 | if (addr == (addr_t) &dummy32->regs.psw.mask) { | 562 | if (addr == (addr_t) &dummy32->regs.psw.mask) { |
558 | /* Fake a 31 bit psw mask. */ | 563 | /* Fake a 31 bit psw mask. */ |
559 | tmp = (__u32)(regs->psw.mask >> 32); | 564 | tmp = (__u32)(regs->psw.mask >> 32); |
560 | tmp = psw32_user_bits | (tmp & PSW32_MASK_USER); | 565 | tmp &= PSW32_MASK_USER | PSW32_MASK_RI; |
566 | tmp |= PSW32_USER_BITS; | ||
561 | } else if (addr == (addr_t) &dummy32->regs.psw.addr) { | 567 | } else if (addr == (addr_t) &dummy32->regs.psw.addr) { |
562 | /* Fake a 31 bit psw address. */ | 568 | /* Fake a 31 bit psw address. */ |
563 | tmp = (__u32) regs->psw.addr | | 569 | tmp = (__u32) regs->psw.addr | |
@@ -654,13 +660,16 @@ static int __poke_user_compat(struct task_struct *child, | |||
654 | * psw, gprs, acrs and orig_gpr2 are stored on the stack | 660 | * psw, gprs, acrs and orig_gpr2 are stored on the stack |
655 | */ | 661 | */ |
656 | if (addr == (addr_t) &dummy32->regs.psw.mask) { | 662 | if (addr == (addr_t) &dummy32->regs.psw.mask) { |
663 | __u32 mask = PSW32_MASK_USER; | ||
664 | |||
665 | mask |= is_ri_task(child) ? PSW32_MASK_RI : 0; | ||
657 | /* Build a 64 bit psw mask from 31 bit mask. */ | 666 | /* Build a 64 bit psw mask from 31 bit mask. */ |
658 | if ((tmp & ~PSW32_MASK_USER) != psw32_user_bits) | 667 | if ((tmp & ~mask) != PSW32_USER_BITS) |
659 | /* Invalid psw mask. */ | 668 | /* Invalid psw mask. */ |
660 | return -EINVAL; | 669 | return -EINVAL; |
661 | regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) | | 670 | regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) | |
662 | (regs->psw.mask & PSW_MASK_BA) | | 671 | (regs->psw.mask & PSW_MASK_BA) | |
663 | (__u64)(tmp & PSW32_MASK_USER) << 32; | 672 | (__u64)(tmp & mask) << 32; |
664 | } else if (addr == (addr_t) &dummy32->regs.psw.addr) { | 673 | } else if (addr == (addr_t) &dummy32->regs.psw.addr) { |
665 | /* Build a 64 bit psw address from 31 bit address. */ | 674 | /* Build a 64 bit psw address from 31 bit address. */ |
666 | regs->psw.addr = (__u64) tmp & PSW32_ADDR_INSN; | 675 | regs->psw.addr = (__u64) tmp & PSW32_ADDR_INSN; |
@@ -696,8 +705,7 @@ static int __poke_user_compat(struct task_struct *child, | |||
696 | * floating point regs. are stored in the thread structure | 705 | * floating point regs. are stored in the thread structure |
697 | */ | 706 | */ |
698 | if (addr == (addr_t) &dummy32->regs.fp_regs.fpc && | 707 | if (addr == (addr_t) &dummy32->regs.fp_regs.fpc && |
699 | (tmp & ~FPC_VALID_MASK) != 0) | 708 | test_fp_ctl(tmp)) |
700 | /* Invalid floating point control. */ | ||
701 | return -EINVAL; | 709 | return -EINVAL; |
702 | offset = addr - (addr_t) &dummy32->regs.fp_regs; | 710 | offset = addr - (addr_t) &dummy32->regs.fp_regs; |
703 | *(__u32 *)((addr_t) &child->thread.fp_regs + offset) = tmp; | 711 | *(__u32 *)((addr_t) &child->thread.fp_regs + offset) = tmp; |
@@ -895,8 +903,10 @@ static int s390_fpregs_get(struct task_struct *target, | |||
895 | const struct user_regset *regset, unsigned int pos, | 903 | const struct user_regset *regset, unsigned int pos, |
896 | unsigned int count, void *kbuf, void __user *ubuf) | 904 | unsigned int count, void *kbuf, void __user *ubuf) |
897 | { | 905 | { |
898 | if (target == current) | 906 | if (target == current) { |
899 | save_fp_regs(&target->thread.fp_regs); | 907 | save_fp_ctl(&target->thread.fp_regs.fpc); |
908 | save_fp_regs(target->thread.fp_regs.fprs); | ||
909 | } | ||
900 | 910 | ||
901 | return user_regset_copyout(&pos, &count, &kbuf, &ubuf, | 911 | return user_regset_copyout(&pos, &count, &kbuf, &ubuf, |
902 | &target->thread.fp_regs, 0, -1); | 912 | &target->thread.fp_regs, 0, -1); |
@@ -909,19 +919,21 @@ static int s390_fpregs_set(struct task_struct *target, | |||
909 | { | 919 | { |
910 | int rc = 0; | 920 | int rc = 0; |
911 | 921 | ||
912 | if (target == current) | 922 | if (target == current) { |
913 | save_fp_regs(&target->thread.fp_regs); | 923 | save_fp_ctl(&target->thread.fp_regs.fpc); |
924 | save_fp_regs(target->thread.fp_regs.fprs); | ||
925 | } | ||
914 | 926 | ||
915 | /* If setting FPC, must validate it first. */ | 927 | /* If setting FPC, must validate it first. */ |
916 | if (count > 0 && pos < offsetof(s390_fp_regs, fprs)) { | 928 | if (count > 0 && pos < offsetof(s390_fp_regs, fprs)) { |
917 | u32 fpc[2] = { target->thread.fp_regs.fpc, 0 }; | 929 | u32 ufpc[2] = { target->thread.fp_regs.fpc, 0 }; |
918 | rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &fpc, | 930 | rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &ufpc, |
919 | 0, offsetof(s390_fp_regs, fprs)); | 931 | 0, offsetof(s390_fp_regs, fprs)); |
920 | if (rc) | 932 | if (rc) |
921 | return rc; | 933 | return rc; |
922 | if ((fpc[0] & ~FPC_VALID_MASK) != 0 || fpc[1] != 0) | 934 | if (ufpc[1] != 0 || test_fp_ctl(ufpc[0])) |
923 | return -EINVAL; | 935 | return -EINVAL; |
924 | target->thread.fp_regs.fpc = fpc[0]; | 936 | target->thread.fp_regs.fpc = ufpc[0]; |
925 | } | 937 | } |
926 | 938 | ||
927 | if (rc == 0 && count > 0) | 939 | if (rc == 0 && count > 0) |
@@ -929,8 +941,10 @@ static int s390_fpregs_set(struct task_struct *target, | |||
929 | target->thread.fp_regs.fprs, | 941 | target->thread.fp_regs.fprs, |
930 | offsetof(s390_fp_regs, fprs), -1); | 942 | offsetof(s390_fp_regs, fprs), -1); |
931 | 943 | ||
932 | if (rc == 0 && target == current) | 944 | if (rc == 0 && target == current) { |
933 | restore_fp_regs(&target->thread.fp_regs); | 945 | restore_fp_ctl(&target->thread.fp_regs.fpc); |
946 | restore_fp_regs(target->thread.fp_regs.fprs); | ||
947 | } | ||
934 | 948 | ||
935 | return rc; | 949 | return rc; |
936 | } | 950 | } |