Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 262832bc authored by Alice Frosi's avatar Alice Frosi Committed by Martin Schwidefsky
Browse files

s390/ptrace: add runtime instrumention register get/set



Add runtime instrumention register get and set which allows to read
and modify the runtime instrumention control block.

Signed-off-by: default avatarAlice Frosi <alice@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent bb59c2da
Loading
Loading
Loading
Loading
+109 −0
Original line number Original line Diff line number Diff line
@@ -30,6 +30,9 @@
#include <linux/uaccess.h>
#include <linux/uaccess.h>
#include <asm/unistd.h>
#include <asm/unistd.h>
#include <asm/switch_to.h>
#include <asm/switch_to.h>
#include <asm/runtime_instr.h>
#include <asm/facility.h>

#include "entry.h"
#include "entry.h"


#ifdef CONFIG_COMPAT
#ifdef CONFIG_COMPAT
@@ -1239,6 +1242,96 @@ static int s390_gs_bc_set(struct task_struct *target,
				  data, 0, sizeof(struct gs_cb));
				  data, 0, sizeof(struct gs_cb));
}
}


static bool is_ri_cb_valid(struct runtime_instr_cb *cb)
{
	return (cb->rca & 0x1f) == 0 &&
		(cb->roa & 0xfff) == 0 &&
		(cb->rla & 0xfff) == 0xfff &&
		cb->s == 1 &&
		cb->k == 1 &&
		cb->h == 0 &&
		cb->reserved1 == 0 &&
		cb->ps == 1 &&
		cb->qs == 0 &&
		cb->pc == 1 &&
		cb->qc == 0 &&
		cb->reserved2 == 0 &&
		cb->key == PAGE_DEFAULT_KEY &&
		cb->reserved3 == 0 &&
		cb->reserved4 == 0 &&
		cb->reserved5 == 0 &&
		cb->reserved6 == 0 &&
		cb->reserved7 == 0 &&
		cb->reserved8 == 0 &&
		cb->rla >= cb->roa &&
		cb->rca >= cb->roa &&
		cb->rca <= cb->rla+1 &&
		cb->m < 3;
}

static int s390_runtime_instr_get(struct task_struct *target,
				const struct user_regset *regset,
				unsigned int pos, unsigned int count,
				void *kbuf, void __user *ubuf)
{
	struct runtime_instr_cb *data = target->thread.ri_cb;

	if (!test_facility(64))
		return -ENODEV;
	if (!data)
		return -ENODATA;

	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				   data, 0, sizeof(struct runtime_instr_cb));
}

static int s390_runtime_instr_set(struct task_struct *target,
				  const struct user_regset *regset,
				  unsigned int pos, unsigned int count,
				  const void *kbuf, const void __user *ubuf)
{
	struct runtime_instr_cb ri_cb = { }, *data = NULL;
	int rc;

	if (!test_facility(64))
		return -ENODEV;

	if (!target->thread.ri_cb) {
		data = kzalloc(sizeof(*data), GFP_KERNEL);
		if (!data)
			return -ENOMEM;
	}

	if (target->thread.ri_cb) {
		if (target == current)
			store_runtime_instr_cb(&ri_cb);
		else
			ri_cb = *target->thread.ri_cb;
	}

	rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
				&ri_cb, 0, sizeof(struct runtime_instr_cb));
	if (rc) {
		kfree(data);
		return -EFAULT;
	}

	if (!is_ri_cb_valid(&ri_cb)) {
		kfree(data);
		return -EINVAL;
	}

	preempt_disable();
	if (!target->thread.ri_cb)
		target->thread.ri_cb = data;
	*target->thread.ri_cb = ri_cb;
	if (target == current)
		load_runtime_instr_cb(target->thread.ri_cb);
	preempt_enable();

	return 0;
}

static const struct user_regset s390_regsets[] = {
static const struct user_regset s390_regsets[] = {
	{
	{
		.core_note_type = NT_PRSTATUS,
		.core_note_type = NT_PRSTATUS,
@@ -1312,6 +1405,14 @@ static const struct user_regset s390_regsets[] = {
		.get = s390_gs_bc_get,
		.get = s390_gs_bc_get,
		.set = s390_gs_bc_set,
		.set = s390_gs_bc_set,
	},
	},
	{
		.core_note_type = NT_S390_RI_CB,
		.n = sizeof(struct runtime_instr_cb) / sizeof(__u64),
		.size = sizeof(__u64),
		.align = sizeof(__u64),
		.get = s390_runtime_instr_get,
		.set = s390_runtime_instr_set,
	},
};
};


static const struct user_regset_view user_s390_view = {
static const struct user_regset_view user_s390_view = {
@@ -1548,6 +1649,14 @@ static const struct user_regset s390_compat_regsets[] = {
		.get = s390_gs_cb_get,
		.get = s390_gs_cb_get,
		.set = s390_gs_cb_set,
		.set = s390_gs_cb_set,
	},
	},
	{
		.core_note_type = NT_S390_RI_CB,
		.n = sizeof(struct runtime_instr_cb) / sizeof(__u64),
		.size = sizeof(__u64),
		.align = sizeof(__u64),
		.get = s390_runtime_instr_get,
		.set = s390_runtime_instr_set,
	},
};
};


static const struct user_regset_view user_s390_compat_view = {
static const struct user_regset_view user_s390_compat_view = {
+1 −0
Original line number Original line Diff line number Diff line
@@ -411,6 +411,7 @@ typedef struct elf64_shdr {
#define NT_S390_VXRS_HIGH	0x30a	/* s390 vector registers 16-31 */
#define NT_S390_VXRS_HIGH	0x30a	/* s390 vector registers 16-31 */
#define NT_S390_GS_CB	0x30b		/* s390 guarded storage registers */
#define NT_S390_GS_CB	0x30b		/* s390 guarded storage registers */
#define NT_S390_GS_BC	0x30c		/* s390 guarded storage broadcast control block */
#define NT_S390_GS_BC	0x30c		/* s390 guarded storage broadcast control block */
#define NT_S390_RI_CB	0x30d		/* s390 runtime instrumentation */
#define NT_ARM_VFP	0x400		/* ARM VFP/NEON registers */
#define NT_ARM_VFP	0x400		/* ARM VFP/NEON registers */
#define NT_ARM_TLS	0x401		/* ARM TLS register */
#define NT_ARM_TLS	0x401		/* ARM TLS register */
#define NT_ARM_HW_BREAK	0x402		/* ARM hardware breakpoint registers */
#define NT_ARM_HW_BREAK	0x402		/* ARM hardware breakpoint registers */