13911ee2cSEd Maste /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 33911ee2cSEd Maste * 43911ee2cSEd Maste * Copyright (c) 1994-1996 Søren Schmidt 53911ee2cSEd Maste * Copyright (c) 2018 Turing Robotic Industries Inc. 63911ee2cSEd Maste * 73911ee2cSEd Maste * Redistribution and use in source and binary forms, with or without 83911ee2cSEd Maste * modification, are permitted provided that the following conditions 93911ee2cSEd Maste * are met: 103911ee2cSEd Maste * 1. Redistributions of source code must retain the above copyright 113911ee2cSEd Maste * notice, this list of conditions and the following disclaimer. 123911ee2cSEd Maste * 2. Redistributions in binary form must reproduce the above copyright 133911ee2cSEd Maste * notice, this list of conditions and the following disclaimer in the 143911ee2cSEd Maste * documentation and/or other materials provided with the distribution. 153911ee2cSEd Maste * 163911ee2cSEd Maste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 173911ee2cSEd Maste * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 183911ee2cSEd Maste * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 193911ee2cSEd Maste * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 203911ee2cSEd Maste * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 213911ee2cSEd Maste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 223911ee2cSEd Maste * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 233911ee2cSEd Maste * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 243911ee2cSEd Maste * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 253911ee2cSEd Maste * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 263911ee2cSEd Maste * SUCH DAMAGE. 273911ee2cSEd Maste */ 283911ee2cSEd Maste 2974465145SDmitry Chagin #define __ELF_WORD_SIZE 64 3074465145SDmitry Chagin 313911ee2cSEd Maste #include <sys/param.h> 323911ee2cSEd Maste #include <sys/elf.h> 333911ee2cSEd Maste #include <sys/exec.h> 343911ee2cSEd Maste #include <sys/imgact.h> 353911ee2cSEd Maste #include <sys/imgact_elf.h> 363911ee2cSEd Maste #include <sys/kernel.h> 37ccc510b4SEdward Tomasz Napierala #include <sys/ktr.h> 383911ee2cSEd Maste #include <sys/lock.h> 393911ee2cSEd Maste #include <sys/module.h> 403911ee2cSEd Maste #include <sys/mutex.h> 413911ee2cSEd Maste #include <sys/proc.h> 429931033bSDmitry Chagin #include <sys/stddef.h> 43ccc510b4SEdward Tomasz Napierala #include <sys/syscallsubr.h> 443911ee2cSEd Maste #include <sys/sysctl.h> 453911ee2cSEd Maste #include <sys/sysent.h> 463911ee2cSEd Maste 4755d3e181SDmitry Chagin #include <vm/vm.h> 48027d727dSDmitry Chagin #include <vm/vm_param.h> 493911ee2cSEd Maste 503911ee2cSEd Maste #include <arm64/linux/linux.h> 513911ee2cSEd Maste #include <arm64/linux/linux_proto.h> 5274465145SDmitry Chagin #include <compat/linux/linux_elf.h> 533911ee2cSEd Maste #include <compat/linux/linux_emul.h> 540a4b664aSDmitry Chagin #include <compat/linux/linux_fork.h> 553911ee2cSEd Maste #include <compat/linux/linux_ioctl.h> 563911ee2cSEd Maste #include <compat/linux/linux_mib.h> 573911ee2cSEd Maste #include <compat/linux/linux_misc.h> 58ccc510b4SEdward Tomasz Napierala #include <compat/linux/linux_signal.h> 59b5f20658SEdward Tomasz Napierala #include <compat/linux/linux_util.h> 603911ee2cSEd Maste #include <compat/linux/linux_vdso.h> 613911ee2cSEd Maste 6221f24617SDmitry Chagin #include <arm64/linux/linux_sigframe.h> 6321f24617SDmitry Chagin 64b501b2aeSEdward Tomasz Napierala #include <machine/md_var.h> 652555f175SKonstantin Belousov #include <machine/pcb.h> 66953a7d7cSAlex Richardson #ifdef VFP 67953a7d7cSAlex Richardson #include <machine/vfp.h> 68953a7d7cSAlex Richardson #endif 69953a7d7cSAlex Richardson 703911ee2cSEd Maste MODULE_VERSION(linux64elf, 1); 713911ee2cSEd Maste 729931033bSDmitry Chagin #define LINUX_VDSOPAGE_SIZE PAGE_SIZE * 2 739931033bSDmitry Chagin #define LINUX_VDSOPAGE (VM_MAXUSER_ADDRESS - \ 749931033bSDmitry Chagin LINUX_VDSOPAGE_SIZE) 759931033bSDmitry Chagin #define LINUX_SHAREDPAGE (LINUX_VDSOPAGE - PAGE_SIZE) 769931033bSDmitry Chagin /* 779931033bSDmitry Chagin * PAGE_SIZE - the size 789931033bSDmitry Chagin * of the native SHAREDPAGE 799931033bSDmitry Chagin */ 809931033bSDmitry Chagin #define LINUX_USRSTACK LINUX_SHAREDPAGE 819931033bSDmitry Chagin #define LINUX_PS_STRINGS (LINUX_USRSTACK - \ 829931033bSDmitry Chagin sizeof(struct ps_strings)) 839931033bSDmitry Chagin 843911ee2cSEd Maste static int linux_szsigcode; 859931033bSDmitry Chagin static vm_object_t linux_vdso_obj; 869931033bSDmitry Chagin static char *linux_vdso_mapping; 879931033bSDmitry Chagin extern char _binary_linux_vdso_so_o_start; 889931033bSDmitry Chagin extern char _binary_linux_vdso_so_o_end; 899931033bSDmitry Chagin static vm_offset_t linux_vdso_base; 903911ee2cSEd Maste 913911ee2cSEd Maste extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL]; 921da65dcbSMitchell Horne extern const char *linux_syscallnames[]; 933911ee2cSEd Maste 943911ee2cSEd Maste SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler); 953911ee2cSEd Maste 963911ee2cSEd Maste static void linux_vdso_install(const void *param); 973911ee2cSEd Maste static void linux_vdso_deinstall(const void *param); 989931033bSDmitry Chagin static void linux_vdso_reloc(char *mapping, Elf_Addr offset); 993911ee2cSEd Maste static void linux_set_syscall_retval(struct thread *td, int error); 1003911ee2cSEd Maste static int linux_fetch_syscall_args(struct thread *td); 1013911ee2cSEd Maste static void linux_exec_setregs(struct thread *td, struct image_params *imgp, 10231174518SJohn Baldwin uintptr_t stack); 1039931033bSDmitry Chagin static void linux_exec_sysvec_init(void *param); 1045fd9cd53SDmitry Chagin static int linux_on_exec_vmspace(struct proc *p, 1055fd9cd53SDmitry Chagin struct image_params *imgp); 1063911ee2cSEd Maste 1079931033bSDmitry Chagin LINUX_VDSO_SYM_CHAR(linux_platform); 1089931033bSDmitry Chagin LINUX_VDSO_SYM_INTPTR(kern_timekeep_base); 109d957343fSDmitry Chagin LINUX_VDSO_SYM_INTPTR(__user_rt_sigreturn); 1109931033bSDmitry Chagin 1113911ee2cSEd Maste static int 1123911ee2cSEd Maste linux_fetch_syscall_args(struct thread *td) 1133911ee2cSEd Maste { 1143911ee2cSEd Maste struct proc *p; 1153911ee2cSEd Maste struct syscall_args *sa; 1163911ee2cSEd Maste register_t *ap; 1173911ee2cSEd Maste 1183911ee2cSEd Maste p = td->td_proc; 1193911ee2cSEd Maste ap = td->td_frame->tf_x; 1203911ee2cSEd Maste sa = &td->td_sa; 1213911ee2cSEd Maste 1223911ee2cSEd Maste sa->code = td->td_frame->tf_x[8]; 123cf98bc28SDavid Chisnall sa->original_code = sa->code; 1243911ee2cSEd Maste /* LINUXTODO: generic syscall? */ 1253911ee2cSEd Maste if (sa->code >= p->p_sysent->sv_size) 126*39024a89SKonstantin Belousov sa->callp = &nosys_sysent; 1273911ee2cSEd Maste else 1283911ee2cSEd Maste sa->callp = &p->p_sysent->sv_table[sa->code]; 1293911ee2cSEd Maste 130adb12675SBrooks Davis if (sa->callp->sy_narg > nitems(sa->args)) 131adb12675SBrooks Davis panic("ARM64TODO: Could we have more than %zu args?", 132adb12675SBrooks Davis nitems(sa->args)); 133adb12675SBrooks Davis memcpy(sa->args, ap, nitems(sa->args) * sizeof(register_t)); 1343911ee2cSEd Maste 1353911ee2cSEd Maste td->td_retval[0] = 0; 1363911ee2cSEd Maste return (0); 1373911ee2cSEd Maste } 1383911ee2cSEd Maste 1393911ee2cSEd Maste static void 1403911ee2cSEd Maste linux_set_syscall_retval(struct thread *td, int error) 1413911ee2cSEd Maste { 1423911ee2cSEd Maste 1438e5d76e6SAndrew Turner td->td_retval[1] = td->td_frame->tf_x[1]; 1448e5d76e6SAndrew Turner cpu_set_syscall_retval(td, error); 145c26391f4SEdward Tomasz Napierala 146c26391f4SEdward Tomasz Napierala if (__predict_false(error != 0)) { 147866b1f51SEdward Tomasz Napierala if (error != ERESTART && error != EJUSTRETURN) 148866b1f51SEdward Tomasz Napierala td->td_frame->tf_x[0] = bsd_to_linux_errno(error); 149c26391f4SEdward Tomasz Napierala } 1503911ee2cSEd Maste } 1513911ee2cSEd Maste 1527d8c9839SDmitry Chagin void 1537d8c9839SDmitry Chagin linux64_arch_copyout_auxargs(struct image_params *imgp, Elf_Auxinfo **pos) 1543911ee2cSEd Maste { 1553911ee2cSEd Maste 1567d8c9839SDmitry Chagin AUXARGS_ENTRY((*pos), LINUX_AT_SYSINFO_EHDR, linux_vdso_base); 1577d8c9839SDmitry Chagin AUXARGS_ENTRY((*pos), LINUX_AT_HWCAP, *imgp->sysent->sv_hwcap); 1587d8c9839SDmitry Chagin AUXARGS_ENTRY((*pos), LINUX_AT_HWCAP2, *imgp->sysent->sv_hwcap2); 1597d8c9839SDmitry Chagin AUXARGS_ENTRY((*pos), LINUX_AT_PLATFORM, PTROUT(linux_platform)); 1605caa67faSJohn Baldwin } 1615caa67faSJohn Baldwin 1623911ee2cSEd Maste /* 1633911ee2cSEd Maste * Reset registers to default values on exec. 1643911ee2cSEd Maste */ 1653911ee2cSEd Maste static void 16631174518SJohn Baldwin linux_exec_setregs(struct thread *td, struct image_params *imgp, 16731174518SJohn Baldwin uintptr_t stack) 1683911ee2cSEd Maste { 1693911ee2cSEd Maste struct trapframe *regs = td->td_frame; 170a2a8b582SMitchell Horne struct pcb *pcb = td->td_pcb; 1713911ee2cSEd Maste 1723911ee2cSEd Maste memset(regs, 0, sizeof(*regs)); 1733911ee2cSEd Maste regs->tf_sp = stack; 1743911ee2cSEd Maste regs->tf_elr = imgp->entry_addr; 175a2a8b582SMitchell Horne pcb->pcb_tpidr_el0 = 0; 176a2a8b582SMitchell Horne pcb->pcb_tpidrro_el0 = 0; 1770723b409SJohn Baldwin WRITE_SPECIALREG(tpidrro_el0, 0); 1780723b409SJohn Baldwin WRITE_SPECIALREG(tpidr_el0, 0); 1790723b409SJohn Baldwin 180953a7d7cSAlex Richardson #ifdef VFP 181a2a8b582SMitchell Horne vfp_reset_state(td, pcb); 182953a7d7cSAlex Richardson #endif 183a2a8b582SMitchell Horne 184a2a8b582SMitchell Horne /* 185a2a8b582SMitchell Horne * Clear debug register state. It is not applicable to the new process. 186a2a8b582SMitchell Horne */ 187a2a8b582SMitchell Horne bzero(&pcb->pcb_dbg_regs, sizeof(pcb->pcb_dbg_regs)); 1883911ee2cSEd Maste } 1893911ee2cSEd Maste 1903911ee2cSEd Maste int 1913911ee2cSEd Maste linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args) 1923911ee2cSEd Maste { 193c56480a8SDmitry Chagin struct l_sigframe *frame; 194c56480a8SDmitry Chagin ucontext_t uc; 195ccc510b4SEdward Tomasz Napierala struct trapframe *tf; 196ccc510b4SEdward Tomasz Napierala int error; 1973911ee2cSEd Maste 198ccc510b4SEdward Tomasz Napierala tf = td->td_frame; 199c56480a8SDmitry Chagin frame = (struct l_sigframe *)tf->tf_sp; 200ccc510b4SEdward Tomasz Napierala 201c56480a8SDmitry Chagin if (copyin((void *)&frame->uc, &uc, sizeof(uc))) 202ccc510b4SEdward Tomasz Napierala return (EFAULT); 203ccc510b4SEdward Tomasz Napierala 204c56480a8SDmitry Chagin error = set_mcontext(td, &uc.uc_mcontext); 205ccc510b4SEdward Tomasz Napierala if (error != 0) 206ccc510b4SEdward Tomasz Napierala return (error); 207ccc510b4SEdward Tomasz Napierala 208ccc510b4SEdward Tomasz Napierala /* Restore signal mask. */ 209c56480a8SDmitry Chagin kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0); 210ccc510b4SEdward Tomasz Napierala 211ccc510b4SEdward Tomasz Napierala return (EJUSTRETURN); 2123911ee2cSEd Maste } 2133911ee2cSEd Maste 2143911ee2cSEd Maste static void 2153911ee2cSEd Maste linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) 2163911ee2cSEd Maste { 217ccc510b4SEdward Tomasz Napierala struct thread *td; 218ccc510b4SEdward Tomasz Napierala struct proc *p; 219ccc510b4SEdward Tomasz Napierala struct trapframe *tf; 220c56480a8SDmitry Chagin struct l_sigframe *fp, *frame; 221c56480a8SDmitry Chagin struct l_fpsimd_context *fpsimd; 222c56480a8SDmitry Chagin struct l_esr_context *esr; 223c56480a8SDmitry Chagin l_stack_t uc_stack; 224c56480a8SDmitry Chagin ucontext_t uc; 225c56480a8SDmitry Chagin uint8_t *scr; 226ccc510b4SEdward Tomasz Napierala struct sigacts *psp; 227109fd18aSDmitry Chagin int onstack, sig, issiginfo; 2283911ee2cSEd Maste 229ccc510b4SEdward Tomasz Napierala td = curthread; 230ccc510b4SEdward Tomasz Napierala p = td->td_proc; 231ccc510b4SEdward Tomasz Napierala PROC_LOCK_ASSERT(p, MA_OWNED); 232ccc510b4SEdward Tomasz Napierala 233ccc510b4SEdward Tomasz Napierala sig = ksi->ksi_signo; 234ccc510b4SEdward Tomasz Napierala psp = p->p_sigacts; 235ccc510b4SEdward Tomasz Napierala mtx_assert(&psp->ps_mtx, MA_OWNED); 236ccc510b4SEdward Tomasz Napierala 237ccc510b4SEdward Tomasz Napierala tf = td->td_frame; 238ccc510b4SEdward Tomasz Napierala onstack = sigonstack(tf->tf_sp); 239109fd18aSDmitry Chagin issiginfo = SIGISMEMBER(psp->ps_siginfo, sig); 240ccc510b4SEdward Tomasz Napierala 241ccc510b4SEdward Tomasz Napierala CTR4(KTR_SIG, "sendsig: td=%p (%s) catcher=%p sig=%d", td, p->p_comm, 242ccc510b4SEdward Tomasz Napierala catcher, sig); 243ccc510b4SEdward Tomasz Napierala 244ccc510b4SEdward Tomasz Napierala /* Allocate and validate space for the signal handler context. */ 245ccc510b4SEdward Tomasz Napierala if ((td->td_pflags & TDP_ALTSTACK) != 0 && !onstack && 246ccc510b4SEdward Tomasz Napierala SIGISMEMBER(psp->ps_sigonstack, sig)) { 247ccc510b4SEdward Tomasz Napierala fp = (struct l_sigframe *)((uintptr_t)td->td_sigstk.ss_sp + 248ccc510b4SEdward Tomasz Napierala td->td_sigstk.ss_size); 249ccc510b4SEdward Tomasz Napierala #if defined(COMPAT_43) 250ccc510b4SEdward Tomasz Napierala td->td_sigstk.ss_flags |= SS_ONSTACK; 251ccc510b4SEdward Tomasz Napierala #endif 252ccc510b4SEdward Tomasz Napierala } else { 253ccc510b4SEdward Tomasz Napierala fp = (struct l_sigframe *)td->td_frame->tf_sp; 254ccc510b4SEdward Tomasz Napierala } 255ccc510b4SEdward Tomasz Napierala 256ccc510b4SEdward Tomasz Napierala /* Make room, keeping the stack aligned */ 257ccc510b4SEdward Tomasz Napierala fp--; 258ccc510b4SEdward Tomasz Napierala fp = (struct l_sigframe *)STACKALIGN(fp); 259ccc510b4SEdward Tomasz Napierala 260c56480a8SDmitry Chagin get_mcontext(td, &uc.uc_mcontext, 0); 261c56480a8SDmitry Chagin uc.uc_sigmask = *mask; 262ccc510b4SEdward Tomasz Napierala 263c56480a8SDmitry Chagin uc_stack.ss_sp = PTROUT(td->td_sigstk.ss_sp); 264c56480a8SDmitry Chagin uc_stack.ss_size = td->td_sigstk.ss_size; 265c56480a8SDmitry Chagin uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) != 0 ? 266c56480a8SDmitry Chagin (onstack ? LINUX_SS_ONSTACK : 0) : LINUX_SS_DISABLE; 267ccc510b4SEdward Tomasz Napierala mtx_unlock(&psp->ps_mtx); 268ccc510b4SEdward Tomasz Napierala PROC_UNLOCK(td->td_proc); 269ccc510b4SEdward Tomasz Napierala 270c56480a8SDmitry Chagin /* Fill in the frame to copy out */ 271c56480a8SDmitry Chagin frame = malloc(sizeof(*frame), M_LINUX, M_WAITOK | M_ZERO); 272c56480a8SDmitry Chagin 273c56480a8SDmitry Chagin memcpy(&frame->sf.sf_uc.uc_sc.regs, tf->tf_x, sizeof(tf->tf_x)); 274c56480a8SDmitry Chagin frame->sf.sf_uc.uc_sc.regs[30] = tf->tf_lr; 275c56480a8SDmitry Chagin frame->sf.sf_uc.uc_sc.sp = tf->tf_sp; 276bf3a14b4SDmitry Chagin frame->sf.sf_uc.uc_sc.pc = tf->tf_elr; 277c56480a8SDmitry Chagin frame->sf.sf_uc.uc_sc.pstate = tf->tf_spsr; 278c56480a8SDmitry Chagin frame->sf.sf_uc.uc_sc.fault_address = (register_t)ksi->ksi_addr; 279c56480a8SDmitry Chagin 280c56480a8SDmitry Chagin /* Stack frame for unwinding */ 281c56480a8SDmitry Chagin frame->fp = tf->tf_x[29]; 2822cdeb89eSDmitry Chagin frame->lr = tf->tf_elr; 283c56480a8SDmitry Chagin 284c56480a8SDmitry Chagin /* Translate the signal. */ 285c56480a8SDmitry Chagin sig = bsd_to_linux_signal(sig); 286c56480a8SDmitry Chagin siginfo_to_lsiginfo(&ksi->ksi_info, &frame->sf.sf_si, sig); 287c56480a8SDmitry Chagin bsd_to_linux_sigset(mask, &frame->sf.sf_uc.uc_sigmask); 288c56480a8SDmitry Chagin 289c56480a8SDmitry Chagin /* 290c56480a8SDmitry Chagin * Prepare fpsimd & esr. Does not check sizes, as 291c56480a8SDmitry Chagin * __reserved is big enougth. 292c56480a8SDmitry Chagin */ 293c56480a8SDmitry Chagin scr = (uint8_t *)&frame->sf.sf_uc.uc_sc.__reserved; 294c56480a8SDmitry Chagin #ifdef VFP 295c56480a8SDmitry Chagin fpsimd = (struct l_fpsimd_context *) scr; 296c56480a8SDmitry Chagin fpsimd->head.magic = L_FPSIMD_MAGIC; 297c56480a8SDmitry Chagin fpsimd->head.size = sizeof(struct l_fpsimd_context); 298c56480a8SDmitry Chagin fpsimd->fpsr = uc.uc_mcontext.mc_fpregs.fp_sr; 299c56480a8SDmitry Chagin fpsimd->fpcr = uc.uc_mcontext.mc_fpregs.fp_cr; 300c56480a8SDmitry Chagin 301c56480a8SDmitry Chagin memcpy(fpsimd->vregs, &uc.uc_mcontext.mc_fpregs.fp_q, 302c56480a8SDmitry Chagin sizeof(uc.uc_mcontext.mc_fpregs.fp_q)); 303c56480a8SDmitry Chagin scr += roundup(sizeof(struct l_fpsimd_context), 16); 304c56480a8SDmitry Chagin #endif 305c56480a8SDmitry Chagin if (ksi->ksi_addr != 0) { 306c56480a8SDmitry Chagin esr = (struct l_esr_context *) scr; 307c56480a8SDmitry Chagin esr->head.magic = L_ESR_MAGIC; 308c56480a8SDmitry Chagin esr->head.size = sizeof(struct l_esr_context); 309c56480a8SDmitry Chagin esr->esr = tf->tf_esr; 310c56480a8SDmitry Chagin } 311c56480a8SDmitry Chagin 312c56480a8SDmitry Chagin memcpy(&frame->sf.sf_uc.uc_stack, &uc_stack, sizeof(uc_stack)); 313c56480a8SDmitry Chagin memcpy(&frame->uc, &uc, sizeof(uc)); 314c56480a8SDmitry Chagin 315ccc510b4SEdward Tomasz Napierala /* Copy the sigframe out to the user's stack. */ 316c56480a8SDmitry Chagin if (copyout(frame, fp, sizeof(*fp)) != 0) { 317ccc510b4SEdward Tomasz Napierala /* Process has trashed its stack. Kill it. */ 318c56480a8SDmitry Chagin free(frame, M_LINUX); 319ccc510b4SEdward Tomasz Napierala CTR2(KTR_SIG, "sendsig: sigexit td=%p fp=%p", td, fp); 320ccc510b4SEdward Tomasz Napierala PROC_LOCK(p); 321ccc510b4SEdward Tomasz Napierala sigexit(td, SIGILL); 322ccc510b4SEdward Tomasz Napierala } 323c56480a8SDmitry Chagin free(frame, M_LINUX); 324ccc510b4SEdward Tomasz Napierala 325ccc510b4SEdward Tomasz Napierala tf->tf_x[0]= sig; 326109fd18aSDmitry Chagin if (issiginfo) { 327c56480a8SDmitry Chagin tf->tf_x[1] = (register_t)&fp->sf.sf_si; 328c56480a8SDmitry Chagin tf->tf_x[2] = (register_t)&fp->sf.sf_uc; 329109fd18aSDmitry Chagin } else { 330109fd18aSDmitry Chagin tf->tf_x[1] = 0; 331109fd18aSDmitry Chagin tf->tf_x[2] = 0; 332109fd18aSDmitry Chagin } 3332cdeb89eSDmitry Chagin tf->tf_x[29] = (register_t)&fp->fp; 334d957343fSDmitry Chagin tf->tf_elr = (register_t)catcher; 335ccc510b4SEdward Tomasz Napierala tf->tf_sp = (register_t)fp; 336d957343fSDmitry Chagin tf->tf_lr = (register_t)__user_rt_sigreturn; 337ccc510b4SEdward Tomasz Napierala 338ccc510b4SEdward Tomasz Napierala CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_elr, 339ccc510b4SEdward Tomasz Napierala tf->tf_sp); 340ccc510b4SEdward Tomasz Napierala 341ccc510b4SEdward Tomasz Napierala PROC_LOCK(p); 342ccc510b4SEdward Tomasz Napierala mtx_lock(&psp->ps_mtx); 3433911ee2cSEd Maste } 3443911ee2cSEd Maste 3453911ee2cSEd Maste struct sysentvec elf_linux_sysvec = { 3463911ee2cSEd Maste .sv_size = LINUX_SYS_MAXSYSCALL, 3473911ee2cSEd Maste .sv_table = linux_sysent, 3486039e966SDmitry Chagin .sv_fixup = __elfN(freebsd_fixup), 3493911ee2cSEd Maste .sv_sendsig = linux_rt_sendsig, 3509931033bSDmitry Chagin .sv_sigcode = &_binary_linux_vdso_so_o_start, 3513911ee2cSEd Maste .sv_szsigcode = &linux_szsigcode, 3523911ee2cSEd Maste .sv_name = "Linux ELF64", 3533911ee2cSEd Maste .sv_coredump = elf64_coredump, 354435754a5SEdward Tomasz Napierala .sv_elf_core_osabi = ELFOSABI_NONE, 35545d99014SEdward Tomasz Napierala .sv_elf_core_abi_vendor = LINUX_ABI_VENDOR, 35645d99014SEdward Tomasz Napierala .sv_elf_core_prepare_notes = linux64_prepare_notes, 3573911ee2cSEd Maste .sv_minsigstksz = LINUX_MINSIGSTKSZ, 3583911ee2cSEd Maste .sv_minuser = VM_MIN_ADDRESS, 3593911ee2cSEd Maste .sv_maxuser = VM_MAXUSER_ADDRESS, 3609931033bSDmitry Chagin .sv_usrstack = LINUX_USRSTACK, 3619931033bSDmitry Chagin .sv_psstrings = LINUX_PS_STRINGS, 3623fc21fddSMark Johnston .sv_psstringssz = sizeof(struct ps_strings), 363d4f55cc8SEd Maste .sv_stackprot = VM_PROT_READ | VM_PROT_WRITE, 3647d8c9839SDmitry Chagin .sv_copyout_auxargs = __linuxN(copyout_auxargs), 3656039e966SDmitry Chagin .sv_copyout_strings = __linuxN(copyout_strings), 3663911ee2cSEd Maste .sv_setregs = linux_exec_setregs, 3673911ee2cSEd Maste .sv_fixlimit = NULL, 3683911ee2cSEd Maste .sv_maxssiz = NULL, 369870e197dSKonstantin Belousov .sv_flags = SV_ABI_LINUX | SV_LP64 | SV_SHP | SV_SIG_DISCIGN | 3709931033bSDmitry Chagin SV_SIG_WAITNDQ | SV_TIMEKEEP, 3713911ee2cSEd Maste .sv_set_syscall_retval = linux_set_syscall_retval, 3723911ee2cSEd Maste .sv_fetch_syscall_args = linux_fetch_syscall_args, 3731da65dcbSMitchell Horne .sv_syscallnames = linux_syscallnames, 3749931033bSDmitry Chagin .sv_shared_page_base = LINUX_SHAREDPAGE, 3753911ee2cSEd Maste .sv_shared_page_len = PAGE_SIZE, 3763911ee2cSEd Maste .sv_schedtail = linux_schedtail, 3773911ee2cSEd Maste .sv_thread_detach = linux_thread_detach, 37884a3963dSEdward Tomasz Napierala .sv_trap = NULL, 379b501b2aeSEdward Tomasz Napierala .sv_hwcap = &elf_hwcap, 380b501b2aeSEdward Tomasz Napierala .sv_hwcap2 = &elf_hwcap2, 3815fd9cd53SDmitry Chagin .sv_onexec = linux_on_exec_vmspace, 3824815f175SKonstantin Belousov .sv_onexit = linux_on_exit, 3834815f175SKonstantin Belousov .sv_ontdexit = linux_thread_dtor, 384598f6fb4SKonstantin Belousov .sv_setid_allowed = &linux_setid_allowed_query, 3853911ee2cSEd Maste }; 3863911ee2cSEd Maste 3875fd9cd53SDmitry Chagin static int 3885fd9cd53SDmitry Chagin linux_on_exec_vmspace(struct proc *p, struct image_params *imgp) 3895fd9cd53SDmitry Chagin { 3909931033bSDmitry Chagin int error; 3915fd9cd53SDmitry Chagin 3929931033bSDmitry Chagin error = linux_map_vdso(p, linux_vdso_obj, linux_vdso_base, 3939931033bSDmitry Chagin LINUX_VDSOPAGE_SIZE, imgp); 3949931033bSDmitry Chagin if (error == 0) 395fd745e1dSDmitry Chagin error = linux_on_exec(p, imgp); 3969931033bSDmitry Chagin return (error); 3975fd9cd53SDmitry Chagin } 3985fd9cd53SDmitry Chagin 39909cffde9SDmitry Chagin /* 40009cffde9SDmitry Chagin * linux_vdso_install() and linux_exec_sysvec_init() must be called 40109cffde9SDmitry Chagin * after exec_sysvec_init() which is SI_SUB_EXEC (SI_ORDER_ANY). 40209cffde9SDmitry Chagin */ 4033911ee2cSEd Maste static void 4049931033bSDmitry Chagin linux_exec_sysvec_init(void *param) 4059931033bSDmitry Chagin { 4069931033bSDmitry Chagin l_uintptr_t *ktimekeep_base; 4079931033bSDmitry Chagin struct sysentvec *sv; 4089931033bSDmitry Chagin ptrdiff_t tkoff; 4099931033bSDmitry Chagin 4109931033bSDmitry Chagin sv = param; 4119931033bSDmitry Chagin /* Fill timekeep_base */ 4129931033bSDmitry Chagin exec_sysvec_init(sv); 4139931033bSDmitry Chagin 4149931033bSDmitry Chagin tkoff = kern_timekeep_base - linux_vdso_base; 4159931033bSDmitry Chagin ktimekeep_base = (l_uintptr_t *)(linux_vdso_mapping + tkoff); 416361971fbSKornel Dulęba *ktimekeep_base = sv->sv_shared_page_base + sv->sv_timekeep_offset; 4179931033bSDmitry Chagin } 41809cffde9SDmitry Chagin SYSINIT(elf_linux_exec_sysvec_init, SI_SUB_EXEC + 1, SI_ORDER_ANY, 4199931033bSDmitry Chagin linux_exec_sysvec_init, &elf_linux_sysvec); 4209931033bSDmitry Chagin 4219931033bSDmitry Chagin static void 4223911ee2cSEd Maste linux_vdso_install(const void *param) 4233911ee2cSEd Maste { 4249931033bSDmitry Chagin char *vdso_start = &_binary_linux_vdso_so_o_start; 4259931033bSDmitry Chagin char *vdso_end = &_binary_linux_vdso_so_o_end; 4263911ee2cSEd Maste 4279931033bSDmitry Chagin linux_szsigcode = vdso_end - vdso_start; 4289931033bSDmitry Chagin MPASS(linux_szsigcode <= LINUX_VDSOPAGE_SIZE); 4293911ee2cSEd Maste 4309931033bSDmitry Chagin linux_vdso_base = LINUX_VDSOPAGE; 4313911ee2cSEd Maste 4329931033bSDmitry Chagin __elfN(linux_vdso_fixup)(vdso_start, linux_vdso_base); 4333911ee2cSEd Maste 4349931033bSDmitry Chagin linux_vdso_obj = __elfN(linux_shared_page_init) 4359931033bSDmitry Chagin (&linux_vdso_mapping, LINUX_VDSOPAGE_SIZE); 4369931033bSDmitry Chagin bcopy(vdso_start, linux_vdso_mapping, linux_szsigcode); 4373911ee2cSEd Maste 4389931033bSDmitry Chagin linux_vdso_reloc(linux_vdso_mapping, linux_vdso_base); 4393911ee2cSEd Maste } 44009cffde9SDmitry Chagin SYSINIT(elf_linux_vdso_init, SI_SUB_EXEC + 1, SI_ORDER_FIRST, 4413911ee2cSEd Maste linux_vdso_install, NULL); 4423911ee2cSEd Maste 4433911ee2cSEd Maste static void 4443911ee2cSEd Maste linux_vdso_deinstall(const void *param) 4453911ee2cSEd Maste { 4463911ee2cSEd Maste 4479931033bSDmitry Chagin __elfN(linux_shared_page_fini)(linux_vdso_obj, 4489931033bSDmitry Chagin linux_vdso_mapping, LINUX_VDSOPAGE_SIZE); 4493911ee2cSEd Maste } 4503911ee2cSEd Maste SYSUNINIT(elf_linux_vdso_uninit, SI_SUB_EXEC, SI_ORDER_FIRST, 4513911ee2cSEd Maste linux_vdso_deinstall, NULL); 4523911ee2cSEd Maste 4539931033bSDmitry Chagin static void 4549931033bSDmitry Chagin linux_vdso_reloc(char *mapping, Elf_Addr offset) 4559931033bSDmitry Chagin { 4569931033bSDmitry Chagin Elf_Size rtype, symidx; 4579931033bSDmitry Chagin const Elf_Rela *rela; 4589931033bSDmitry Chagin const Elf_Shdr *shdr; 4599931033bSDmitry Chagin const Elf_Ehdr *ehdr; 4609931033bSDmitry Chagin Elf_Addr *where; 4619931033bSDmitry Chagin Elf_Addr addr, addend; 4629931033bSDmitry Chagin int i, relacnt; 4639931033bSDmitry Chagin 4649931033bSDmitry Chagin MPASS(offset != 0); 4659931033bSDmitry Chagin 4669931033bSDmitry Chagin relacnt = 0; 4679931033bSDmitry Chagin ehdr = (const Elf_Ehdr *)mapping; 4689931033bSDmitry Chagin shdr = (const Elf_Shdr *)(mapping + ehdr->e_shoff); 4699931033bSDmitry Chagin for (i = 0; i < ehdr->e_shnum; i++) 4709931033bSDmitry Chagin { 4719931033bSDmitry Chagin switch (shdr[i].sh_type) { 4729931033bSDmitry Chagin case SHT_REL: 4739931033bSDmitry Chagin printf("Linux Aarch64 vDSO: unexpected Rel section\n"); 4749931033bSDmitry Chagin break; 4759931033bSDmitry Chagin case SHT_RELA: 4769931033bSDmitry Chagin rela = (const Elf_Rela *)(mapping + shdr[i].sh_offset); 4779931033bSDmitry Chagin relacnt = shdr[i].sh_size / sizeof(*rela); 4789931033bSDmitry Chagin } 4799931033bSDmitry Chagin } 4809931033bSDmitry Chagin 4819931033bSDmitry Chagin for (i = 0; i < relacnt; i++, rela++) { 4829931033bSDmitry Chagin where = (Elf_Addr *)(mapping + rela->r_offset); 4839931033bSDmitry Chagin addend = rela->r_addend; 4849931033bSDmitry Chagin rtype = ELF_R_TYPE(rela->r_info); 4859931033bSDmitry Chagin symidx = ELF_R_SYM(rela->r_info); 4869931033bSDmitry Chagin 4879931033bSDmitry Chagin switch (rtype) { 4889931033bSDmitry Chagin case R_AARCH64_NONE: /* none */ 4899931033bSDmitry Chagin break; 4909931033bSDmitry Chagin 4919931033bSDmitry Chagin case R_AARCH64_RELATIVE: /* B + A */ 4929931033bSDmitry Chagin addr = (Elf_Addr)(mapping + addend); 4939931033bSDmitry Chagin if (*where != addr) 4949931033bSDmitry Chagin *where = addr; 4959931033bSDmitry Chagin break; 4969931033bSDmitry Chagin default: 4979931033bSDmitry Chagin printf("Linux Aarch64 vDSO: unexpected relocation type %ld, " 4989931033bSDmitry Chagin "symbol index %ld\n", rtype, symidx); 4999931033bSDmitry Chagin } 5009931033bSDmitry Chagin } 5019931033bSDmitry Chagin } 5029931033bSDmitry Chagin 5033911ee2cSEd Maste static Elf_Brandnote linux64_brandnote = { 5043911ee2cSEd Maste .hdr.n_namesz = sizeof(GNU_ABI_VENDOR), 5053911ee2cSEd Maste .hdr.n_descsz = 16, 5063911ee2cSEd Maste .hdr.n_type = 1, 5073911ee2cSEd Maste .vendor = GNU_ABI_VENDOR, 5083911ee2cSEd Maste .flags = BN_TRANSLATE_OSREL, 5093911ee2cSEd Maste .trans_osrel = linux_trans_osrel 5103911ee2cSEd Maste }; 5113911ee2cSEd Maste 5123911ee2cSEd Maste static Elf64_Brandinfo linux_glibc2brand = { 5133911ee2cSEd Maste .brand = ELFOSABI_LINUX, 5143911ee2cSEd Maste .machine = EM_AARCH64, 5153911ee2cSEd Maste .compat_3_brand = "Linux", 5163911ee2cSEd Maste .interp_path = "/lib64/ld-linux-x86-64.so.2", 5173911ee2cSEd Maste .sysvec = &elf_linux_sysvec, 5183911ee2cSEd Maste .interp_newpath = NULL, 5193911ee2cSEd Maste .brand_note = &linux64_brandnote, 5203911ee2cSEd Maste .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE 5213911ee2cSEd Maste }; 5223911ee2cSEd Maste 5233911ee2cSEd Maste Elf64_Brandinfo *linux_brandlist[] = { 5243911ee2cSEd Maste &linux_glibc2brand, 5253911ee2cSEd Maste NULL 5263911ee2cSEd Maste }; 5273911ee2cSEd Maste 5283911ee2cSEd Maste static int 5293911ee2cSEd Maste linux64_elf_modevent(module_t mod, int type, void *data) 5303911ee2cSEd Maste { 5313911ee2cSEd Maste Elf64_Brandinfo **brandinfo; 5323911ee2cSEd Maste struct linux_ioctl_handler**lihp; 5333911ee2cSEd Maste int error; 5343911ee2cSEd Maste 5353911ee2cSEd Maste error = 0; 5363911ee2cSEd Maste switch(type) { 5373911ee2cSEd Maste case MOD_LOAD: 5383911ee2cSEd Maste for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; 5393911ee2cSEd Maste ++brandinfo) 5403911ee2cSEd Maste if (elf64_insert_brand_entry(*brandinfo) < 0) 5413911ee2cSEd Maste error = EINVAL; 5423911ee2cSEd Maste if (error == 0) { 5433911ee2cSEd Maste SET_FOREACH(lihp, linux_ioctl_handler_set) 5443911ee2cSEd Maste linux_ioctl_register_handler(*lihp); 5453911ee2cSEd Maste stclohz = (stathz ? stathz : hz); 5463911ee2cSEd Maste if (bootverbose) 5473911ee2cSEd Maste printf("Linux arm64 ELF exec handler installed\n"); 5483911ee2cSEd Maste } 5493911ee2cSEd Maste break; 5503911ee2cSEd Maste case MOD_UNLOAD: 5513911ee2cSEd Maste for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; 5523911ee2cSEd Maste ++brandinfo) 5533911ee2cSEd Maste if (elf64_brand_inuse(*brandinfo)) 5543911ee2cSEd Maste error = EBUSY; 5553911ee2cSEd Maste if (error == 0) { 5563911ee2cSEd Maste for (brandinfo = &linux_brandlist[0]; 5573911ee2cSEd Maste *brandinfo != NULL; ++brandinfo) 5583911ee2cSEd Maste if (elf64_remove_brand_entry(*brandinfo) < 0) 5593911ee2cSEd Maste error = EINVAL; 5603911ee2cSEd Maste } 5613911ee2cSEd Maste if (error == 0) { 5623911ee2cSEd Maste SET_FOREACH(lihp, linux_ioctl_handler_set) 5633911ee2cSEd Maste linux_ioctl_unregister_handler(*lihp); 5643911ee2cSEd Maste if (bootverbose) 565ae8330b4SDmitry Chagin printf("Linux arm64 ELF exec handler removed\n"); 5663911ee2cSEd Maste } else 567ae8330b4SDmitry Chagin printf("Could not deinstall Linux arm64 ELF interpreter entry\n"); 5683911ee2cSEd Maste break; 5693911ee2cSEd Maste default: 5703911ee2cSEd Maste return (EOPNOTSUPP); 5713911ee2cSEd Maste } 5723911ee2cSEd Maste return (error); 5733911ee2cSEd Maste } 5743911ee2cSEd Maste 5753911ee2cSEd Maste static moduledata_t linux64_elf_mod = { 5763911ee2cSEd Maste "linux64elf", 5773911ee2cSEd Maste linux64_elf_modevent, 5783911ee2cSEd Maste 0 5793911ee2cSEd Maste }; 5803911ee2cSEd Maste 5813911ee2cSEd Maste DECLARE_MODULE_TIED(linux64elf, linux64_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY); 5823911ee2cSEd Maste MODULE_DEPEND(linux64elf, linux_common, 1, 1, 1); 5833911ee2cSEd Maste FEATURE(linux64, "AArch64 Linux 64bit support"); 584