mirror of
https://github.com/freebsd/freebsd-src
synced 2024-07-21 18:27:22 +00:00
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
This commit is contained in:
parent
69d5783ae8
commit
7e6437c084
|
@ -461,8 +461,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
|
||||
|
@ -501,8 +505,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
|
||||
}
|
||||
|
@ -585,6 +616,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)
|
||||
{
|
||||
|
@ -593,6 +649,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;
|
||||
|
@ -612,19 +669,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);
|
||||
|
@ -636,6 +689,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. */
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue