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, 70 insertions, 0 deletions
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index e4be113fbac6..a314c57f4e94 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -42,6 +42,7 @@ enum s390_regset {
42 REGSET_GENERAL, 42 REGSET_GENERAL,
43 REGSET_FP, 43 REGSET_FP,
44 REGSET_LAST_BREAK, 44 REGSET_LAST_BREAK,
45 REGSET_TDB,
45 REGSET_SYSTEM_CALL, 46 REGSET_SYSTEM_CALL,
46 REGSET_GENERAL_EXTENDED, 47 REGSET_GENERAL_EXTENDED,
47}; 48};
@@ -52,6 +53,22 @@ void update_per_regs(struct task_struct *task)
52 struct thread_struct *thread = &task->thread; 53 struct thread_struct *thread = &task->thread;
53 struct per_regs old, new; 54 struct per_regs old, new;
54 55
56#ifdef CONFIG_64BIT
57 /* Take care of the enable/disable of transactional execution. */
58 if (MACHINE_HAS_TE) {
59 unsigned long cr0, cr0_new;
60
61 __ctl_store(cr0, 0, 0);
62 /* set or clear transaction execution bits 8 and 9. */
63 if (task->thread.per_flags & PER_FLAG_NO_TE)
64 cr0_new = cr0 & ~(3UL << 54);
65 else
66 cr0_new = cr0 | (3UL << 54);
67 /* Only load control register 0 if necessary. */
68 if (cr0 != cr0_new)
69 __ctl_load(cr0_new, 0, 0);
70 }
71#endif
55 /* Copy user specified PER registers */ 72 /* Copy user specified PER registers */
56 new.control = thread->per_user.control; 73 new.control = thread->per_user.control;
57 new.start = thread->per_user.start; 74 new.start = thread->per_user.start;
@@ -60,6 +77,10 @@ void update_per_regs(struct task_struct *task)
60 /* merge TIF_SINGLE_STEP into user specified PER registers. */ 77 /* merge TIF_SINGLE_STEP into user specified PER registers. */
61 if (test_tsk_thread_flag(task, TIF_SINGLE_STEP)) { 78 if (test_tsk_thread_flag(task, TIF_SINGLE_STEP)) {
62 new.control |= PER_EVENT_IFETCH; 79 new.control |= PER_EVENT_IFETCH;
80#ifdef CONFIG_64BIT
81 new.control |= PER_CONTROL_SUSPENSION;
82 new.control |= PER_EVENT_TRANSACTION_END;
83#endif
63 new.start = 0; 84 new.start = 0;
64 new.end = PSW_ADDR_INSN; 85 new.end = PSW_ADDR_INSN;
65 } 86 }
@@ -100,6 +121,7 @@ void ptrace_disable(struct task_struct *task)
100 memset(&task->thread.per_event, 0, sizeof(task->thread.per_event)); 121 memset(&task->thread.per_event, 0, sizeof(task->thread.per_event));
101 clear_tsk_thread_flag(task, TIF_SINGLE_STEP); 122 clear_tsk_thread_flag(task, TIF_SINGLE_STEP);
102 clear_tsk_thread_flag(task, TIF_PER_TRAP); 123 clear_tsk_thread_flag(task, TIF_PER_TRAP);
124 task->thread.per_flags = 0;
103} 125}
104 126
105#ifndef CONFIG_64BIT 127#ifndef CONFIG_64BIT
@@ -416,6 +438,16 @@ long arch_ptrace(struct task_struct *child, long request,
416 put_user(task_thread_info(child)->last_break, 438 put_user(task_thread_info(child)->last_break,
417 (unsigned long __user *) data); 439 (unsigned long __user *) data);
418 return 0; 440 return 0;
441 case PTRACE_ENABLE_TE:
442 if (!MACHINE_HAS_TE)
443 return -EIO;
444 child->thread.per_flags &= ~PER_FLAG_NO_TE;
445 return 0;
446 case PTRACE_DISABLE_TE:
447 if (!MACHINE_HAS_TE)
448 return -EIO;
449 child->thread.per_flags |= PER_FLAG_NO_TE;
450 return 0;
419 default: 451 default:
420 /* Removing high order bit from addr (only for 31 bit). */ 452 /* Removing high order bit from addr (only for 31 bit). */
421 addr &= PSW_ADDR_INSN; 453 addr &= PSW_ADDR_INSN;
@@ -903,6 +935,28 @@ static int s390_last_break_set(struct task_struct *target,
903 return 0; 935 return 0;
904} 936}
905 937
938static int s390_tdb_get(struct task_struct *target,
939 const struct user_regset *regset,
940 unsigned int pos, unsigned int count,
941 void *kbuf, void __user *ubuf)
942{
943 struct pt_regs *regs = task_pt_regs(target);
944 unsigned char *data;
945
946 if (!(regs->int_code & 0x200))
947 return -ENODATA;
948 data = target->thread.trap_tdb;
949 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, data, 0, 256);
950}
951
952static int s390_tdb_set(struct task_struct *target,
953 const struct user_regset *regset,
954 unsigned int pos, unsigned int count,
955 const void *kbuf, const void __user *ubuf)
956{
957 return 0;
958}
959
906#endif 960#endif
907 961
908static int s390_system_call_get(struct task_struct *target, 962static int s390_system_call_get(struct task_struct *target,
@@ -951,6 +1005,14 @@ static const struct user_regset s390_regsets[] = {
951 .get = s390_last_break_get, 1005 .get = s390_last_break_get,
952 .set = s390_last_break_set, 1006 .set = s390_last_break_set,
953 }, 1007 },
1008 [REGSET_TDB] = {
1009 .core_note_type = NT_S390_TDB,
1010 .n = 1,
1011 .size = 256,
1012 .align = 1,
1013 .get = s390_tdb_get,
1014 .set = s390_tdb_set,
1015 },
954#endif 1016#endif
955 [REGSET_SYSTEM_CALL] = { 1017 [REGSET_SYSTEM_CALL] = {
956 .core_note_type = NT_S390_SYSTEM_CALL, 1018 .core_note_type = NT_S390_SYSTEM_CALL,
@@ -1148,6 +1210,14 @@ static const struct user_regset s390_compat_regsets[] = {
1148 .get = s390_compat_last_break_get, 1210 .get = s390_compat_last_break_get,
1149 .set = s390_compat_last_break_set, 1211 .set = s390_compat_last_break_set,
1150 }, 1212 },
1213 [REGSET_TDB] = {
1214 .core_note_type = NT_S390_TDB,
1215 .n = 1,
1216 .size = 256,
1217 .align = 1,
1218 .get = s390_tdb_get,
1219 .set = s390_tdb_set,
1220 },
1151 [REGSET_SYSTEM_CALL] = { 1221 [REGSET_SYSTEM_CALL] = {
1152 .core_note_type = NT_S390_SYSTEM_CALL, 1222 .core_note_type = NT_S390_SYSTEM_CALL,
1153 .n = 1, 1223 .n = 1,