s390/ptrace: PTRACE_TE_ABORT_RAND

The patch implements a s390 specific ptrace request
PTRACE_TE_ABORT_RAND to modify the randomness of spontaneous
aborts of memory transactions of the transaction execution
facility. The data argument of the ptrace request is used to
specify the levels of randomness, 0 for normal operation, 1 to
abort every transaction at a random instruction, and 2 to abort
a random transaction at a random instruction. The default is 0
for normal operation.

Acked-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Michael Mueller <mimu@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
Michael Mueller
2013-07-02 22:58:26 +02:00
committed by Martin Schwidefsky
parent 47188d39b5
commit 64597f9dae
4 changed files with 51 additions and 14 deletions

View File

@@ -47,7 +47,7 @@ enum s390_regset {
REGSET_GENERAL_EXTENDED,
};
void update_per_regs(struct task_struct *task)
void update_cr_regs(struct task_struct *task)
{
struct pt_regs *regs = task_pt_regs(task);
struct thread_struct *thread = &task->thread;
@@ -56,17 +56,25 @@ void update_per_regs(struct task_struct *task)
#ifdef CONFIG_64BIT
/* Take care of the enable/disable of transactional execution. */
if (MACHINE_HAS_TE) {
unsigned long cr0, cr0_new;
unsigned long cr[3], cr_new[3];
__ctl_store(cr0, 0, 0);
/* set or clear transaction execution bits 8 and 9. */
__ctl_store(cr, 0, 2);
cr_new[1] = cr[1];
/* Set or clear transaction execution TXC/PIFO bits 8 and 9. */
if (task->thread.per_flags & PER_FLAG_NO_TE)
cr0_new = cr0 & ~(3UL << 54);
cr_new[0] = cr[0] & ~(3UL << 54);
else
cr0_new = cr0 | (3UL << 54);
/* Only load control register 0 if necessary. */
if (cr0 != cr0_new)
__ctl_load(cr0_new, 0, 0);
cr_new[0] = cr[0] | (3UL << 54);
/* Set or clear transaction execution TDC bits 62 and 63. */
cr_new[2] = cr[2] & ~3UL;
if (task->thread.per_flags & PER_FLAG_TE_ABORT_RAND) {
if (task->thread.per_flags & PER_FLAG_TE_ABORT_RAND_TEND)
cr_new[2] |= 1UL;
else
cr_new[2] |= 2UL;
}
if (memcmp(&cr_new, &cr, sizeof(cr)))
__ctl_load(cr_new, 0, 2);
}
#endif
/* Copy user specified PER registers */
@@ -100,14 +108,14 @@ void user_enable_single_step(struct task_struct *task)
{
set_tsk_thread_flag(task, TIF_SINGLE_STEP);
if (task == current)
update_per_regs(task);
update_cr_regs(task);
}
void user_disable_single_step(struct task_struct *task)
{
clear_tsk_thread_flag(task, TIF_SINGLE_STEP);
if (task == current)
update_per_regs(task);
update_cr_regs(task);
}
/*
@@ -447,6 +455,26 @@ long arch_ptrace(struct task_struct *child, long request,
if (!MACHINE_HAS_TE)
return -EIO;
child->thread.per_flags |= PER_FLAG_NO_TE;
child->thread.per_flags &= ~PER_FLAG_TE_ABORT_RAND;
return 0;
case PTRACE_TE_ABORT_RAND:
if (!MACHINE_HAS_TE || (child->thread.per_flags & PER_FLAG_NO_TE))
return -EIO;
switch (data) {
case 0UL:
child->thread.per_flags &= ~PER_FLAG_TE_ABORT_RAND;
break;
case 1UL:
child->thread.per_flags |= PER_FLAG_TE_ABORT_RAND;
child->thread.per_flags |= PER_FLAG_TE_ABORT_RAND_TEND;
break;
case 2UL:
child->thread.per_flags |= PER_FLAG_TE_ABORT_RAND;
child->thread.per_flags &= ~PER_FLAG_TE_ABORT_RAND_TEND;
break;
default:
return -EINVAL;
}
return 0;
default:
/* Removing high order bit from addr (only for 31 bit). */