diff mbox series

[v1,15/20] arm64: add POE signal support

Message ID 20230927140123.5283-16-joey.gouly@arm.com (mailing list archive)
State New, archived
Headers show
Series Permission Overlay Extension | expand

Commit Message

Joey Gouly Sept. 27, 2023, 2:01 p.m. UTC
Add PKEY support to signals, by saving and restoring POR_EL0 from the stackframe.

Signed-off-by: Joey Gouly <joey.gouly@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will@kernel.org>
---
 arch/arm64/include/uapi/asm/sigcontext.h |  7 ++++
 arch/arm64/kernel/signal.c               | 51 ++++++++++++++++++++++++
 2 files changed, 58 insertions(+)

Comments

Mark Brown Oct. 5, 2023, 2:34 p.m. UTC | #1
On Wed, Sep 27, 2023 at 03:01:18PM +0100, Joey Gouly wrote:
> Add PKEY support to signals, by saving and restoring POR_EL0 from the stackframe.

It'd be nice to have at least a basic test that validates that we
generate a POE signal frame when expected, though that should be a very
minor thing which is unlikely to ever actually spot anything.

I'd also expect to see matching support added to ptrace.
Mark Brown Oct. 9, 2023, 2:49 p.m. UTC | #2
On Thu, Oct 05, 2023 at 03:34:29PM +0100, Mark Brown wrote:
> On Wed, Sep 27, 2023 at 03:01:18PM +0100, Joey Gouly wrote:
> > Add PKEY support to signals, by saving and restoring POR_EL0 from the stackframe.

> It'd be nice to have at least a basic test that validates that we
> generate a POE signal frame when expected, though that should be a very
> minor thing which is unlikely to ever actually spot anything.

Actually, now I think about it we at least need an update to the frame
parser in userspace so it knows about the new frame.  Without that it'll
warn whenver it parses the signal context on any system that has POE
enabled.
Joey Gouly Oct. 10, 2023, 9:57 a.m. UTC | #3
Hi Mark,

On Thu, Oct 05, 2023 at 03:34:29PM +0100, Mark Brown wrote:
> On Wed, Sep 27, 2023 at 03:01:18PM +0100, Joey Gouly wrote:
> > Add PKEY support to signals, by saving and restoring POR_EL0 from the stackframe.
> 
> It'd be nice to have at least a basic test that validates that we
> generate a POE signal frame when expected, though that should be a very
> minor thing which is unlikely to ever actually spot anything.
> 
> I'd also expect to see matching support added to ptrace.

The selftests/mm/protection_keys.c looks for the POE signal frame, do you think
we need a separate test?

I will look into ptrace.

Thanks,
Joey
Joey Gouly Oct. 10, 2023, 9:58 a.m. UTC | #4
Hi Mark,

On Mon, Oct 09, 2023 at 03:49:29PM +0100, Mark Brown wrote:
> On Thu, Oct 05, 2023 at 03:34:29PM +0100, Mark Brown wrote:
> > On Wed, Sep 27, 2023 at 03:01:18PM +0100, Joey Gouly wrote:
> > > Add PKEY support to signals, by saving and restoring POR_EL0 from the stackframe.
> 
> > It'd be nice to have at least a basic test that validates that we
> > generate a POE signal frame when expected, though that should be a very
> > minor thing which is unlikely to ever actually spot anything.
> 
> Actually, now I think about it we at least need an update to the frame
> parser in userspace so it knows about the new frame.  Without that it'll
> warn whenver it parses the signal context on any system that has POE
> enabled.

Do you mean in libc?

Thanks,
Joey
Mark Brown Oct. 10, 2023, 11:48 a.m. UTC | #5
On Tue, Oct 10, 2023 at 10:58:02AM +0100, Joey Gouly wrote:
> On Mon, Oct 09, 2023 at 03:49:29PM +0100, Mark Brown wrote:

> > Actually, now I think about it we at least need an update to the frame
> > parser in userspace so it knows about the new frame.  Without that it'll
> > warn whenver it parses the signal context on any system that has POE
> > enabled.

> Do you mean in libc?

No, in the signal handling selftests.
Mark Brown Oct. 10, 2023, 11:56 a.m. UTC | #6
On Tue, Oct 10, 2023 at 10:57:02AM +0100, Joey Gouly wrote:
> On Thu, Oct 05, 2023 at 03:34:29PM +0100, Mark Brown wrote:
> > On Wed, Sep 27, 2023 at 03:01:18PM +0100, Joey Gouly wrote:

> > > Add PKEY support to signals, by saving and restoring POR_EL0 from the stackframe.

> > It'd be nice to have at least a basic test that validates that we
> > generate a POE signal frame when expected, though that should be a very
> > minor thing which is unlikely to ever actually spot anything.

> The selftests/mm/protection_keys.c looks for the POE signal frame, do you think
> we need a separate test?

Like I say it'd be a very minor thing to have one - it is more just a
thing you'd go looking for in the signals tests rather than something
that's absolutely essential.  For trivial things like TPIDR2 I've just
added a trivial thing that verifies that the frame is present iff the
matching HWCAP is set.  Having the test in the mm tests is probably fine
though.
diff mbox series

Patch

diff --git a/arch/arm64/include/uapi/asm/sigcontext.h b/arch/arm64/include/uapi/asm/sigcontext.h
index f23c1dc3f002..cef85eeaf541 100644
--- a/arch/arm64/include/uapi/asm/sigcontext.h
+++ b/arch/arm64/include/uapi/asm/sigcontext.h
@@ -98,6 +98,13 @@  struct esr_context {
 	__u64 esr;
 };
 
+#define POE_MAGIC	0x504f4530
+
+struct poe_context {
+	struct _aarch64_ctx head;
+	__u64 por_el0;
+};
+
 /*
  * extra_context: describes extra space in the signal frame for
  * additional structures that don't fit in sigcontext.__reserved[].
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 0e8beb3349ea..3517271ae0dc 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -62,6 +62,7 @@  struct rt_sigframe_user_layout {
 	unsigned long zt_offset;
 	unsigned long extra_offset;
 	unsigned long end_offset;
+	unsigned long poe_offset;
 };
 
 #define BASE_SIGFRAME_SIZE round_up(sizeof(struct rt_sigframe), 16)
@@ -182,6 +183,8 @@  struct user_ctxs {
 	u32 za_size;
 	struct zt_context __user *zt;
 	u32 zt_size;
+	struct poe_context __user *poe;
+	u32 poe_size;
 };
 
 static int preserve_fpsimd_context(struct fpsimd_context __user *ctx)
@@ -227,6 +230,20 @@  static int restore_fpsimd_context(struct user_ctxs *user)
 	return err ? -EFAULT : 0;
 }
 
+static int restore_poe_context(struct user_ctxs *user)
+{
+	u64 por_el0;
+	int err = 0;
+
+	if (user->poe_size != sizeof(*user->poe))
+		return -EINVAL;
+
+	__get_user_error(por_el0, &(user->poe->por_el0), err);
+	if (!err)
+		write_sysreg_s(por_el0, SYS_POR_EL0);
+
+	return err;
+}
 
 #ifdef CONFIG_ARM64_SVE
 
@@ -590,6 +607,7 @@  static int parse_user_sigframe(struct user_ctxs *user,
 	user->tpidr2 = NULL;
 	user->za = NULL;
 	user->zt = NULL;
+	user->poe = NULL;
 
 	if (!IS_ALIGNED((unsigned long)base, 16))
 		goto invalid;
@@ -640,6 +658,17 @@  static int parse_user_sigframe(struct user_ctxs *user,
 			/* ignore */
 			break;
 
+		case POE_MAGIC:
+			if (!cpus_have_final_cap(ARM64_HAS_S1POE))
+				goto invalid;
+
+			if (user->poe)
+				goto invalid;
+
+			user->poe = (struct poe_context __user *)head;
+			user->poe_size = size;
+			break;
+
 		case SVE_MAGIC:
 			if (!system_supports_sve() && !system_supports_sme())
 				goto invalid;
@@ -812,6 +841,9 @@  static int restore_sigframe(struct pt_regs *regs,
 	if (err == 0 && system_supports_sme2() && user.zt)
 		err = restore_zt_context(&user);
 
+	if (err == 0 && cpus_have_final_cap(ARM64_HAS_S1POE) && user.poe)
+		err = restore_poe_context(&user);
+
 	return err;
 }
 
@@ -928,6 +960,13 @@  static int setup_sigframe_layout(struct rt_sigframe_user_layout *user,
 		}
 	}
 
+	if (cpus_have_const_cap(ARM64_HAS_S1POE)) {
+		err = sigframe_alloc(user, &user->poe_offset,
+				     sizeof(struct poe_context));
+		if (err)
+			return err;
+	}
+
 	return sigframe_alloc_end(user);
 }
 
@@ -968,6 +1007,15 @@  static int setup_sigframe(struct rt_sigframe_user_layout *user,
 		__put_user_error(current->thread.fault_code, &esr_ctx->esr, err);
 	}
 
+	if (cpus_have_final_cap(ARM64_HAS_S1POE) && err == 0 && user->poe_offset) {
+		struct poe_context __user *poe_ctx =
+			apply_user_offset(user, user->poe_offset);
+
+		__put_user_error(POE_MAGIC, &poe_ctx->head.magic, err);
+		__put_user_error(sizeof(*poe_ctx), &poe_ctx->head.size, err);
+		__put_user_error(read_sysreg_s(SYS_POR_EL0), &poe_ctx->por_el0, err);
+	}
+
 	/* Scalable Vector Extension state (including streaming), if present */
 	if ((system_supports_sve() || system_supports_sme()) &&
 	    err == 0 && user->sve_offset) {
@@ -1119,6 +1167,9 @@  static void setup_return(struct pt_regs *regs, struct k_sigaction *ka,
 		sme_smstop();
 	}
 
+	if (cpus_have_final_cap(ARM64_HAS_S1POE))
+		write_sysreg_s(POR_EL0_INIT, SYS_POR_EL0);
+
 	if (ka->sa.sa_flags & SA_RESTORER)
 		sigtramp = ka->sa.sa_restorer;
 	else