2018-06-25 10:12:33 -04:00
|
|
|
/*-
|
2023-05-10 11:40:58 -04:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
2018-06-25 10:12:33 -04:00
|
|
|
*
|
|
|
|
|
* Copyright (c) 1994-1996 Søren Schmidt
|
|
|
|
|
* Copyright (c) 2018 Turing Robotic Industries Inc.
|
|
|
|
|
*
|
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
|
* are met:
|
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
|
*
|
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <sys/cdefs.h>
|
|
|
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
|
|
2023-02-02 09:58:06 -05:00
|
|
|
#define __ELF_WORD_SIZE 64
|
|
|
|
|
|
2018-06-25 10:12:33 -04:00
|
|
|
#include <sys/param.h>
|
|
|
|
|
#include <sys/elf.h>
|
|
|
|
|
#include <sys/exec.h>
|
|
|
|
|
#include <sys/imgact.h>
|
|
|
|
|
#include <sys/imgact_elf.h>
|
|
|
|
|
#include <sys/kernel.h>
|
2021-07-25 02:22:47 -04:00
|
|
|
#include <sys/ktr.h>
|
2018-06-25 10:12:33 -04:00
|
|
|
#include <sys/lock.h>
|
|
|
|
|
#include <sys/module.h>
|
|
|
|
|
#include <sys/mutex.h>
|
|
|
|
|
#include <sys/proc.h>
|
2021-07-20 03:01:18 -04:00
|
|
|
#include <sys/stddef.h>
|
2021-07-25 02:22:47 -04:00
|
|
|
#include <sys/syscallsubr.h>
|
2018-06-25 10:12:33 -04:00
|
|
|
#include <sys/sysctl.h>
|
|
|
|
|
#include <sys/sysent.h>
|
|
|
|
|
|
2021-07-20 03:01:18 -04:00
|
|
|
#include <vm/pmap.h>
|
2023-02-14 09:46:33 -05:00
|
|
|
#include <vm/vm.h>
|
2021-07-20 03:01:18 -04:00
|
|
|
#include <vm/vm_map.h>
|
|
|
|
|
#include <vm/vm_page.h>
|
2018-06-25 10:12:33 -04:00
|
|
|
|
|
|
|
|
#include <arm64/linux/linux.h>
|
|
|
|
|
#include <arm64/linux/linux_proto.h>
|
|
|
|
|
#include <compat/linux/linux_dtrace.h>
|
2023-02-02 09:58:06 -05:00
|
|
|
#include <compat/linux/linux_elf.h>
|
2018-06-25 10:12:33 -04:00
|
|
|
#include <compat/linux/linux_emul.h>
|
2021-08-12 04:49:01 -04:00
|
|
|
#include <compat/linux/linux_fork.h>
|
2018-06-25 10:12:33 -04:00
|
|
|
#include <compat/linux/linux_ioctl.h>
|
|
|
|
|
#include <compat/linux/linux_mib.h>
|
|
|
|
|
#include <compat/linux/linux_misc.h>
|
2021-07-25 02:22:47 -04:00
|
|
|
#include <compat/linux/linux_signal.h>
|
2019-12-16 15:07:04 -05:00
|
|
|
#include <compat/linux/linux_util.h>
|
2018-06-25 10:12:33 -04:00
|
|
|
#include <compat/linux/linux_vdso.h>
|
|
|
|
|
|
2022-05-15 14:03:01 -04:00
|
|
|
#include <arm64/linux/linux_sigframe.h>
|
|
|
|
|
|
2021-06-01 08:12:25 -04:00
|
|
|
#include <machine/md_var.h>
|
2023-01-31 17:47:40 -05:00
|
|
|
#include <machine/pcb.h>
|
2021-03-09 14:11:40 -05:00
|
|
|
#ifdef VFP
|
|
|
|
|
#include <machine/vfp.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2018-06-25 10:12:33 -04:00
|
|
|
MODULE_VERSION(linux64elf, 1);
|
|
|
|
|
|
2021-07-20 03:01:18 -04:00
|
|
|
#define LINUX_VDSOPAGE_SIZE PAGE_SIZE * 2
|
|
|
|
|
#define LINUX_VDSOPAGE (VM_MAXUSER_ADDRESS - \
|
|
|
|
|
LINUX_VDSOPAGE_SIZE)
|
|
|
|
|
#define LINUX_SHAREDPAGE (LINUX_VDSOPAGE - PAGE_SIZE)
|
|
|
|
|
/*
|
|
|
|
|
* PAGE_SIZE - the size
|
|
|
|
|
* of the native SHAREDPAGE
|
|
|
|
|
*/
|
|
|
|
|
#define LINUX_USRSTACK LINUX_SHAREDPAGE
|
|
|
|
|
#define LINUX_PS_STRINGS (LINUX_USRSTACK - \
|
|
|
|
|
sizeof(struct ps_strings))
|
|
|
|
|
|
2018-06-25 10:12:33 -04:00
|
|
|
static int linux_szsigcode;
|
2021-07-20 03:01:18 -04:00
|
|
|
static vm_object_t linux_vdso_obj;
|
|
|
|
|
static char *linux_vdso_mapping;
|
|
|
|
|
extern char _binary_linux_vdso_so_o_start;
|
|
|
|
|
extern char _binary_linux_vdso_so_o_end;
|
|
|
|
|
static vm_offset_t linux_vdso_base;
|
2018-06-25 10:12:33 -04:00
|
|
|
|
|
|
|
|
extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL];
|
2022-10-28 17:19:39 -04:00
|
|
|
extern const char *linux_syscallnames[];
|
2018-06-25 10:12:33 -04:00
|
|
|
|
|
|
|
|
SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler);
|
|
|
|
|
|
|
|
|
|
static void linux_vdso_install(const void *param);
|
|
|
|
|
static void linux_vdso_deinstall(const void *param);
|
2021-07-20 03:01:18 -04:00
|
|
|
static void linux_vdso_reloc(char *mapping, Elf_Addr offset);
|
2018-06-25 10:12:33 -04:00
|
|
|
static void linux_set_syscall_retval(struct thread *td, int error);
|
|
|
|
|
static int linux_fetch_syscall_args(struct thread *td);
|
|
|
|
|
static void linux_exec_setregs(struct thread *td, struct image_params *imgp,
|
2019-12-03 18:17:54 -05:00
|
|
|
uintptr_t stack);
|
2021-07-20 03:01:18 -04:00
|
|
|
static void linux_exec_sysvec_init(void *param);
|
2021-07-20 02:56:25 -04:00
|
|
|
static int linux_on_exec_vmspace(struct proc *p,
|
|
|
|
|
struct image_params *imgp);
|
2018-06-25 10:12:33 -04:00
|
|
|
|
|
|
|
|
/* DTrace init */
|
|
|
|
|
LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE);
|
|
|
|
|
|
|
|
|
|
/* DTrace probes */
|
|
|
|
|
LIN_SDT_PROBE_DEFINE0(sysvec, linux_exec_setregs, todo);
|
|
|
|
|
|
2021-07-20 03:01:18 -04:00
|
|
|
LINUX_VDSO_SYM_CHAR(linux_platform);
|
|
|
|
|
LINUX_VDSO_SYM_INTPTR(kern_timekeep_base);
|
2023-05-14 17:27:31 -04:00
|
|
|
LINUX_VDSO_SYM_INTPTR(__user_rt_sigreturn);
|
2021-07-20 03:01:18 -04:00
|
|
|
|
2018-06-25 10:12:33 -04:00
|
|
|
static int
|
|
|
|
|
linux_fetch_syscall_args(struct thread *td)
|
|
|
|
|
{
|
|
|
|
|
struct proc *p;
|
|
|
|
|
struct syscall_args *sa;
|
|
|
|
|
register_t *ap;
|
|
|
|
|
|
|
|
|
|
p = td->td_proc;
|
|
|
|
|
ap = td->td_frame->tf_x;
|
|
|
|
|
sa = &td->td_sa;
|
|
|
|
|
|
|
|
|
|
sa->code = td->td_frame->tf_x[8];
|
2021-07-10 12:19:52 -04:00
|
|
|
sa->original_code = sa->code;
|
2018-06-25 10:12:33 -04:00
|
|
|
/* LINUXTODO: generic syscall? */
|
|
|
|
|
if (sa->code >= p->p_sysent->sv_size)
|
|
|
|
|
sa->callp = &p->p_sysent->sv_table[0];
|
|
|
|
|
else
|
|
|
|
|
sa->callp = &p->p_sysent->sv_table[sa->code];
|
|
|
|
|
|
2021-12-08 13:45:15 -05:00
|
|
|
if (sa->callp->sy_narg > nitems(sa->args))
|
|
|
|
|
panic("ARM64TODO: Could we have more than %zu args?",
|
|
|
|
|
nitems(sa->args));
|
|
|
|
|
memcpy(sa->args, ap, nitems(sa->args) * sizeof(register_t));
|
2018-06-25 10:12:33 -04:00
|
|
|
|
|
|
|
|
td->td_retval[0] = 0;
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
linux_set_syscall_retval(struct thread *td, int error)
|
|
|
|
|
{
|
2018-06-25 18:36:25 -04:00
|
|
|
|
|
|
|
|
td->td_retval[1] = td->td_frame->tf_x[1];
|
|
|
|
|
cpu_set_syscall_retval(td, error);
|
2020-09-15 12:41:21 -04:00
|
|
|
|
|
|
|
|
if (__predict_false(error != 0)) {
|
2020-10-27 08:49:40 -04:00
|
|
|
if (error != ERESTART && error != EJUSTRETURN)
|
|
|
|
|
td->td_frame->tf_x[0] = bsd_to_linux_errno(error);
|
2020-09-15 12:41:21 -04:00
|
|
|
}
|
2018-06-25 10:12:33 -04:00
|
|
|
}
|
|
|
|
|
|
2023-04-22 15:16:02 -04:00
|
|
|
void
|
|
|
|
|
linux64_arch_copyout_auxargs(struct image_params *imgp, Elf_Auxinfo **pos)
|
2018-06-25 10:12:33 -04:00
|
|
|
{
|
2023-04-22 15:16:02 -04:00
|
|
|
|
|
|
|
|
AUXARGS_ENTRY((*pos), LINUX_AT_SYSINFO_EHDR, linux_vdso_base);
|
|
|
|
|
AUXARGS_ENTRY((*pos), LINUX_AT_HWCAP, *imgp->sysent->sv_hwcap);
|
|
|
|
|
AUXARGS_ENTRY((*pos), LINUX_AT_HWCAP2, *imgp->sysent->sv_hwcap2);
|
|
|
|
|
AUXARGS_ENTRY((*pos), LINUX_AT_PLATFORM, PTROUT(linux_platform));
|
2019-11-15 18:01:43 -05:00
|
|
|
}
|
|
|
|
|
|
2018-06-25 10:12:33 -04:00
|
|
|
/*
|
|
|
|
|
* Reset registers to default values on exec.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2019-12-03 18:17:54 -05:00
|
|
|
linux_exec_setregs(struct thread *td, struct image_params *imgp,
|
|
|
|
|
uintptr_t stack)
|
2018-06-25 10:12:33 -04:00
|
|
|
{
|
|
|
|
|
struct trapframe *regs = td->td_frame;
|
2021-04-09 10:13:21 -04:00
|
|
|
struct pcb *pcb = td->td_pcb;
|
2018-06-25 10:12:33 -04:00
|
|
|
|
|
|
|
|
/* LINUXTODO: validate */
|
|
|
|
|
LIN_SDT_PROBE0(sysvec, linux_exec_setregs, todo);
|
|
|
|
|
|
|
|
|
|
memset(regs, 0, sizeof(*regs));
|
|
|
|
|
/* glibc start.S registers function pointer in x0 with atexit. */
|
|
|
|
|
regs->tf_sp = stack;
|
|
|
|
|
#if 0 /* LINUXTODO: See if this is used. */
|
|
|
|
|
regs->tf_lr = imgp->entry_addr;
|
|
|
|
|
#else
|
|
|
|
|
regs->tf_lr = 0xffffffffffffffff;
|
|
|
|
|
#endif
|
|
|
|
|
regs->tf_elr = imgp->entry_addr;
|
2021-03-09 14:11:40 -05:00
|
|
|
|
2021-04-09 10:13:21 -04:00
|
|
|
pcb->pcb_tpidr_el0 = 0;
|
|
|
|
|
pcb->pcb_tpidrro_el0 = 0;
|
2021-03-17 16:19:04 -04:00
|
|
|
WRITE_SPECIALREG(tpidrro_el0, 0);
|
|
|
|
|
WRITE_SPECIALREG(tpidr_el0, 0);
|
|
|
|
|
|
2021-03-09 14:11:40 -05:00
|
|
|
#ifdef VFP
|
2021-04-09 10:13:21 -04:00
|
|
|
vfp_reset_state(td, pcb);
|
2021-03-09 14:11:40 -05:00
|
|
|
#endif
|
2021-04-09 10:13:21 -04:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Clear debug register state. It is not applicable to the new process.
|
|
|
|
|
*/
|
|
|
|
|
bzero(&pcb->pcb_dbg_regs, sizeof(pcb->pcb_dbg_regs));
|
2018-06-25 10:12:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args)
|
|
|
|
|
{
|
2022-05-15 14:10:50 -04:00
|
|
|
struct l_sigframe *frame;
|
|
|
|
|
ucontext_t uc;
|
2021-07-25 02:22:47 -04:00
|
|
|
struct trapframe *tf;
|
|
|
|
|
int error;
|
2018-06-25 10:12:33 -04:00
|
|
|
|
2021-07-25 02:22:47 -04:00
|
|
|
tf = td->td_frame;
|
2022-05-15 14:10:50 -04:00
|
|
|
frame = (struct l_sigframe *)tf->tf_sp;
|
2021-07-25 02:22:47 -04:00
|
|
|
|
2022-05-15 14:10:50 -04:00
|
|
|
if (copyin((void *)&frame->uc, &uc, sizeof(uc)))
|
2021-07-25 02:22:47 -04:00
|
|
|
return (EFAULT);
|
|
|
|
|
|
2022-05-15 14:10:50 -04:00
|
|
|
error = set_mcontext(td, &uc.uc_mcontext);
|
2021-07-25 02:22:47 -04:00
|
|
|
if (error != 0)
|
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
|
|
/* Restore signal mask. */
|
2022-05-15 14:10:50 -04:00
|
|
|
kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0);
|
2021-07-25 02:22:47 -04:00
|
|
|
|
|
|
|
|
return (EJUSTRETURN);
|
2018-06-25 10:12:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
|
|
|
|
|
{
|
2021-07-25 02:22:47 -04:00
|
|
|
struct thread *td;
|
|
|
|
|
struct proc *p;
|
|
|
|
|
struct trapframe *tf;
|
2022-05-15 14:10:50 -04:00
|
|
|
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;
|
2021-07-25 02:22:47 -04:00
|
|
|
struct sigacts *psp;
|
2022-05-30 12:53:12 -04:00
|
|
|
int onstack, sig, issiginfo;
|
2021-07-25 02:22:47 -04:00
|
|
|
|
|
|
|
|
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);
|
2022-05-30 12:53:12 -04:00
|
|
|
issiginfo = SIGISMEMBER(psp->ps_siginfo, sig);
|
2021-07-25 02:22:47 -04:00
|
|
|
|
|
|
|
|
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 l_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 l_sigframe *)td->td_frame->tf_sp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Make room, keeping the stack aligned */
|
|
|
|
|
fp--;
|
|
|
|
|
fp = (struct l_sigframe *)STACKALIGN(fp);
|
|
|
|
|
|
2022-05-15 14:10:50 -04:00
|
|
|
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);
|
|
|
|
|
|
2021-07-25 02:22:47 -04:00
|
|
|
/* Fill in the frame to copy out */
|
2022-05-15 14:10:50 -04:00
|
|
|
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;
|
linux(4): Fix stack unwinding on arm64 [1/2]
An Aarch64 sigreturn trampoline frame can't currently be described in
a DWARF .eh_frame section, because Aarch64 does not define a register
number for PC and provide no direct way to encode PC of the previous
frame. Instead, unwinders (libgcc, gdb, libunwind) detect the sigreturn
frame by looking for the sigreturn instruction. If a sigreturn frame is
detected, unwinders restores all the gprs, SP and PC by assuming that
sp points to an rt_sigframe Linux kernel struct
When entering the kernel, the link register (lr) contains the return
address of the previous frame, the exception link register (elr) contains
the address of the next instruction after the one which generated the
exception, i.e., PC.
MFC after: 1 week
2023-05-14 17:24:57 -04:00
|
|
|
frame->sf.sf_uc.uc_sc.pc = tf->tf_elr;
|
2022-05-15 14:10:50 -04:00
|
|
|
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];
|
2023-05-14 17:25:57 -04:00
|
|
|
frame->lr = tf->tf_elr;
|
2021-07-25 02:22:47 -04:00
|
|
|
|
|
|
|
|
/* Translate the signal. */
|
|
|
|
|
sig = bsd_to_linux_signal(sig);
|
2022-05-15 14:10:50 -04:00
|
|
|
siginfo_to_lsiginfo(&ksi->ksi_info, &frame->sf.sf_si, sig);
|
|
|
|
|
bsd_to_linux_sigset(mask, &frame->sf.sf_uc.uc_sigmask);
|
2021-07-25 02:22:47 -04:00
|
|
|
|
2022-05-15 14:10:50 -04:00
|
|
|
/*
|
|
|
|
|
* 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));
|
2021-07-25 02:22:47 -04:00
|
|
|
|
|
|
|
|
/* Copy the sigframe out to the user's stack. */
|
2022-05-15 14:10:50 -04:00
|
|
|
if (copyout(frame, fp, sizeof(*fp)) != 0) {
|
2021-07-25 02:22:47 -04:00
|
|
|
/* Process has trashed its stack. Kill it. */
|
2022-05-15 14:10:50 -04:00
|
|
|
free(frame, M_LINUX);
|
2021-07-25 02:22:47 -04:00
|
|
|
CTR2(KTR_SIG, "sendsig: sigexit td=%p fp=%p", td, fp);
|
|
|
|
|
PROC_LOCK(p);
|
|
|
|
|
sigexit(td, SIGILL);
|
|
|
|
|
}
|
2022-05-15 14:10:50 -04:00
|
|
|
free(frame, M_LINUX);
|
2021-07-25 02:22:47 -04:00
|
|
|
|
|
|
|
|
tf->tf_x[0]= sig;
|
2022-05-30 12:53:12 -04:00
|
|
|
if (issiginfo) {
|
|
|
|
|
tf->tf_x[1] = (register_t)&fp->sf.sf_si;
|
|
|
|
|
tf->tf_x[2] = (register_t)&fp->sf.sf_uc;
|
|
|
|
|
} else {
|
|
|
|
|
tf->tf_x[1] = 0;
|
|
|
|
|
tf->tf_x[2] = 0;
|
|
|
|
|
}
|
2023-05-14 17:25:57 -04:00
|
|
|
tf->tf_x[29] = (register_t)&fp->fp;
|
2023-05-14 17:27:31 -04:00
|
|
|
tf->tf_elr = (register_t)catcher;
|
2021-07-25 02:22:47 -04:00
|
|
|
tf->tf_sp = (register_t)fp;
|
2023-05-14 17:27:31 -04:00
|
|
|
tf->tf_lr = (register_t)__user_rt_sigreturn;
|
2021-07-25 02:22:47 -04:00
|
|
|
|
|
|
|
|
CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_elr,
|
|
|
|
|
tf->tf_sp);
|
2018-06-25 10:12:33 -04:00
|
|
|
|
2021-07-25 02:22:47 -04:00
|
|
|
PROC_LOCK(p);
|
|
|
|
|
mtx_lock(&psp->ps_mtx);
|
2018-06-25 10:12:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct sysentvec elf_linux_sysvec = {
|
|
|
|
|
.sv_size = LINUX_SYS_MAXSYSCALL,
|
|
|
|
|
.sv_table = linux_sysent,
|
2023-02-02 09:58:07 -05:00
|
|
|
.sv_fixup = __elfN(freebsd_fixup),
|
2018-06-25 10:12:33 -04:00
|
|
|
.sv_sendsig = linux_rt_sendsig,
|
2021-07-20 03:01:18 -04:00
|
|
|
.sv_sigcode = &_binary_linux_vdso_so_o_start,
|
2018-06-25 10:12:33 -04:00
|
|
|
.sv_szsigcode = &linux_szsigcode,
|
|
|
|
|
.sv_name = "Linux ELF64",
|
|
|
|
|
.sv_coredump = elf64_coredump,
|
2021-06-29 03:49:04 -04:00
|
|
|
.sv_elf_core_osabi = ELFOSABI_NONE,
|
2021-07-03 03:05:44 -04:00
|
|
|
.sv_elf_core_abi_vendor = LINUX_ABI_VENDOR,
|
|
|
|
|
.sv_elf_core_prepare_notes = linux64_prepare_notes,
|
2018-06-25 10:12:33 -04:00
|
|
|
.sv_minsigstksz = LINUX_MINSIGSTKSZ,
|
|
|
|
|
.sv_minuser = VM_MIN_ADDRESS,
|
|
|
|
|
.sv_maxuser = VM_MAXUSER_ADDRESS,
|
2021-07-20 03:01:18 -04:00
|
|
|
.sv_usrstack = LINUX_USRSTACK,
|
|
|
|
|
.sv_psstrings = LINUX_PS_STRINGS,
|
2022-01-17 11:42:07 -05:00
|
|
|
.sv_psstringssz = sizeof(struct ps_strings),
|
2019-11-04 16:23:30 -05:00
|
|
|
.sv_stackprot = VM_PROT_READ | VM_PROT_WRITE,
|
2023-04-22 15:16:02 -04:00
|
|
|
.sv_copyout_auxargs = __linuxN(copyout_auxargs),
|
2023-02-02 09:58:07 -05:00
|
|
|
.sv_copyout_strings = __linuxN(copyout_strings),
|
2018-06-25 10:12:33 -04:00
|
|
|
.sv_setregs = linux_exec_setregs,
|
|
|
|
|
.sv_fixlimit = NULL,
|
|
|
|
|
.sv_maxssiz = NULL,
|
2021-06-05 14:18:21 -04:00
|
|
|
.sv_flags = SV_ABI_LINUX | SV_LP64 | SV_SHP | SV_SIG_DISCIGN |
|
2021-07-20 03:01:18 -04:00
|
|
|
SV_SIG_WAITNDQ | SV_TIMEKEEP,
|
2018-06-25 10:12:33 -04:00
|
|
|
.sv_set_syscall_retval = linux_set_syscall_retval,
|
|
|
|
|
.sv_fetch_syscall_args = linux_fetch_syscall_args,
|
2022-10-28 17:19:39 -04:00
|
|
|
.sv_syscallnames = linux_syscallnames,
|
2021-07-20 03:01:18 -04:00
|
|
|
.sv_shared_page_base = LINUX_SHAREDPAGE,
|
2018-06-25 10:12:33 -04:00
|
|
|
.sv_shared_page_len = PAGE_SIZE,
|
|
|
|
|
.sv_schedtail = linux_schedtail,
|
|
|
|
|
.sv_thread_detach = linux_thread_detach,
|
2021-07-13 05:52:13 -04:00
|
|
|
.sv_trap = NULL,
|
2021-06-01 08:12:25 -04:00
|
|
|
.sv_hwcap = &elf_hwcap,
|
|
|
|
|
.sv_hwcap2 = &elf_hwcap2,
|
2021-07-20 02:56:25 -04:00
|
|
|
.sv_onexec = linux_on_exec_vmspace,
|
2020-11-23 13:18:16 -05:00
|
|
|
.sv_onexit = linux_on_exit,
|
|
|
|
|
.sv_ontdexit = linux_thread_dtor,
|
2021-01-14 08:51:52 -05:00
|
|
|
.sv_setid_allowed = &linux_setid_allowed_query,
|
2018-06-25 10:12:33 -04:00
|
|
|
};
|
|
|
|
|
|
2021-07-20 02:56:25 -04:00
|
|
|
static int
|
|
|
|
|
linux_on_exec_vmspace(struct proc *p, struct image_params *imgp)
|
|
|
|
|
{
|
2021-07-20 03:01:18 -04:00
|
|
|
int error;
|
2021-07-20 02:56:25 -04:00
|
|
|
|
2021-07-20 03:01:18 -04:00
|
|
|
error = linux_map_vdso(p, linux_vdso_obj, linux_vdso_base,
|
|
|
|
|
LINUX_VDSOPAGE_SIZE, imgp);
|
|
|
|
|
if (error == 0)
|
2023-05-29 04:16:46 -04:00
|
|
|
error = linux_on_exec(p, imgp);
|
2021-07-20 03:01:18 -04:00
|
|
|
return (error);
|
2021-07-20 02:56:25 -04:00
|
|
|
}
|
|
|
|
|
|
2021-07-20 03:02:34 -04:00
|
|
|
/*
|
|
|
|
|
* linux_vdso_install() and linux_exec_sysvec_init() must be called
|
|
|
|
|
* after exec_sysvec_init() which is SI_SUB_EXEC (SI_ORDER_ANY).
|
|
|
|
|
*/
|
2018-06-25 10:12:33 -04:00
|
|
|
static void
|
2021-07-20 03:01:18 -04:00
|
|
|
linux_exec_sysvec_init(void *param)
|
2018-06-25 10:12:33 -04:00
|
|
|
{
|
2021-07-20 03:01:18 -04:00
|
|
|
l_uintptr_t *ktimekeep_base;
|
|
|
|
|
struct sysentvec *sv;
|
|
|
|
|
ptrdiff_t tkoff;
|
2018-06-25 10:12:33 -04:00
|
|
|
|
2021-07-20 03:01:18 -04:00
|
|
|
sv = param;
|
|
|
|
|
/* Fill timekeep_base */
|
|
|
|
|
exec_sysvec_init(sv);
|
2018-06-25 10:12:33 -04:00
|
|
|
|
2021-07-20 03:01:18 -04:00
|
|
|
tkoff = kern_timekeep_base - linux_vdso_base;
|
|
|
|
|
ktimekeep_base = (l_uintptr_t *)(linux_vdso_mapping + tkoff);
|
2022-06-02 03:58:12 -04:00
|
|
|
*ktimekeep_base = sv->sv_shared_page_base + sv->sv_timekeep_offset;
|
2021-07-20 03:01:18 -04:00
|
|
|
}
|
2021-07-20 03:02:34 -04:00
|
|
|
SYSINIT(elf_linux_exec_sysvec_init, SI_SUB_EXEC + 1, SI_ORDER_ANY,
|
2021-07-20 03:01:18 -04:00
|
|
|
linux_exec_sysvec_init, &elf_linux_sysvec);
|
2018-06-25 10:12:33 -04:00
|
|
|
|
2021-07-20 03:01:18 -04:00
|
|
|
static void
|
|
|
|
|
linux_vdso_install(const void *param)
|
|
|
|
|
{
|
|
|
|
|
char *vdso_start = &_binary_linux_vdso_so_o_start;
|
|
|
|
|
char *vdso_end = &_binary_linux_vdso_so_o_end;
|
|
|
|
|
|
|
|
|
|
linux_szsigcode = vdso_end - vdso_start;
|
|
|
|
|
MPASS(linux_szsigcode <= LINUX_VDSOPAGE_SIZE);
|
|
|
|
|
|
|
|
|
|
linux_vdso_base = LINUX_VDSOPAGE;
|
2018-06-25 10:12:33 -04:00
|
|
|
|
2021-07-20 03:01:18 -04:00
|
|
|
__elfN(linux_vdso_fixup)(vdso_start, linux_vdso_base);
|
2018-06-25 10:12:33 -04:00
|
|
|
|
2021-07-20 03:01:18 -04:00
|
|
|
linux_vdso_obj = __elfN(linux_shared_page_init)
|
|
|
|
|
(&linux_vdso_mapping, LINUX_VDSOPAGE_SIZE);
|
|
|
|
|
bcopy(vdso_start, linux_vdso_mapping, linux_szsigcode);
|
2018-06-25 10:12:33 -04:00
|
|
|
|
2021-07-20 03:01:18 -04:00
|
|
|
linux_vdso_reloc(linux_vdso_mapping, linux_vdso_base);
|
2018-06-25 10:12:33 -04:00
|
|
|
}
|
2021-07-20 03:02:34 -04:00
|
|
|
SYSINIT(elf_linux_vdso_init, SI_SUB_EXEC + 1, SI_ORDER_FIRST,
|
2018-06-25 10:12:33 -04:00
|
|
|
linux_vdso_install, NULL);
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
linux_vdso_deinstall(const void *param)
|
|
|
|
|
{
|
|
|
|
|
|
2021-07-20 03:01:18 -04:00
|
|
|
__elfN(linux_shared_page_fini)(linux_vdso_obj,
|
|
|
|
|
linux_vdso_mapping, LINUX_VDSOPAGE_SIZE);
|
2018-06-25 10:12:33 -04:00
|
|
|
}
|
|
|
|
|
SYSUNINIT(elf_linux_vdso_uninit, SI_SUB_EXEC, SI_ORDER_FIRST,
|
|
|
|
|
linux_vdso_deinstall, NULL);
|
|
|
|
|
|
2021-07-20 03:01:18 -04:00
|
|
|
static void
|
|
|
|
|
linux_vdso_reloc(char *mapping, Elf_Addr offset)
|
|
|
|
|
{
|
|
|
|
|
Elf_Size rtype, symidx;
|
|
|
|
|
const Elf_Rela *rela;
|
|
|
|
|
const Elf_Shdr *shdr;
|
|
|
|
|
const Elf_Ehdr *ehdr;
|
|
|
|
|
Elf_Addr *where;
|
|
|
|
|
Elf_Addr addr, addend;
|
|
|
|
|
int i, relacnt;
|
|
|
|
|
|
|
|
|
|
MPASS(offset != 0);
|
|
|
|
|
|
|
|
|
|
relacnt = 0;
|
|
|
|
|
ehdr = (const Elf_Ehdr *)mapping;
|
|
|
|
|
shdr = (const Elf_Shdr *)(mapping + ehdr->e_shoff);
|
|
|
|
|
for (i = 0; i < ehdr->e_shnum; i++)
|
|
|
|
|
{
|
|
|
|
|
switch (shdr[i].sh_type) {
|
|
|
|
|
case SHT_REL:
|
|
|
|
|
printf("Linux Aarch64 vDSO: unexpected Rel section\n");
|
|
|
|
|
break;
|
|
|
|
|
case SHT_RELA:
|
|
|
|
|
rela = (const Elf_Rela *)(mapping + shdr[i].sh_offset);
|
|
|
|
|
relacnt = shdr[i].sh_size / sizeof(*rela);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < relacnt; i++, rela++) {
|
|
|
|
|
where = (Elf_Addr *)(mapping + rela->r_offset);
|
|
|
|
|
addend = rela->r_addend;
|
|
|
|
|
rtype = ELF_R_TYPE(rela->r_info);
|
|
|
|
|
symidx = ELF_R_SYM(rela->r_info);
|
|
|
|
|
|
|
|
|
|
switch (rtype) {
|
|
|
|
|
case R_AARCH64_NONE: /* none */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case R_AARCH64_RELATIVE: /* B + A */
|
|
|
|
|
addr = (Elf_Addr)(mapping + addend);
|
|
|
|
|
if (*where != addr)
|
|
|
|
|
*where = addr;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
printf("Linux Aarch64 vDSO: unexpected relocation type %ld, "
|
|
|
|
|
"symbol index %ld\n", rtype, symidx);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-25 10:12:33 -04:00
|
|
|
static Elf_Brandnote linux64_brandnote = {
|
|
|
|
|
.hdr.n_namesz = sizeof(GNU_ABI_VENDOR),
|
|
|
|
|
.hdr.n_descsz = 16,
|
|
|
|
|
.hdr.n_type = 1,
|
|
|
|
|
.vendor = GNU_ABI_VENDOR,
|
|
|
|
|
.flags = BN_TRANSLATE_OSREL,
|
|
|
|
|
.trans_osrel = linux_trans_osrel
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static Elf64_Brandinfo linux_glibc2brand = {
|
|
|
|
|
.brand = ELFOSABI_LINUX,
|
|
|
|
|
.machine = EM_AARCH64,
|
|
|
|
|
.compat_3_brand = "Linux",
|
|
|
|
|
.interp_path = "/lib64/ld-linux-x86-64.so.2",
|
|
|
|
|
.sysvec = &elf_linux_sysvec,
|
|
|
|
|
.interp_newpath = NULL,
|
|
|
|
|
.brand_note = &linux64_brandnote,
|
|
|
|
|
.flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Elf64_Brandinfo *linux_brandlist[] = {
|
|
|
|
|
&linux_glibc2brand,
|
|
|
|
|
NULL
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
linux64_elf_modevent(module_t mod, int type, void *data)
|
|
|
|
|
{
|
|
|
|
|
Elf64_Brandinfo **brandinfo;
|
|
|
|
|
struct linux_ioctl_handler**lihp;
|
|
|
|
|
int error;
|
|
|
|
|
|
|
|
|
|
error = 0;
|
|
|
|
|
switch(type) {
|
|
|
|
|
case MOD_LOAD:
|
|
|
|
|
for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
|
|
|
|
|
++brandinfo)
|
|
|
|
|
if (elf64_insert_brand_entry(*brandinfo) < 0)
|
|
|
|
|
error = EINVAL;
|
|
|
|
|
if (error == 0) {
|
|
|
|
|
SET_FOREACH(lihp, linux_ioctl_handler_set)
|
|
|
|
|
linux_ioctl_register_handler(*lihp);
|
|
|
|
|
stclohz = (stathz ? stathz : hz);
|
|
|
|
|
if (bootverbose)
|
|
|
|
|
printf("Linux arm64 ELF exec handler installed\n");
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case MOD_UNLOAD:
|
|
|
|
|
for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
|
|
|
|
|
++brandinfo)
|
|
|
|
|
if (elf64_brand_inuse(*brandinfo))
|
|
|
|
|
error = EBUSY;
|
|
|
|
|
if (error == 0) {
|
|
|
|
|
for (brandinfo = &linux_brandlist[0];
|
|
|
|
|
*brandinfo != NULL; ++brandinfo)
|
|
|
|
|
if (elf64_remove_brand_entry(*brandinfo) < 0)
|
|
|
|
|
error = EINVAL;
|
|
|
|
|
}
|
|
|
|
|
if (error == 0) {
|
|
|
|
|
SET_FOREACH(lihp, linux_ioctl_handler_set)
|
|
|
|
|
linux_ioctl_unregister_handler(*lihp);
|
|
|
|
|
if (bootverbose)
|
2021-07-20 03:05:08 -04:00
|
|
|
printf("Linux arm64 ELF exec handler removed\n");
|
2018-06-25 10:12:33 -04:00
|
|
|
} else
|
2021-07-20 03:05:08 -04:00
|
|
|
printf("Could not deinstall Linux arm64 ELF interpreter entry\n");
|
2018-06-25 10:12:33 -04:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return (EOPNOTSUPP);
|
|
|
|
|
}
|
|
|
|
|
return (error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static moduledata_t linux64_elf_mod = {
|
|
|
|
|
"linux64elf",
|
|
|
|
|
linux64_elf_modevent,
|
|
|
|
|
0
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
DECLARE_MODULE_TIED(linux64elf, linux64_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY);
|
|
|
|
|
MODULE_DEPEND(linux64elf, linux_common, 1, 1, 1);
|
|
|
|
|
FEATURE(linux64, "AArch64 Linux 64bit support");
|