mirror of
https://github.com/opnsense/src.git
synced 2026-06-09 08:43:19 -04:00
arm64: Use the Linux sigframe to restore registers
When returning from a Linux signal use the Linux sigframe to find the register values to restore. Remove the FreeBSD ucontext from the stack as it's now unneeded. Reviewed by: dchagin, emaste Sponsored by: Arm Ltd Differential Revision: https://reviews.freebsd.org/D42360
This commit is contained in:
parent
cb0259b6df
commit
070a4ff82a
2 changed files with 89 additions and 10 deletions
|
|
@ -76,7 +76,6 @@ struct l_sigframe {
|
|||
/* frame_record */
|
||||
uint64_t fp;
|
||||
uint64_t lr;
|
||||
ucontext_t uc;
|
||||
};
|
||||
|
||||
#define LINUX_MINSIGSTKSZ roundup(sizeof(struct l_sigframe), 16)
|
||||
|
|
|
|||
|
|
@ -187,28 +187,109 @@ linux_exec_setregs(struct thread *td, struct image_params *imgp,
|
|||
bzero(&pcb->pcb_dbg_regs, sizeof(pcb->pcb_dbg_regs));
|
||||
}
|
||||
|
||||
static bool
|
||||
linux_parse_sigreturn_ctx(struct thread *td, struct l_sigcontext *sc)
|
||||
{
|
||||
struct l_fpsimd_context *fpsimd;
|
||||
struct _l_aarch64_ctx *ctx;
|
||||
int offset;
|
||||
|
||||
offset = 0;
|
||||
while (1) {
|
||||
/* The offset must be 16 byte aligned */
|
||||
if ((offset & 15) != 0)
|
||||
return (false);
|
||||
|
||||
/* Check for buffer overflow of the ctx */
|
||||
if ((offset + sizeof(*ctx)) >
|
||||
sizeof(sc->__reserved))
|
||||
return (false);
|
||||
|
||||
ctx = (struct _l_aarch64_ctx *)&sc->__reserved[offset];
|
||||
|
||||
/* Check for buffer overflow of the data */
|
||||
if ((offset + ctx->size) > sizeof(sc->__reserved))
|
||||
return (false);
|
||||
|
||||
switch(ctx->magic) {
|
||||
case 0:
|
||||
if (ctx->size != 0)
|
||||
return (false);
|
||||
return (true);
|
||||
case L_ESR_MAGIC:
|
||||
/* Ignore */
|
||||
break;
|
||||
#ifdef VFP
|
||||
case L_FPSIMD_MAGIC:
|
||||
fpsimd = (struct l_fpsimd_context *)ctx;
|
||||
|
||||
/*
|
||||
* Discard any vfp state for the current thread, we
|
||||
* are about to override it.
|
||||
*/
|
||||
critical_enter();
|
||||
vfp_discard(td);
|
||||
critical_exit();
|
||||
|
||||
td->td_pcb->pcb_fpustate.vfp_fpcr = fpsimd->fpcr;
|
||||
td->td_pcb->pcb_fpustate.vfp_fpsr = fpsimd->fpsr;
|
||||
memcpy(td->td_pcb->pcb_fpustate.vfp_regs,
|
||||
fpsimd->vregs, sizeof(fpsimd->vregs));
|
||||
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return (false);
|
||||
}
|
||||
|
||||
offset += ctx->size;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args)
|
||||
{
|
||||
struct l_rt_sigframe *sf;
|
||||
struct l_sigframe *frame;
|
||||
ucontext_t uc;
|
||||
struct trapframe *tf;
|
||||
sigset_t bmask;
|
||||
int error;
|
||||
|
||||
sf = malloc(sizeof(*sf), M_LINUX, M_WAITOK | M_ZERO);
|
||||
|
||||
tf = td->td_frame;
|
||||
frame = (struct l_sigframe *)tf->tf_sp;
|
||||
|
||||
if (copyin((void *)&frame->uc, &uc, sizeof(uc)))
|
||||
return (EFAULT);
|
||||
|
||||
error = set_mcontext(td, &uc.uc_mcontext);
|
||||
if (error != 0)
|
||||
error = copyin((void *)&frame->sf, sf, sizeof(*sf));
|
||||
if (error != 0) {
|
||||
free(sf, M_LINUX);
|
||||
return (error);
|
||||
}
|
||||
|
||||
memcpy(tf->tf_x, sf->sf_uc.uc_sc.regs, sizeof(tf->tf_x));
|
||||
tf->tf_lr = sf->sf_uc.uc_sc.regs[30];
|
||||
tf->tf_sp = sf->sf_uc.uc_sc.sp;
|
||||
tf->tf_elr = sf->sf_uc.uc_sc.pc;
|
||||
|
||||
if ((sf->sf_uc.uc_sc.pstate & PSR_M_MASK) != PSR_M_EL0t ||
|
||||
(sf->sf_uc.uc_sc.pstate & PSR_AARCH32) != 0 ||
|
||||
(sf->sf_uc.uc_sc.pstate & PSR_DAIF) !=
|
||||
(td->td_frame->tf_spsr & PSR_DAIF))
|
||||
goto einval;
|
||||
tf->tf_spsr = sf->sf_uc.uc_sc.pstate;
|
||||
|
||||
if (!linux_parse_sigreturn_ctx(td, &sf->sf_uc.uc_sc))
|
||||
goto einval;
|
||||
|
||||
/* Restore signal mask. */
|
||||
kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0);
|
||||
linux_to_bsd_sigset(&sf->sf_uc.uc_sigmask, &bmask);
|
||||
kern_sigprocmask(td, SIG_SETMASK, &bmask, NULL, 0);
|
||||
free(sf, M_LINUX);
|
||||
|
||||
return (EJUSTRETURN);
|
||||
einval:
|
||||
free(sf, M_LINUX);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -310,7 +391,6 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
|
|||
}
|
||||
|
||||
memcpy(&frame->sf.sf_uc.uc_stack, &uc_stack, sizeof(uc_stack));
|
||||
memcpy(&frame->uc, &uc, sizeof(uc));
|
||||
|
||||
/* Copy the sigframe out to the user's stack. */
|
||||
if (copyout(frame, fp, sizeof(*fp)) != 0) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue