/*- * Copyright (c) 1998-1999 Andrew Gallatin * All rights reserved. * * Based heavily on imgact_linux.c which is * Copyright (c) 1994-1996 Søren Schmidt. * Which in turn is based heavily on /sys/kern/imgact_aout.c which is: * Copyright (c) 1993, David Greenman * * 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 * in this position and unchanged. * 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. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern struct sysentvec osf1_sysvec; #ifdef DEBUG #define DPRINTF(a) printf a; #else #define DPRINTF(a) #endif static int exec_osf1_imgact(struct image_params *imgp) { int error; int path_not_saved; size_t bytes; const struct ecoff_exechdr *execp; const struct ecoff_aouthdr *eap; struct vmspace *vmspace; vm_offset_t baddr; vm_offset_t bsize; vm_offset_t bss_start; vm_offset_t daddr; vm_offset_t dend; vm_offset_t dsize; vm_offset_t raw_dend; vm_offset_t taddr; vm_offset_t tend; vm_offset_t tsize; struct nameidata *ndp; Osf_Auxargs *osf_auxargs; struct thread *td; GIANT_REQUIRED; execp = (const struct ecoff_exechdr*)imgp->image_header; eap = &execp->a; ndp = NULL; td = FIRST_THREAD_IN_PROC(imgp->proc); /* check to make sure we have an alpha ecoff executable */ if (ECOFF_BADMAG(execp)) return -1; /* verfify it an OSF/1 exectutable */ if (eap->magic != ECOFF_ZMAGIC) { printf("unknown ecoff magic %x\n", eap->magic); return ENOEXEC; } osf_auxargs = malloc(sizeof(Osf_Auxargs), M_TEMP, M_WAITOK | M_ZERO); imgp->auxargs = osf_auxargs; osf_auxargs->executable = osf_auxargs->exec_path; path_not_saved = copystr(imgp->args->fname, osf_auxargs->executable, PATH_MAX, &bytes); if (execp->f.f_flags & DYNAMIC_FLAG) { if (path_not_saved) { uprintf("path to dynamic exectutable not found\n"); free(imgp->auxargs, M_TEMP); return(path_not_saved); } /* * Unmap the executable & attempt to slide in * /sbin/loader in its place. */ if (imgp->firstpage) exec_unmap_first_page(imgp); /* * Replicate what execve does, and map the first * page of the loader. */ ndp = (struct nameidata *)malloc(sizeof(struct nameidata), M_TEMP, M_WAITOK); NDINIT(ndp, LOOKUP, LOCKLEAF | FOLLOW | SAVENAME, UIO_SYSSPACE, "/compat/osf1/sbin/loader", td); error = namei(ndp); if (error) { uprintf("imgact_osf1: can't read /compat/osf1/sbin/loader\n"); free(imgp->auxargs, M_TEMP); free(ndp, M_TEMP); return(error); } NDFREE(ndp, NDF_ONLY_PNBUF); if (imgp->vp) { vput(imgp->vp); /* leaking in the nameizone ??? XXX */ } imgp->vp = ndp->ni_vp; error = exec_map_first_page(imgp); osf_auxargs->loader = "/compat/osf1/sbin/loader"; } execp = (const struct ecoff_exechdr*)imgp->image_header; eap = &execp->a; taddr = ECOFF_SEGMENT_ALIGN(execp, eap->text_start); tend = round_page(eap->text_start + eap->tsize); tsize = tend - taddr; daddr = ECOFF_SEGMENT_ALIGN(execp, eap->data_start); dend = round_page(eap->data_start + eap->dsize); dsize = dend - daddr; bss_start = ECOFF_SEGMENT_ALIGN(execp, eap->bss_start); bsize = eap->bsize; imgp->entry_addr = eap->entry; /* * Destroy old process VM and create a new one (with a new stack). */ exec_new_vmspace(imgp, &osf1_sysvec); /* * The vm space can now be changed. */ vmspace = imgp->proc->p_vmspace; imgp->interpreted = 0; imgp->proc->p_sysent = &osf1_sysvec; /* set up text segment */ if ((error = vm_mmap(&vmspace->vm_map, &taddr, tsize, VM_PROT_READ|VM_PROT_EXECUTE, VM_PROT_ALL, MAP_FIXED|MAP_COPY, OBJT_VNODE, imgp->vp, ECOFF_TXTOFF(execp)))) { DPRINTF(("%s(%d): error = %d\n", __FILE__, __LINE__, error)); goto bail; } /* .. data .. */ if ((error = vm_mmap(&vmspace->vm_map, &daddr, dsize, VM_PROT_READ|VM_PROT_EXECUTE|VM_PROT_WRITE, VM_PROT_ALL, MAP_FIXED|MAP_COPY, OBJT_VNODE, imgp->vp, ECOFF_DATOFF(execp)))) { DPRINTF(("%s(%d): error = %d\n", __FILE__, __LINE__, error)); goto bail; } /* .. bss .. */ if (round_page(bsize)) { baddr = bss_start; if ((error = vm_map_find(&vmspace->vm_map, NULL, (vm_offset_t) 0, &baddr, round_page(bsize), FALSE, VM_PROT_ALL, VM_PROT_ALL, FALSE))) { DPRINTF(("%s(%d): error = %d\n", __FILE__, __LINE__, error)); goto bail; } } raw_dend = (eap->data_start + eap->dsize); if (dend > raw_dend) { caddr_t zeros; zeros = malloc(dend-raw_dend,M_TEMP,M_WAITOK|M_ZERO); if ((error = copyout(zeros, (caddr_t)raw_dend, dend-raw_dend))) { uprintf("Can't zero start of bss, error %d\n",error); free(zeros,M_TEMP); goto bail; } free(zeros,M_TEMP); } vmspace->vm_tsize = btoc(round_page(tsize)); vmspace->vm_dsize = btoc((round_page(dsize) + round_page(bsize))); vmspace->vm_taddr = (caddr_t)taddr; vmspace->vm_daddr = (caddr_t)daddr; return(0); bail: free(imgp->auxargs, M_TEMP); if (ndp) { VOP_CLOSE(ndp->ni_vp, FREAD, td->td_ucred, td); vrele(ndp->ni_vp); free(ndp, M_TEMP); } return(error); } /* * Tell kern_execve.c about it, with a little help from the linker. */ struct execsw osf1_execsw = { exec_osf1_imgact, "OSF/1 ECOFF" }; EXEC_SET(osf1_ecoff, osf1_execsw);