1*44eef7c2Schristos /* $NetBSD: linux_exec_elf32.c,v 1.4 1995/04/22 19:48:34 christos Exp $ */ 23bf459f3Sfvdl 33bf459f3Sfvdl /* 43bf459f3Sfvdl * Copyright (c) 1995 Frank van der Linden 53bf459f3Sfvdl * All rights reserved. 63bf459f3Sfvdl * 73bf459f3Sfvdl * Redistribution and use in source and binary forms, with or without 83bf459f3Sfvdl * modification, are permitted provided that the following conditions 93bf459f3Sfvdl * are met: 103bf459f3Sfvdl * 1. Redistributions of source code must retain the above copyright 113bf459f3Sfvdl * notice, this list of conditions and the following disclaimer. 123bf459f3Sfvdl * 2. Redistributions in binary form must reproduce the above copyright 133bf459f3Sfvdl * notice, this list of conditions and the following disclaimer in the 143bf459f3Sfvdl * documentation and/or other materials provided with the distribution. 153bf459f3Sfvdl * 3. All advertising materials mentioning features or use of this software 163bf459f3Sfvdl * must display the following acknowledgement: 173bf459f3Sfvdl * This product includes software developed for the NetBSD Project 183bf459f3Sfvdl * by Frank van der Linden 193bf459f3Sfvdl * 4. The name of the author may not be used to endorse or promote products 203bf459f3Sfvdl * derived from this software without specific prior written permission 213bf459f3Sfvdl * 223bf459f3Sfvdl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 233bf459f3Sfvdl * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 243bf459f3Sfvdl * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 253bf459f3Sfvdl * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 263bf459f3Sfvdl * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 273bf459f3Sfvdl * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 283bf459f3Sfvdl * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 293bf459f3Sfvdl * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 303bf459f3Sfvdl * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 313bf459f3Sfvdl * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 323bf459f3Sfvdl * 333bf459f3Sfvdl * based on kern/exec_aout.c and compat/sunos/sunos_exec.c 343bf459f3Sfvdl */ 353bf459f3Sfvdl 363bf459f3Sfvdl #include <sys/param.h> 373bf459f3Sfvdl #include <sys/systm.h> 383bf459f3Sfvdl #include <sys/filedesc.h> 393bf459f3Sfvdl #include <sys/kernel.h> 403bf459f3Sfvdl #include <sys/proc.h> 413bf459f3Sfvdl #include <sys/mount.h> 423bf459f3Sfvdl #include <sys/malloc.h> 433bf459f3Sfvdl #include <sys/namei.h> 443bf459f3Sfvdl #include <sys/vnode.h> 453bf459f3Sfvdl #include <sys/file.h> 463bf459f3Sfvdl #include <sys/resourcevar.h> 473bf459f3Sfvdl #include <sys/wait.h> 483bf459f3Sfvdl 493bf459f3Sfvdl #include <sys/mman.h> 503bf459f3Sfvdl #include <vm/vm.h> 513bf459f3Sfvdl #include <vm/vm_param.h> 523bf459f3Sfvdl #include <vm/vm_map.h> 533bf459f3Sfvdl #include <vm/vm_kern.h> 543bf459f3Sfvdl #include <vm/vm_pager.h> 553bf459f3Sfvdl 563bf459f3Sfvdl #include <machine/cpu.h> 573bf459f3Sfvdl #include <machine/reg.h> 583bf459f3Sfvdl #include <machine/exec.h> 59*44eef7c2Schristos #include <machine/linux_machdep.h> 603bf459f3Sfvdl 613bf459f3Sfvdl #include <compat/linux/linux_types.h> 62*44eef7c2Schristos #include <compat/linux/linux_syscall.h> 633bf459f3Sfvdl #include <compat/linux/linux_syscallargs.h> 643bf459f3Sfvdl #include <compat/linux/linux_util.h> 653bf459f3Sfvdl #include <compat/linux/linux_exec.h> 663bf459f3Sfvdl 67*44eef7c2Schristos static void *linux_copyargs __P((struct exec_package *, struct ps_strings *, 68*44eef7c2Schristos void *, void *)); 69*44eef7c2Schristos 70*44eef7c2Schristos #define LINUX_AUX_ARGSIZ 2 71*44eef7c2Schristos 72*44eef7c2Schristos extern int linux_error[]; 73*44eef7c2Schristos extern struct sysent linux_sysent[]; 74*44eef7c2Schristos extern char *linux_syscallnames[]; 75*44eef7c2Schristos 76*44eef7c2Schristos struct emul emul_linux = { 77*44eef7c2Schristos "linux", 78*44eef7c2Schristos linux_error, 79*44eef7c2Schristos linux_sendsig, 80*44eef7c2Schristos LINUX_SYS_syscall, 81*44eef7c2Schristos LINUX_SYS_MAXSYSCALL, 82*44eef7c2Schristos linux_sysent, 83*44eef7c2Schristos linux_syscallnames, 84*44eef7c2Schristos LINUX_AUX_ARGSIZ, 85*44eef7c2Schristos linux_copyargs, 86*44eef7c2Schristos setregs, 87*44eef7c2Schristos linux_sigcode, 88*44eef7c2Schristos linux_esigcode, 89*44eef7c2Schristos }; 90*44eef7c2Schristos 91*44eef7c2Schristos 92*44eef7c2Schristos static void * 93*44eef7c2Schristos linux_copyargs(pack, arginfo, stack, argp) 94*44eef7c2Schristos struct exec_package *pack; 95*44eef7c2Schristos struct ps_strings *arginfo; 96*44eef7c2Schristos void *stack; 97*44eef7c2Schristos void *argp; 98*44eef7c2Schristos { 99*44eef7c2Schristos char **cpp = stack; 100*44eef7c2Schristos char **stk = stack; 101*44eef7c2Schristos char *dp, *sp; 102*44eef7c2Schristos size_t len; 103*44eef7c2Schristos void *nullp = NULL; 104*44eef7c2Schristos int argc = arginfo->ps_nargvstr; 105*44eef7c2Schristos int envc = arginfo->ps_nenvstr; 106*44eef7c2Schristos 107*44eef7c2Schristos if (copyout(&argc, cpp++, sizeof(argc))) 108*44eef7c2Schristos return NULL; 109*44eef7c2Schristos 110*44eef7c2Schristos /* leave room for envp and argv */ 111*44eef7c2Schristos cpp += 2; 112*44eef7c2Schristos if (copyout(&cpp, &stk[1], sizeof (cpp))) 113*44eef7c2Schristos return NULL; 114*44eef7c2Schristos 115*44eef7c2Schristos dp = (char *) (cpp + argc + envc + 2); 116*44eef7c2Schristos sp = argp; 117*44eef7c2Schristos 118*44eef7c2Schristos /* XXX don't copy them out, remap them! */ 119*44eef7c2Schristos arginfo->ps_argvstr = dp; /* remember location of argv for later */ 120*44eef7c2Schristos 121*44eef7c2Schristos for (; --argc >= 0; sp += len, dp += len) 122*44eef7c2Schristos if (copyout(&dp, cpp++, sizeof(dp)) || 123*44eef7c2Schristos copyoutstr(sp, dp, ARG_MAX, &len)) 124*44eef7c2Schristos return NULL; 125*44eef7c2Schristos 126*44eef7c2Schristos if (copyout(&nullp, cpp++, sizeof(nullp))) 127*44eef7c2Schristos return NULL; 128*44eef7c2Schristos 129*44eef7c2Schristos if (copyout(&cpp, &stk[2], sizeof (cpp))) 130*44eef7c2Schristos return NULL; 131*44eef7c2Schristos 132*44eef7c2Schristos arginfo->ps_envstr = dp; /* remember location of envp for later */ 133*44eef7c2Schristos 134*44eef7c2Schristos for (; --envc >= 0; sp += len, dp += len) 135*44eef7c2Schristos if (copyout(&dp, cpp++, sizeof(dp)) || 136*44eef7c2Schristos copyoutstr(sp, dp, ARG_MAX, &len)) 137*44eef7c2Schristos return NULL; 138*44eef7c2Schristos 139*44eef7c2Schristos if (copyout(&nullp, cpp++, sizeof(nullp))) 140*44eef7c2Schristos return NULL; 141*44eef7c2Schristos 142*44eef7c2Schristos return cpp; 143*44eef7c2Schristos } 144*44eef7c2Schristos 145*44eef7c2Schristos 1463bf459f3Sfvdl int 1473bf459f3Sfvdl exec_linux_aout_makecmds(p, epp) 1483bf459f3Sfvdl struct proc *p; 1493bf459f3Sfvdl struct exec_package *epp; 1503bf459f3Sfvdl { 1513bf459f3Sfvdl struct exec *linux_ep = epp->ep_hdr; 1523bf459f3Sfvdl int machtype, magic; 1533bf459f3Sfvdl int error = ENOEXEC; 1543bf459f3Sfvdl 1553bf459f3Sfvdl magic = LINUX_N_MAGIC(linux_ep); 1563bf459f3Sfvdl machtype = LINUX_N_MACHTYPE(linux_ep); 1573bf459f3Sfvdl 1583bf459f3Sfvdl 1593bf459f3Sfvdl if (machtype != LINUX_MID_MACHINE) 1603bf459f3Sfvdl return (ENOEXEC); 1613bf459f3Sfvdl 1623bf459f3Sfvdl switch (magic) { 1633bf459f3Sfvdl case QMAGIC: 1643bf459f3Sfvdl error = exec_linux_aout_prep_qmagic(p, epp); 1653bf459f3Sfvdl break; 1663bf459f3Sfvdl case ZMAGIC: 1673bf459f3Sfvdl error = exec_linux_aout_prep_zmagic(p, epp); 1683bf459f3Sfvdl break; 1693bf459f3Sfvdl case NMAGIC: 1703bf459f3Sfvdl error = exec_linux_aout_prep_nmagic(p, epp); 1713bf459f3Sfvdl break; 1723bf459f3Sfvdl case OMAGIC: 1733bf459f3Sfvdl error = exec_linux_aout_prep_omagic(p, epp); 1743bf459f3Sfvdl break; 1753bf459f3Sfvdl } 176*44eef7c2Schristos if (error == 0) 177*44eef7c2Schristos epp->ep_emul = &emul_linux; 1783bf459f3Sfvdl return error; 1793bf459f3Sfvdl } 1803bf459f3Sfvdl 1813bf459f3Sfvdl /* 1823bf459f3Sfvdl * Since text starts at 0x400 in Linux ZMAGIC executables, and 0x400 1833bf459f3Sfvdl * is very likely not page aligned on most architectures, it is treated 1843bf459f3Sfvdl * as an NMAGIC here. XXX 1853bf459f3Sfvdl */ 1863bf459f3Sfvdl 1873bf459f3Sfvdl int 1883bf459f3Sfvdl exec_linux_aout_prep_zmagic(p, epp) 1893bf459f3Sfvdl struct proc *p; 1903bf459f3Sfvdl struct exec_package *epp; 1913bf459f3Sfvdl { 1923bf459f3Sfvdl struct exec *execp = epp->ep_hdr; 1933bf459f3Sfvdl 1943bf459f3Sfvdl epp->ep_taddr = LINUX_N_TXTADDR(*execp, ZMAGIC); 1953bf459f3Sfvdl epp->ep_tsize = execp->a_text; 1963bf459f3Sfvdl epp->ep_daddr = LINUX_N_DATADDR(*execp, ZMAGIC); 1973bf459f3Sfvdl epp->ep_dsize = execp->a_data + execp->a_bss; 1983bf459f3Sfvdl epp->ep_entry = execp->a_entry; 1993bf459f3Sfvdl 2003bf459f3Sfvdl /* set up command for text segment */ 2013bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_text, 2023bf459f3Sfvdl epp->ep_taddr, epp->ep_vp, LINUX_N_TXTOFF(*execp, ZMAGIC), 2033bf459f3Sfvdl VM_PROT_READ|VM_PROT_EXECUTE); 2043bf459f3Sfvdl 2053bf459f3Sfvdl /* set up command for data segment */ 2063bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_data, 2073bf459f3Sfvdl epp->ep_daddr, epp->ep_vp, LINUX_N_DATOFF(*execp, ZMAGIC), 2083bf459f3Sfvdl VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 2093bf459f3Sfvdl 2103bf459f3Sfvdl /* set up command for bss segment */ 2113bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, execp->a_bss, 2123bf459f3Sfvdl epp->ep_daddr + execp->a_data, NULLVP, 0, 2133bf459f3Sfvdl VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 2143bf459f3Sfvdl 2153bf459f3Sfvdl return exec_aout_setup_stack(p, epp); 2163bf459f3Sfvdl } 2173bf459f3Sfvdl 2183bf459f3Sfvdl /* 2193bf459f3Sfvdl * exec_aout_prep_nmagic(): Prepare Linux NMAGIC package. 2203bf459f3Sfvdl * Not different from the normal stuff. 2213bf459f3Sfvdl */ 2223bf459f3Sfvdl 2233bf459f3Sfvdl int 2243bf459f3Sfvdl exec_linux_aout_prep_nmagic(p, epp) 2253bf459f3Sfvdl struct proc *p; 2263bf459f3Sfvdl struct exec_package *epp; 2273bf459f3Sfvdl { 2283bf459f3Sfvdl struct exec *execp = epp->ep_hdr; 2293bf459f3Sfvdl long bsize, baddr; 2303bf459f3Sfvdl 2313bf459f3Sfvdl epp->ep_taddr = LINUX_N_TXTADDR(*execp, NMAGIC); 2323bf459f3Sfvdl epp->ep_tsize = execp->a_text; 2333bf459f3Sfvdl epp->ep_daddr = LINUX_N_DATADDR(*execp, NMAGIC); 2343bf459f3Sfvdl epp->ep_dsize = execp->a_data + execp->a_bss; 2353bf459f3Sfvdl epp->ep_entry = execp->a_entry; 2363bf459f3Sfvdl 2373bf459f3Sfvdl /* set up command for text segment */ 2383bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_text, 2393bf459f3Sfvdl epp->ep_taddr, epp->ep_vp, LINUX_N_TXTOFF(*execp, NMAGIC), 2403bf459f3Sfvdl VM_PROT_READ|VM_PROT_EXECUTE); 2413bf459f3Sfvdl 2423bf459f3Sfvdl /* set up command for data segment */ 2433bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_data, 2443bf459f3Sfvdl epp->ep_daddr, epp->ep_vp, LINUX_N_DATOFF(*execp, NMAGIC), 2453bf459f3Sfvdl VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 2463bf459f3Sfvdl 2473bf459f3Sfvdl /* set up command for bss segment */ 2483bf459f3Sfvdl baddr = roundup(epp->ep_daddr + execp->a_data, NBPG); 2493bf459f3Sfvdl bsize = epp->ep_daddr + epp->ep_dsize - baddr; 2503bf459f3Sfvdl if (bsize > 0) 2513bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr, 2523bf459f3Sfvdl NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 2533bf459f3Sfvdl 2543bf459f3Sfvdl return exec_aout_setup_stack(p, epp); 2553bf459f3Sfvdl } 2563bf459f3Sfvdl 2573bf459f3Sfvdl /* 2583bf459f3Sfvdl * exec_aout_prep_omagic(): Prepare Linux OMAGIC package. 2593bf459f3Sfvdl * Business as usual. 2603bf459f3Sfvdl */ 2613bf459f3Sfvdl 2623bf459f3Sfvdl int 2633bf459f3Sfvdl exec_linux_aout_prep_omagic(p, epp) 2643bf459f3Sfvdl struct proc *p; 2653bf459f3Sfvdl struct exec_package *epp; 2663bf459f3Sfvdl { 2673bf459f3Sfvdl struct exec *execp = epp->ep_hdr; 2683bf459f3Sfvdl long dsize, bsize, baddr; 2693bf459f3Sfvdl 2703bf459f3Sfvdl epp->ep_taddr = LINUX_N_TXTADDR(*execp, OMAGIC); 2713bf459f3Sfvdl epp->ep_tsize = execp->a_text; 2723bf459f3Sfvdl epp->ep_daddr = LINUX_N_DATADDR(*execp, OMAGIC); 2733bf459f3Sfvdl epp->ep_dsize = execp->a_data + execp->a_bss; 2743bf459f3Sfvdl epp->ep_entry = execp->a_entry; 2753bf459f3Sfvdl 2763bf459f3Sfvdl /* set up command for text and data segments */ 2773bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, 2783bf459f3Sfvdl execp->a_text + execp->a_data, epp->ep_taddr, epp->ep_vp, 2793bf459f3Sfvdl LINUX_N_TXTOFF(*execp, OMAGIC), VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 2803bf459f3Sfvdl 2813bf459f3Sfvdl /* set up command for bss segment */ 2823bf459f3Sfvdl baddr = roundup(epp->ep_daddr + execp->a_data, NBPG); 2833bf459f3Sfvdl bsize = epp->ep_daddr + epp->ep_dsize - baddr; 2843bf459f3Sfvdl if (bsize > 0) 2853bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr, 2863bf459f3Sfvdl NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 2873bf459f3Sfvdl 2883bf459f3Sfvdl /* 2893bf459f3Sfvdl * Make sure (# of pages) mapped above equals (vm_tsize + vm_dsize); 2903bf459f3Sfvdl * obreak(2) relies on this fact. Both `vm_tsize' and `vm_dsize' are 2913bf459f3Sfvdl * computed (in execve(2)) by rounding *up* `ep_tsize' and `ep_dsize' 2923bf459f3Sfvdl * respectively to page boundaries. 2933bf459f3Sfvdl * Compensate `ep_dsize' for the amount of data covered by the last 2943bf459f3Sfvdl * text page. 2953bf459f3Sfvdl */ 2963bf459f3Sfvdl dsize = epp->ep_dsize + execp->a_text - roundup(execp->a_text, NBPG); 2973bf459f3Sfvdl epp->ep_dsize = (dsize > 0) ? dsize : 0; 2983bf459f3Sfvdl return exec_aout_setup_stack(p, epp); 2993bf459f3Sfvdl } 3003bf459f3Sfvdl 3013bf459f3Sfvdl int 3023bf459f3Sfvdl exec_linux_aout_prep_qmagic(p, epp) 3033bf459f3Sfvdl struct proc *p; 3043bf459f3Sfvdl struct exec_package *epp; 3053bf459f3Sfvdl { 3063bf459f3Sfvdl struct exec *execp = epp->ep_hdr; 3073bf459f3Sfvdl 3083bf459f3Sfvdl epp->ep_taddr = LINUX_N_TXTADDR(*execp, QMAGIC); 3093bf459f3Sfvdl epp->ep_tsize = execp->a_text; 3103bf459f3Sfvdl epp->ep_daddr = LINUX_N_DATADDR(*execp, QMAGIC); 3113bf459f3Sfvdl epp->ep_dsize = execp->a_data + execp->a_bss; 3123bf459f3Sfvdl epp->ep_entry = execp->a_entry; 3133bf459f3Sfvdl 3143bf459f3Sfvdl /* 3153bf459f3Sfvdl * check if vnode is in open for writing, because we want to 3163bf459f3Sfvdl * demand-page out of it. if it is, don't do it, for various 3173bf459f3Sfvdl * reasons 3183bf459f3Sfvdl */ 3193bf459f3Sfvdl if ((execp->a_text != 0 || execp->a_data != 0) && 3203bf459f3Sfvdl epp->ep_vp->v_writecount != 0) { 3213bf459f3Sfvdl #ifdef DIAGNOSTIC 3223bf459f3Sfvdl if (epp->ep_vp->v_flag & VTEXT) 3233bf459f3Sfvdl panic("exec: a VTEXT vnode has writecount != 0\n"); 3243bf459f3Sfvdl #endif 3253bf459f3Sfvdl return ETXTBSY; 3263bf459f3Sfvdl } 3273bf459f3Sfvdl epp->ep_vp->v_flag |= VTEXT; 3283bf459f3Sfvdl 3293bf459f3Sfvdl /* set up command for text segment */ 3303bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_text, 3313bf459f3Sfvdl epp->ep_taddr, epp->ep_vp, LINUX_N_TXTOFF(*execp, QMAGIC), 3323bf459f3Sfvdl VM_PROT_READ|VM_PROT_EXECUTE); 3333bf459f3Sfvdl 3343bf459f3Sfvdl /* set up command for data segment */ 3353bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_data, 3363bf459f3Sfvdl epp->ep_daddr, epp->ep_vp, LINUX_N_DATOFF(*execp, QMAGIC), 3373bf459f3Sfvdl VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 3383bf459f3Sfvdl 3393bf459f3Sfvdl /* set up command for bss segment */ 3403bf459f3Sfvdl NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, execp->a_bss, 3413bf459f3Sfvdl epp->ep_daddr + execp->a_data, NULLVP, 0, 3423bf459f3Sfvdl VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 3433bf459f3Sfvdl 3443bf459f3Sfvdl return exec_aout_setup_stack(p, epp); 3453bf459f3Sfvdl } 3463bf459f3Sfvdl 3473bf459f3Sfvdl /* 3483bf459f3Sfvdl * The Linux system call to load shared libraries. The current shared 3493bf459f3Sfvdl * libraries are just (QMAGIC) a.out files that are mapped onto a fixed 3503bf459f3Sfvdl * address * in the process' address space. The address is given in 3513bf459f3Sfvdl * a_entry. Read in the header, set up some VM commands and run them. 3523bf459f3Sfvdl * 3533bf459f3Sfvdl * Yes, both text and data are mapped at once, so we're left with 3543bf459f3Sfvdl * writeable text for the shared libs. The Linux crt0 seemed to break 3553bf459f3Sfvdl * sometimes when data was mapped seperately. It munmapped a uselib() 3563bf459f3Sfvdl * of ld.so by hand, which failed with shared text and data for ld.so 3573bf459f3Sfvdl * Yuck. 3583bf459f3Sfvdl * 3593bf459f3Sfvdl * Because of the problem with ZMAGIC executables (text starts 3603bf459f3Sfvdl * at 0x400 in the file, but needs t be mapped at 0), ZMAGIC 3613bf459f3Sfvdl * shared libs are not handled very efficiently :-( 3623bf459f3Sfvdl */ 3633bf459f3Sfvdl 3643bf459f3Sfvdl int 3653bf459f3Sfvdl linux_uselib(p, uap, retval) 3663bf459f3Sfvdl struct proc *p; 3673bf459f3Sfvdl struct linux_uselib_args /* { 3683bf459f3Sfvdl syscallarg(char *) path; 3693bf459f3Sfvdl } */ *uap; 3703bf459f3Sfvdl register_t *retval; 3713bf459f3Sfvdl { 3723bf459f3Sfvdl caddr_t sg; 3733bf459f3Sfvdl long bsize, dsize, tsize, taddr, baddr, daddr; 3743bf459f3Sfvdl struct nameidata ni; 3753bf459f3Sfvdl struct vnode *vp; 3763bf459f3Sfvdl struct exec hdr; 3773bf459f3Sfvdl struct exec_vmcmd_set vcset; 3783bf459f3Sfvdl int rem, i, magic, error; 3793bf459f3Sfvdl 3803bf459f3Sfvdl sg = stackgap_init(); 381182c23c8Sfvdl CHECK_ALT_EXIST(p, &sg, SCARG(uap, path)); 3823bf459f3Sfvdl 3833bf459f3Sfvdl NDINIT(&ni, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 3843bf459f3Sfvdl 3853bf459f3Sfvdl if ((error = namei(&ni))) 3863bf459f3Sfvdl return error; 3873bf459f3Sfvdl 3883bf459f3Sfvdl vp = ni.ni_vp; 3893bf459f3Sfvdl 3903bf459f3Sfvdl if ((error = vn_rdwr(UIO_READ, vp, (caddr_t) &hdr, LINUX_AOUT_HDR_SIZE, 3913bf459f3Sfvdl 0, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, 3923bf459f3Sfvdl &rem, p))) { 3933bf459f3Sfvdl vrele(vp); 3943bf459f3Sfvdl return error; 3953bf459f3Sfvdl } 3963bf459f3Sfvdl 3973bf459f3Sfvdl if (rem != 0) { 3983bf459f3Sfvdl vrele(vp); 3993bf459f3Sfvdl return ENOEXEC; 4003bf459f3Sfvdl } 4013bf459f3Sfvdl 4023bf459f3Sfvdl magic = LINUX_N_MAGIC(&hdr); 4033bf459f3Sfvdl taddr = hdr.a_entry & (~(NBPG - 1)); 4043bf459f3Sfvdl tsize = hdr.a_text; 4053bf459f3Sfvdl daddr = taddr + tsize; 4063bf459f3Sfvdl dsize = hdr.a_data + hdr.a_bss; 4073bf459f3Sfvdl 4083bf459f3Sfvdl if ((hdr.a_text != 0 || hdr.a_data != 0) && vp->v_writecount != 0) { 4093bf459f3Sfvdl vrele(vp); 4103bf459f3Sfvdl return ETXTBSY; 4113bf459f3Sfvdl } 4123bf459f3Sfvdl vp->v_flag |= VTEXT; 4133bf459f3Sfvdl 4143bf459f3Sfvdl vcset.evs_cnt = 0; 4153bf459f3Sfvdl vcset.evs_used = 0; 4163bf459f3Sfvdl 4173bf459f3Sfvdl NEW_VMCMD(&vcset, 4183bf459f3Sfvdl magic == ZMAGIC ? vmcmd_map_readvn : vmcmd_map_pagedvn, 4193bf459f3Sfvdl hdr.a_text + hdr.a_data, taddr, 4203bf459f3Sfvdl vp, LINUX_N_TXTOFF(hdr, magic), 4213bf459f3Sfvdl VM_PROT_READ|VM_PROT_EXECUTE|VM_PROT_WRITE); 4223bf459f3Sfvdl 4233bf459f3Sfvdl baddr = roundup(daddr + hdr.a_data, NBPG); 4243bf459f3Sfvdl bsize = daddr + dsize - baddr; 4253bf459f3Sfvdl if (bsize > 0) { 4263bf459f3Sfvdl NEW_VMCMD(&vcset, vmcmd_map_zero, bsize, baddr, 4273bf459f3Sfvdl NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 4283bf459f3Sfvdl } 4293bf459f3Sfvdl 4303bf459f3Sfvdl for (i = 0; i < vcset.evs_used && !error; i++) { 4313bf459f3Sfvdl struct exec_vmcmd *vcp; 4323bf459f3Sfvdl 4333bf459f3Sfvdl vcp = &vcset.evs_cmds[i]; 4343bf459f3Sfvdl error = (*vcp->ev_proc)(p, vcp); 4353bf459f3Sfvdl } 4363bf459f3Sfvdl 4373bf459f3Sfvdl kill_vmcmds(&vcset); 4383bf459f3Sfvdl 4393bf459f3Sfvdl vrele(vp); 4403bf459f3Sfvdl 4413bf459f3Sfvdl return error; 4423bf459f3Sfvdl } 4433bf459f3Sfvdl 4443bf459f3Sfvdl /* 4453bf459f3Sfvdl * Execve(2). Just check the alternate emulation path, and pass it on 4463bf459f3Sfvdl * to the NetBSD execve(). 4473bf459f3Sfvdl */ 4483bf459f3Sfvdl int 4493bf459f3Sfvdl linux_execve(p, uap, retval) 4503bf459f3Sfvdl struct proc *p; 4513bf459f3Sfvdl struct linux_execve_args /* { 4523bf459f3Sfvdl syscallarg(char *) path; 4533bf459f3Sfvdl syscallarg(char **) argv; 4543bf459f3Sfvdl syscallarg(char **) envp; 4553bf459f3Sfvdl } */ *uap; 4563bf459f3Sfvdl register_t *retval; 4573bf459f3Sfvdl { 4583bf459f3Sfvdl caddr_t sg; 4593bf459f3Sfvdl 4603bf459f3Sfvdl sg = stackgap_init(); 461182c23c8Sfvdl CHECK_ALT_EXIST(p, &sg, SCARG(uap, path)); 4623bf459f3Sfvdl 4633bf459f3Sfvdl return execve(p, uap, retval); 4643bf459f3Sfvdl } 465