diff options
Diffstat (limited to 'sys/amd64/linux32/linux32_sysvec.c')
-rw-r--r-- | sys/amd64/linux32/linux32_sysvec.c | 149 |
1 files changed, 21 insertions, 128 deletions
diff --git a/sys/amd64/linux32/linux32_sysvec.c b/sys/amd64/linux32/linux32_sysvec.c index e9162f04d3f7..19b4af7661f0 100644 --- a/sys/amd64/linux32/linux32_sysvec.c +++ b/sys/amd64/linux32/linux32_sysvec.c @@ -32,11 +32,6 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "opt_compat.h" - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #ifndef COMPAT_FREEBSD32 #error "Unable to compile Linux-emulator due to missing COMPAT_FREEBSD32 option!" #endif @@ -44,44 +39,31 @@ __FBSDID("$FreeBSD$"); #define __ELF_WORD_SIZE 32 #include <sys/param.h> -#include <sys/systm.h> #include <sys/exec.h> -#include <sys/fcntl.h> #include <sys/imgact.h> #include <sys/imgact_elf.h> #include <sys/kernel.h> #include <sys/lock.h> -#include <sys/malloc.h> #include <sys/module.h> #include <sys/mutex.h> #include <sys/proc.h> -#include <sys/resourcevar.h> #include <sys/stddef.h> -#include <sys/signalvar.h> #include <sys/syscallsubr.h> #include <sys/sysctl.h> #include <sys/sysent.h> -#include <sys/sysproto.h> -#include <sys/vnode.h> -#include <sys/eventhandler.h> -#include <vm/vm.h> #include <vm/pmap.h> -#include <vm/vm_extern.h> +#include <vm/vm.h> #include <vm/vm_map.h> -#include <vm/vm_object.h> -#include <vm/vm_page.h> #include <vm/vm_param.h> -#include <machine/cpu.h> #include <machine/md_var.h> -#include <machine/pcb.h> -#include <machine/specialreg.h> #include <machine/trap.h> #include <x86/linux/linux_x86.h> #include <amd64/linux32/linux.h> #include <amd64/linux32/linux32_proto.h> +#include <compat/linux/linux_elf.h> #include <compat/linux/linux_emul.h> #include <compat/linux/linux_fork.h> #include <compat/linux/linux_ioctl.h> @@ -113,11 +95,10 @@ extern char _binary_linux32_vdso_so_o_end; static vm_offset_t linux_vdso_base; extern struct sysent linux32_sysent[LINUX32_SYS_MAXSYSCALL]; +extern const char *linux32_syscallnames[]; SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler); -static int linux_fixup_elf(uintptr_t *stack_base, - struct image_params *iparams); static int linux_copyout_strings(struct image_params *imgp, uintptr_t *stack_base); static void linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask); @@ -127,7 +108,6 @@ static void linux_exec_sysvec_init(void *param); static int linux_on_exec_vmspace(struct proc *p, struct image_params *imgp); static void linux32_fixlimit(struct rlimit *rl, int which); -static bool linux32_trans_osrel(const Elf_Note *note, int32_t *osrel); static void linux_vdso_install(const void *param); static void linux_vdso_deinstall(const void *param); static void linux_vdso_reloc(char *mapping, Elf_Addr offset); @@ -151,74 +131,15 @@ LINUX_VDSO_SYM_INTPTR(kern_tsc_selector); LINUX_VDSO_SYM_INTPTR(kern_cpu_selector); LINUX_VDSO_SYM_CHAR(linux_platform); -static int -linux_copyout_auxargs(struct image_params *imgp, uintptr_t base) +void +linux32_arch_copyout_auxargs(struct image_params *imgp, Elf_Auxinfo **pos) { - Elf32_Auxargs *args; - Elf32_Auxinfo *argarray, *pos; - int error, issetugid; - - args = (Elf32_Auxargs *)imgp->auxargs; - argarray = pos = malloc(LINUX_AT_COUNT * sizeof(*pos), M_TEMP, - M_WAITOK | M_ZERO); - - issetugid = imgp->proc->p_flag & P_SUGID ? 1 : 0; - AUXARGS_ENTRY(pos, LINUX_AT_SYSINFO, __kernel_vsyscall); - AUXARGS_ENTRY(pos, LINUX_AT_SYSINFO_EHDR, linux_vdso_base); - AUXARGS_ENTRY(pos, LINUX_AT_HWCAP, cpu_feature); - AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz); - /* - * Do not export AT_CLKTCK when emulating Linux kernel prior to 2.4.0, - * as it has appeared in the 2.4.0-rc7 first time. - * Being exported, AT_CLKTCK is returned by sysconf(_SC_CLK_TCK), - * glibc falls back to the hard-coded CLK_TCK value when aux entry - * is not present. - * Also see linux_times() implementation. - */ - if (linux_kernver(curthread) >= LINUX_KERNVER_2004000) - AUXARGS_ENTRY(pos, LINUX_AT_CLKTCK, stclohz); - AUXARGS_ENTRY(pos, AT_PHDR, args->phdr); - AUXARGS_ENTRY(pos, AT_PHENT, args->phent); - AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum); - AUXARGS_ENTRY(pos, AT_BASE, args->base); - AUXARGS_ENTRY(pos, AT_FLAGS, args->flags); - AUXARGS_ENTRY(pos, AT_ENTRY, args->entry); - AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_ucred->cr_ruid); - AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid); - AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_ucred->cr_rgid); - AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid); - AUXARGS_ENTRY(pos, LINUX_AT_SECURE, issetugid); - AUXARGS_ENTRY(pos, LINUX_AT_RANDOM, PTROUT(imgp->canary)); - AUXARGS_ENTRY(pos, LINUX_AT_HWCAP2, 0); - if (imgp->execpathp != 0) - AUXARGS_ENTRY(pos, LINUX_AT_EXECFN, PTROUT(imgp->execpathp)); - if (args->execfd != -1) - AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); - AUXARGS_ENTRY(pos, LINUX_AT_PLATFORM, PTROUT(linux_platform)); - AUXARGS_ENTRY(pos, AT_NULL, 0); - - free(imgp->auxargs, M_TEMP); - imgp->auxargs = NULL; - KASSERT(pos - argarray <= LINUX_AT_COUNT, ("Too many auxargs")); - - error = copyout(argarray, (void *)base, - sizeof(*argarray) * LINUX_AT_COUNT); - free(argarray, M_TEMP); - return (error); -} - -static int -linux_fixup_elf(uintptr_t *stack_base, struct image_params *imgp) -{ - Elf32_Addr *base; - - base = (Elf32_Addr *)*stack_base; - base--; - if (suword32(base, (uint32_t)imgp->args->argc) == -1) - return (EFAULT); - *stack_base = (uintptr_t)base; - return (0); + AUXARGS_ENTRY((*pos), LINUX_AT_SYSINFO, __kernel_vsyscall); + AUXARGS_ENTRY((*pos), LINUX_AT_SYSINFO_EHDR, linux_vdso_base); + AUXARGS_ENTRY((*pos), LINUX_AT_HWCAP, cpu_feature); + AUXARGS_ENTRY((*pos), LINUX_AT_HWCAP2, linux_x86_elf_hwcap2()); + AUXARGS_ENTRY((*pos), LINUX_AT_PLATFORM, PTROUT(linux_platform)); } static void @@ -604,13 +525,13 @@ linux32_fetch_syscall_args(struct thread *td) sa->args[2] = frame->tf_rdx; sa->args[3] = frame->tf_rsi; sa->args[4] = frame->tf_rdi; - sa->args[5] = frame->tf_rbp; /* Unconfirmed */ + sa->args[5] = frame->tf_rbp; sa->code = frame->tf_rax; sa->original_code = sa->code; if (sa->code >= p->p_sysent->sv_size) /* nosys */ - sa->callp = &p->p_sysent->sv_table[p->p_sysent->sv_size - 1]; + sa->callp = &nosys_sysent; else sa->callp = &p->p_sysent->sv_table[sa->code]; @@ -856,7 +777,7 @@ linux32_fixlimit(struct rlimit *rl, int which) struct sysentvec elf_linux_sysvec = { .sv_size = LINUX32_SYS_MAXSYSCALL, .sv_table = linux32_sysent, - .sv_fixup = linux_fixup_elf, + .sv_fixup = elf32_freebsd_fixup, .sv_sendsig = linux_sendsig, .sv_sigcode = &_binary_linux32_vdso_so_o_start, .sv_szsigcode = &linux_szsigcode, @@ -865,7 +786,6 @@ struct sysentvec elf_linux_sysvec = { .sv_elf_core_osabi = ELFOSABI_NONE, .sv_elf_core_abi_vendor = LINUX_ABI_VENDOR, .sv_elf_core_prepare_notes = linux32_prepare_notes, - .sv_imgact_try = linux_exec_imgact_try, .sv_minsigstksz = LINUX_MINSIGSTKSZ, .sv_minuser = VM_MIN_ADDRESS, .sv_maxuser = LINUX32_MAXUSER, @@ -873,7 +793,7 @@ struct sysentvec elf_linux_sysvec = { .sv_psstrings = LINUX32_PS_STRINGS, .sv_psstringssz = sizeof(struct linux32_ps_strings), .sv_stackprot = VM_PROT_ALL, - .sv_copyout_auxargs = linux_copyout_auxargs, + .sv_copyout_auxargs = __linuxN(copyout_auxargs), .sv_copyout_strings = linux_copyout_strings, .sv_setregs = linux_exec_setregs, .sv_fixlimit = linux32_fixlimit, @@ -882,12 +802,14 @@ struct sysentvec elf_linux_sysvec = { SV_SIG_DISCIGN | SV_SIG_WAITNDQ | SV_TIMEKEEP, .sv_set_syscall_retval = linux32_set_syscall_retval, .sv_fetch_syscall_args = linux32_fetch_syscall_args, - .sv_syscallnames = NULL, + .sv_syscallnames = linux32_syscallnames, .sv_shared_page_base = LINUX32_SHAREDPAGE, .sv_shared_page_len = PAGE_SIZE, .sv_schedtail = linux_schedtail, .sv_thread_detach = linux_thread_detach, .sv_trap = NULL, + .sv_hwcap = NULL, + .sv_hwcap2 = NULL, .sv_onexec = linux_on_exec_vmspace, .sv_onexit = linux_on_exit, .sv_ontdexit = linux_thread_dtor, @@ -903,7 +825,7 @@ linux_on_exec_vmspace(struct proc *p, struct image_params *imgp) error = linux_map_vdso(p, linux_vdso_obj, linux_vdso_base, LINUX32_VDSOPAGE_SIZE, imgp); if (error == 0) - linux_on_exec(p, imgp); + error = linux_on_exec(p, imgp); return (error); } @@ -924,7 +846,7 @@ linux_exec_sysvec_init(void *param) tkoff = kern_timekeep_base - linux_vdso_base; ktimekeep_base = (l_uintptr_t *)(linux_vdso_mapping + tkoff); - *ktimekeep_base = sv->sv_timekeep_base; + *ktimekeep_base = sv->sv_shared_page_base + sv->sv_timekeep_offset; tkoff = kern_tsc_selector - linux_vdso_base; ktsc_selector = (l_uintptr_t *)(linux_vdso_mapping + tkoff); @@ -1029,46 +951,19 @@ linux_vdso_reloc(char *mapping, Elf_Addr offset) } } -static char GNU_ABI_VENDOR[] = "GNU"; -static int GNULINUX_ABI_DESC = 0; - -static bool -linux32_trans_osrel(const Elf_Note *note, int32_t *osrel) -{ - const Elf32_Word *desc; - uintptr_t p; - - p = (uintptr_t)(note + 1); - p += roundup2(note->n_namesz, sizeof(Elf32_Addr)); - - desc = (const Elf32_Word *)p; - if (desc[0] != GNULINUX_ABI_DESC) - return (false); - - /* - * For Linux we encode osrel using the Linux convention of - * (version << 16) | (major << 8) | (minor) - * See macro in linux_mib.h - */ - *osrel = LINUX_KERNVER(desc[1], desc[2], desc[3]); - - return (true); -} - static Elf_Brandnote linux32_brandnote = { .hdr.n_namesz = sizeof(GNU_ABI_VENDOR), .hdr.n_descsz = 16, /* XXX at least 16 */ .hdr.n_type = 1, .vendor = GNU_ABI_VENDOR, .flags = BN_TRANSLATE_OSREL, - .trans_osrel = linux32_trans_osrel + .trans_osrel = linux_trans_osrel }; static Elf32_Brandinfo linux_brand = { .brand = ELFOSABI_LINUX, .machine = EM_386, .compat_3_brand = "Linux", - .emul_path = linux_emul_path, .interp_path = "/lib/ld-linux.so.1", .sysvec = &elf_linux_sysvec, .interp_newpath = NULL, @@ -1080,7 +975,6 @@ static Elf32_Brandinfo linux_glibc2brand = { .brand = ELFOSABI_LINUX, .machine = EM_386, .compat_3_brand = "Linux", - .emul_path = linux_emul_path, .interp_path = "/lib/ld-linux.so.2", .sysvec = &elf_linux_sysvec, .interp_newpath = NULL, @@ -1092,7 +986,6 @@ static Elf32_Brandinfo linux_muslbrand = { .brand = ELFOSABI_LINUX, .machine = EM_386, .compat_3_brand = "Linux", - .emul_path = linux_emul_path, .interp_path = "/lib/ld-musl-i386.so.1", .sysvec = &elf_linux_sysvec, .interp_newpath = NULL, @@ -1101,7 +994,7 @@ static Elf32_Brandinfo linux_muslbrand = { LINUX_BI_FUTEX_REQUEUE }; -Elf32_Brandinfo *linux_brandlist[] = { +static Elf32_Brandinfo *linux_brandlist[] = { &linux_brand, &linux_glibc2brand, &linux_muslbrand, |