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.c50
1 files changed, 39 insertions, 11 deletions
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index a314c57f4e94..e9fadb04e3c6 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -47,7 +47,7 @@ enum s390_regset {
47 REGSET_GENERAL_EXTENDED, 47 REGSET_GENERAL_EXTENDED,
48}; 48};
49 49
50void update_per_regs(struct task_struct *task) 50void update_cr_regs(struct task_struct *task)
51{ 51{
52 struct pt_regs *regs = task_pt_regs(task); 52 struct pt_regs *regs = task_pt_regs(task);
53 struct thread_struct *thread = &task->thread; 53 struct thread_struct *thread = &task->thread;
@@ -56,17 +56,25 @@ void update_per_regs(struct task_struct *task)
56#ifdef CONFIG_64BIT 56#ifdef CONFIG_64BIT
57 /* Take care of the enable/disable of transactional execution. */ 57 /* Take care of the enable/disable of transactional execution. */
58 if (MACHINE_HAS_TE) { 58 if (MACHINE_HAS_TE) {
59 unsigned long cr0, cr0_new; 59 unsigned long cr[3], cr_new[3];
60 60
61 __ctl_store(cr0, 0, 0); 61 __ctl_store(cr, 0, 2);
62 /* set or clear transaction execution bits 8 and 9. */ 62 cr_new[1] = cr[1];
63 /* Set or clear transaction execution TXC/PIFO bits 8 and 9. */
63 if (task->thread.per_flags & PER_FLAG_NO_TE) 64 if (task->thread.per_flags & PER_FLAG_NO_TE)
64 cr0_new = cr0 & ~(3UL << 54); 65 cr_new[0] = cr[0] & ~(3UL << 54);
65 else 66 else
66 cr0_new = cr0 | (3UL << 54); 67 cr_new[0] = cr[0] | (3UL << 54);
67 /* Only load control register 0 if necessary. */ 68 /* Set or clear transaction execution TDC bits 62 and 63. */
68 if (cr0 != cr0_new) 69 cr_new[2] = cr[2] & ~3UL;
69 __ctl_load(cr0_new, 0, 0); 70 if (task->thread.per_flags & PER_FLAG_TE_ABORT_RAND) {
71 if (task->thread.per_flags & PER_FLAG_TE_ABORT_RAND_TEND)
72 cr_new[2] |= 1UL;
73 else
74 cr_new[2] |= 2UL;
75 }
76 if (memcmp(&cr_new, &cr, sizeof(cr)))
77 __ctl_load(cr_new, 0, 2);
70 } 78 }
71#endif 79#endif
72 /* Copy user specified PER registers */ 80 /* Copy user specified PER registers */
@@ -100,14 +108,14 @@ void user_enable_single_step(struct task_struct *task)
100{ 108{
101 set_tsk_thread_flag(task, TIF_SINGLE_STEP); 109 set_tsk_thread_flag(task, TIF_SINGLE_STEP);
102 if (task == current) 110 if (task == current)
103 update_per_regs(task); 111 update_cr_regs(task);
104} 112}
105 113
106void user_disable_single_step(struct task_struct *task) 114void user_disable_single_step(struct task_struct *task)
107{ 115{
108 clear_tsk_thread_flag(task, TIF_SINGLE_STEP); 116 clear_tsk_thread_flag(task, TIF_SINGLE_STEP);
109 if (task == current) 117 if (task == current)
110 update_per_regs(task); 118 update_cr_regs(task);
111} 119}
112 120
113/* 121/*
@@ -447,6 +455,26 @@ long arch_ptrace(struct task_struct *child, long request,
447 if (!MACHINE_HAS_TE) 455 if (!MACHINE_HAS_TE)
448 return -EIO; 456 return -EIO;
449 child->thread.per_flags |= PER_FLAG_NO_TE; 457 child->thread.per_flags |= PER_FLAG_NO_TE;
458 child->thread.per_flags &= ~PER_FLAG_TE_ABORT_RAND;
459 return 0;
460 case PTRACE_TE_ABORT_RAND:
461 if (!MACHINE_HAS_TE || (child->thread.per_flags & PER_FLAG_NO_TE))
462 return -EIO;
463 switch (data) {
464 case 0UL:
465 child->thread.per_flags &= ~PER_FLAG_TE_ABORT_RAND;
466 break;
467 case 1UL:
468 child->thread.per_flags |= PER_FLAG_TE_ABORT_RAND;
469 child->thread.per_flags |= PER_FLAG_TE_ABORT_RAND_TEND;
470 break;
471 case 2UL:
472 child->thread.per_flags |= PER_FLAG_TE_ABORT_RAND;
473 child->thread.per_flags &= ~PER_FLAG_TE_ABORT_RAND_TEND;
474 break;
475 default:
476 return -EINVAL;
477 }
450 return 0; 478 return 0;
451 default: 479 default:
452 /* Removing high order bit from addr (only for 31 bit). */ 480 /* Removing high order bit from addr (only for 31 bit). */