diff options
author | Michael Mueller <mimu@linux.vnet.ibm.com> | 2013-07-02 16:58:26 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2013-07-16 06:21:56 -0400 |
commit | 64597f9dae1850e0360ae2e9b5485d4b5d1fdf4c (patch) | |
tree | d32a327697cccd38cfacdc86bdaf6ed6a4f3365e /arch | |
parent | 47188d39b5deeebf41f87a02af1b3935866364cf (diff) |
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>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/s390/include/asm/processor.h | 10 | ||||
-rw-r--r-- | arch/s390/include/asm/switch_to.h | 4 | ||||
-rw-r--r-- | arch/s390/include/uapi/asm/ptrace.h | 1 | ||||
-rw-r--r-- | arch/s390/kernel/ptrace.c | 50 |
4 files changed, 51 insertions, 14 deletions
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index 6b499870662f..b0e6435b2f02 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h | |||
@@ -91,7 +91,15 @@ struct thread_struct { | |||
91 | #endif | 91 | #endif |
92 | }; | 92 | }; |
93 | 93 | ||
94 | #define PER_FLAG_NO_TE 1UL /* Flag to disable transactions. */ | 94 | /* Flag to disable transactions. */ |
95 | #define PER_FLAG_NO_TE 1UL | ||
96 | /* Flag to enable random transaction aborts. */ | ||
97 | #define PER_FLAG_TE_ABORT_RAND 2UL | ||
98 | /* Flag to specify random transaction abort mode: | ||
99 | * - abort each transaction at a random instruction before TEND if set. | ||
100 | * - abort random transactions at a random instruction if cleared. | ||
101 | */ | ||
102 | #define PER_FLAG_TE_ABORT_RAND_TEND 4UL | ||
95 | 103 | ||
96 | typedef struct thread_struct thread_struct; | 104 | typedef struct thread_struct thread_struct; |
97 | 105 | ||
diff --git a/arch/s390/include/asm/switch_to.h b/arch/s390/include/asm/switch_to.h index f3a9e0f92704..80b6f11263c4 100644 --- a/arch/s390/include/asm/switch_to.h +++ b/arch/s390/include/asm/switch_to.h | |||
@@ -10,7 +10,7 @@ | |||
10 | #include <linux/thread_info.h> | 10 | #include <linux/thread_info.h> |
11 | 11 | ||
12 | extern struct task_struct *__switch_to(void *, void *); | 12 | extern struct task_struct *__switch_to(void *, void *); |
13 | extern void update_per_regs(struct task_struct *task); | 13 | extern void update_cr_regs(struct task_struct *task); |
14 | 14 | ||
15 | static inline void save_fp_regs(s390_fp_regs *fpregs) | 15 | static inline void save_fp_regs(s390_fp_regs *fpregs) |
16 | { | 16 | { |
@@ -86,7 +86,7 @@ static inline void restore_access_regs(unsigned int *acrs) | |||
86 | restore_fp_regs(&next->thread.fp_regs); \ | 86 | restore_fp_regs(&next->thread.fp_regs); \ |
87 | restore_access_regs(&next->thread.acrs[0]); \ | 87 | restore_access_regs(&next->thread.acrs[0]); \ |
88 | restore_ri_cb(next->thread.ri_cb, prev->thread.ri_cb); \ | 88 | restore_ri_cb(next->thread.ri_cb, prev->thread.ri_cb); \ |
89 | update_per_regs(next); \ | 89 | update_cr_regs(next); \ |
90 | } \ | 90 | } \ |
91 | prev = __switch_to(prev,next); \ | 91 | prev = __switch_to(prev,next); \ |
92 | } while (0) | 92 | } while (0) |
diff --git a/arch/s390/include/uapi/asm/ptrace.h b/arch/s390/include/uapi/asm/ptrace.h index 3aa9f1ec5b29..7a84619e315e 100644 --- a/arch/s390/include/uapi/asm/ptrace.h +++ b/arch/s390/include/uapi/asm/ptrace.h | |||
@@ -400,6 +400,7 @@ typedef struct | |||
400 | #define PTRACE_POKE_SYSTEM_CALL 0x5008 | 400 | #define PTRACE_POKE_SYSTEM_CALL 0x5008 |
401 | #define PTRACE_ENABLE_TE 0x5009 | 401 | #define PTRACE_ENABLE_TE 0x5009 |
402 | #define PTRACE_DISABLE_TE 0x5010 | 402 | #define PTRACE_DISABLE_TE 0x5010 |
403 | #define PTRACE_TE_ABORT_RAND 0x5011 | ||
403 | 404 | ||
404 | /* | 405 | /* |
405 | * PT_PROT definition is loosely based on hppa bsd definition in | 406 | * PT_PROT definition is loosely based on hppa bsd definition in |
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 | ||
50 | void update_per_regs(struct task_struct *task) | 50 | void 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 | ||
106 | void user_disable_single_step(struct task_struct *task) | 114 | void 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). */ |