1*151fa70fSchristos /* $NetBSD: linux_exec_elf32.c,v 1.13 1996/04/05 00:01:10 christos Exp $ */ 23bf459f3Sfvdl 33bf459f3Sfvdl /* 43bf459f3Sfvdl * Copyright (c) 1995 Frank van der Linden 5fb777788Sfvdl * Copyright (c) 1994 Christos Zoulas 63bf459f3Sfvdl * All rights reserved. 73bf459f3Sfvdl * 83bf459f3Sfvdl * Redistribution and use in source and binary forms, with or without 93bf459f3Sfvdl * modification, are permitted provided that the following conditions 103bf459f3Sfvdl * are met: 113bf459f3Sfvdl * 1. Redistributions of source code must retain the above copyright 123bf459f3Sfvdl * notice, this list of conditions and the following disclaimer. 133bf459f3Sfvdl * 2. Redistributions in binary form must reproduce the above copyright 143bf459f3Sfvdl * notice, this list of conditions and the following disclaimer in the 153bf459f3Sfvdl * documentation and/or other materials provided with the distribution. 16fb777788Sfvdl * 3. The name of the author may not be used to endorse or promote products 173bf459f3Sfvdl * derived from this software without specific prior written permission 183bf459f3Sfvdl * 193bf459f3Sfvdl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 203bf459f3Sfvdl * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 213bf459f3Sfvdl * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 223bf459f3Sfvdl * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 233bf459f3Sfvdl * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 243bf459f3Sfvdl * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 253bf459f3Sfvdl * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 263bf459f3Sfvdl * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 273bf459f3Sfvdl * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 283bf459f3Sfvdl * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 293bf459f3Sfvdl * 30fb777788Sfvdl * based on exec_aout.c, sunos_exec.c and svr4_exec.c 313bf459f3Sfvdl */ 323bf459f3Sfvdl 333bf459f3Sfvdl #include <sys/param.h> 343bf459f3Sfvdl #include <sys/systm.h> 353bf459f3Sfvdl #include <sys/kernel.h> 363bf459f3Sfvdl #include <sys/proc.h> 373bf459f3Sfvdl #include <sys/malloc.h> 383bf459f3Sfvdl #include <sys/namei.h> 393bf459f3Sfvdl #include <sys/vnode.h> 40*151fa70fSchristos #include <sys/mount.h> 41c4aaa600Sfvdl #include <sys/exec_elf.h> 423bf459f3Sfvdl 433bf459f3Sfvdl #include <sys/mman.h> 44*151fa70fSchristos #include <sys/syscallargs.h> 45*151fa70fSchristos 463bf459f3Sfvdl #include <vm/vm.h> 473bf459f3Sfvdl #include <vm/vm_param.h> 483bf459f3Sfvdl #include <vm/vm_map.h> 493bf459f3Sfvdl 503bf459f3Sfvdl #include <machine/cpu.h> 513bf459f3Sfvdl #include <machine/reg.h> 523bf459f3Sfvdl #include <machine/exec.h> 5344eef7c2Schristos #include <machine/linux_machdep.h> 543bf459f3Sfvdl 553bf459f3Sfvdl #include <compat/linux/linux_types.h> 5644eef7c2Schristos #include <compat/linux/linux_syscall.h> 5788b8e43aSmycroft #include <compat/linux/linux_signal.h> 583bf459f3Sfvdl #include <compat/linux/linux_syscallargs.h> 593bf459f3Sfvdl #include <compat/linux/linux_util.h> 603bf459f3Sfvdl #include <compat/linux/linux_exec.h> 613bf459f3Sfvdl 62fc7cfb5fSfvdl static void *linux_aout_copyargs __P((struct exec_package *, 63fc7cfb5fSfvdl struct ps_strings *, void *, void *)); 64fc7cfb5fSfvdl 65fc7cfb5fSfvdl #define LINUX_AOUT_AUX_ARGSIZ 2 66c4aaa600Sfvdl #define LINUX_ELF_AUX_ARGSIZ (sizeof(AuxInfo) * 8 / sizeof(char *)) 67c4aaa600Sfvdl 6844eef7c2Schristos 696b95b513Schristos const char linux_emul_path[] = "/emul/linux"; 7044eef7c2Schristos extern int linux_error[]; 71245f292fSmycroft extern char linux_sigcode[], linux_esigcode[]; 7244eef7c2Schristos extern struct sysent linux_sysent[]; 7344eef7c2Schristos extern char *linux_syscallnames[]; 7444eef7c2Schristos 75*151fa70fSchristos int exec_linux_aout_prep_zmagic __P((struct proc *, struct exec_package *)); 76*151fa70fSchristos int exec_linux_aout_prep_nmagic __P((struct proc *, struct exec_package *)); 77*151fa70fSchristos int exec_linux_aout_prep_omagic __P((struct proc *, struct exec_package *)); 78*151fa70fSchristos int exec_linux_aout_prep_qmagic __P((struct proc *, struct exec_package *)); 79*151fa70fSchristos 80fc7cfb5fSfvdl struct emul emul_linux_aout = { 8144eef7c2Schristos "linux", 8244eef7c2Schristos linux_error, 8344eef7c2Schristos linux_sendsig, 8444eef7c2Schristos LINUX_SYS_syscall, 8544eef7c2Schristos LINUX_SYS_MAXSYSCALL, 8644eef7c2Schristos linux_sysent, 8744eef7c2Schristos linux_syscallnames, 88fc7cfb5fSfvdl LINUX_AOUT_AUX_ARGSIZ, 89fc7cfb5fSfvdl linux_aout_copyargs, 90fc7cfb5fSfvdl setregs, 91fc7cfb5fSfvdl linux_sigcode, 92fc7cfb5fSfvdl linux_esigcode, 93fc7cfb5fSfvdl }; 94fc7cfb5fSfvdl 95fc7cfb5fSfvdl struct emul emul_linux_elf = { 96fc7cfb5fSfvdl "linux", 97fc7cfb5fSfvdl linux_error, 98fc7cfb5fSfvdl linux_sendsig, 99fc7cfb5fSfvdl LINUX_SYS_syscall, 100fc7cfb5fSfvdl LINUX_SYS_MAXSYSCALL, 101fc7cfb5fSfvdl linux_sysent, 102fc7cfb5fSfvdl linux_syscallnames, 103fc7cfb5fSfvdl LINUX_ELF_AUX_ARGSIZ, 104c4aaa600Sfvdl elf_copyargs, 10544eef7c2Schristos setregs, 10644eef7c2Schristos linux_sigcode, 10744eef7c2Schristos linux_esigcode, 10844eef7c2Schristos }; 10944eef7c2Schristos 11044eef7c2Schristos 11144eef7c2Schristos static void * 112fc7cfb5fSfvdl linux_aout_copyargs(pack, arginfo, stack, argp) 11344eef7c2Schristos struct exec_package *pack; 11444eef7c2Schristos struct ps_strings *arginfo; 11544eef7c2Schristos void *stack; 11644eef7c2Schristos void *argp; 11744eef7c2Schristos { 11844eef7c2Schristos char **cpp = stack; 11944eef7c2Schristos char **stk = stack; 12044eef7c2Schristos char *dp, *sp; 12144eef7c2Schristos size_t len; 12244eef7c2Schristos void *nullp = NULL; 12344eef7c2Schristos int argc = arginfo->ps_nargvstr; 12444eef7c2Schristos int envc = arginfo->ps_nenvstr; 12544eef7c2Schristos 12644eef7c2Schristos if (copyout(&argc, cpp++, sizeof(argc))) 12744eef7c2Schristos return NULL; 12844eef7c2Schristos 12944eef7c2Schristos /* leave room for envp and argv */ 13044eef7c2Schristos cpp += 2; 13144eef7c2Schristos if (copyout(&cpp, &stk[1], sizeof (cpp))) 13244eef7c2Schristos return NULL; 13344eef7c2Schristos 13444eef7c2Schristos dp = (char *) (cpp + argc + envc + 2); 13544eef7c2Schristos sp = argp; 13644eef7c2Schristos 13744eef7c2Schristos /* XXX don't copy them out, remap them! */ 138bfd22ffdSmycroft arginfo->ps_argvstr = cpp; /* remember location of argv for later */ 13944eef7c2Schristos 14044eef7c2Schristos for (; --argc >= 0; sp += len, dp += len) 14144eef7c2Schristos if (copyout(&dp, cpp++, sizeof(dp)) || 14244eef7c2Schristos copyoutstr(sp, dp, ARG_MAX, &len)) 14344eef7c2Schristos return NULL; 14444eef7c2Schristos 14544eef7c2Schristos if (copyout(&nullp, cpp++, sizeof(nullp))) 14644eef7c2Schristos return NULL; 14744eef7c2Schristos 14844eef7c2Schristos if (copyout(&cpp, &stk[2], sizeof (cpp))) 14944eef7c2Schristos return NULL; 15044eef7c2Schristos 151bfd22ffdSmycroft arginfo->ps_envstr = cpp; /* remember location of envp for later */ 15244eef7c2Schristos 15344eef7c2Schristos for (; --envc >= 0; sp += len, dp += len) 15444eef7c2Schristos if (copyout(&dp, cpp++, sizeof(dp)) || 15544eef7c2Schristos copyoutstr(sp, dp, ARG_MAX, &len)) 15644eef7c2Schristos return NULL; 15744eef7c2Schristos 15844eef7c2Schristos if (copyout(&nullp, cpp++, sizeof(nullp))) 15944eef7c2Schristos return NULL; 16044eef7c2Schristos 16144eef7c2Schristos return cpp; 16244eef7c2Schristos } 16344eef7c2Schristos 1643bf459f3Sfvdl int 1653bf459f3Sfvdl exec_linux_aout_makecmds(p, epp) 1663bf459f3Sfvdl struct proc *p; 1673bf459f3Sfvdl struct exec_package *epp; 1683bf459f3Sfvdl { 1693bf459f3Sfvdl struct exec *linux_ep = epp->ep_hdr; 1703bf459f3Sfvdl int machtype, magic; 1713bf459f3Sfvdl int error = ENOEXEC; 1723bf459f3Sfvdl 1733bf459f3Sfvdl magic = LINUX_N_MAGIC(linux_ep); 1743bf459f3Sfvdl machtype = LINUX_N_MACHTYPE(linux_ep); 1753bf459f3Sfvdl 1763bf459f3Sfvdl 1773bf459f3Sfvdl if (machtype != LINUX_MID_MACHINE) 1783bf459f3Sfvdl return (ENOEXEC); 1793bf459f3Sfvdl 1803bf459f3Sfvdl switch (magic) { 1813bf459f3Sfvdl case QMAGIC: 1823bf459f3Sfvdl error = exec_linux_aout_prep_qmagic(p, epp); 1833bf459f3Sfvdl break; 1843bf459f3Sfvdl case ZMAGIC: 1853bf459f3Sfvdl error = exec_linux_aout_prep_zmagic(p, epp); 1863bf459f3Sfvdl break; 1873bf459f3Sfvdl case NMAGIC: 1883bf459f3Sfvdl error = exec_linux_aout_prep_nmagic(p, epp); 1893bf459f3Sfvdl break; 1903bf459f3Sfvdl case OMAGIC: 1913bf459f3Sfvdl error = exec_linux_aout_prep_omagic(p, epp); 1923bf459f3Sfvdl break; 1933bf459f3Sfvdl } 19444eef7c2Schristos if (error == 0) 195fc7cfb5fSfvdl epp->ep_emul = &emul_linux_aout; 1963bf459f3Sfvdl return error; 1973bf459f3Sfvdl } 1983bf459f3Sfvdl 1993bf459f3Sfvdl /* 2003bf459f3Sfvdl * Since text starts at 0x400 in Linux ZMAGIC executables, and 0x400 2013bf459f3Sfvdl * is very likely not page aligned on most architectures, it is treated 2023bf459f3Sfvdl * as an NMAGIC here. XXX 2033bf459f3Sfvdl */ 2043bf459f3Sfvdl 2053bf459f3Sfvdl int 2063bf459f3Sfvdl exec_linux_aout_prep_zmagic(p, epp) 2073bf459f3Sfvdl struct proc *p; 2083bf459f3Sfvdl struct exec_package *epp; 2093bf459f3Sfvdl { 2103bf459f3Sfvdl struct exec *execp = epp->ep_hdr; 2113bf459f3Sfvdl 2123bf459f3Sfvdl epp->ep_taddr = LINUX_N_TXTADDR(*execp, ZMAGIC); 2133bf459f3Sfvdl epp->ep_tsize = execp->a_text; 2143bf459f3Sfvdl epp->ep_daddr = LINUX_N_DATADDR(*execp, ZMAGIC); 2153bf459f3Sfvdl epp->ep_dsize = execp->a_data + execp->a_bss; 2163bf459f3Sfvdl epp->ep_entry = execp->a_entry; 2173bf459f3Sfvdl 2183bf459f3Sfvdl /* set up command for text segment */ 2193bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_text, 2203bf459f3Sfvdl epp->ep_taddr, epp->ep_vp, LINUX_N_TXTOFF(*execp, ZMAGIC), 2213bf459f3Sfvdl VM_PROT_READ|VM_PROT_EXECUTE); 2223bf459f3Sfvdl 2233bf459f3Sfvdl /* set up command for data segment */ 2243bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_data, 2253bf459f3Sfvdl epp->ep_daddr, epp->ep_vp, LINUX_N_DATOFF(*execp, ZMAGIC), 2263bf459f3Sfvdl VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 2273bf459f3Sfvdl 2283bf459f3Sfvdl /* set up command for bss segment */ 2293bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, execp->a_bss, 2303bf459f3Sfvdl epp->ep_daddr + execp->a_data, NULLVP, 0, 2313bf459f3Sfvdl VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 2323bf459f3Sfvdl 2333bf459f3Sfvdl return exec_aout_setup_stack(p, epp); 2343bf459f3Sfvdl } 2353bf459f3Sfvdl 2363bf459f3Sfvdl /* 2373bf459f3Sfvdl * exec_aout_prep_nmagic(): Prepare Linux NMAGIC package. 2383bf459f3Sfvdl * Not different from the normal stuff. 2393bf459f3Sfvdl */ 2403bf459f3Sfvdl 2413bf459f3Sfvdl int 2423bf459f3Sfvdl exec_linux_aout_prep_nmagic(p, epp) 2433bf459f3Sfvdl struct proc *p; 2443bf459f3Sfvdl struct exec_package *epp; 2453bf459f3Sfvdl { 2463bf459f3Sfvdl struct exec *execp = epp->ep_hdr; 2473bf459f3Sfvdl long bsize, baddr; 2483bf459f3Sfvdl 2493bf459f3Sfvdl epp->ep_taddr = LINUX_N_TXTADDR(*execp, NMAGIC); 2503bf459f3Sfvdl epp->ep_tsize = execp->a_text; 2513bf459f3Sfvdl epp->ep_daddr = LINUX_N_DATADDR(*execp, NMAGIC); 2523bf459f3Sfvdl epp->ep_dsize = execp->a_data + execp->a_bss; 2533bf459f3Sfvdl epp->ep_entry = execp->a_entry; 2543bf459f3Sfvdl 2553bf459f3Sfvdl /* set up command for text segment */ 2563bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_text, 2573bf459f3Sfvdl epp->ep_taddr, epp->ep_vp, LINUX_N_TXTOFF(*execp, NMAGIC), 2583bf459f3Sfvdl VM_PROT_READ|VM_PROT_EXECUTE); 2593bf459f3Sfvdl 2603bf459f3Sfvdl /* set up command for data segment */ 2613bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_data, 2623bf459f3Sfvdl epp->ep_daddr, epp->ep_vp, LINUX_N_DATOFF(*execp, NMAGIC), 2633bf459f3Sfvdl VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 2643bf459f3Sfvdl 2653bf459f3Sfvdl /* set up command for bss segment */ 2663bf459f3Sfvdl baddr = roundup(epp->ep_daddr + execp->a_data, NBPG); 2673bf459f3Sfvdl bsize = epp->ep_daddr + epp->ep_dsize - baddr; 2683bf459f3Sfvdl if (bsize > 0) 2693bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr, 2703bf459f3Sfvdl NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 2713bf459f3Sfvdl 2723bf459f3Sfvdl return exec_aout_setup_stack(p, epp); 2733bf459f3Sfvdl } 2743bf459f3Sfvdl 2753bf459f3Sfvdl /* 2763bf459f3Sfvdl * exec_aout_prep_omagic(): Prepare Linux OMAGIC package. 2773bf459f3Sfvdl * Business as usual. 2783bf459f3Sfvdl */ 2793bf459f3Sfvdl 2803bf459f3Sfvdl int 2813bf459f3Sfvdl exec_linux_aout_prep_omagic(p, epp) 2823bf459f3Sfvdl struct proc *p; 2833bf459f3Sfvdl struct exec_package *epp; 2843bf459f3Sfvdl { 2853bf459f3Sfvdl struct exec *execp = epp->ep_hdr; 2863bf459f3Sfvdl long dsize, bsize, baddr; 2873bf459f3Sfvdl 2883bf459f3Sfvdl epp->ep_taddr = LINUX_N_TXTADDR(*execp, OMAGIC); 2893bf459f3Sfvdl epp->ep_tsize = execp->a_text; 2903bf459f3Sfvdl epp->ep_daddr = LINUX_N_DATADDR(*execp, OMAGIC); 2913bf459f3Sfvdl epp->ep_dsize = execp->a_data + execp->a_bss; 2923bf459f3Sfvdl epp->ep_entry = execp->a_entry; 2933bf459f3Sfvdl 2943bf459f3Sfvdl /* set up command for text and data segments */ 2953bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, 2963bf459f3Sfvdl execp->a_text + execp->a_data, epp->ep_taddr, epp->ep_vp, 2973bf459f3Sfvdl LINUX_N_TXTOFF(*execp, OMAGIC), VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 2983bf459f3Sfvdl 2993bf459f3Sfvdl /* set up command for bss segment */ 3003bf459f3Sfvdl baddr = roundup(epp->ep_daddr + execp->a_data, NBPG); 3013bf459f3Sfvdl bsize = epp->ep_daddr + epp->ep_dsize - baddr; 3023bf459f3Sfvdl if (bsize > 0) 3033bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr, 3043bf459f3Sfvdl NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 3053bf459f3Sfvdl 3063bf459f3Sfvdl /* 3073bf459f3Sfvdl * Make sure (# of pages) mapped above equals (vm_tsize + vm_dsize); 3083bf459f3Sfvdl * obreak(2) relies on this fact. Both `vm_tsize' and `vm_dsize' are 3093bf459f3Sfvdl * computed (in execve(2)) by rounding *up* `ep_tsize' and `ep_dsize' 3103bf459f3Sfvdl * respectively to page boundaries. 3113bf459f3Sfvdl * Compensate `ep_dsize' for the amount of data covered by the last 3123bf459f3Sfvdl * text page. 3133bf459f3Sfvdl */ 3143bf459f3Sfvdl dsize = epp->ep_dsize + execp->a_text - roundup(execp->a_text, NBPG); 3153bf459f3Sfvdl epp->ep_dsize = (dsize > 0) ? dsize : 0; 3163bf459f3Sfvdl return exec_aout_setup_stack(p, epp); 3173bf459f3Sfvdl } 3183bf459f3Sfvdl 3193bf459f3Sfvdl int 3203bf459f3Sfvdl exec_linux_aout_prep_qmagic(p, epp) 3213bf459f3Sfvdl struct proc *p; 3223bf459f3Sfvdl struct exec_package *epp; 3233bf459f3Sfvdl { 3243bf459f3Sfvdl struct exec *execp = epp->ep_hdr; 3253bf459f3Sfvdl 3263bf459f3Sfvdl epp->ep_taddr = LINUX_N_TXTADDR(*execp, QMAGIC); 3273bf459f3Sfvdl epp->ep_tsize = execp->a_text; 3283bf459f3Sfvdl epp->ep_daddr = LINUX_N_DATADDR(*execp, QMAGIC); 3293bf459f3Sfvdl epp->ep_dsize = execp->a_data + execp->a_bss; 3303bf459f3Sfvdl epp->ep_entry = execp->a_entry; 3313bf459f3Sfvdl 3323bf459f3Sfvdl /* 3333bf459f3Sfvdl * check if vnode is in open for writing, because we want to 3343bf459f3Sfvdl * demand-page out of it. if it is, don't do it, for various 3353bf459f3Sfvdl * reasons 3363bf459f3Sfvdl */ 3373bf459f3Sfvdl if ((execp->a_text != 0 || execp->a_data != 0) && 3383bf459f3Sfvdl epp->ep_vp->v_writecount != 0) { 3393bf459f3Sfvdl #ifdef DIAGNOSTIC 3403bf459f3Sfvdl if (epp->ep_vp->v_flag & VTEXT) 3413bf459f3Sfvdl panic("exec: a VTEXT vnode has writecount != 0\n"); 3423bf459f3Sfvdl #endif 3433bf459f3Sfvdl return ETXTBSY; 3443bf459f3Sfvdl } 3453bf459f3Sfvdl epp->ep_vp->v_flag |= VTEXT; 3463bf459f3Sfvdl 3473bf459f3Sfvdl /* set up command for text segment */ 3483bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_text, 3493bf459f3Sfvdl epp->ep_taddr, epp->ep_vp, LINUX_N_TXTOFF(*execp, QMAGIC), 3503bf459f3Sfvdl VM_PROT_READ|VM_PROT_EXECUTE); 3513bf459f3Sfvdl 3523bf459f3Sfvdl /* set up command for data segment */ 3533bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_data, 3543bf459f3Sfvdl epp->ep_daddr, epp->ep_vp, LINUX_N_DATOFF(*execp, QMAGIC), 3553bf459f3Sfvdl VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 3563bf459f3Sfvdl 3573bf459f3Sfvdl /* set up command for bss segment */ 3583bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, execp->a_bss, 3593bf459f3Sfvdl epp->ep_daddr + execp->a_data, NULLVP, 0, 3603bf459f3Sfvdl VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 3613bf459f3Sfvdl 3623bf459f3Sfvdl return exec_aout_setup_stack(p, epp); 3633bf459f3Sfvdl } 3643bf459f3Sfvdl 365fc7cfb5fSfvdl int 366c4aaa600Sfvdl linux_elf_probe(p, epp, itp, pos) 367fc7cfb5fSfvdl struct proc *p; 368fc7cfb5fSfvdl struct exec_package *epp; 369c4aaa600Sfvdl char *itp; 370c4aaa600Sfvdl u_long *pos; 371fc7cfb5fSfvdl { 372c4aaa600Sfvdl char *bp; 373fc7cfb5fSfvdl int error; 374c4aaa600Sfvdl size_t len; 375fc7cfb5fSfvdl 376c4aaa600Sfvdl if (itp[0]) { 3776b95b513Schristos if ((error = emul_find(p, NULL, linux_emul_path, itp, &bp, 0))) 378c4aaa600Sfvdl return error; 379c4aaa600Sfvdl if ((error = copystr(bp, itp, MAXPATHLEN, &len))) 380c4aaa600Sfvdl return error; 381c4aaa600Sfvdl free(bp, M_TEMP); 382fc7cfb5fSfvdl } 383fc7cfb5fSfvdl epp->ep_emul = &emul_linux_elf; 384c4aaa600Sfvdl *pos = ELF32_NO_ADDR; 385c4aaa600Sfvdl return 0; 386fc7cfb5fSfvdl } 387c4aaa600Sfvdl 388fc7cfb5fSfvdl /* 389fc7cfb5fSfvdl * The Linux system call to load shared libraries, a.out version. The 390fc7cfb5fSfvdl * a.out shared libs are just files that are mapped onto a fixed 391fc7cfb5fSfvdl * address in the process' address space. The address is given in 3923bf459f3Sfvdl * a_entry. Read in the header, set up some VM commands and run them. 3933bf459f3Sfvdl * 3943bf459f3Sfvdl * Yes, both text and data are mapped at once, so we're left with 3953bf459f3Sfvdl * writeable text for the shared libs. The Linux crt0 seemed to break 3963bf459f3Sfvdl * sometimes when data was mapped seperately. It munmapped a uselib() 3973bf459f3Sfvdl * of ld.so by hand, which failed with shared text and data for ld.so 3983bf459f3Sfvdl * Yuck. 3993bf459f3Sfvdl * 4003bf459f3Sfvdl * Because of the problem with ZMAGIC executables (text starts 401fc7cfb5fSfvdl * at 0x400 in the file, but needs to be mapped at 0), ZMAGIC 4023bf459f3Sfvdl * shared libs are not handled very efficiently :-( 4033bf459f3Sfvdl */ 4043bf459f3Sfvdl 4053bf459f3Sfvdl int 406245f292fSmycroft linux_sys_uselib(p, v, retval) 4073bf459f3Sfvdl struct proc *p; 408e1da0d53Sthorpej void *v; 4093bf459f3Sfvdl register_t *retval; 4103bf459f3Sfvdl { 411245f292fSmycroft struct linux_sys_uselib_args /* { 412e1da0d53Sthorpej syscallarg(char *) path; 413e1da0d53Sthorpej } */ *uap = v; 4143bf459f3Sfvdl caddr_t sg; 4153bf459f3Sfvdl long bsize, dsize, tsize, taddr, baddr, daddr; 4163bf459f3Sfvdl struct nameidata ni; 4173bf459f3Sfvdl struct vnode *vp; 4183bf459f3Sfvdl struct exec hdr; 4193bf459f3Sfvdl struct exec_vmcmd_set vcset; 4203bf459f3Sfvdl int rem, i, magic, error; 4213bf459f3Sfvdl 4226b95b513Schristos sg = stackgap_init(p->p_emul); 4236b95b513Schristos LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path)); 4243bf459f3Sfvdl 4253bf459f3Sfvdl NDINIT(&ni, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 4263bf459f3Sfvdl 4273bf459f3Sfvdl if ((error = namei(&ni))) 4283bf459f3Sfvdl return error; 4293bf459f3Sfvdl 4303bf459f3Sfvdl vp = ni.ni_vp; 4313bf459f3Sfvdl 4323bf459f3Sfvdl if ((error = vn_rdwr(UIO_READ, vp, (caddr_t) &hdr, LINUX_AOUT_HDR_SIZE, 4333bf459f3Sfvdl 0, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, 4343bf459f3Sfvdl &rem, p))) { 4353bf459f3Sfvdl vrele(vp); 4363bf459f3Sfvdl return error; 4373bf459f3Sfvdl } 4383bf459f3Sfvdl 4393bf459f3Sfvdl if (rem != 0) { 4403bf459f3Sfvdl vrele(vp); 4413bf459f3Sfvdl return ENOEXEC; 4423bf459f3Sfvdl } 4433bf459f3Sfvdl 444fc7cfb5fSfvdl if (LINUX_N_MACHTYPE(&hdr) != LINUX_MID_MACHINE) 445fc7cfb5fSfvdl return ENOEXEC; 446fc7cfb5fSfvdl 4473bf459f3Sfvdl magic = LINUX_N_MAGIC(&hdr); 4483bf459f3Sfvdl taddr = hdr.a_entry & (~(NBPG - 1)); 4493bf459f3Sfvdl tsize = hdr.a_text; 4503bf459f3Sfvdl daddr = taddr + tsize; 4513bf459f3Sfvdl dsize = hdr.a_data + hdr.a_bss; 4523bf459f3Sfvdl 4533bf459f3Sfvdl if ((hdr.a_text != 0 || hdr.a_data != 0) && vp->v_writecount != 0) { 4543bf459f3Sfvdl vrele(vp); 4553bf459f3Sfvdl return ETXTBSY; 4563bf459f3Sfvdl } 4573bf459f3Sfvdl vp->v_flag |= VTEXT; 4583bf459f3Sfvdl 4593bf459f3Sfvdl vcset.evs_cnt = 0; 4603bf459f3Sfvdl vcset.evs_used = 0; 4613bf459f3Sfvdl 4623bf459f3Sfvdl NEW_VMCMD(&vcset, 4633bf459f3Sfvdl magic == ZMAGIC ? vmcmd_map_readvn : vmcmd_map_pagedvn, 4643bf459f3Sfvdl hdr.a_text + hdr.a_data, taddr, 4653bf459f3Sfvdl vp, LINUX_N_TXTOFF(hdr, magic), 4663bf459f3Sfvdl VM_PROT_READ|VM_PROT_EXECUTE|VM_PROT_WRITE); 4673bf459f3Sfvdl 4683bf459f3Sfvdl baddr = roundup(daddr + hdr.a_data, NBPG); 4693bf459f3Sfvdl bsize = daddr + dsize - baddr; 4703bf459f3Sfvdl if (bsize > 0) { 4713bf459f3Sfvdl NEW_VMCMD(&vcset, vmcmd_map_zero, bsize, baddr, 4723bf459f3Sfvdl NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 4733bf459f3Sfvdl } 4743bf459f3Sfvdl 4753bf459f3Sfvdl for (i = 0; i < vcset.evs_used && !error; i++) { 4763bf459f3Sfvdl struct exec_vmcmd *vcp; 4773bf459f3Sfvdl 4783bf459f3Sfvdl vcp = &vcset.evs_cmds[i]; 4793bf459f3Sfvdl error = (*vcp->ev_proc)(p, vcp); 4803bf459f3Sfvdl } 4813bf459f3Sfvdl 4823bf459f3Sfvdl kill_vmcmds(&vcset); 4833bf459f3Sfvdl 4843bf459f3Sfvdl vrele(vp); 4853bf459f3Sfvdl 4863bf459f3Sfvdl return error; 4873bf459f3Sfvdl } 4883bf459f3Sfvdl 4893bf459f3Sfvdl /* 4903bf459f3Sfvdl * Execve(2). Just check the alternate emulation path, and pass it on 4913bf459f3Sfvdl * to the NetBSD execve(). 4923bf459f3Sfvdl */ 4933bf459f3Sfvdl int 494245f292fSmycroft linux_sys_execve(p, v, retval) 4953bf459f3Sfvdl struct proc *p; 496e1da0d53Sthorpej void *v; 497e1da0d53Sthorpej register_t *retval; 498e1da0d53Sthorpej { 499245f292fSmycroft struct linux_sys_execve_args /* { 5003bf459f3Sfvdl syscallarg(char *) path; 5013bf459f3Sfvdl syscallarg(char **) argv; 5023bf459f3Sfvdl syscallarg(char **) envp; 503e1da0d53Sthorpej } */ *uap = v; 5043bf459f3Sfvdl caddr_t sg; 5053bf459f3Sfvdl 5066b95b513Schristos sg = stackgap_init(p->p_emul); 5076b95b513Schristos LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path)); 5083bf459f3Sfvdl 509245f292fSmycroft return sys_execve(p, uap, retval); 5103bf459f3Sfvdl } 511