Index: sys/arm64/linux/linux_locore.asm =================================================================== --- sys/arm64/linux/linux_locore.asm +++ sys/arm64/linux/linux_locore.asm @@ -45,6 +45,7 @@ .text ENTRY(__kernel_rt_sigreturn) - brk #0 /* LINUXTODO: implement __kernel_rt_sigreturn */ + ldr x8, =LINUX_SYS_linux_rt_sigreturn + svc #0 ret END(__kernel_rt_sigreturn) Index: sys/arm64/linux/linux_sysvec.c =================================================================== --- sys/arm64/linux/linux_sysvec.c +++ sys/arm64/linux/linux_sysvec.c @@ -37,12 +37,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include @@ -407,18 +409,102 @@ int linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args) { + struct sigframe frame; + struct trapframe *tf; + int error; + + tf = td->td_frame; + + if (copyin((void *)tf->tf_sp, &frame, sizeof(frame))) + return (EFAULT); - /* LINUXTODO: implement */ - LIN_SDT_PROBE0(sysvec, linux_rt_sigreturn, todo); - return (EDOOFUS); + error = set_mcontext(td, &frame.sf_uc.uc_mcontext); + if (error != 0) + return (error); + + /* Restore signal mask. */ + kern_sigprocmask(td, SIG_SETMASK, &frame.sf_uc.uc_sigmask, NULL, 0); + + return (EJUSTRETURN); } static void linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) { + struct thread *td; + struct proc *p; + struct trapframe *tf; + struct sigframe *fp, frame; + struct sigacts *psp; + struct sysentvec *sysent; + int onstack, sig; + uint32_t spsr; + + td = curthread; + p = td->td_proc; + PROC_LOCK_ASSERT(p, MA_OWNED); + + sig = ksi->ksi_signo; + psp = p->p_sigacts; + mtx_assert(&psp->ps_mtx, MA_OWNED); + + tf = td->td_frame; + onstack = sigonstack(tf->tf_sp); + + CTR4(KTR_SIG, "sendsig: td=%p (%s) catcher=%p sig=%d", td, p->p_comm, + catcher, sig); + + /* 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 + + 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; + } + + /* 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); + spsr = frame.sf_uc.uc_mcontext.mc_gpregs.gp_spsr; + frame.sf_si = ksi->ksi_info; + 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); + + /* Copy the sigframe out to the user's stack. */ + if (copyout(&frame, fp, sizeof(*fp)) != 0) { + /* Process has trashed its stack. Kill it. */ + CTR2(KTR_SIG, "sendsig: sigexit td=%p fp=%p", td, fp); + PROC_LOCK(p); + sigexit(td, SIGILL); + } + + 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_sp = (register_t)fp; + sysent = p->p_sysent; + KASSERT(sysent->sv_sigcode_base != 0, ("%s: NULL sv_sigcode_base", __func__)); + tf->tf_lr = (register_t)sysent->sv_sigcode_base; + + CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_elr, + tf->tf_sp); - /* LINUXTODO: implement */ - LIN_SDT_PROBE0(sysvec, linux_rt_sendsig, todo); + PROC_LOCK(p); + mtx_lock(&psp->ps_mtx); } struct sysentvec elf_linux_sysvec = { @@ -453,6 +539,7 @@ .sv_syscallnames = NULL, .sv_shared_page_base = LINUX_SHAREDPAGE, .sv_shared_page_len = PAGE_SIZE, + .sv_sigcode_base = 0, /* Filled in by linux_vdso_install(). */ .sv_schedtail = linux_schedtail, .sv_thread_detach = linux_thread_detach, .sv_trap = NULL, @@ -516,6 +603,7 @@ bcopy(vdso_start, linux_vdso_mapping, linux_szsigcode); linux_vdso_reloc(linux_vdso_mapping, linux_vdso_base); + elf_linux_sysvec.sv_sigcode_base = __kernel_rt_sigreturn; } SYSINIT(elf_linux_vdso_init, SI_SUB_EXEC + 1, SI_ORDER_FIRST, linux_vdso_install, NULL);