diff options
Diffstat (limited to 'arch/s390/kernel/ptrace.c')
-rw-r--r-- | arch/s390/kernel/ptrace.c | 70 |
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 | ||
938 | static 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 | |||
952 | static 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 | ||
908 | static int s390_system_call_get(struct task_struct *target, | 962 | static 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, |