aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/ptrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/kernel/ptrace.c')
-rw-r--r--arch/s390/kernel/ptrace.c70
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}