#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: linux_exec.c,v 1.124 2020/05/03 01:06:56 thorpej Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/lwp.h>
#include <sys/proc.h>
#include <sys/namei.h>
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/exec.h>
#include <sys/exec_elf.h>
#include <sys/futex.h>
#include <sys/mman.h>
#include <sys/syscallargs.h>
#include <sys/ptrace.h>
#include <uvm/uvm_extern.h>
#include <sys/cpu.h>
#include <machine/reg.h>
#include <compat/linux/common/linux_types.h>
#include <compat/linux/common/linux_signal.h>
#include <compat/linux/common/linux_util.h>
#include <compat/linux/common/linux_sched.h>
#include <compat/linux/common/linux_machdep.h>
#include <compat/linux/common/linux_misc.h>
#include <compat/linux/common/linux_exec.h>
#include <compat/linux/common/linux_ipc.h>
#include <compat/linux/common/linux_sem.h>
#include <compat/linux/linux_syscallargs.h>
#include <compat/linux/linux_syscall.h>
#include <compat/linux/common/linux_misc.h>
#include <compat/linux/common/linux_errno.h>
#include <compat/linux/common/linux_emuldata.h>
extern struct sysent linux_sysent[];
extern const uint32_t linux_sysent_nomodbits[];
extern const char * const linux_syscallnames[];
extern char linux_sigcode[], linux_esigcode[];
struct uvm_object *emul_linux_object;
struct emul emul_linux = {
.e_name = "linux",
.e_path = "/emul/linux",
#ifndef __HAVE_MINIMAL_EMUL
.e_flags = 0,
.e_errno = native_to_linux_errno,
.e_nosys = LINUX_SYS_syscall,
.e_nsysent = LINUX_SYS_NSYSENT,
#endif
.e_sysent = linux_sysent,
.e_nomodbits = linux_sysent_nomodbits,
.e_syscallnames = linux_syscallnames,
.e_sendsig = linux_sendsig,
.e_trapsignal = linux_trapsignal,
.e_sigcode = linux_sigcode,
.e_esigcode = linux_esigcode,
.e_sigobject = &emul_linux_object,
.e_setregs = linux_setregs,
.e_proc_exec = linux_e_proc_exec,
.e_proc_fork = linux_e_proc_fork,
.e_proc_exit = linux_e_proc_exit,
.e_lwp_fork = linux_e_lwp_fork,
.e_lwp_exit = linux_e_lwp_exit,
#ifdef __HAVE_SYSCALL_INTERN
.e_syscall_intern = linux_syscall_intern,
#else
#error Implement __HAVE_SYSCALL_INTERN for this platform
#endif
.e_sysctlovly = NULL,
.e_vm_default_addr = uvm_default_mapaddr,
.e_usertrap = linux_usertrap,
.e_ucsize = 0,
.e_startlwp = NULL
};
void
linux_e_proc_exec(struct proc *p, struct exec_package *epp)
{
struct lwp *l;
l = LIST_FIRST(&p->p_lwps);
if (l->l_emuldata == NULL) {
l->l_emuldata = kmem_zalloc(sizeof(struct linux_emuldata), KM_SLEEP);
} else {
memset(l->l_emuldata, 0, sizeof (struct linux_emuldata));
}
KASSERT(p->p_nlwps == 1);
}
void
linux_e_proc_exit(struct proc *p)
{
struct lwp *l;
KASSERT(p->p_nlwps == 1);
l = LIST_FIRST(&p->p_lwps);
linux_e_lwp_exit(l);
}
void
linux_e_proc_fork(struct proc *p2, struct lwp *l1, int flags)
{
struct linux_emuldata *led1, *led2;
struct lwp *l2;
KASSERT(p2->p_nlwps == 1);
l2 = LIST_FIRST(&p2->p_lwps);
led1 = l1->l_emuldata;
led2 = l2->l_emuldata;
led2->led_child_tidptr = led1->led_child_tidptr;
}
void
linux_e_lwp_fork(struct lwp *l1, struct lwp *l2)
{
struct linux_emuldata *led2;
led2 = kmem_zalloc(sizeof(*led2), KM_SLEEP);
l2->l_emuldata = led2;
}
void
linux_e_lwp_exit(struct lwp *l)
{
struct linux_emuldata *led;
register_t retval;
int error, zero = 0;
led = l->l_emuldata;
if (led->led_clear_tid != NULL) {
error = copyout(&zero, led->led_clear_tid, sizeof(zero));
#ifdef DEBUG_LINUX
if (error != 0)
printf("%s: cannot clear TID\n", __func__);
#endif
error = linux_do_futex((int *)led->led_clear_tid, FUTEX_WAKE,
INT_MAX, NULL, NULL, 0, 0, &retval);
if (error)
printf("%s: linux_sys_futex failed\n", __func__);
}
led = l->l_emuldata;
l->l_emuldata = NULL;
kmem_free(led, sizeof(*led));
}