aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390
diff options
context:
space:
mode:
authorJan Glauber <jang@linux.vnet.ibm.com>2012-07-31 04:52:05 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2012-09-26 09:45:02 -0400
commite4b8b3f33fcaa0ed6e6b5482a606091d8cd20beb (patch)
tree7f1e47eafd75cb11bed5b91c2c13813eb6204fc8 /arch/s390
parent0d804b20735d974534abb422f723d404b779433a (diff)
s390: add support for runtime instrumentation
Allow user-space threads to use runtime instrumentation (RI). To enable RI for a thread there is a new s390 specific system call, sys_s390_runtime_instr, that takes as parameter a realtime signal number. If the RI facility is available the system call sets up a control block for the calling thread with the appropriate permissions for the thread to modify the control block. The user-space thread can then use the store and modify RI instructions to alter the control block and start/stop the instrumentation via RION/RIOFF. If the user specified program buffer runs full RI triggers an external interrupt. The external interrupt is translated to a real-time signal that is delivered to the thread that enabled RI on that CPU. The number of the real-time signal is the number specified in the RI system call. So, user-space can select any available real-time signal number in case the application itself uses real-time signals for other purposes. The kernel saves the RI control blocks on task switch only if the running thread was enabled for RI. Therefore, the performance impact on task switch should be negligible if RI is not used. RI is only enabled for user-space mode and is disabled for the supervisor state. Reviewed-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Jan Glauber <jang@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390')
-rw-r--r--arch/s390/include/asm/cpu_mf.h4
-rw-r--r--arch/s390/include/asm/irq.h1
-rw-r--r--arch/s390/include/asm/processor.h4
-rw-r--r--arch/s390/include/asm/ptrace.h4
-rw-r--r--arch/s390/include/asm/runtime_instr.h98
-rw-r--r--arch/s390/include/asm/switch_to.h2
-rw-r--r--arch/s390/include/asm/unistd.h3
-rw-r--r--arch/s390/kernel/Makefile2
-rw-r--r--arch/s390/kernel/compat_wrapper.S5
-rw-r--r--arch/s390/kernel/dis.c21
-rw-r--r--arch/s390/kernel/irq.c1
-rw-r--r--arch/s390/kernel/process.c7
-rw-r--r--arch/s390/kernel/runtime_instr.c150
-rw-r--r--arch/s390/kernel/syscalls.S1
14 files changed, 300 insertions, 3 deletions
diff --git a/arch/s390/include/asm/cpu_mf.h b/arch/s390/include/asm/cpu_mf.h
index a3afecdae145..35f0020b7ba7 100644
--- a/arch/s390/include/asm/cpu_mf.h
+++ b/arch/s390/include/asm/cpu_mf.h
@@ -21,11 +21,15 @@
21#define CPU_MF_INT_SF_LSDA (1 << 22) /* loss of sample data alert */ 21#define CPU_MF_INT_SF_LSDA (1 << 22) /* loss of sample data alert */
22#define CPU_MF_INT_CF_CACA (1 << 7) /* counter auth. change alert */ 22#define CPU_MF_INT_CF_CACA (1 << 7) /* counter auth. change alert */
23#define CPU_MF_INT_CF_LCDA (1 << 6) /* loss of counter data alert */ 23#define CPU_MF_INT_CF_LCDA (1 << 6) /* loss of counter data alert */
24#define CPU_MF_INT_RI_HALTED (1 << 5) /* run-time instr. halted */
25#define CPU_MF_INT_RI_BUF_FULL (1 << 4) /* run-time instr. program
26 buffer full */
24 27
25#define CPU_MF_INT_CF_MASK (CPU_MF_INT_CF_CACA|CPU_MF_INT_CF_LCDA) 28#define CPU_MF_INT_CF_MASK (CPU_MF_INT_CF_CACA|CPU_MF_INT_CF_LCDA)
26#define CPU_MF_INT_SF_MASK (CPU_MF_INT_SF_IAE|CPU_MF_INT_SF_ISE| \ 29#define CPU_MF_INT_SF_MASK (CPU_MF_INT_SF_IAE|CPU_MF_INT_SF_ISE| \
27 CPU_MF_INT_SF_PRA|CPU_MF_INT_SF_SACA| \ 30 CPU_MF_INT_SF_PRA|CPU_MF_INT_SF_SACA| \
28 CPU_MF_INT_SF_LSDA) 31 CPU_MF_INT_SF_LSDA)
32#define CPU_MF_INT_RI_MASK (CPU_MF_INT_RI_HALTED|CPU_MF_INT_RI_BUF_FULL)
29 33
30/* CPU measurement facility support */ 34/* CPU measurement facility support */
31static inline int cpum_cf_avail(void) 35static inline int cpum_cf_avail(void)
diff --git a/arch/s390/include/asm/irq.h b/arch/s390/include/asm/irq.h
index 33cc59071581..6703dd986fd4 100644
--- a/arch/s390/include/asm/irq.h
+++ b/arch/s390/include/asm/irq.h
@@ -19,6 +19,7 @@ enum interruption_class {
19 EXTINT_IUC, 19 EXTINT_IUC,
20 EXTINT_CMS, 20 EXTINT_CMS,
21 EXTINT_CMC, 21 EXTINT_CMC,
22 EXTINT_CMR,
22 IOINT_CIO, 23 IOINT_CIO,
23 IOINT_QAI, 24 IOINT_QAI,
24 IOINT_DAS, 25 IOINT_DAS,
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h
index d4477ba99a16..0fff583d2c7c 100644
--- a/arch/s390/include/asm/processor.h
+++ b/arch/s390/include/asm/processor.h
@@ -17,6 +17,7 @@
17#include <asm/page.h> 17#include <asm/page.h>
18#include <asm/ptrace.h> 18#include <asm/ptrace.h>
19#include <asm/setup.h> 19#include <asm/setup.h>
20#include <asm/runtime_instr.h>
20 21
21/* 22/*
22 * Default implementation of macro that returns current 23 * Default implementation of macro that returns current
@@ -78,6 +79,9 @@ struct thread_struct {
78 /* pfault_wait is used to block the process on a pfault event */ 79 /* pfault_wait is used to block the process on a pfault event */
79 unsigned long pfault_wait; 80 unsigned long pfault_wait;
80 struct list_head list; 81 struct list_head list;
82 /* cpu runtime instrumentation */
83 struct runtime_instr_cb *ri_cb;
84 int ri_signum;
81}; 85};
82 86
83typedef struct thread_struct thread_struct; 87typedef struct thread_struct thread_struct;
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h
index d5f08ea566ed..5c32bae6b760 100644
--- a/arch/s390/include/asm/ptrace.h
+++ b/arch/s390/include/asm/ptrace.h
@@ -235,6 +235,7 @@ typedef struct
235#define PSW_MASK_ASC 0x0000C000UL 235#define PSW_MASK_ASC 0x0000C000UL
236#define PSW_MASK_CC 0x00003000UL 236#define PSW_MASK_CC 0x00003000UL
237#define PSW_MASK_PM 0x00000F00UL 237#define PSW_MASK_PM 0x00000F00UL
238#define PSW_MASK_RI 0x00000000UL
238#define PSW_MASK_EA 0x00000000UL 239#define PSW_MASK_EA 0x00000000UL
239#define PSW_MASK_BA 0x00000000UL 240#define PSW_MASK_BA 0x00000000UL
240 241
@@ -264,10 +265,11 @@ typedef struct
264#define PSW_MASK_ASC 0x0000C00000000000UL 265#define PSW_MASK_ASC 0x0000C00000000000UL
265#define PSW_MASK_CC 0x0000300000000000UL 266#define PSW_MASK_CC 0x0000300000000000UL
266#define PSW_MASK_PM 0x00000F0000000000UL 267#define PSW_MASK_PM 0x00000F0000000000UL
268#define PSW_MASK_RI 0x0000008000000000UL
267#define PSW_MASK_EA 0x0000000100000000UL 269#define PSW_MASK_EA 0x0000000100000000UL
268#define PSW_MASK_BA 0x0000000080000000UL 270#define PSW_MASK_BA 0x0000000080000000UL
269 271
270#define PSW_MASK_USER 0x00003F0180000000UL 272#define PSW_MASK_USER 0x00003F8180000000UL
271 273
272#define PSW_ADDR_AMODE 0x0000000000000000UL 274#define PSW_ADDR_AMODE 0x0000000000000000UL
273#define PSW_ADDR_INSN 0xFFFFFFFFFFFFFFFFUL 275#define PSW_ADDR_INSN 0xFFFFFFFFFFFFFFFFUL
diff --git a/arch/s390/include/asm/runtime_instr.h b/arch/s390/include/asm/runtime_instr.h
new file mode 100644
index 000000000000..830da737ff85
--- /dev/null
+++ b/arch/s390/include/asm/runtime_instr.h
@@ -0,0 +1,98 @@
1#ifndef _RUNTIME_INSTR_H
2#define _RUNTIME_INSTR_H
3
4#define S390_RUNTIME_INSTR_START 0x1
5#define S390_RUNTIME_INSTR_STOP 0x2
6
7struct runtime_instr_cb {
8 __u64 buf_current;
9 __u64 buf_origin;
10 __u64 buf_limit;
11
12 __u32 valid : 1;
13 __u32 pstate : 1;
14 __u32 pstate_set_buf : 1;
15 __u32 home_space : 1;
16 __u32 altered : 1;
17 __u32 : 3;
18 __u32 pstate_sample : 1;
19 __u32 sstate_sample : 1;
20 __u32 pstate_collect : 1;
21 __u32 sstate_collect : 1;
22 __u32 : 1;
23 __u32 halted_int : 1;
24 __u32 int_requested : 1;
25 __u32 buffer_full_int : 1;
26 __u32 key : 4;
27 __u32 : 9;
28 __u32 rgs : 3;
29
30 __u32 mode : 4;
31 __u32 next : 1;
32 __u32 mae : 1;
33 __u32 : 2;
34 __u32 call_type_br : 1;
35 __u32 return_type_br : 1;
36 __u32 other_type_br : 1;
37 __u32 bc_other_type : 1;
38 __u32 emit : 1;
39 __u32 tx_abort : 1;
40 __u32 : 2;
41 __u32 bp_xn : 1;
42 __u32 bp_xt : 1;
43 __u32 bp_ti : 1;
44 __u32 bp_ni : 1;
45 __u32 suppr_y : 1;
46 __u32 suppr_z : 1;
47
48 __u32 dc_miss_extra : 1;
49 __u32 lat_lev_ignore : 1;
50 __u32 ic_lat_lev : 4;
51 __u32 dc_lat_lev : 4;
52
53 __u64 reserved1;
54 __u64 scaling_factor;
55 __u64 rsic;
56 __u64 reserved2;
57} __packed __aligned(8);
58
59extern struct runtime_instr_cb runtime_instr_empty_cb;
60
61static inline void load_runtime_instr_cb(struct runtime_instr_cb *cb)
62{
63 asm volatile(".insn rsy,0xeb0000000060,0,0,%0" /* LRIC */
64 : : "Q" (*cb));
65}
66
67static inline void store_runtime_instr_cb(struct runtime_instr_cb *cb)
68{
69 asm volatile(".insn rsy,0xeb0000000061,0,0,%0" /* STRIC */
70 : "=Q" (*cb) : : "cc");
71}
72
73static inline void save_ri_cb(struct runtime_instr_cb *cb_prev)
74{
75#ifdef CONFIG_64BIT
76 if (cb_prev)
77 store_runtime_instr_cb(cb_prev);
78#endif
79}
80
81static inline void restore_ri_cb(struct runtime_instr_cb *cb_next,
82 struct runtime_instr_cb *cb_prev)
83{
84#ifdef CONFIG_64BIT
85 if (cb_next)
86 load_runtime_instr_cb(cb_next);
87 else if (cb_prev)
88 load_runtime_instr_cb(&runtime_instr_empty_cb);
89#endif
90}
91
92#ifdef CONFIG_64BIT
93extern void exit_thread_runtime_instr(void);
94#else
95static inline void exit_thread_runtime_instr(void) { }
96#endif
97
98#endif /* _RUNTIME_INSTR_H */
diff --git a/arch/s390/include/asm/switch_to.h b/arch/s390/include/asm/switch_to.h
index f223068b7822..dc4967b0e056 100644
--- a/arch/s390/include/asm/switch_to.h
+++ b/arch/s390/include/asm/switch_to.h
@@ -80,10 +80,12 @@ static inline void restore_access_regs(unsigned int *acrs)
80 if (prev->mm) { \ 80 if (prev->mm) { \
81 save_fp_regs(&prev->thread.fp_regs); \ 81 save_fp_regs(&prev->thread.fp_regs); \
82 save_access_regs(&prev->thread.acrs[0]); \ 82 save_access_regs(&prev->thread.acrs[0]); \
83 save_ri_cb(prev->thread.ri_cb); \
83 } \ 84 } \
84 if (next->mm) { \ 85 if (next->mm) { \
85 restore_fp_regs(&next->thread.fp_regs); \ 86 restore_fp_regs(&next->thread.fp_regs); \
86 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); \
87 update_per_regs(next); \ 89 update_per_regs(next); \
88 } \ 90 } \
89 prev = __switch_to(prev,next); \ 91 prev = __switch_to(prev,next); \
diff --git a/arch/s390/include/asm/unistd.h b/arch/s390/include/asm/unistd.h
index 6756e78f4808..da2c2f4f7642 100644
--- a/arch/s390/include/asm/unistd.h
+++ b/arch/s390/include/asm/unistd.h
@@ -277,7 +277,8 @@
277#define __NR_setns 339 277#define __NR_setns 339
278#define __NR_process_vm_readv 340 278#define __NR_process_vm_readv 340
279#define __NR_process_vm_writev 341 279#define __NR_process_vm_writev 341
280#define NR_syscalls 342 280#define __NR_s390_runtime_instr 342
281#define NR_syscalls 343
281 282
282/* 283/*
283 * There are some system calls that are not present on 64 bit, some 284 * There are some system calls that are not present on 64 bit, some
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
index 9a111b621f4e..bba01bf678a6 100644
--- a/arch/s390/kernel/Makefile
+++ b/arch/s390/kernel/Makefile
@@ -49,7 +49,7 @@ obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
49obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o 49obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o
50obj-$(CONFIG_CRASH_DUMP) += crash_dump.o 50obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
51obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_cpum_cf.o 51obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_cpum_cf.o
52obj-$(CONFIG_64BIT) += cache.o 52obj-$(CONFIG_64BIT) += runtime_instr.o cache.o
53 53
54# Kexec part 54# Kexec part
55S390_KEXEC_OBJS := machine_kexec.o 55S390_KEXEC_OBJS := machine_kexec.o
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S
index 2d82cfcbce5b..5f7928fe34ce 100644
--- a/arch/s390/kernel/compat_wrapper.S
+++ b/arch/s390/kernel/compat_wrapper.S
@@ -1646,3 +1646,8 @@ ENTRY(compat_sys_process_vm_writev_wrapper)
1646 llgf %r0,164(%r15) # unsigned long 1646 llgf %r0,164(%r15) # unsigned long
1647 stg %r0,160(%r15) 1647 stg %r0,160(%r15)
1648 jg compat_sys_process_vm_writev 1648 jg compat_sys_process_vm_writev
1649
1650ENTRY(sys_s390_runtime_instr_wrapper)
1651 lgfr %r2,%r2 # int
1652 lgfr %r3,%r3 # int
1653 jg sys_s390_runtime_instr
diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c
index 84fd7e920bfe..4bc67db63522 100644
--- a/arch/s390/kernel/dis.c
+++ b/arch/s390/kernel/dis.c
@@ -315,6 +315,8 @@ enum {
315 LONG_INSN_POPCNT, 315 LONG_INSN_POPCNT,
316 LONG_INSN_RISBHG, 316 LONG_INSN_RISBHG,
317 LONG_INSN_RISBLG, 317 LONG_INSN_RISBLG,
318 LONG_INSN_RINEXT,
319 LONG_INSN_RIEMIT,
318}; 320};
319 321
320static char *long_insn_name[] = { 322static char *long_insn_name[] = {
@@ -330,6 +332,8 @@ static char *long_insn_name[] = {
330 [LONG_INSN_POPCNT] = "popcnt", 332 [LONG_INSN_POPCNT] = "popcnt",
331 [LONG_INSN_RISBHG] = "risbhg", 333 [LONG_INSN_RISBHG] = "risbhg",
332 [LONG_INSN_RISBLG] = "risblk", 334 [LONG_INSN_RISBLG] = "risblk",
335 [LONG_INSN_RINEXT] = "rinext",
336 [LONG_INSN_RIEMIT] = "riemit",
333}; 337};
334 338
335static struct insn opcode[] = { 339static struct insn opcode[] = {
@@ -582,6 +586,17 @@ static struct insn opcode_a7[] = {
582 { "", 0, INSTR_INVALID } 586 { "", 0, INSTR_INVALID }
583}; 587};
584 588
589static struct insn opcode_aa[] = {
590#ifdef CONFIG_64BIT
591 { { 0, LONG_INSN_RINEXT }, 0x00, INSTR_RI_RI },
592 { "rion", 0x01, INSTR_RI_RI },
593 { "tric", 0x02, INSTR_RI_RI },
594 { "rioff", 0x03, INSTR_RI_RI },
595 { { 0, LONG_INSN_RIEMIT }, 0x04, INSTR_RI_RI },
596#endif
597 { "", 0, INSTR_INVALID }
598};
599
585static struct insn opcode_b2[] = { 600static struct insn opcode_b2[] = {
586#ifdef CONFIG_64BIT 601#ifdef CONFIG_64BIT
587 { "sske", 0x2b, INSTR_RRF_M0RR }, 602 { "sske", 0x2b, INSTR_RRF_M0RR },
@@ -1210,6 +1225,9 @@ static struct insn opcode_eb[] = {
1210 { "cliy", 0x55, INSTR_SIY_URD }, 1225 { "cliy", 0x55, INSTR_SIY_URD },
1211 { "oiy", 0x56, INSTR_SIY_URD }, 1226 { "oiy", 0x56, INSTR_SIY_URD },
1212 { "xiy", 0x57, INSTR_SIY_URD }, 1227 { "xiy", 0x57, INSTR_SIY_URD },
1228 { "lric", 0x60, INSTR_RSY_RDRM },
1229 { "stric", 0x61, INSTR_RSY_RDRM },
1230 { "mric", 0x62, INSTR_RSY_RDRM },
1213 { "icmh", 0x80, INSTR_RSE_RURD }, 1231 { "icmh", 0x80, INSTR_RSE_RURD },
1214 { "icmh", 0x80, INSTR_RSY_RURD }, 1232 { "icmh", 0x80, INSTR_RSY_RURD },
1215 { "icmy", 0x81, INSTR_RSY_RURD }, 1233 { "icmy", 0x81, INSTR_RSY_RURD },
@@ -1408,6 +1426,9 @@ static struct insn *find_insn(unsigned char *code)
1408 case 0xa7: 1426 case 0xa7:
1409 table = opcode_a7; 1427 table = opcode_a7;
1410 break; 1428 break;
1429 case 0xaa:
1430 table = opcode_aa;
1431 break;
1411 case 0xb2: 1432 case 0xb2:
1412 table = opcode_b2; 1433 table = opcode_b2;
1413 break; 1434 break;
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c
index a22fdca6a663..c1b44934fe64 100644
--- a/arch/s390/kernel/irq.c
+++ b/arch/s390/kernel/irq.c
@@ -44,6 +44,7 @@ static const struct irq_class intrclass_names[] = {
44 {.name = "IUC", .desc = "[EXT] IUCV" }, 44 {.name = "IUC", .desc = "[EXT] IUCV" },
45 {.name = "CMS", .desc = "[EXT] CPU-Measurement: Sampling" }, 45 {.name = "CMS", .desc = "[EXT] CPU-Measurement: Sampling" },
46 {.name = "CMC", .desc = "[EXT] CPU-Measurement: Counter" }, 46 {.name = "CMC", .desc = "[EXT] CPU-Measurement: Counter" },
47 {.name = "CMR", .desc = "[EXT] CPU-Measurement: RI" },
47 {.name = "CIO", .desc = "[I/O] Common I/O Layer Interrupt" }, 48 {.name = "CIO", .desc = "[I/O] Common I/O Layer Interrupt" },
48 {.name = "QAI", .desc = "[I/O] QDIO Adapter Interrupt" }, 49 {.name = "QAI", .desc = "[I/O] QDIO Adapter Interrupt" },
49 {.name = "DAS", .desc = "[I/O] DASD" }, 50 {.name = "DAS", .desc = "[I/O] DASD" },
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index 733175373a4c..cb4328e49c75 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -30,6 +30,7 @@
30#include <asm/nmi.h> 30#include <asm/nmi.h>
31#include <asm/smp.h> 31#include <asm/smp.h>
32#include <asm/switch_to.h> 32#include <asm/switch_to.h>
33#include <asm/runtime_instr.h>
33#include "entry.h" 34#include "entry.h"
34 35
35asmlinkage void ret_from_fork(void) asm ("ret_from_fork"); 36asmlinkage void ret_from_fork(void) asm ("ret_from_fork");
@@ -132,6 +133,7 @@ EXPORT_SYMBOL(kernel_thread);
132 */ 133 */
133void exit_thread(void) 134void exit_thread(void)
134{ 135{
136 exit_thread_runtime_instr();
135} 137}
136 138
137void flush_thread(void) 139void flush_thread(void)
@@ -170,6 +172,11 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp,
170 /* Save access registers to new thread structure. */ 172 /* Save access registers to new thread structure. */
171 save_access_regs(&p->thread.acrs[0]); 173 save_access_regs(&p->thread.acrs[0]);
172 174
175 /* Don't copy runtime instrumentation info */
176 p->thread.ri_cb = NULL;
177 p->thread.ri_signum = 0;
178 frame->childregs.psw.mask &= ~PSW_MASK_RI;
179
173#ifndef CONFIG_64BIT 180#ifndef CONFIG_64BIT
174 /* 181 /*
175 * save fprs to current->thread.fp_regs to merge them with 182 * save fprs to current->thread.fp_regs to merge them with
diff --git a/arch/s390/kernel/runtime_instr.c b/arch/s390/kernel/runtime_instr.c
new file mode 100644
index 000000000000..e27e23da0e60
--- /dev/null
+++ b/arch/s390/kernel/runtime_instr.c
@@ -0,0 +1,150 @@
1/*
2 * Copyright IBM Corp. 2012
3 * Author(s): Jan Glauber <jang@linux.vnet.ibm.com>
4 */
5
6#include <linux/kernel.h>
7#include <linux/syscalls.h>
8#include <linux/signal.h>
9#include <linux/mm.h>
10#include <linux/slab.h>
11#include <linux/init.h>
12#include <linux/errno.h>
13#include <linux/kernel_stat.h>
14#include <asm/runtime_instr.h>
15#include <asm/cpu_mf.h>
16#include <asm/irq.h>
17
18/* empty control block to disable RI by loading it */
19struct runtime_instr_cb runtime_instr_empty_cb;
20
21static int runtime_instr_avail(void)
22{
23 return test_facility(64);
24}
25
26static void disable_runtime_instr(void)
27{
28 struct pt_regs *regs = task_pt_regs(current);
29
30 load_runtime_instr_cb(&runtime_instr_empty_cb);
31
32 /*
33 * Make sure the RI bit is deleted from the PSW. If the user did not
34 * switch off RI before the system call the process will get a
35 * specification exception otherwise.
36 */
37 regs->psw.mask &= ~PSW_MASK_RI;
38}
39
40static void init_runtime_instr_cb(struct runtime_instr_cb *cb)
41{
42 cb->buf_limit = 0xfff;
43 if (addressing_mode == HOME_SPACE_MODE)
44 cb->home_space = 1;
45 cb->int_requested = 1;
46 cb->pstate = 1;
47 cb->pstate_set_buf = 1;
48 cb->pstate_sample = 1;
49 cb->pstate_collect = 1;
50 cb->key = PAGE_DEFAULT_KEY;
51 cb->valid = 1;
52}
53
54void exit_thread_runtime_instr(void)
55{
56 struct task_struct *task = current;
57
58 if (!task->thread.ri_cb)
59 return;
60 disable_runtime_instr();
61 kfree(task->thread.ri_cb);
62 task->thread.ri_signum = 0;
63 task->thread.ri_cb = NULL;
64}
65
66static void runtime_instr_int_handler(struct ext_code ext_code,
67 unsigned int param32, unsigned long param64)
68{
69 struct siginfo info;
70
71 if (!(param32 & CPU_MF_INT_RI_MASK))
72 return;
73
74 kstat_cpu(smp_processor_id()).irqs[EXTINT_CMR]++;
75
76 if (!current->thread.ri_cb)
77 return;
78 if (current->thread.ri_signum < SIGRTMIN ||
79 current->thread.ri_signum > SIGRTMAX) {
80 WARN_ON_ONCE(1);
81 return;
82 }
83
84 memset(&info, 0, sizeof(info));
85 info.si_signo = current->thread.ri_signum;
86 info.si_code = SI_QUEUE;
87 if (param32 & CPU_MF_INT_RI_BUF_FULL)
88 info.si_int = ENOBUFS;
89 else if (param32 & CPU_MF_INT_RI_HALTED)
90 info.si_int = ECANCELED;
91 else
92 return; /* unknown reason */
93
94 send_sig_info(current->thread.ri_signum, &info, current);
95}
96
97SYSCALL_DEFINE2(s390_runtime_instr, int, command, int, signum)
98{
99 struct runtime_instr_cb *cb;
100
101 if (!runtime_instr_avail())
102 return -EOPNOTSUPP;
103
104 if (command == S390_RUNTIME_INSTR_STOP) {
105 preempt_disable();
106 exit_thread_runtime_instr();
107 preempt_enable();
108 return 0;
109 }
110
111 if (command != S390_RUNTIME_INSTR_START ||
112 (signum < SIGRTMIN || signum > SIGRTMAX))
113 return -EINVAL;
114
115 if (!current->thread.ri_cb) {
116 cb = kzalloc(sizeof(*cb), GFP_KERNEL);
117 if (!cb)
118 return -ENOMEM;
119 } else {
120 cb = current->thread.ri_cb;
121 memset(cb, 0, sizeof(*cb));
122 }
123
124 init_runtime_instr_cb(cb);
125 current->thread.ri_signum = signum;
126
127 /* now load the control block to make it available */
128 preempt_disable();
129 current->thread.ri_cb = cb;
130 load_runtime_instr_cb(cb);
131 preempt_enable();
132 return 0;
133}
134
135static int __init runtime_instr_init(void)
136{
137 int rc;
138
139 if (!runtime_instr_avail())
140 return 0;
141
142 measurement_alert_subclass_register();
143 rc = register_external_interrupt(0x1407, runtime_instr_int_handler);
144 if (rc)
145 measurement_alert_subclass_unregister();
146 else
147 pr_info("Runtime instrumentation facility initialized\n");
148 return rc;
149}
150device_initcall(runtime_instr_init);
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S
index bcab2f04ba58..539f0a7701e4 100644
--- a/arch/s390/kernel/syscalls.S
+++ b/arch/s390/kernel/syscalls.S
@@ -350,3 +350,4 @@ SYSCALL(sys_syncfs,sys_syncfs,sys_syncfs_wrapper)
350SYSCALL(sys_setns,sys_setns,sys_setns_wrapper) 350SYSCALL(sys_setns,sys_setns,sys_setns_wrapper)
351SYSCALL(sys_process_vm_readv,sys_process_vm_readv,compat_sys_process_vm_readv_wrapper) /* 340 */ 351SYSCALL(sys_process_vm_readv,sys_process_vm_readv,compat_sys_process_vm_readv_wrapper) /* 340 */
352SYSCALL(sys_process_vm_writev,sys_process_vm_writev,compat_sys_process_vm_writev_wrapper) 352SYSCALL(sys_process_vm_writev,sys_process_vm_writev,compat_sys_process_vm_writev_wrapper)
353SYSCALL(sys_ni_syscall,sys_s390_runtime_instr,sys_s390_runtime_instr_wrapper)