Commit 39e54499 authored by Mark Brown's avatar Mark Brown Committed by Catalin Marinas
Browse files

arm64/signal: Include TPIDR2 in the signal context



Add a new signal frame record for TPIDR2 using the same format as we
already use for ESR with different magic, a header with the value from the
register appended as the only data. If SME is supported then this record is
always included.

Signed-off-by: default avatarMark Brown <broonie@kernel.org>
Reviewed-by: default avatarSzabolcs Nagy <szabolcs.nagy@arm.com>
Link: https://lore.kernel.org/r/20221208-arm64-tpidr2-sig-v3-2-c77c6c8775f4@kernel.org


Signed-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
parent 17d0c4a2
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -144,6 +144,14 @@ struct sve_context {

#define SVE_SIG_FLAG_SM	0x1	/* Context describes streaming mode */

/* TPIDR2_EL0 context */
#define TPIDR2_MAGIC	0x54504902

struct tpidr2_context {
	struct _aarch64_ctx head;
	__u64 tpidr2;
};

#define ZA_MAGIC	0x54366345

struct za_context {
+59 −0
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ struct rt_sigframe_user_layout {
	unsigned long fpsimd_offset;
	unsigned long esr_offset;
	unsigned long sve_offset;
	unsigned long tpidr2_offset;
	unsigned long za_offset;
	unsigned long extra_offset;
	unsigned long end_offset;
@@ -220,6 +221,7 @@ static int restore_fpsimd_context(struct fpsimd_context __user *ctx)
struct user_ctxs {
	struct fpsimd_context __user *fpsimd;
	struct sve_context __user *sve;
	struct tpidr2_context __user *tpidr2;
	struct za_context __user *za;
};

@@ -361,6 +363,32 @@ extern int preserve_sve_context(void __user *ctx);

#ifdef CONFIG_ARM64_SME

static int preserve_tpidr2_context(struct tpidr2_context __user *ctx)
{
	int err = 0;

	current->thread.tpidr2_el0 = read_sysreg_s(SYS_TPIDR2_EL0);

	__put_user_error(TPIDR2_MAGIC, &ctx->head.magic, err);
	__put_user_error(sizeof(*ctx), &ctx->head.size, err);
	__put_user_error(current->thread.tpidr2_el0, &ctx->tpidr2, err);

	return err;
}

static int restore_tpidr2_context(struct user_ctxs *user)
{
	u64 tpidr2_el0;
	int err = 0;

	/* Magic and size were validated deciding to call this function */
	__get_user_error(tpidr2_el0, &user->tpidr2->tpidr2, err);
	if (!err)
		current->thread.tpidr2_el0 = tpidr2_el0;

	return err;
}

static int preserve_za_context(struct za_context __user *ctx)
{
	int err = 0;
@@ -450,6 +478,8 @@ static int restore_za_context(struct user_ctxs *user)
#else /* ! CONFIG_ARM64_SME */

/* Turn any non-optimised out attempts to use these into a link error: */
extern int preserve_tpidr2_context(void __user *ctx);
extern int restore_tpidr2_context(struct user_ctxs *user);
extern int preserve_za_context(void __user *ctx);
extern int restore_za_context(struct user_ctxs *user);

@@ -468,6 +498,7 @@ static int parse_user_sigframe(struct user_ctxs *user,

	user->fpsimd = NULL;
	user->sve = NULL;
	user->tpidr2 = NULL;
	user->za = NULL;

	if (!IS_ALIGNED((unsigned long)base, 16))
@@ -534,6 +565,19 @@ static int parse_user_sigframe(struct user_ctxs *user,
			user->sve = (struct sve_context __user *)head;
			break;

		case TPIDR2_MAGIC:
			if (!system_supports_sme())
				goto invalid;

			if (user->tpidr2)
				goto invalid;

			if (size != sizeof(*user->tpidr2))
				goto invalid;

			user->tpidr2 = (struct tpidr2_context __user *)head;
			break;

		case ZA_MAGIC:
			if (!system_supports_sme())
				goto invalid;
@@ -666,6 +710,9 @@ static int restore_sigframe(struct pt_regs *regs,
			err = restore_fpsimd_context(user.fpsimd);
	}

	if (err == 0 && system_supports_sme() && user.tpidr2)
		err = restore_tpidr2_context(&user);

	if (err == 0 && system_supports_sme() && user.za)
		err = restore_za_context(&user);

@@ -760,6 +807,11 @@ static int setup_sigframe_layout(struct rt_sigframe_user_layout *user,
		else
			vl = task_get_sme_vl(current);

		err = sigframe_alloc(user, &user->tpidr2_offset,
				     sizeof(struct tpidr2_context));
		if (err)
			return err;

		if (thread_za_enabled(&current->thread))
			vq = sve_vq_from_vl(vl);

@@ -817,6 +869,13 @@ static int setup_sigframe(struct rt_sigframe_user_layout *user,
		err |= preserve_sve_context(sve_ctx);
	}

	/* TPIDR2 if supported */
	if (system_supports_sme() && err == 0) {
		struct tpidr2_context __user *tpidr2_ctx =
			apply_user_offset(user, user->tpidr2_offset);
		err |= preserve_tpidr2_context(tpidr2_ctx);
	}

	/* ZA state if present */
	if (system_supports_sme() && err == 0 && user->za_offset) {
		struct za_context __user *za_ctx =