diff options
| author | Dmitry Chagin <dchagin@FreeBSD.org> | 2022-05-15 18:10:50 +0000 |
|---|---|---|
| committer | Dmitry Chagin <dchagin@FreeBSD.org> | 2022-05-15 18:10:50 +0000 |
| commit | c56480a832354aff995f9d0bc5da4ccf27dfe78a (patch) | |
| tree | 88578b369405aa046c2303691f8decbd07bfeda7 /sys/arm64/linux/linux_sysvec.c | |
| parent | 08e201a3b4624d84f67f4587ab21b4b4abf61e76 (diff) | |
Diffstat (limited to 'sys/arm64/linux/linux_sysvec.c')
| -rw-r--r-- | sys/arm64/linux/linux_sysvec.c | 90 |
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); |
