13911ee2cSEd Maste /*- 23911ee2cSEd Maste * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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 293911ee2cSEd Maste #include <sys/cdefs.h> 303911ee2cSEd Maste __FBSDID("$FreeBSD$"); 313911ee2cSEd Maste 3274465145SDmitry Chagin #define __ELF_WORD_SIZE 64 3374465145SDmitry Chagin 343911ee2cSEd Maste #include <sys/param.h> 353911ee2cSEd Maste #include <sys/elf.h> 363911ee2cSEd Maste #include <sys/exec.h> 373911ee2cSEd Maste #include <sys/imgact.h> 383911ee2cSEd Maste #include <sys/imgact_elf.h> 393911ee2cSEd Maste #include <sys/kernel.h> 40ccc510b4SEdward Tomasz Napierala #include <sys/ktr.h> 413911ee2cSEd Maste #include <sys/lock.h> 423911ee2cSEd Maste #include <sys/module.h> 433911ee2cSEd Maste #include <sys/mutex.h> 443911ee2cSEd Maste #include <sys/proc.h> 459931033bSDmitry Chagin #include <sys/stddef.h> 46ccc510b4SEdward Tomasz Napierala #include <sys/syscallsubr.h> 473911ee2cSEd Maste #include <sys/sysctl.h> 483911ee2cSEd Maste #include <sys/sysent.h> 493911ee2cSEd Maste 509931033bSDmitry Chagin #include <vm/pmap.h> 5155d3e181SDmitry Chagin #include <vm/vm.h> 529931033bSDmitry Chagin #include <vm/vm_map.h> 539931033bSDmitry Chagin #include <vm/vm_page.h> 543911ee2cSEd Maste 553911ee2cSEd Maste #include <arm64/linux/linux.h> 563911ee2cSEd Maste #include <arm64/linux/linux_proto.h> 573911ee2cSEd Maste #include <compat/linux/linux_dtrace.h> 5874465145SDmitry Chagin #include <compat/linux/linux_elf.h> 593911ee2cSEd Maste #include <compat/linux/linux_emul.h> 600a4b664aSDmitry Chagin #include <compat/linux/linux_fork.h> 613911ee2cSEd Maste #include <compat/linux/linux_ioctl.h> 623911ee2cSEd Maste #include <compat/linux/linux_mib.h> 633911ee2cSEd Maste #include <compat/linux/linux_misc.h> 64ccc510b4SEdward Tomasz Napierala #include <compat/linux/linux_signal.h> 65b5f20658SEdward Tomasz Napierala #include <compat/linux/linux_util.h> 663911ee2cSEd Maste #include <compat/linux/linux_vdso.h> 673911ee2cSEd Maste 6821f24617SDmitry Chagin #include <arm64/linux/linux_sigframe.h> 6921f24617SDmitry Chagin 70b501b2aeSEdward Tomasz Napierala #include <machine/md_var.h> 712555f175SKonstantin Belousov #include <machine/pcb.h> 72953a7d7cSAlex Richardson #ifdef VFP 73953a7d7cSAlex Richardson #include <machine/vfp.h> 74953a7d7cSAlex Richardson #endif 75953a7d7cSAlex Richardson 763911ee2cSEd Maste MODULE_VERSION(linux64elf, 1); 773911ee2cSEd Maste 789931033bSDmitry Chagin #define LINUX_VDSOPAGE_SIZE PAGE_SIZE * 2 799931033bSDmitry Chagin #define LINUX_VDSOPAGE (VM_MAXUSER_ADDRESS - \ 809931033bSDmitry Chagin LINUX_VDSOPAGE_SIZE) 819931033bSDmitry Chagin #define LINUX_SHAREDPAGE (LINUX_VDSOPAGE - PAGE_SIZE) 829931033bSDmitry Chagin /* 839931033bSDmitry Chagin * PAGE_SIZE - the size 849931033bSDmitry Chagin * of the native SHAREDPAGE 859931033bSDmitry Chagin */ 869931033bSDmitry Chagin #define LINUX_USRSTACK LINUX_SHAREDPAGE 879931033bSDmitry Chagin #define LINUX_PS_STRINGS (LINUX_USRSTACK - \ 889931033bSDmitry Chagin sizeof(struct ps_strings)) 899931033bSDmitry Chagin 903911ee2cSEd Maste static int linux_szsigcode; 919931033bSDmitry Chagin static vm_object_t linux_vdso_obj; 929931033bSDmitry Chagin static char *linux_vdso_mapping; 939931033bSDmitry Chagin extern char _binary_linux_vdso_so_o_start; 949931033bSDmitry Chagin extern char _binary_linux_vdso_so_o_end; 959931033bSDmitry Chagin static vm_offset_t linux_vdso_base; 963911ee2cSEd Maste 973911ee2cSEd Maste extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL]; 981da65dcbSMitchell Horne extern const char *linux_syscallnames[]; 993911ee2cSEd Maste 1003911ee2cSEd Maste SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler); 1013911ee2cSEd Maste 1023911ee2cSEd Maste static void linux_vdso_install(const void *param); 1033911ee2cSEd Maste static void linux_vdso_deinstall(const void *param); 1049931033bSDmitry Chagin static void linux_vdso_reloc(char *mapping, Elf_Addr offset); 1053911ee2cSEd Maste static void linux_set_syscall_retval(struct thread *td, int error); 1063911ee2cSEd Maste static int linux_fetch_syscall_args(struct thread *td); 1073911ee2cSEd Maste static void linux_exec_setregs(struct thread *td, struct image_params *imgp, 10831174518SJohn Baldwin uintptr_t stack); 1099931033bSDmitry Chagin static void linux_exec_sysvec_init(void *param); 1105fd9cd53SDmitry Chagin static int linux_on_exec_vmspace(struct proc *p, 1115fd9cd53SDmitry Chagin struct image_params *imgp); 1123911ee2cSEd Maste 1133911ee2cSEd Maste /* DTrace init */ 1143911ee2cSEd Maste LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); 1153911ee2cSEd Maste 1163911ee2cSEd Maste /* DTrace probes */ 1173911ee2cSEd Maste LIN_SDT_PROBE_DEFINE0(sysvec, linux_exec_setregs, todo); 1183911ee2cSEd Maste 1199931033bSDmitry Chagin LINUX_VDSO_SYM_CHAR(linux_platform); 1209931033bSDmitry Chagin LINUX_VDSO_SYM_INTPTR(kern_timekeep_base); 121c56480a8SDmitry Chagin LINUX_VDSO_SYM_INTPTR(linux_vdso_sigcode); 1229931033bSDmitry Chagin 1233911ee2cSEd Maste static int 1243911ee2cSEd Maste linux_fetch_syscall_args(struct thread *td) 1253911ee2cSEd Maste { 1263911ee2cSEd Maste struct proc *p; 1273911ee2cSEd Maste struct syscall_args *sa; 1283911ee2cSEd Maste register_t *ap; 1293911ee2cSEd Maste 1303911ee2cSEd Maste p = td->td_proc; 1313911ee2cSEd Maste ap = td->td_frame->tf_x; 1323911ee2cSEd Maste sa = &td->td_sa; 1333911ee2cSEd Maste 1343911ee2cSEd Maste sa->code = td->td_frame->tf_x[8]; 135cf98bc28SDavid Chisnall sa->original_code = sa->code; 1363911ee2cSEd Maste /* LINUXTODO: generic syscall? */ 1373911ee2cSEd Maste if (sa->code >= p->p_sysent->sv_size) 1383911ee2cSEd Maste sa->callp = &p->p_sysent->sv_table[0]; 1393911ee2cSEd Maste else 1403911ee2cSEd Maste sa->callp = &p->p_sysent->sv_table[sa->code]; 1413911ee2cSEd Maste 142adb12675SBrooks Davis if (sa->callp->sy_narg > nitems(sa->args)) 143adb12675SBrooks Davis panic("ARM64TODO: Could we have more than %zu args?", 144adb12675SBrooks Davis nitems(sa->args)); 145adb12675SBrooks Davis memcpy(sa->args, ap, nitems(sa->args) * sizeof(register_t)); 1463911ee2cSEd Maste 1473911ee2cSEd Maste td->td_retval[0] = 0; 1483911ee2cSEd Maste return (0); 1493911ee2cSEd Maste } 1503911ee2cSEd Maste 1513911ee2cSEd Maste static void 1523911ee2cSEd Maste linux_set_syscall_retval(struct thread *td, int error) 1533911ee2cSEd Maste { 1543911ee2cSEd Maste 1558e5d76e6SAndrew Turner td->td_retval[1] = td->td_frame->tf_x[1]; 1568e5d76e6SAndrew Turner cpu_set_syscall_retval(td, error); 157c26391f4SEdward Tomasz Napierala 158c26391f4SEdward Tomasz Napierala if (__predict_false(error != 0)) { 159866b1f51SEdward Tomasz Napierala if (error != ERESTART && error != EJUSTRETURN) 160866b1f51SEdward Tomasz Napierala td->td_frame->tf_x[0] = bsd_to_linux_errno(error); 161c26391f4SEdward Tomasz Napierala } 1623911ee2cSEd Maste } 1633911ee2cSEd Maste 164*7d8c9839SDmitry Chagin void 165*7d8c9839SDmitry Chagin linux64_arch_copyout_auxargs(struct image_params *imgp, Elf_Auxinfo **pos) 1663911ee2cSEd Maste { 1673911ee2cSEd Maste 168*7d8c9839SDmitry Chagin AUXARGS_ENTRY((*pos), LINUX_AT_SYSINFO_EHDR, linux_vdso_base); 169*7d8c9839SDmitry Chagin AUXARGS_ENTRY((*pos), LINUX_AT_HWCAP, *imgp->sysent->sv_hwcap); 170*7d8c9839SDmitry Chagin AUXARGS_ENTRY((*pos), LINUX_AT_HWCAP2, *imgp->sysent->sv_hwcap2); 171*7d8c9839SDmitry Chagin AUXARGS_ENTRY((*pos), LINUX_AT_PLATFORM, PTROUT(linux_platform)); 1725caa67faSJohn Baldwin } 1735caa67faSJohn Baldwin 1743911ee2cSEd Maste /* 1753911ee2cSEd Maste * Reset registers to default values on exec. 1763911ee2cSEd Maste */ 1773911ee2cSEd Maste static void 17831174518SJohn Baldwin linux_exec_setregs(struct thread *td, struct image_params *imgp, 17931174518SJohn Baldwin uintptr_t stack) 1803911ee2cSEd Maste { 1813911ee2cSEd Maste struct trapframe *regs = td->td_frame; 182a2a8b582SMitchell Horne struct pcb *pcb = td->td_pcb; 1833911ee2cSEd Maste 1843911ee2cSEd Maste /* LINUXTODO: validate */ 1853911ee2cSEd Maste LIN_SDT_PROBE0(sysvec, linux_exec_setregs, todo); 1863911ee2cSEd Maste 1873911ee2cSEd Maste memset(regs, 0, sizeof(*regs)); 1883911ee2cSEd Maste /* glibc start.S registers function pointer in x0 with atexit. */ 1893911ee2cSEd Maste regs->tf_sp = stack; 1903911ee2cSEd Maste #if 0 /* LINUXTODO: See if this is used. */ 1913911ee2cSEd Maste regs->tf_lr = imgp->entry_addr; 1923911ee2cSEd Maste #else 1933911ee2cSEd Maste regs->tf_lr = 0xffffffffffffffff; 1943911ee2cSEd Maste #endif 1953911ee2cSEd Maste regs->tf_elr = imgp->entry_addr; 196953a7d7cSAlex Richardson 197a2a8b582SMitchell Horne pcb->pcb_tpidr_el0 = 0; 198a2a8b582SMitchell Horne pcb->pcb_tpidrro_el0 = 0; 1990723b409SJohn Baldwin WRITE_SPECIALREG(tpidrro_el0, 0); 2000723b409SJohn Baldwin WRITE_SPECIALREG(tpidr_el0, 0); 2010723b409SJohn Baldwin 202953a7d7cSAlex Richardson #ifdef VFP 203a2a8b582SMitchell Horne vfp_reset_state(td, pcb); 204953a7d7cSAlex Richardson #endif 205a2a8b582SMitchell Horne 206a2a8b582SMitchell Horne /* 207a2a8b582SMitchell Horne * Clear debug register state. It is not applicable to the new process. 208a2a8b582SMitchell Horne */ 209a2a8b582SMitchell Horne bzero(&pcb->pcb_dbg_regs, sizeof(pcb->pcb_dbg_regs)); 2103911ee2cSEd Maste } 2113911ee2cSEd Maste 2123911ee2cSEd Maste int 2133911ee2cSEd Maste linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args) 2143911ee2cSEd Maste { 215c56480a8SDmitry Chagin struct l_sigframe *frame; 216c56480a8SDmitry Chagin ucontext_t uc; 217ccc510b4SEdward Tomasz Napierala struct trapframe *tf; 218ccc510b4SEdward Tomasz Napierala int error; 2193911ee2cSEd Maste 220ccc510b4SEdward Tomasz Napierala tf = td->td_frame; 221c56480a8SDmitry Chagin frame = (struct l_sigframe *)tf->tf_sp; 222ccc510b4SEdward Tomasz Napierala 223c56480a8SDmitry Chagin if (copyin((void *)&frame->uc, &uc, sizeof(uc))) 224ccc510b4SEdward Tomasz Napierala return (EFAULT); 225ccc510b4SEdward Tomasz Napierala 226c56480a8SDmitry Chagin error = set_mcontext(td, &uc.uc_mcontext); 227ccc510b4SEdward Tomasz Napierala if (error != 0) 228ccc510b4SEdward Tomasz Napierala return (error); 229ccc510b4SEdward Tomasz Napierala 230ccc510b4SEdward Tomasz Napierala /* Restore signal mask. */ 231c56480a8SDmitry Chagin kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0); 232ccc510b4SEdward Tomasz Napierala 233ccc510b4SEdward Tomasz Napierala return (EJUSTRETURN); 2343911ee2cSEd Maste } 2353911ee2cSEd Maste 2363911ee2cSEd Maste static void 2373911ee2cSEd Maste linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) 2383911ee2cSEd Maste { 239ccc510b4SEdward Tomasz Napierala struct thread *td; 240ccc510b4SEdward Tomasz Napierala struct proc *p; 241ccc510b4SEdward Tomasz Napierala struct trapframe *tf; 242c56480a8SDmitry Chagin struct l_sigframe *fp, *frame; 243c56480a8SDmitry Chagin struct l_fpsimd_context *fpsimd; 244c56480a8SDmitry Chagin struct l_esr_context *esr; 245c56480a8SDmitry Chagin l_stack_t uc_stack; 246c56480a8SDmitry Chagin ucontext_t uc; 247c56480a8SDmitry Chagin uint8_t *scr; 248ccc510b4SEdward Tomasz Napierala struct sigacts *psp; 249109fd18aSDmitry Chagin int onstack, sig, issiginfo; 2503911ee2cSEd Maste 251ccc510b4SEdward Tomasz Napierala td = curthread; 252ccc510b4SEdward Tomasz Napierala p = td->td_proc; 253ccc510b4SEdward Tomasz Napierala PROC_LOCK_ASSERT(p, MA_OWNED); 254ccc510b4SEdward Tomasz Napierala 255ccc510b4SEdward Tomasz Napierala sig = ksi->ksi_signo; 256ccc510b4SEdward Tomasz Napierala psp = p->p_sigacts; 257ccc510b4SEdward Tomasz Napierala mtx_assert(&psp->ps_mtx, MA_OWNED); 258ccc510b4SEdward Tomasz Napierala 259ccc510b4SEdward Tomasz Napierala tf = td->td_frame; 260ccc510b4SEdward Tomasz Napierala onstack = sigonstack(tf->tf_sp); 261109fd18aSDmitry Chagin issiginfo = SIGISMEMBER(psp->ps_siginfo, sig); 262ccc510b4SEdward Tomasz Napierala 263ccc510b4SEdward Tomasz Napierala CTR4(KTR_SIG, "sendsig: td=%p (%s) catcher=%p sig=%d", td, p->p_comm, 264ccc510b4SEdward Tomasz Napierala catcher, sig); 265ccc510b4SEdward Tomasz Napierala 266ccc510b4SEdward Tomasz Napierala /* Allocate and validate space for the signal handler context. */ 267ccc510b4SEdward Tomasz Napierala if ((td->td_pflags & TDP_ALTSTACK) != 0 && !onstack && 268ccc510b4SEdward Tomasz Napierala SIGISMEMBER(psp->ps_sigonstack, sig)) { 269ccc510b4SEdward Tomasz Napierala fp = (struct l_sigframe *)((uintptr_t)td->td_sigstk.ss_sp + 270ccc510b4SEdward Tomasz Napierala td->td_sigstk.ss_size); 271ccc510b4SEdward Tomasz Napierala #if defined(COMPAT_43) 272ccc510b4SEdward Tomasz Napierala td->td_sigstk.ss_flags |= SS_ONSTACK; 273ccc510b4SEdward Tomasz Napierala #endif 274ccc510b4SEdward Tomasz Napierala } else { 275ccc510b4SEdward Tomasz Napierala fp = (struct l_sigframe *)td->td_frame->tf_sp; 276ccc510b4SEdward Tomasz Napierala } 277ccc510b4SEdward Tomasz Napierala 278ccc510b4SEdward Tomasz Napierala /* Make room, keeping the stack aligned */ 279ccc510b4SEdward Tomasz Napierala fp--; 280ccc510b4SEdward Tomasz Napierala fp = (struct l_sigframe *)STACKALIGN(fp); 281ccc510b4SEdward Tomasz Napierala 282c56480a8SDmitry Chagin get_mcontext(td, &uc.uc_mcontext, 0); 283c56480a8SDmitry Chagin uc.uc_sigmask = *mask; 284ccc510b4SEdward Tomasz Napierala 285c56480a8SDmitry Chagin uc_stack.ss_sp = PTROUT(td->td_sigstk.ss_sp); 286c56480a8SDmitry Chagin uc_stack.ss_size = td->td_sigstk.ss_size; 287c56480a8SDmitry Chagin uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) != 0 ? 288c56480a8SDmitry Chagin (onstack ? LINUX_SS_ONSTACK : 0) : LINUX_SS_DISABLE; 289ccc510b4SEdward Tomasz Napierala mtx_unlock(&psp->ps_mtx); 290ccc510b4SEdward Tomasz Napierala PROC_UNLOCK(td->td_proc); 291ccc510b4SEdward Tomasz Napierala 292c56480a8SDmitry Chagin /* Fill in the frame to copy out */ 293c56480a8SDmitry Chagin frame = malloc(sizeof(*frame), M_LINUX, M_WAITOK | M_ZERO); 294c56480a8SDmitry Chagin 295c56480a8SDmitry Chagin memcpy(&frame->sf.sf_uc.uc_sc.regs, tf->tf_x, sizeof(tf->tf_x)); 296c56480a8SDmitry Chagin frame->sf.sf_uc.uc_sc.regs[30] = tf->tf_lr; 297c56480a8SDmitry Chagin frame->sf.sf_uc.uc_sc.sp = tf->tf_sp; 298c56480a8SDmitry Chagin frame->sf.sf_uc.uc_sc.pc = tf->tf_lr; 299c56480a8SDmitry Chagin frame->sf.sf_uc.uc_sc.pstate = tf->tf_spsr; 300c56480a8SDmitry Chagin frame->sf.sf_uc.uc_sc.fault_address = (register_t)ksi->ksi_addr; 301c56480a8SDmitry Chagin 302c56480a8SDmitry Chagin /* Stack frame for unwinding */ 303c56480a8SDmitry Chagin frame->fp = tf->tf_x[29]; 304c56480a8SDmitry Chagin frame->lr = tf->tf_lr; 305c56480a8SDmitry Chagin 306c56480a8SDmitry Chagin /* Translate the signal. */ 307c56480a8SDmitry Chagin sig = bsd_to_linux_signal(sig); 308c56480a8SDmitry Chagin siginfo_to_lsiginfo(&ksi->ksi_info, &frame->sf.sf_si, sig); 309c56480a8SDmitry Chagin bsd_to_linux_sigset(mask, &frame->sf.sf_uc.uc_sigmask); 310c56480a8SDmitry Chagin 311c56480a8SDmitry Chagin /* 312c56480a8SDmitry Chagin * Prepare fpsimd & esr. Does not check sizes, as 313c56480a8SDmitry Chagin * __reserved is big enougth. 314c56480a8SDmitry Chagin */ 315c56480a8SDmitry Chagin scr = (uint8_t *)&frame->sf.sf_uc.uc_sc.__reserved; 316c56480a8SDmitry Chagin #ifdef VFP 317c56480a8SDmitry Chagin fpsimd = (struct l_fpsimd_context *) scr; 318c56480a8SDmitry Chagin fpsimd->head.magic = L_FPSIMD_MAGIC; 319c56480a8SDmitry Chagin fpsimd->head.size = sizeof(struct l_fpsimd_context); 320c56480a8SDmitry Chagin fpsimd->fpsr = uc.uc_mcontext.mc_fpregs.fp_sr; 321c56480a8SDmitry Chagin fpsimd->fpcr = uc.uc_mcontext.mc_fpregs.fp_cr; 322c56480a8SDmitry Chagin 323c56480a8SDmitry Chagin memcpy(fpsimd->vregs, &uc.uc_mcontext.mc_fpregs.fp_q, 324c56480a8SDmitry Chagin sizeof(uc.uc_mcontext.mc_fpregs.fp_q)); 325c56480a8SDmitry Chagin scr += roundup(sizeof(struct l_fpsimd_context), 16); 326c56480a8SDmitry Chagin #endif 327c56480a8SDmitry Chagin if (ksi->ksi_addr != 0) { 328c56480a8SDmitry Chagin esr = (struct l_esr_context *) scr; 329c56480a8SDmitry Chagin esr->head.magic = L_ESR_MAGIC; 330c56480a8SDmitry Chagin esr->head.size = sizeof(struct l_esr_context); 331c56480a8SDmitry Chagin esr->esr = tf->tf_esr; 332c56480a8SDmitry Chagin } 333c56480a8SDmitry Chagin 334c56480a8SDmitry Chagin memcpy(&frame->sf.sf_uc.uc_stack, &uc_stack, sizeof(uc_stack)); 335c56480a8SDmitry Chagin memcpy(&frame->uc, &uc, sizeof(uc)); 336c56480a8SDmitry Chagin 337ccc510b4SEdward Tomasz Napierala /* Copy the sigframe out to the user's stack. */ 338c56480a8SDmitry Chagin if (copyout(frame, fp, sizeof(*fp)) != 0) { 339ccc510b4SEdward Tomasz Napierala /* Process has trashed its stack. Kill it. */ 340c56480a8SDmitry Chagin free(frame, M_LINUX); 341ccc510b4SEdward Tomasz Napierala CTR2(KTR_SIG, "sendsig: sigexit td=%p fp=%p", td, fp); 342ccc510b4SEdward Tomasz Napierala PROC_LOCK(p); 343ccc510b4SEdward Tomasz Napierala sigexit(td, SIGILL); 344ccc510b4SEdward Tomasz Napierala } 345c56480a8SDmitry Chagin free(frame, M_LINUX); 346ccc510b4SEdward Tomasz Napierala 347ccc510b4SEdward Tomasz Napierala tf->tf_x[0]= sig; 348109fd18aSDmitry Chagin if (issiginfo) { 349c56480a8SDmitry Chagin tf->tf_x[1] = (register_t)&fp->sf.sf_si; 350c56480a8SDmitry Chagin tf->tf_x[2] = (register_t)&fp->sf.sf_uc; 351109fd18aSDmitry Chagin } else { 352109fd18aSDmitry Chagin tf->tf_x[1] = 0; 353109fd18aSDmitry Chagin tf->tf_x[2] = 0; 354109fd18aSDmitry Chagin } 355c56480a8SDmitry Chagin tf->tf_x[8] = (register_t)catcher; 356ccc510b4SEdward Tomasz Napierala tf->tf_sp = (register_t)fp; 357c56480a8SDmitry Chagin tf->tf_elr = (register_t)linux_vdso_sigcode; 358ccc510b4SEdward Tomasz Napierala 359ccc510b4SEdward Tomasz Napierala CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_elr, 360ccc510b4SEdward Tomasz Napierala tf->tf_sp); 361ccc510b4SEdward Tomasz Napierala 362ccc510b4SEdward Tomasz Napierala PROC_LOCK(p); 363ccc510b4SEdward Tomasz Napierala mtx_lock(&psp->ps_mtx); 3643911ee2cSEd Maste } 3653911ee2cSEd Maste 3663911ee2cSEd Maste struct sysentvec elf_linux_sysvec = { 3673911ee2cSEd Maste .sv_size = LINUX_SYS_MAXSYSCALL, 3683911ee2cSEd Maste .sv_table = linux_sysent, 3696039e966SDmitry Chagin .sv_fixup = __elfN(freebsd_fixup), 3703911ee2cSEd Maste .sv_sendsig = linux_rt_sendsig, 3719931033bSDmitry Chagin .sv_sigcode = &_binary_linux_vdso_so_o_start, 3723911ee2cSEd Maste .sv_szsigcode = &linux_szsigcode, 3733911ee2cSEd Maste .sv_name = "Linux ELF64", 3743911ee2cSEd Maste .sv_coredump = elf64_coredump, 375435754a5SEdward Tomasz Napierala .sv_elf_core_osabi = ELFOSABI_NONE, 37645d99014SEdward Tomasz Napierala .sv_elf_core_abi_vendor = LINUX_ABI_VENDOR, 37745d99014SEdward Tomasz Napierala .sv_elf_core_prepare_notes = linux64_prepare_notes, 3783911ee2cSEd Maste .sv_imgact_try = linux_exec_imgact_try, 3793911ee2cSEd Maste .sv_minsigstksz = LINUX_MINSIGSTKSZ, 3803911ee2cSEd Maste .sv_minuser = VM_MIN_ADDRESS, 3813911ee2cSEd Maste .sv_maxuser = VM_MAXUSER_ADDRESS, 3829931033bSDmitry Chagin .sv_usrstack = LINUX_USRSTACK, 3839931033bSDmitry Chagin .sv_psstrings = LINUX_PS_STRINGS, 3843fc21fddSMark Johnston .sv_psstringssz = sizeof(struct ps_strings), 385d4f55cc8SEd Maste .sv_stackprot = VM_PROT_READ | VM_PROT_WRITE, 386*7d8c9839SDmitry Chagin .sv_copyout_auxargs = __linuxN(copyout_auxargs), 3876039e966SDmitry Chagin .sv_copyout_strings = __linuxN(copyout_strings), 3883911ee2cSEd Maste .sv_setregs = linux_exec_setregs, 3893911ee2cSEd Maste .sv_fixlimit = NULL, 3903911ee2cSEd Maste .sv_maxssiz = NULL, 391870e197dSKonstantin Belousov .sv_flags = SV_ABI_LINUX | SV_LP64 | SV_SHP | SV_SIG_DISCIGN | 3929931033bSDmitry Chagin SV_SIG_WAITNDQ | SV_TIMEKEEP, 3933911ee2cSEd Maste .sv_set_syscall_retval = linux_set_syscall_retval, 3943911ee2cSEd Maste .sv_fetch_syscall_args = linux_fetch_syscall_args, 3951da65dcbSMitchell Horne .sv_syscallnames = linux_syscallnames, 3969931033bSDmitry Chagin .sv_shared_page_base = LINUX_SHAREDPAGE, 3973911ee2cSEd Maste .sv_shared_page_len = PAGE_SIZE, 3983911ee2cSEd Maste .sv_schedtail = linux_schedtail, 3993911ee2cSEd Maste .sv_thread_detach = linux_thread_detach, 40084a3963dSEdward Tomasz Napierala .sv_trap = NULL, 401b501b2aeSEdward Tomasz Napierala .sv_hwcap = &elf_hwcap, 402b501b2aeSEdward Tomasz Napierala .sv_hwcap2 = &elf_hwcap2, 4035fd9cd53SDmitry Chagin .sv_onexec = linux_on_exec_vmspace, 4044815f175SKonstantin Belousov .sv_onexit = linux_on_exit, 4054815f175SKonstantin Belousov .sv_ontdexit = linux_thread_dtor, 406598f6fb4SKonstantin Belousov .sv_setid_allowed = &linux_setid_allowed_query, 4073911ee2cSEd Maste }; 4083911ee2cSEd Maste 4095fd9cd53SDmitry Chagin static int 4105fd9cd53SDmitry Chagin linux_on_exec_vmspace(struct proc *p, struct image_params *imgp) 4115fd9cd53SDmitry Chagin { 4129931033bSDmitry Chagin int error; 4135fd9cd53SDmitry Chagin 4149931033bSDmitry Chagin error = linux_map_vdso(p, linux_vdso_obj, linux_vdso_base, 4159931033bSDmitry Chagin LINUX_VDSOPAGE_SIZE, imgp); 4169931033bSDmitry Chagin if (error == 0) 4175fd9cd53SDmitry Chagin linux_on_exec(p, imgp); 4189931033bSDmitry Chagin return (error); 4195fd9cd53SDmitry Chagin } 4205fd9cd53SDmitry Chagin 42109cffde9SDmitry Chagin /* 42209cffde9SDmitry Chagin * linux_vdso_install() and linux_exec_sysvec_init() must be called 42309cffde9SDmitry Chagin * after exec_sysvec_init() which is SI_SUB_EXEC (SI_ORDER_ANY). 42409cffde9SDmitry Chagin */ 4253911ee2cSEd Maste static void 4269931033bSDmitry Chagin linux_exec_sysvec_init(void *param) 4279931033bSDmitry Chagin { 4289931033bSDmitry Chagin l_uintptr_t *ktimekeep_base; 4299931033bSDmitry Chagin struct sysentvec *sv; 4309931033bSDmitry Chagin ptrdiff_t tkoff; 4319931033bSDmitry Chagin 4329931033bSDmitry Chagin sv = param; 4339931033bSDmitry Chagin /* Fill timekeep_base */ 4349931033bSDmitry Chagin exec_sysvec_init(sv); 4359931033bSDmitry Chagin 4369931033bSDmitry Chagin tkoff = kern_timekeep_base - linux_vdso_base; 4379931033bSDmitry Chagin ktimekeep_base = (l_uintptr_t *)(linux_vdso_mapping + tkoff); 438361971fbSKornel Dulęba *ktimekeep_base = sv->sv_shared_page_base + sv->sv_timekeep_offset; 4399931033bSDmitry Chagin } 44009cffde9SDmitry Chagin SYSINIT(elf_linux_exec_sysvec_init, SI_SUB_EXEC + 1, SI_ORDER_ANY, 4419931033bSDmitry Chagin linux_exec_sysvec_init, &elf_linux_sysvec); 4429931033bSDmitry Chagin 4439931033bSDmitry Chagin static void 4443911ee2cSEd Maste linux_vdso_install(const void *param) 4453911ee2cSEd Maste { 4469931033bSDmitry Chagin char *vdso_start = &_binary_linux_vdso_so_o_start; 4479931033bSDmitry Chagin char *vdso_end = &_binary_linux_vdso_so_o_end; 4483911ee2cSEd Maste 4499931033bSDmitry Chagin linux_szsigcode = vdso_end - vdso_start; 4509931033bSDmitry Chagin MPASS(linux_szsigcode <= LINUX_VDSOPAGE_SIZE); 4513911ee2cSEd Maste 4529931033bSDmitry Chagin linux_vdso_base = LINUX_VDSOPAGE; 4533911ee2cSEd Maste 4549931033bSDmitry Chagin __elfN(linux_vdso_fixup)(vdso_start, linux_vdso_base); 4553911ee2cSEd Maste 4569931033bSDmitry Chagin linux_vdso_obj = __elfN(linux_shared_page_init) 4579931033bSDmitry Chagin (&linux_vdso_mapping, LINUX_VDSOPAGE_SIZE); 4589931033bSDmitry Chagin bcopy(vdso_start, linux_vdso_mapping, linux_szsigcode); 4593911ee2cSEd Maste 4609931033bSDmitry Chagin linux_vdso_reloc(linux_vdso_mapping, linux_vdso_base); 4613911ee2cSEd Maste } 46209cffde9SDmitry Chagin SYSINIT(elf_linux_vdso_init, SI_SUB_EXEC + 1, SI_ORDER_FIRST, 4633911ee2cSEd Maste linux_vdso_install, NULL); 4643911ee2cSEd Maste 4653911ee2cSEd Maste static void 4663911ee2cSEd Maste linux_vdso_deinstall(const void *param) 4673911ee2cSEd Maste { 4683911ee2cSEd Maste 4699931033bSDmitry Chagin __elfN(linux_shared_page_fini)(linux_vdso_obj, 4709931033bSDmitry Chagin linux_vdso_mapping, LINUX_VDSOPAGE_SIZE); 4713911ee2cSEd Maste } 4723911ee2cSEd Maste SYSUNINIT(elf_linux_vdso_uninit, SI_SUB_EXEC, SI_ORDER_FIRST, 4733911ee2cSEd Maste linux_vdso_deinstall, NULL); 4743911ee2cSEd Maste 4759931033bSDmitry Chagin static void 4769931033bSDmitry Chagin linux_vdso_reloc(char *mapping, Elf_Addr offset) 4779931033bSDmitry Chagin { 4789931033bSDmitry Chagin Elf_Size rtype, symidx; 4799931033bSDmitry Chagin const Elf_Rela *rela; 4809931033bSDmitry Chagin const Elf_Shdr *shdr; 4819931033bSDmitry Chagin const Elf_Ehdr *ehdr; 4829931033bSDmitry Chagin Elf_Addr *where; 4839931033bSDmitry Chagin Elf_Addr addr, addend; 4849931033bSDmitry Chagin int i, relacnt; 4859931033bSDmitry Chagin 4869931033bSDmitry Chagin MPASS(offset != 0); 4879931033bSDmitry Chagin 4889931033bSDmitry Chagin relacnt = 0; 4899931033bSDmitry Chagin ehdr = (const Elf_Ehdr *)mapping; 4909931033bSDmitry Chagin shdr = (const Elf_Shdr *)(mapping + ehdr->e_shoff); 4919931033bSDmitry Chagin for (i = 0; i < ehdr->e_shnum; i++) 4929931033bSDmitry Chagin { 4939931033bSDmitry Chagin switch (shdr[i].sh_type) { 4949931033bSDmitry Chagin case SHT_REL: 4959931033bSDmitry Chagin printf("Linux Aarch64 vDSO: unexpected Rel section\n"); 4969931033bSDmitry Chagin break; 4979931033bSDmitry Chagin case SHT_RELA: 4989931033bSDmitry Chagin rela = (const Elf_Rela *)(mapping + shdr[i].sh_offset); 4999931033bSDmitry Chagin relacnt = shdr[i].sh_size / sizeof(*rela); 5009931033bSDmitry Chagin } 5019931033bSDmitry Chagin } 5029931033bSDmitry Chagin 5039931033bSDmitry Chagin for (i = 0; i < relacnt; i++, rela++) { 5049931033bSDmitry Chagin where = (Elf_Addr *)(mapping + rela->r_offset); 5059931033bSDmitry Chagin addend = rela->r_addend; 5069931033bSDmitry Chagin rtype = ELF_R_TYPE(rela->r_info); 5079931033bSDmitry Chagin symidx = ELF_R_SYM(rela->r_info); 5089931033bSDmitry Chagin 5099931033bSDmitry Chagin switch (rtype) { 5109931033bSDmitry Chagin case R_AARCH64_NONE: /* none */ 5119931033bSDmitry Chagin break; 5129931033bSDmitry Chagin 5139931033bSDmitry Chagin case R_AARCH64_RELATIVE: /* B + A */ 5149931033bSDmitry Chagin addr = (Elf_Addr)(mapping + addend); 5159931033bSDmitry Chagin if (*where != addr) 5169931033bSDmitry Chagin *where = addr; 5179931033bSDmitry Chagin break; 5189931033bSDmitry Chagin default: 5199931033bSDmitry Chagin printf("Linux Aarch64 vDSO: unexpected relocation type %ld, " 5209931033bSDmitry Chagin "symbol index %ld\n", rtype, symidx); 5219931033bSDmitry Chagin } 5229931033bSDmitry Chagin } 5239931033bSDmitry Chagin } 5249931033bSDmitry Chagin 5253911ee2cSEd Maste static Elf_Brandnote linux64_brandnote = { 5263911ee2cSEd Maste .hdr.n_namesz = sizeof(GNU_ABI_VENDOR), 5273911ee2cSEd Maste .hdr.n_descsz = 16, 5283911ee2cSEd Maste .hdr.n_type = 1, 5293911ee2cSEd Maste .vendor = GNU_ABI_VENDOR, 5303911ee2cSEd Maste .flags = BN_TRANSLATE_OSREL, 5313911ee2cSEd Maste .trans_osrel = linux_trans_osrel 5323911ee2cSEd Maste }; 5333911ee2cSEd Maste 5343911ee2cSEd Maste static Elf64_Brandinfo linux_glibc2brand = { 5353911ee2cSEd Maste .brand = ELFOSABI_LINUX, 5363911ee2cSEd Maste .machine = EM_AARCH64, 5373911ee2cSEd Maste .compat_3_brand = "Linux", 538b5f20658SEdward Tomasz Napierala .emul_path = linux_emul_path, 5393911ee2cSEd Maste .interp_path = "/lib64/ld-linux-x86-64.so.2", 5403911ee2cSEd Maste .sysvec = &elf_linux_sysvec, 5413911ee2cSEd Maste .interp_newpath = NULL, 5423911ee2cSEd Maste .brand_note = &linux64_brandnote, 5433911ee2cSEd Maste .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE 5443911ee2cSEd Maste }; 5453911ee2cSEd Maste 5463911ee2cSEd Maste Elf64_Brandinfo *linux_brandlist[] = { 5473911ee2cSEd Maste &linux_glibc2brand, 5483911ee2cSEd Maste NULL 5493911ee2cSEd Maste }; 5503911ee2cSEd Maste 5513911ee2cSEd Maste static int 5523911ee2cSEd Maste linux64_elf_modevent(module_t mod, int type, void *data) 5533911ee2cSEd Maste { 5543911ee2cSEd Maste Elf64_Brandinfo **brandinfo; 5553911ee2cSEd Maste struct linux_ioctl_handler**lihp; 5563911ee2cSEd Maste int error; 5573911ee2cSEd Maste 5583911ee2cSEd Maste error = 0; 5593911ee2cSEd Maste switch(type) { 5603911ee2cSEd Maste case MOD_LOAD: 5613911ee2cSEd Maste for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; 5623911ee2cSEd Maste ++brandinfo) 5633911ee2cSEd Maste if (elf64_insert_brand_entry(*brandinfo) < 0) 5643911ee2cSEd Maste error = EINVAL; 5653911ee2cSEd Maste if (error == 0) { 5663911ee2cSEd Maste SET_FOREACH(lihp, linux_ioctl_handler_set) 5673911ee2cSEd Maste linux_ioctl_register_handler(*lihp); 5683911ee2cSEd Maste stclohz = (stathz ? stathz : hz); 5693911ee2cSEd Maste if (bootverbose) 5703911ee2cSEd Maste printf("Linux arm64 ELF exec handler installed\n"); 5713911ee2cSEd Maste } 5723911ee2cSEd Maste break; 5733911ee2cSEd Maste case MOD_UNLOAD: 5743911ee2cSEd Maste for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; 5753911ee2cSEd Maste ++brandinfo) 5763911ee2cSEd Maste if (elf64_brand_inuse(*brandinfo)) 5773911ee2cSEd Maste error = EBUSY; 5783911ee2cSEd Maste if (error == 0) { 5793911ee2cSEd Maste for (brandinfo = &linux_brandlist[0]; 5803911ee2cSEd Maste *brandinfo != NULL; ++brandinfo) 5813911ee2cSEd Maste if (elf64_remove_brand_entry(*brandinfo) < 0) 5823911ee2cSEd Maste error = EINVAL; 5833911ee2cSEd Maste } 5843911ee2cSEd Maste if (error == 0) { 5853911ee2cSEd Maste SET_FOREACH(lihp, linux_ioctl_handler_set) 5863911ee2cSEd Maste linux_ioctl_unregister_handler(*lihp); 5873911ee2cSEd Maste if (bootverbose) 588ae8330b4SDmitry Chagin printf("Linux arm64 ELF exec handler removed\n"); 5893911ee2cSEd Maste } else 590ae8330b4SDmitry Chagin printf("Could not deinstall Linux arm64 ELF interpreter entry\n"); 5913911ee2cSEd Maste break; 5923911ee2cSEd Maste default: 5933911ee2cSEd Maste return (EOPNOTSUPP); 5943911ee2cSEd Maste } 5953911ee2cSEd Maste return (error); 5963911ee2cSEd Maste } 5973911ee2cSEd Maste 5983911ee2cSEd Maste static moduledata_t linux64_elf_mod = { 5993911ee2cSEd Maste "linux64elf", 6003911ee2cSEd Maste linux64_elf_modevent, 6013911ee2cSEd Maste 0 6023911ee2cSEd Maste }; 6033911ee2cSEd Maste 6043911ee2cSEd Maste DECLARE_MODULE_TIED(linux64elf, linux64_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY); 6053911ee2cSEd Maste MODULE_DEPEND(linux64elf, linux_common, 1, 1, 1); 6063911ee2cSEd Maste FEATURE(linux64, "AArch64 Linux 64bit support"); 607