git: 254d54f0733f - stable/14 - arm64: Support passing more registers to signals
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 02 Sep 2024 08:50:37 UTC
The branch stable/14 has been updated by andrew:
URL: https://cgit.FreeBSD.org/src/commit/?id=254d54f0733fe139108cb576cf37f16102659181
commit 254d54f0733fe139108cb576cf37f16102659181
Author: Andrew Turner <andrew@FreeBSD.org>
AuthorDate: 2024-03-21 10:13:16 +0000
Commit: Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2024-09-02 08:44:19 +0000
arm64: Support passing more registers to signals
To support recent extensions to the Arm architecture we may need to
store more or larger registers when sending a signal.
To support this create a list of these extra registers. Userspace that
needs to access a register in the signal handler can then walk the list
to find the correct register struct and read/write its contents.
Reviewed by: kib, markj (earlier version)
Sponsored by: Arm Ltd
Differential Revision: https://reviews.freebsd.org/D43302
(cherry picked from commit 7e6437c08415ade75403f1ecad75167257e8ea3c)
---
sys/arm64/arm64/exec_machdep.c | 85 +++++++++++++++++++++++++++++++++++++++---
sys/arm64/include/ucontext.h | 16 +++++++-
2 files changed, 94 insertions(+), 7 deletions(-)
diff --git a/sys/arm64/arm64/exec_machdep.c b/sys/arm64/arm64/exec_machdep.c
index 4efa3ceaae40..bc4ee178db23 100644
--- a/sys/arm64/arm64/exec_machdep.c
+++ b/sys/arm64/arm64/exec_machdep.c
@@ -462,8 +462,12 @@ int
set_mcontext(struct thread *td, mcontext_t *mcp)
{
#define PSR_13_MASK 0xfffffffful
+ struct arm64_reg_context ctx;
struct trapframe *tf = td->td_frame;
uint64_t spsr;
+ vm_offset_t addr;
+ int error;
+ bool done;
spsr = mcp->mc_gpregs.gp_spsr;
#ifdef COMPAT_FREEBSD13
@@ -502,8 +506,35 @@ set_mcontext(struct thread *td, mcontext_t *mcp)
READ_SPECIALREG(mdscr_el1) | MDSCR_SS);
isb();
}
+
set_fpcontext(td, mcp);
+ /* Read any register contexts we find */
+ if (mcp->mc_ptr != 0) {
+ addr = mcp->mc_ptr;
+
+ done = false;
+ do {
+ if (!__is_aligned(addr,
+ _Alignof(struct arm64_reg_context)))
+ return (EINVAL);
+
+ error = copyin((const void *)addr, &ctx, sizeof(ctx));
+ if (error != 0)
+ return (error);
+
+ switch (ctx.ctx_id) {
+ case ARM64_CTX_END:
+ done = true;
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ addr += ctx.ctx_size;
+ } while (!done);
+ }
+
return (0);
#undef PSR_13_MASK
}
@@ -586,6 +617,31 @@ sys_sigreturn(struct thread *td, struct sigreturn_args *uap)
return (EJUSTRETURN);
}
+static bool
+sendsig_ctx_end(struct thread *td, vm_offset_t *addrp)
+{
+ struct arm64_reg_context end_ctx;
+ vm_offset_t ctx_addr;
+
+ *addrp -= sizeof(end_ctx);
+ ctx_addr = *addrp;
+
+ memset(&end_ctx, 0, sizeof(end_ctx));
+ end_ctx.ctx_id = ARM64_CTX_END;
+ end_ctx.ctx_size = sizeof(end_ctx);
+
+ if (copyout(&end_ctx, (void *)ctx_addr, sizeof(end_ctx)) != 0)
+ return (false);
+
+ return (true);
+}
+
+typedef bool(*ctx_func)(struct thread *, vm_offset_t *);
+static const ctx_func ctx_funcs[] = {
+ sendsig_ctx_end, /* Must be first to end the linked list */
+ NULL,
+};
+
void
sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
{
@@ -594,6 +650,7 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
struct trapframe *tf;
struct sigframe *fp, frame;
struct sigacts *psp;
+ vm_offset_t addr;
int onstack, sig;
td = curthread;
@@ -613,19 +670,15 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
/* Allocate and validate space for the signal handler context. */
if ((td->td_pflags & TDP_ALTSTACK) != 0 && !onstack &&
SIGISMEMBER(psp->ps_sigonstack, sig)) {
- fp = (struct sigframe *)((uintptr_t)td->td_sigstk.ss_sp +
+ addr = ((uintptr_t)td->td_sigstk.ss_sp +
td->td_sigstk.ss_size);
#if defined(COMPAT_43)
td->td_sigstk.ss_flags |= SS_ONSTACK;
#endif
} else {
- fp = (struct sigframe *)td->td_frame->tf_sp;
+ addr = td->td_frame->tf_sp;
}
- /* Make room, keeping the stack aligned */
- fp--;
- fp = (struct sigframe *)STACKALIGN(fp);
-
/* Fill in the frame to copy out */
bzero(&frame, sizeof(frame));
get_mcontext(td, &frame.sf_uc.uc_mcontext, 0);
@@ -637,6 +690,26 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
mtx_unlock(&psp->ps_mtx);
PROC_UNLOCK(td->td_proc);
+ for (int i = 0; ctx_funcs[i] != NULL; i++) {
+ if (!ctx_funcs[i](td, &addr)) {
+ /* Process has trashed its stack. Kill it. */
+ CTR4(KTR_SIG,
+ "sendsig: frame sigexit td=%p fp=%#lx func[%d]=%p",
+ td, addr, i, ctx_funcs[i]);
+ PROC_LOCK(p);
+ sigexit(td, SIGILL);
+ /* NOTREACHED */
+ }
+ }
+
+ /* Point at the first context */
+ frame.sf_uc.uc_mcontext.mc_ptr = addr;
+
+ /* Make room, keeping the stack aligned */
+ fp = (struct sigframe *)addr;
+ fp--;
+ fp = (struct sigframe *)STACKALIGN(fp);
+
/* Copy the sigframe out to the user's stack. */
if (copyout(&frame, fp, sizeof(*fp)) != 0) {
/* Process has trashed its stack. Kill it. */
diff --git a/sys/arm64/include/ucontext.h b/sys/arm64/include/ucontext.h
index e9b914315a19..dedbd061ec6b 100644
--- a/sys/arm64/include/ucontext.h
+++ b/sys/arm64/include/ucontext.h
@@ -51,15 +51,29 @@ struct fpregs {
int fp_pad;
};
+/*
+ * Support for registers that don't fit into gpregs or fpregs, e.g. SVE.
+ * There are some registers that have been added so are optional. To support
+ * these create an array of headers that point at the register data.
+ */
+struct arm64_reg_context {
+ __uint32_t ctx_id;
+ __uint32_t ctx_size;
+};
+
+#define ARM64_CTX_END 0xa5a5a5a5
+
struct __mcontext {
struct gpregs mc_gpregs;
struct fpregs mc_fpregs;
int mc_flags;
#define _MC_FP_VALID 0x1 /* Set when mc_fpregs has valid data */
int mc_pad; /* Padding */
- __uint64_t mc_spare[8]; /* Space for expansion, set to zero */
+ __uint64_t mc_ptr; /* Address of extra_regs struct */
+ __uint64_t mc_spare[7]; /* Space for expansion, set to zero */
};
+
typedef struct __mcontext mcontext_t;
#ifdef COMPAT_FREEBSD32