summaryrefslogtreecommitdiff
path: root/sys/arm64/linux/linux_sysvec.c
diff options
context:
space:
mode:
authorDmitry Chagin <dchagin@FreeBSD.org>2022-05-15 18:10:50 +0000
committerDmitry Chagin <dchagin@FreeBSD.org>2022-05-15 18:10:50 +0000
commitc56480a832354aff995f9d0bc5da4ccf27dfe78a (patch)
tree88578b369405aa046c2303691f8decbd07bfeda7 /sys/arm64/linux/linux_sysvec.c
parent08e201a3b4624d84f67f4587ab21b4b4abf61e76 (diff)
Diffstat (limited to 'sys/arm64/linux/linux_sysvec.c')
-rw-r--r--sys/arm64/linux/linux_sysvec.c90
1 files changed, 69 insertions, 21 deletions
diff --git a/sys/arm64/linux/linux_sysvec.c b/sys/arm64/linux/linux_sysvec.c
index 3d3e64f15c6c..461a00bf5b33 100644
--- a/sys/arm64/linux/linux_sysvec.c
+++ b/sys/arm64/linux/linux_sysvec.c
@@ -128,7 +128,7 @@ LIN_SDT_PROBE_DEFINE0(sysvec, linux_elf_fixup, todo);
LINUX_VDSO_SYM_CHAR(linux_platform);
LINUX_VDSO_SYM_INTPTR(kern_timekeep_base);
-LINUX_VDSO_SYM_INTPTR(__kernel_rt_sigreturn);
+LINUX_VDSO_SYM_INTPTR(linux_vdso_sigcode);
/* LINUXTODO: do we have traps to translate? */
static int
@@ -405,21 +405,23 @@ linux_exec_setregs(struct thread *td, struct image_params *imgp,
int
linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args)
{
- struct l_sigframe frame;
+ struct l_sigframe *frame;
+ ucontext_t uc;
struct trapframe *tf;
int error;
tf = td->td_frame;
+ frame = (struct l_sigframe *)tf->tf_sp;
- if (copyin((void *)tf->tf_sp, &frame, sizeof(frame)))
+ if (copyin((void *)&frame->uc, &uc, sizeof(uc)))
return (EFAULT);
- error = set_mcontext(td, &frame.sf_uc.uc_mcontext);
+ error = set_mcontext(td, &uc.uc_mcontext);
if (error != 0)
return (error);
/* Restore signal mask. */
- kern_sigprocmask(td, SIG_SETMASK, &frame.sf_uc.uc_sigmask, NULL, 0);
+ kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0);
return (EJUSTRETURN);
}
@@ -430,7 +432,12 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
struct thread *td;
struct proc *p;
struct trapframe *tf;
- struct l_sigframe *fp, frame;
+ struct l_sigframe *fp, *frame;
+ struct l_fpsimd_context *fpsimd;
+ struct l_esr_context *esr;
+ l_stack_t uc_stack;
+ ucontext_t uc;
+ uint8_t *scr;
struct sigacts *psp;
int onstack, sig;
@@ -464,36 +471,77 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
fp--;
fp = (struct l_sigframe *)STACKALIGN(fp);
+ get_mcontext(td, &uc.uc_mcontext, 0);
+ uc.uc_sigmask = *mask;
+
+ uc_stack.ss_sp = PTROUT(td->td_sigstk.ss_sp);
+ uc_stack.ss_size = td->td_sigstk.ss_size;
+ uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) != 0 ?
+ (onstack ? LINUX_SS_ONSTACK : 0) : LINUX_SS_DISABLE;
+ mtx_unlock(&psp->ps_mtx);
+ PROC_UNLOCK(td->td_proc);
+
/* Fill in the frame to copy out */
- bzero(&frame, sizeof(frame));
- get_mcontext(td, &frame.sf_uc.uc_mcontext, 0);
+ frame = malloc(sizeof(*frame), M_LINUX, M_WAITOK | M_ZERO);
+
+ memcpy(&frame->sf.sf_uc.uc_sc.regs, tf->tf_x, sizeof(tf->tf_x));
+ frame->sf.sf_uc.uc_sc.regs[30] = tf->tf_lr;
+ frame->sf.sf_uc.uc_sc.sp = tf->tf_sp;
+ frame->sf.sf_uc.uc_sc.pc = tf->tf_lr;
+ frame->sf.sf_uc.uc_sc.pstate = tf->tf_spsr;
+ frame->sf.sf_uc.uc_sc.fault_address = (register_t)ksi->ksi_addr;
+
+ /* Stack frame for unwinding */
+ frame->fp = tf->tf_x[29];
+ frame->lr = tf->tf_lr;
/* Translate the signal. */
sig = bsd_to_linux_signal(sig);
+ siginfo_to_lsiginfo(&ksi->ksi_info, &frame->sf.sf_si, sig);
+ bsd_to_linux_sigset(mask, &frame->sf.sf_uc.uc_sigmask);
- siginfo_to_lsiginfo(&ksi->ksi_info, &frame.sf_si, sig);
- frame.sf_uc.uc_sigmask = *mask;
- frame.sf_uc.uc_stack = td->td_sigstk;
- frame.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) != 0 ?
- (onstack ? SS_ONSTACK : 0) : SS_DISABLE;
- mtx_unlock(&psp->ps_mtx);
- PROC_UNLOCK(td->td_proc);
+ /*
+ * Prepare fpsimd & esr. Does not check sizes, as
+ * __reserved is big enougth.
+ */
+ scr = (uint8_t *)&frame->sf.sf_uc.uc_sc.__reserved;
+#ifdef VFP
+ fpsimd = (struct l_fpsimd_context *) scr;
+ fpsimd->head.magic = L_FPSIMD_MAGIC;
+ fpsimd->head.size = sizeof(struct l_fpsimd_context);
+ fpsimd->fpsr = uc.uc_mcontext.mc_fpregs.fp_sr;
+ fpsimd->fpcr = uc.uc_mcontext.mc_fpregs.fp_cr;
+
+ memcpy(fpsimd->vregs, &uc.uc_mcontext.mc_fpregs.fp_q,
+ sizeof(uc.uc_mcontext.mc_fpregs.fp_q));
+ scr += roundup(sizeof(struct l_fpsimd_context), 16);
+#endif
+ if (ksi->ksi_addr != 0) {
+ esr = (struct l_esr_context *) scr;
+ esr->head.magic = L_ESR_MAGIC;
+ esr->head.size = sizeof(struct l_esr_context);
+ esr->esr = tf->tf_esr;
+ }
+
+ 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) {
+ if (copyout(frame, fp, sizeof(*fp)) != 0) {
/* Process has trashed its stack. Kill it. */
+ free(frame, M_LINUX);
CTR2(KTR_SIG, "sendsig: sigexit td=%p fp=%p", td, fp);
PROC_LOCK(p);
sigexit(td, SIGILL);
}
+ free(frame, M_LINUX);
tf->tf_x[0]= sig;
- tf->tf_x[1] = (register_t)&fp->sf_si;
- tf->tf_x[2] = (register_t)&fp->sf_uc;
-
- tf->tf_elr = (register_t)catcher;
+ tf->tf_x[1] = (register_t)&fp->sf.sf_si;
+ tf->tf_x[2] = (register_t)&fp->sf.sf_uc;
+ tf->tf_x[8] = (register_t)catcher;
tf->tf_sp = (register_t)fp;
- tf->tf_lr = (register_t)__kernel_rt_sigreturn;
+ tf->tf_elr = (register_t)linux_vdso_sigcode;
CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_elr,
tf->tf_sp);