1 /* $NetBSD: cpu_exec.c,v 1.32 2002/03/06 00:22:09 simonb Exp $ */ 2 3 /* 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by Ralph 8 * Campbell. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * @(#)machdep.c 8.3 (Berkeley) 1/12/94 39 */ 40 41 #include "opt_compat_netbsd.h" 42 #include "opt_compat_ultrix.h" 43 #include "opt_execfmt.h" 44 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #include <sys/proc.h> 48 #include <sys/malloc.h> 49 #include <sys/vnode.h> 50 #include <sys/exec.h> 51 #include <sys/resourcevar.h> 52 53 #include <uvm/uvm_extern.h> 54 55 #ifdef EXEC_ECOFF 56 #include <sys/exec_ecoff.h> 57 #endif 58 #include <sys/exec_elf.h> /* mandatory */ 59 #ifdef COMPAT_09 60 #include <machine/bsd-aout.h> 61 #endif 62 #include <machine/reg.h> 63 #include <mips/regnum.h> /* symbolic register indices */ 64 65 int mips_elf_makecmds(struct proc *, struct exec_package *); 66 67 68 /* 69 * cpu_exec_aout_makecmds(): 70 * cpu-dependent a.out format hook for execve(). 71 * 72 * Determine of the given exec package refers to something which we 73 * understand and, if so, set up the vmcmds for it. 74 * 75 */ 76 int 77 cpu_exec_aout_makecmds(p, epp) 78 struct proc *p; 79 struct exec_package *epp; 80 { 81 int error; 82 83 /* If COMPAT_09 is defined, allow loading of old-style 4.4bsd a.out 84 executables. */ 85 #ifdef COMPAT_09 86 struct bsd_aouthdr *hdr = (struct bsd_aouthdr *)epp->ep_hdr; 87 88 /* Only handle paged files (laziness). */ 89 if (hdr->a_magic != BSD_ZMAGIC) 90 #endif 91 { 92 /* If that failed, try old NetBSD-1.1 elf format */ 93 error = mips_elf_makecmds (p, epp); 94 return error; 95 } 96 97 98 99 #ifdef COMPAT_09 100 epp->ep_taddr = 0x1000; 101 epp->ep_entry = hdr->a_entry; 102 epp->ep_tsize = hdr->a_text; 103 epp->ep_daddr = epp->ep_taddr + hdr->a_text; 104 epp->ep_dsize = hdr->a_data + hdr->a_bss; 105 106 /* 107 * check if vnode is in open for writing, because we want to 108 * demand-page out of it. if it is, don't do it, for various 109 * reasons 110 */ 111 if ((hdr->a_text != 0 || hdr->a_data != 0) 112 && epp->ep_vp->v_writecount != 0) { 113 #ifdef DIAGNOSTIC 114 if (epp->ep_vp->v_flag & VTEXT) 115 panic("exec: a VTEXT vnode has writecount != 0\n"); 116 #endif 117 return ETXTBSY; 118 } 119 epp->ep_vp->v_flag |= VTEXT; 120 121 /* set up command for text segment */ 122 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, hdr->a_text, 123 epp->ep_taddr, epp->ep_vp, 0, VM_PROT_READ|VM_PROT_EXECUTE); 124 125 /* set up command for data segment */ 126 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, hdr->a_data, 127 epp->ep_daddr, epp->ep_vp, hdr->a_text, 128 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 129 130 /* set up command for bss segment */ 131 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, hdr->a_bss, 132 epp->ep_daddr + hdr->a_data, NULLVP, 0, 133 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 134 135 return exec_aout_setup_stack(p, epp); 136 #endif 137 } 138 139 #ifdef EXEC_ECOFF 140 void 141 cpu_exec_ecoff_setregs(p, epp, stack) 142 struct proc *p; 143 struct exec_package *epp; 144 u_long stack; 145 { 146 struct ecoff_exechdr *execp = (struct ecoff_exechdr *)epp->ep_hdr; 147 struct frame *f = (struct frame *)p->p_md.md_regs; 148 149 f->f_regs[GP] = (register_t)execp->a.gp_value; 150 } 151 152 /* 153 * cpu_exec_ecoff_probe() 154 * cpu-dependent ECOFF format hook for execve(). 155 * 156 * Do any machine-dependent diddling of the exec package when doing ECOFF. 157 */ 158 int 159 cpu_exec_ecoff_probe(p, epp) 160 struct proc *p; 161 struct exec_package *epp; 162 { 163 164 /* NetBSD/mips does not have native ECOFF binaries. */ 165 return ENOEXEC; 166 } 167 #endif /* EXEC_ECOFF */ 168 169 /* 170 * mips_elf_makecmds (p, epp) 171 * 172 * Test if an executable is a MIPS ELF executable. If it is, 173 * try to load it. 174 */ 175 176 int 177 mips_elf_makecmds (p, epp) 178 struct proc *p; 179 struct exec_package *epp; 180 { 181 Elf32_Ehdr *ex = (Elf32_Ehdr *)epp->ep_hdr; 182 Elf32_Phdr ph; 183 int i, error; 184 size_t resid; 185 186 /* Make sure we got enough data to check magic numbers... */ 187 if (epp->ep_hdrvalid < sizeof (Elf32_Ehdr)) { 188 #ifdef DIAGNOSTIC 189 if (epp->ep_hdrlen < sizeof (Elf32_Ehdr)) 190 printf ("mips_elf_makecmds: execsw hdrsize too short!\n"); 191 #endif 192 return ENOEXEC; 193 } 194 195 /* See if it's got the basic elf magic number leadin... */ 196 if (memcmp(ex->e_ident, ELFMAG, SELFMAG) != 0) { 197 return ENOEXEC; 198 } 199 200 /* XXX: Check other magic numbers here. */ 201 if (ex->e_ident[EI_CLASS] != ELFCLASS32) { 202 return ENOEXEC; 203 } 204 205 /* See if we got any program header information... */ 206 if (!ex->e_phoff || !ex->e_phnum) { 207 return ENOEXEC; 208 } 209 210 /* Set the entry point... */ 211 epp->ep_entry = ex->e_entry; 212 213 /* 214 * Check if vnode is open for writing, because we want to 215 * demand-page out of it. If it is, don't do it. 216 */ 217 if (epp->ep_vp->v_writecount != 0) { 218 #ifdef DIAGNOSTIC 219 if (epp->ep_vp->v_flag & VTEXT) 220 panic("exec: a VTEXT vnode has writecount != 0\n"); 221 #endif 222 return ETXTBSY; 223 } 224 epp->ep_vp->v_flag |= VTEXT; 225 226 epp->ep_taddr = 0; 227 epp->ep_tsize = 0; 228 epp->ep_daddr = 0; 229 epp->ep_dsize = 0; 230 231 for (i = 0; i < ex->e_phnum; i++) { 232 #ifdef DEBUG 233 /*printf("obsolete elf: mapping %x %x %x\n", resid);*/ 234 #endif 235 if ((error = vn_rdwr(UIO_READ, epp->ep_vp, (caddr_t)&ph, 236 sizeof ph, ex->e_phoff + i * sizeof ph, 237 UIO_SYSSPACE, IO_NODELOCKED, 238 p->p_ucred, &resid, p)) 239 != 0) 240 return error; 241 242 if (resid != 0) { 243 return ENOEXEC; 244 } 245 246 /* We only care about loadable sections... */ 247 if (ph.p_type == PT_LOAD) { 248 int prot = VM_PROT_READ | VM_PROT_EXECUTE; 249 int residue; 250 unsigned vaddr, offset, length; 251 252 vaddr = ph.p_vaddr; 253 offset = ph.p_offset; 254 length = ph.p_filesz; 255 residue = ph.p_memsz - ph.p_filesz; 256 257 if (ph.p_flags & PF_W) { 258 prot |= VM_PROT_WRITE; 259 if (!epp->ep_daddr || vaddr < epp->ep_daddr) 260 epp->ep_daddr = vaddr; 261 epp->ep_dsize += ph.p_memsz; 262 /* Read the data from the file... */ 263 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, 264 length, vaddr, 265 epp->ep_vp, offset, prot); 266 #ifdef OLD_ELF_DEBUG 267 /*XXX*/ printf( 268 "obsolete elf: NEW_VNCMD len %x va %x off %x prot %x residue %x\n", 269 length, vaddr, offset, prot, residue); 270 #endif /*ELF_DEBUG*/ 271 272 if (residue) { 273 vaddr &= ~(NBPG - 1); 274 offset &= ~(NBPG - 1); 275 length = roundup (length + ph.p_vaddr 276 - vaddr, NBPG); 277 residue = (ph.p_vaddr + ph.p_memsz) 278 - (vaddr + length); 279 } 280 } else { 281 vaddr &= ~(NBPG - 1); 282 offset &= ~(NBPG - 1); 283 length = roundup (length + ph.p_vaddr - vaddr, 284 NBPG); 285 residue = (ph.p_vaddr + ph.p_memsz) 286 - (vaddr + length); 287 if (!epp->ep_taddr || vaddr < epp->ep_taddr) 288 epp->ep_taddr = vaddr; 289 epp->ep_tsize += ph.p_memsz; 290 /* Map the data from the file... */ 291 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, 292 length, vaddr, 293 epp->ep_vp, offset, prot); 294 } 295 /* If part of the segment is just zeros (e.g., bss), 296 map that. */ 297 if (residue > 0) { 298 #ifdef OLD_ELF_DEBUG 299 /*XXX*/ printf( 300 "old elf:resid NEW_VNCMD len %x va %x off %x prot %x residue %x\n", 301 length, vaddr + length, offset, prot, residue); 302 #endif /*ELF_DEBUG*/ 303 304 NEW_VMCMD (&epp->ep_vmcmds, vmcmd_map_zero, 305 residue, vaddr + length, 306 NULLVP, 0, prot); 307 } 308 } 309 } 310 311 epp->ep_maxsaddr = USRSTACK - MAXSSIZ; 312 epp->ep_minsaddr = USRSTACK; 313 epp->ep_ssize = p->p_rlimit[RLIMIT_STACK].rlim_cur; 314 315 /* 316 * set up commands for stack. note that this takes *two*, one to 317 * map the part of the stack which we can access, and one to map 318 * the part which we can't. 319 * 320 * arguably, it could be made into one, but that would require the 321 * addition of another mapping proc, which is unnecessary 322 * 323 * note that in memory, things assumed to be: 0 ....... ep_maxsaddr 324 * <stack> ep_minsaddr 325 */ 326 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, 327 ((epp->ep_minsaddr - epp->ep_ssize) - epp->ep_maxsaddr), 328 epp->ep_maxsaddr, NULLVP, 0, VM_PROT_NONE); 329 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, epp->ep_ssize, 330 (epp->ep_minsaddr - epp->ep_ssize), NULLVP, 0, 331 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 332 333 return 0; 334 } 335