diff options
Diffstat (limited to 'arch/s390/kernel/ptrace.c')
-rw-r--r-- | arch/s390/kernel/ptrace.c | 115 |
1 files changed, 83 insertions, 32 deletions
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 99a567b70d16..eabfb4594517 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c | |||
@@ -248,14 +248,27 @@ static unsigned long __peek_user(struct task_struct *child, addr_t addr) | |||
248 | */ | 248 | */ |
249 | tmp = 0; | 249 | tmp = 0; |
250 | 250 | ||
251 | } else if (addr == (addr_t) &dummy->regs.fp_regs.fpc) { | ||
252 | /* | ||
253 | * floating point control reg. is in the thread structure | ||
254 | */ | ||
255 | tmp = child->thread.fp_regs.fpc; | ||
256 | tmp <<= BITS_PER_LONG - 32; | ||
257 | |||
251 | } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { | 258 | } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { |
252 | /* | 259 | /* |
253 | * floating point regs. are stored in the thread structure | 260 | * floating point regs. are either in child->thread.fp_regs |
261 | * or the child->thread.vxrs array | ||
254 | */ | 262 | */ |
255 | offset = addr - (addr_t) &dummy->regs.fp_regs; | 263 | offset = addr - (addr_t) &dummy->regs.fp_regs.fprs; |
256 | tmp = *(addr_t *)((addr_t) &child->thread.fp_regs + offset); | 264 | #ifdef CONFIG_64BIT |
257 | if (addr == (addr_t) &dummy->regs.fp_regs.fpc) | 265 | if (child->thread.vxrs) |
258 | tmp <<= BITS_PER_LONG - 32; | 266 | tmp = *(addr_t *) |
267 | ((addr_t) child->thread.vxrs + 2*offset); | ||
268 | else | ||
269 | #endif | ||
270 | tmp = *(addr_t *) | ||
271 | ((addr_t) &child->thread.fp_regs.fprs + offset); | ||
259 | 272 | ||
260 | } else if (addr < (addr_t) (&dummy->regs.per_info + 1)) { | 273 | } else if (addr < (addr_t) (&dummy->regs.per_info + 1)) { |
261 | /* | 274 | /* |
@@ -383,16 +396,29 @@ static int __poke_user(struct task_struct *child, addr_t addr, addr_t data) | |||
383 | */ | 396 | */ |
384 | return 0; | 397 | return 0; |
385 | 398 | ||
399 | } else if (addr == (addr_t) &dummy->regs.fp_regs.fpc) { | ||
400 | /* | ||
401 | * floating point control reg. is in the thread structure | ||
402 | */ | ||
403 | if ((unsigned int) data != 0 || | ||
404 | test_fp_ctl(data >> (BITS_PER_LONG - 32))) | ||
405 | return -EINVAL; | ||
406 | child->thread.fp_regs.fpc = data >> (BITS_PER_LONG - 32); | ||
407 | |||
386 | } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { | 408 | } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { |
387 | /* | 409 | /* |
388 | * floating point regs. are stored in the thread structure | 410 | * floating point regs. are either in child->thread.fp_regs |
411 | * or the child->thread.vxrs array | ||
389 | */ | 412 | */ |
390 | if (addr == (addr_t) &dummy->regs.fp_regs.fpc) | 413 | offset = addr - (addr_t) &dummy->regs.fp_regs.fprs; |
391 | if ((unsigned int) data != 0 || | 414 | #ifdef CONFIG_64BIT |
392 | test_fp_ctl(data >> (BITS_PER_LONG - 32))) | 415 | if (child->thread.vxrs) |
393 | return -EINVAL; | 416 | *(addr_t *)((addr_t) |
394 | offset = addr - (addr_t) &dummy->regs.fp_regs; | 417 | child->thread.vxrs + 2*offset) = data; |
395 | *(addr_t *)((addr_t) &child->thread.fp_regs + offset) = data; | 418 | else |
419 | #endif | ||
420 | *(addr_t *)((addr_t) | ||
421 | &child->thread.fp_regs.fprs + offset) = data; | ||
396 | 422 | ||
397 | } else if (addr < (addr_t) (&dummy->regs.per_info + 1)) { | 423 | } else if (addr < (addr_t) (&dummy->regs.per_info + 1)) { |
398 | /* | 424 | /* |
@@ -611,12 +637,26 @@ static u32 __peek_user_compat(struct task_struct *child, addr_t addr) | |||
611 | */ | 637 | */ |
612 | tmp = 0; | 638 | tmp = 0; |
613 | 639 | ||
640 | } else if (addr == (addr_t) &dummy32->regs.fp_regs.fpc) { | ||
641 | /* | ||
642 | * floating point control reg. is in the thread structure | ||
643 | */ | ||
644 | tmp = child->thread.fp_regs.fpc; | ||
645 | |||
614 | } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { | 646 | } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { |
615 | /* | 647 | /* |
616 | * floating point regs. are stored in the thread structure | 648 | * floating point regs. are either in child->thread.fp_regs |
649 | * or the child->thread.vxrs array | ||
617 | */ | 650 | */ |
618 | offset = addr - (addr_t) &dummy32->regs.fp_regs; | 651 | offset = addr - (addr_t) &dummy32->regs.fp_regs.fprs; |
619 | tmp = *(__u32 *)((addr_t) &child->thread.fp_regs + offset); | 652 | #ifdef CONFIG_64BIT |
653 | if (child->thread.vxrs) | ||
654 | tmp = *(__u32 *) | ||
655 | ((addr_t) child->thread.vxrs + 2*offset); | ||
656 | else | ||
657 | #endif | ||
658 | tmp = *(__u32 *) | ||
659 | ((addr_t) &child->thread.fp_regs.fprs + offset); | ||
620 | 660 | ||
621 | } else if (addr < (addr_t) (&dummy32->regs.per_info + 1)) { | 661 | } else if (addr < (addr_t) (&dummy32->regs.per_info + 1)) { |
622 | /* | 662 | /* |
@@ -722,15 +762,28 @@ static int __poke_user_compat(struct task_struct *child, | |||
722 | */ | 762 | */ |
723 | return 0; | 763 | return 0; |
724 | 764 | ||
725 | } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { | 765 | } else if (addr == (addr_t) &dummy32->regs.fp_regs.fpc) { |
726 | /* | 766 | /* |
727 | * floating point regs. are stored in the thread structure | 767 | * floating point control reg. is in the thread structure |
728 | */ | 768 | */ |
729 | if (addr == (addr_t) &dummy32->regs.fp_regs.fpc && | 769 | if (test_fp_ctl(tmp)) |
730 | test_fp_ctl(tmp)) | ||
731 | return -EINVAL; | 770 | return -EINVAL; |
732 | offset = addr - (addr_t) &dummy32->regs.fp_regs; | 771 | child->thread.fp_regs.fpc = data; |
733 | *(__u32 *)((addr_t) &child->thread.fp_regs + offset) = tmp; | 772 | |
773 | } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { | ||
774 | /* | ||
775 | * floating point regs. are either in child->thread.fp_regs | ||
776 | * or the child->thread.vxrs array | ||
777 | */ | ||
778 | offset = addr - (addr_t) &dummy32->regs.fp_regs.fprs; | ||
779 | #ifdef CONFIG_64BIT | ||
780 | if (child->thread.vxrs) | ||
781 | *(__u32 *)((addr_t) | ||
782 | child->thread.vxrs + 2*offset) = tmp; | ||
783 | else | ||
784 | #endif | ||
785 | *(__u32 *)((addr_t) | ||
786 | &child->thread.fp_regs.fprs + offset) = tmp; | ||
734 | 787 | ||
735 | } else if (addr < (addr_t) (&dummy32->regs.per_info + 1)) { | 788 | } else if (addr < (addr_t) (&dummy32->regs.per_info + 1)) { |
736 | /* | 789 | /* |
@@ -1038,12 +1091,6 @@ static int s390_tdb_set(struct task_struct *target, | |||
1038 | return 0; | 1091 | return 0; |
1039 | } | 1092 | } |
1040 | 1093 | ||
1041 | static int s390_vxrs_active(struct task_struct *target, | ||
1042 | const struct user_regset *regset) | ||
1043 | { | ||
1044 | return !!target->thread.vxrs; | ||
1045 | } | ||
1046 | |||
1047 | static int s390_vxrs_low_get(struct task_struct *target, | 1094 | static int s390_vxrs_low_get(struct task_struct *target, |
1048 | const struct user_regset *regset, | 1095 | const struct user_regset *regset, |
1049 | unsigned int pos, unsigned int count, | 1096 | unsigned int pos, unsigned int count, |
@@ -1052,6 +1099,8 @@ static int s390_vxrs_low_get(struct task_struct *target, | |||
1052 | __u64 vxrs[__NUM_VXRS_LOW]; | 1099 | __u64 vxrs[__NUM_VXRS_LOW]; |
1053 | int i; | 1100 | int i; |
1054 | 1101 | ||
1102 | if (!MACHINE_HAS_VX) | ||
1103 | return -ENODEV; | ||
1055 | if (target->thread.vxrs) { | 1104 | if (target->thread.vxrs) { |
1056 | if (target == current) | 1105 | if (target == current) |
1057 | save_vx_regs(target->thread.vxrs); | 1106 | save_vx_regs(target->thread.vxrs); |
@@ -1070,6 +1119,8 @@ static int s390_vxrs_low_set(struct task_struct *target, | |||
1070 | __u64 vxrs[__NUM_VXRS_LOW]; | 1119 | __u64 vxrs[__NUM_VXRS_LOW]; |
1071 | int i, rc; | 1120 | int i, rc; |
1072 | 1121 | ||
1122 | if (!MACHINE_HAS_VX) | ||
1123 | return -ENODEV; | ||
1073 | if (!target->thread.vxrs) { | 1124 | if (!target->thread.vxrs) { |
1074 | rc = alloc_vector_registers(target); | 1125 | rc = alloc_vector_registers(target); |
1075 | if (rc) | 1126 | if (rc) |
@@ -1095,6 +1146,8 @@ static int s390_vxrs_high_get(struct task_struct *target, | |||
1095 | { | 1146 | { |
1096 | __vector128 vxrs[__NUM_VXRS_HIGH]; | 1147 | __vector128 vxrs[__NUM_VXRS_HIGH]; |
1097 | 1148 | ||
1149 | if (!MACHINE_HAS_VX) | ||
1150 | return -ENODEV; | ||
1098 | if (target->thread.vxrs) { | 1151 | if (target->thread.vxrs) { |
1099 | if (target == current) | 1152 | if (target == current) |
1100 | save_vx_regs(target->thread.vxrs); | 1153 | save_vx_regs(target->thread.vxrs); |
@@ -1112,6 +1165,8 @@ static int s390_vxrs_high_set(struct task_struct *target, | |||
1112 | { | 1165 | { |
1113 | int rc; | 1166 | int rc; |
1114 | 1167 | ||
1168 | if (!MACHINE_HAS_VX) | ||
1169 | return -ENODEV; | ||
1115 | if (!target->thread.vxrs) { | 1170 | if (!target->thread.vxrs) { |
1116 | rc = alloc_vector_registers(target); | 1171 | rc = alloc_vector_registers(target); |
1117 | if (rc) | 1172 | if (rc) |
@@ -1196,7 +1251,6 @@ static const struct user_regset s390_regsets[] = { | |||
1196 | .n = __NUM_VXRS_LOW, | 1251 | .n = __NUM_VXRS_LOW, |
1197 | .size = sizeof(__u64), | 1252 | .size = sizeof(__u64), |
1198 | .align = sizeof(__u64), | 1253 | .align = sizeof(__u64), |
1199 | .active = s390_vxrs_active, | ||
1200 | .get = s390_vxrs_low_get, | 1254 | .get = s390_vxrs_low_get, |
1201 | .set = s390_vxrs_low_set, | 1255 | .set = s390_vxrs_low_set, |
1202 | }, | 1256 | }, |
@@ -1205,7 +1259,6 @@ static const struct user_regset s390_regsets[] = { | |||
1205 | .n = __NUM_VXRS_HIGH, | 1259 | .n = __NUM_VXRS_HIGH, |
1206 | .size = sizeof(__vector128), | 1260 | .size = sizeof(__vector128), |
1207 | .align = sizeof(__vector128), | 1261 | .align = sizeof(__vector128), |
1208 | .active = s390_vxrs_active, | ||
1209 | .get = s390_vxrs_high_get, | 1262 | .get = s390_vxrs_high_get, |
1210 | .set = s390_vxrs_high_set, | 1263 | .set = s390_vxrs_high_set, |
1211 | }, | 1264 | }, |
@@ -1419,7 +1472,6 @@ static const struct user_regset s390_compat_regsets[] = { | |||
1419 | .n = __NUM_VXRS_LOW, | 1472 | .n = __NUM_VXRS_LOW, |
1420 | .size = sizeof(__u64), | 1473 | .size = sizeof(__u64), |
1421 | .align = sizeof(__u64), | 1474 | .align = sizeof(__u64), |
1422 | .active = s390_vxrs_active, | ||
1423 | .get = s390_vxrs_low_get, | 1475 | .get = s390_vxrs_low_get, |
1424 | .set = s390_vxrs_low_set, | 1476 | .set = s390_vxrs_low_set, |
1425 | }, | 1477 | }, |
@@ -1428,7 +1480,6 @@ static const struct user_regset s390_compat_regsets[] = { | |||
1428 | .n = __NUM_VXRS_HIGH, | 1480 | .n = __NUM_VXRS_HIGH, |
1429 | .size = sizeof(__vector128), | 1481 | .size = sizeof(__vector128), |
1430 | .align = sizeof(__vector128), | 1482 | .align = sizeof(__vector128), |
1431 | .active = s390_vxrs_active, | ||
1432 | .get = s390_vxrs_high_get, | 1483 | .get = s390_vxrs_high_get, |
1433 | .set = s390_vxrs_high_set, | 1484 | .set = s390_vxrs_high_set, |
1434 | }, | 1485 | }, |