Linux Audio

Check our new training course

Loading...
v6.2
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright IBM Corp. 2012
  4 * Author(s): Jan Glauber <jang@linux.vnet.ibm.com>
  5 */
  6
  7#include <linux/kernel.h>
  8#include <linux/syscalls.h>
  9#include <linux/signal.h>
 10#include <linux/mm.h>
 11#include <linux/slab.h>
 12#include <linux/init.h>
 13#include <linux/errno.h>
 14#include <linux/kernel_stat.h>
 15#include <linux/sched/task_stack.h>
 16
 17#include <asm/runtime_instr.h>
 18#include <asm/cpu_mf.h>
 19#include <asm/irq.h>
 20
 21#include "entry.h"
 22
 23/* empty control block to disable RI by loading it */
 24struct runtime_instr_cb runtime_instr_empty_cb;
 25
 26void runtime_instr_release(struct task_struct *tsk)
 27{
 28	kfree(tsk->thread.ri_cb);
 29}
 30
 31static void disable_runtime_instr(void)
 32{
 33	struct task_struct *task = current;
 34	struct pt_regs *regs;
 35
 36	if (!task->thread.ri_cb)
 37		return;
 38	regs = task_pt_regs(task);
 39	preempt_disable();
 40	load_runtime_instr_cb(&runtime_instr_empty_cb);
 41	kfree(task->thread.ri_cb);
 42	task->thread.ri_cb = NULL;
 43	preempt_enable();
 44
 45	/*
 46	 * Make sure the RI bit is deleted from the PSW. If the user did not
 47	 * switch off RI before the system call the process will get a
 48	 * specification exception otherwise.
 49	 */
 50	regs->psw.mask &= ~PSW_MASK_RI;
 51}
 52
 53static void init_runtime_instr_cb(struct runtime_instr_cb *cb)
 54{
 55	cb->rla = 0xfff;
 56	cb->s = 1;
 57	cb->k = 1;
 58	cb->ps = 1;
 59	cb->pc = 1;
 60	cb->key = PAGE_DEFAULT_KEY >> 4;
 61	cb->v = 1;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 62}
 63
 64/*
 65 * The signum argument is unused. In older kernels it was used to
 66 * specify a real-time signal. For backwards compatibility user space
 67 * should pass a valid real-time signal number (the signum argument
 68 * was checked in older kernels).
 69 */
 70SYSCALL_DEFINE2(s390_runtime_instr, int, command, int, signum)
 71{
 72	struct runtime_instr_cb *cb;
 73
 74	if (!test_facility(64))
 75		return -EOPNOTSUPP;
 76
 77	if (command == S390_RUNTIME_INSTR_STOP) {
 78		disable_runtime_instr();
 
 
 79		return 0;
 80	}
 81
 82	if (command != S390_RUNTIME_INSTR_START)
 
 83		return -EINVAL;
 84
 85	if (!current->thread.ri_cb) {
 86		cb = kzalloc(sizeof(*cb), GFP_KERNEL);
 87		if (!cb)
 88			return -ENOMEM;
 89	} else {
 90		cb = current->thread.ri_cb;
 91		memset(cb, 0, sizeof(*cb));
 92	}
 93
 94	init_runtime_instr_cb(cb);
 
 95
 96	/* now load the control block to make it available */
 97	preempt_disable();
 98	current->thread.ri_cb = cb;
 99	load_runtime_instr_cb(cb);
100	preempt_enable();
101	return 0;
102}
v3.15
 
  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	cb->int_requested = 1;
 44	cb->pstate = 1;
 45	cb->pstate_set_buf = 1;
 46	cb->pstate_sample = 1;
 47	cb->pstate_collect = 1;
 48	cb->key = PAGE_DEFAULT_KEY;
 49	cb->valid = 1;
 50}
 51
 52void exit_thread_runtime_instr(void)
 53{
 54	struct task_struct *task = current;
 55
 56	if (!task->thread.ri_cb)
 57		return;
 58	disable_runtime_instr();
 59	kfree(task->thread.ri_cb);
 60	task->thread.ri_signum = 0;
 61	task->thread.ri_cb = NULL;
 62}
 63
 64static void runtime_instr_int_handler(struct ext_code ext_code,
 65				unsigned int param32, unsigned long param64)
 66{
 67	struct siginfo info;
 68
 69	if (!(param32 & CPU_MF_INT_RI_MASK))
 70		return;
 71
 72	inc_irq_stat(IRQEXT_CMR);
 73
 74	if (!current->thread.ri_cb)
 75		return;
 76	if (current->thread.ri_signum < SIGRTMIN ||
 77	    current->thread.ri_signum > SIGRTMAX) {
 78		WARN_ON_ONCE(1);
 79		return;
 80	}
 81
 82	memset(&info, 0, sizeof(info));
 83	info.si_signo = current->thread.ri_signum;
 84	info.si_code = SI_QUEUE;
 85	if (param32 & CPU_MF_INT_RI_BUF_FULL)
 86		info.si_int = ENOBUFS;
 87	else if (param32 & CPU_MF_INT_RI_HALTED)
 88		info.si_int = ECANCELED;
 89	else
 90		return; /* unknown reason */
 91
 92	send_sig_info(current->thread.ri_signum, &info, current);
 93}
 94
 
 
 
 
 
 
 95SYSCALL_DEFINE2(s390_runtime_instr, int, command, int, signum)
 96{
 97	struct runtime_instr_cb *cb;
 98
 99	if (!runtime_instr_avail())
100		return -EOPNOTSUPP;
101
102	if (command == S390_RUNTIME_INSTR_STOP) {
103		preempt_disable();
104		exit_thread_runtime_instr();
105		preempt_enable();
106		return 0;
107	}
108
109	if (command != S390_RUNTIME_INSTR_START ||
110	    (signum < SIGRTMIN || signum > SIGRTMAX))
111		return -EINVAL;
112
113	if (!current->thread.ri_cb) {
114		cb = kzalloc(sizeof(*cb), GFP_KERNEL);
115		if (!cb)
116			return -ENOMEM;
117	} else {
118		cb = current->thread.ri_cb;
119		memset(cb, 0, sizeof(*cb));
120	}
121
122	init_runtime_instr_cb(cb);
123	current->thread.ri_signum = signum;
124
125	/* now load the control block to make it available */
126	preempt_disable();
127	current->thread.ri_cb = cb;
128	load_runtime_instr_cb(cb);
129	preempt_enable();
130	return 0;
131}
132
133static int __init runtime_instr_init(void)
134{
135	int rc;
136
137	if (!runtime_instr_avail())
138		return 0;
139
140	irq_subclass_register(IRQ_SUBCLASS_MEASUREMENT_ALERT);
141	rc = register_external_irq(EXT_IRQ_MEASURE_ALERT,
142				   runtime_instr_int_handler);
143	if (rc)
144		irq_subclass_unregister(IRQ_SUBCLASS_MEASUREMENT_ALERT);
145	else
146		pr_info("Runtime instrumentation facility initialized\n");
147	return rc;
148}
149device_initcall(runtime_instr_init);