1 /* $NetBSD: linux_exec_aout.c,v 1.4 1995/04/22 19:48:34 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1995 Frank van der Linden 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed for the NetBSD Project 18 * by Frank van der Linden 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 * based on kern/exec_aout.c and compat/sunos/sunos_exec.c 34 */ 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/filedesc.h> 39 #include <sys/kernel.h> 40 #include <sys/proc.h> 41 #include <sys/mount.h> 42 #include <sys/malloc.h> 43 #include <sys/namei.h> 44 #include <sys/vnode.h> 45 #include <sys/file.h> 46 #include <sys/resourcevar.h> 47 #include <sys/wait.h> 48 49 #include <sys/mman.h> 50 #include <vm/vm.h> 51 #include <vm/vm_param.h> 52 #include <vm/vm_map.h> 53 #include <vm/vm_kern.h> 54 #include <vm/vm_pager.h> 55 56 #include <machine/cpu.h> 57 #include <machine/reg.h> 58 #include <machine/exec.h> 59 #include <machine/linux_machdep.h> 60 61 #include <compat/linux/linux_types.h> 62 #include <compat/linux/linux_syscall.h> 63 #include <compat/linux/linux_syscallargs.h> 64 #include <compat/linux/linux_util.h> 65 #include <compat/linux/linux_exec.h> 66 67 static void *linux_copyargs __P((struct exec_package *, struct ps_strings *, 68 void *, void *)); 69 70 #define LINUX_AUX_ARGSIZ 2 71 72 extern int linux_error[]; 73 extern struct sysent linux_sysent[]; 74 extern char *linux_syscallnames[]; 75 76 struct emul emul_linux = { 77 "linux", 78 linux_error, 79 linux_sendsig, 80 LINUX_SYS_syscall, 81 LINUX_SYS_MAXSYSCALL, 82 linux_sysent, 83 linux_syscallnames, 84 LINUX_AUX_ARGSIZ, 85 linux_copyargs, 86 setregs, 87 linux_sigcode, 88 linux_esigcode, 89 }; 90 91 92 static void * 93 linux_copyargs(pack, arginfo, stack, argp) 94 struct exec_package *pack; 95 struct ps_strings *arginfo; 96 void *stack; 97 void *argp; 98 { 99 char **cpp = stack; 100 char **stk = stack; 101 char *dp, *sp; 102 size_t len; 103 void *nullp = NULL; 104 int argc = arginfo->ps_nargvstr; 105 int envc = arginfo->ps_nenvstr; 106 107 if (copyout(&argc, cpp++, sizeof(argc))) 108 return NULL; 109 110 /* leave room for envp and argv */ 111 cpp += 2; 112 if (copyout(&cpp, &stk[1], sizeof (cpp))) 113 return NULL; 114 115 dp = (char *) (cpp + argc + envc + 2); 116 sp = argp; 117 118 /* XXX don't copy them out, remap them! */ 119 arginfo->ps_argvstr = dp; /* remember location of argv for later */ 120 121 for (; --argc >= 0; sp += len, dp += len) 122 if (copyout(&dp, cpp++, sizeof(dp)) || 123 copyoutstr(sp, dp, ARG_MAX, &len)) 124 return NULL; 125 126 if (copyout(&nullp, cpp++, sizeof(nullp))) 127 return NULL; 128 129 if (copyout(&cpp, &stk[2], sizeof (cpp))) 130 return NULL; 131 132 arginfo->ps_envstr = dp; /* remember location of envp for later */ 133 134 for (; --envc >= 0; sp += len, dp += len) 135 if (copyout(&dp, cpp++, sizeof(dp)) || 136 copyoutstr(sp, dp, ARG_MAX, &len)) 137 return NULL; 138 139 if (copyout(&nullp, cpp++, sizeof(nullp))) 140 return NULL; 141 142 return cpp; 143 } 144 145 146 int 147 exec_linux_aout_makecmds(p, epp) 148 struct proc *p; 149 struct exec_package *epp; 150 { 151 struct exec *linux_ep = epp->ep_hdr; 152 int machtype, magic; 153 int error = ENOEXEC; 154 155 magic = LINUX_N_MAGIC(linux_ep); 156 machtype = LINUX_N_MACHTYPE(linux_ep); 157 158 159 if (machtype != LINUX_MID_MACHINE) 160 return (ENOEXEC); 161 162 switch (magic) { 163 case QMAGIC: 164 error = exec_linux_aout_prep_qmagic(p, epp); 165 break; 166 case ZMAGIC: 167 error = exec_linux_aout_prep_zmagic(p, epp); 168 break; 169 case NMAGIC: 170 error = exec_linux_aout_prep_nmagic(p, epp); 171 break; 172 case OMAGIC: 173 error = exec_linux_aout_prep_omagic(p, epp); 174 break; 175 } 176 if (error == 0) 177 epp->ep_emul = &emul_linux; 178 return error; 179 } 180 181 /* 182 * Since text starts at 0x400 in Linux ZMAGIC executables, and 0x400 183 * is very likely not page aligned on most architectures, it is treated 184 * as an NMAGIC here. XXX 185 */ 186 187 int 188 exec_linux_aout_prep_zmagic(p, epp) 189 struct proc *p; 190 struct exec_package *epp; 191 { 192 struct exec *execp = epp->ep_hdr; 193 194 epp->ep_taddr = LINUX_N_TXTADDR(*execp, ZMAGIC); 195 epp->ep_tsize = execp->a_text; 196 epp->ep_daddr = LINUX_N_DATADDR(*execp, ZMAGIC); 197 epp->ep_dsize = execp->a_data + execp->a_bss; 198 epp->ep_entry = execp->a_entry; 199 200 /* set up command for text segment */ 201 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_text, 202 epp->ep_taddr, epp->ep_vp, LINUX_N_TXTOFF(*execp, ZMAGIC), 203 VM_PROT_READ|VM_PROT_EXECUTE); 204 205 /* set up command for data segment */ 206 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_data, 207 epp->ep_daddr, epp->ep_vp, LINUX_N_DATOFF(*execp, ZMAGIC), 208 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 209 210 /* set up command for bss segment */ 211 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, execp->a_bss, 212 epp->ep_daddr + execp->a_data, NULLVP, 0, 213 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 214 215 return exec_aout_setup_stack(p, epp); 216 } 217 218 /* 219 * exec_aout_prep_nmagic(): Prepare Linux NMAGIC package. 220 * Not different from the normal stuff. 221 */ 222 223 int 224 exec_linux_aout_prep_nmagic(p, epp) 225 struct proc *p; 226 struct exec_package *epp; 227 { 228 struct exec *execp = epp->ep_hdr; 229 long bsize, baddr; 230 231 epp->ep_taddr = LINUX_N_TXTADDR(*execp, NMAGIC); 232 epp->ep_tsize = execp->a_text; 233 epp->ep_daddr = LINUX_N_DATADDR(*execp, NMAGIC); 234 epp->ep_dsize = execp->a_data + execp->a_bss; 235 epp->ep_entry = execp->a_entry; 236 237 /* set up command for text segment */ 238 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_text, 239 epp->ep_taddr, epp->ep_vp, LINUX_N_TXTOFF(*execp, NMAGIC), 240 VM_PROT_READ|VM_PROT_EXECUTE); 241 242 /* set up command for data segment */ 243 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_data, 244 epp->ep_daddr, epp->ep_vp, LINUX_N_DATOFF(*execp, NMAGIC), 245 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 246 247 /* set up command for bss segment */ 248 baddr = roundup(epp->ep_daddr + execp->a_data, NBPG); 249 bsize = epp->ep_daddr + epp->ep_dsize - baddr; 250 if (bsize > 0) 251 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr, 252 NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 253 254 return exec_aout_setup_stack(p, epp); 255 } 256 257 /* 258 * exec_aout_prep_omagic(): Prepare Linux OMAGIC package. 259 * Business as usual. 260 */ 261 262 int 263 exec_linux_aout_prep_omagic(p, epp) 264 struct proc *p; 265 struct exec_package *epp; 266 { 267 struct exec *execp = epp->ep_hdr; 268 long dsize, bsize, baddr; 269 270 epp->ep_taddr = LINUX_N_TXTADDR(*execp, OMAGIC); 271 epp->ep_tsize = execp->a_text; 272 epp->ep_daddr = LINUX_N_DATADDR(*execp, OMAGIC); 273 epp->ep_dsize = execp->a_data + execp->a_bss; 274 epp->ep_entry = execp->a_entry; 275 276 /* set up command for text and data segments */ 277 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, 278 execp->a_text + execp->a_data, epp->ep_taddr, epp->ep_vp, 279 LINUX_N_TXTOFF(*execp, OMAGIC), VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 280 281 /* set up command for bss segment */ 282 baddr = roundup(epp->ep_daddr + execp->a_data, NBPG); 283 bsize = epp->ep_daddr + epp->ep_dsize - baddr; 284 if (bsize > 0) 285 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr, 286 NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 287 288 /* 289 * Make sure (# of pages) mapped above equals (vm_tsize + vm_dsize); 290 * obreak(2) relies on this fact. Both `vm_tsize' and `vm_dsize' are 291 * computed (in execve(2)) by rounding *up* `ep_tsize' and `ep_dsize' 292 * respectively to page boundaries. 293 * Compensate `ep_dsize' for the amount of data covered by the last 294 * text page. 295 */ 296 dsize = epp->ep_dsize + execp->a_text - roundup(execp->a_text, NBPG); 297 epp->ep_dsize = (dsize > 0) ? dsize : 0; 298 return exec_aout_setup_stack(p, epp); 299 } 300 301 int 302 exec_linux_aout_prep_qmagic(p, epp) 303 struct proc *p; 304 struct exec_package *epp; 305 { 306 struct exec *execp = epp->ep_hdr; 307 308 epp->ep_taddr = LINUX_N_TXTADDR(*execp, QMAGIC); 309 epp->ep_tsize = execp->a_text; 310 epp->ep_daddr = LINUX_N_DATADDR(*execp, QMAGIC); 311 epp->ep_dsize = execp->a_data + execp->a_bss; 312 epp->ep_entry = execp->a_entry; 313 314 /* 315 * check if vnode is in open for writing, because we want to 316 * demand-page out of it. if it is, don't do it, for various 317 * reasons 318 */ 319 if ((execp->a_text != 0 || execp->a_data != 0) && 320 epp->ep_vp->v_writecount != 0) { 321 #ifdef DIAGNOSTIC 322 if (epp->ep_vp->v_flag & VTEXT) 323 panic("exec: a VTEXT vnode has writecount != 0\n"); 324 #endif 325 return ETXTBSY; 326 } 327 epp->ep_vp->v_flag |= VTEXT; 328 329 /* set up command for text segment */ 330 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_text, 331 epp->ep_taddr, epp->ep_vp, LINUX_N_TXTOFF(*execp, QMAGIC), 332 VM_PROT_READ|VM_PROT_EXECUTE); 333 334 /* set up command for data segment */ 335 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_data, 336 epp->ep_daddr, epp->ep_vp, LINUX_N_DATOFF(*execp, QMAGIC), 337 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 338 339 /* set up command for bss segment */ 340 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, execp->a_bss, 341 epp->ep_daddr + execp->a_data, NULLVP, 0, 342 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 343 344 return exec_aout_setup_stack(p, epp); 345 } 346 347 /* 348 * The Linux system call to load shared libraries. The current shared 349 * libraries are just (QMAGIC) a.out files that are mapped onto a fixed 350 * address * in the process' address space. The address is given in 351 * a_entry. Read in the header, set up some VM commands and run them. 352 * 353 * Yes, both text and data are mapped at once, so we're left with 354 * writeable text for the shared libs. The Linux crt0 seemed to break 355 * sometimes when data was mapped seperately. It munmapped a uselib() 356 * of ld.so by hand, which failed with shared text and data for ld.so 357 * Yuck. 358 * 359 * Because of the problem with ZMAGIC executables (text starts 360 * at 0x400 in the file, but needs t be mapped at 0), ZMAGIC 361 * shared libs are not handled very efficiently :-( 362 */ 363 364 int 365 linux_uselib(p, uap, retval) 366 struct proc *p; 367 struct linux_uselib_args /* { 368 syscallarg(char *) path; 369 } */ *uap; 370 register_t *retval; 371 { 372 caddr_t sg; 373 long bsize, dsize, tsize, taddr, baddr, daddr; 374 struct nameidata ni; 375 struct vnode *vp; 376 struct exec hdr; 377 struct exec_vmcmd_set vcset; 378 int rem, i, magic, error; 379 380 sg = stackgap_init(); 381 CHECK_ALT_EXIST(p, &sg, SCARG(uap, path)); 382 383 NDINIT(&ni, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 384 385 if ((error = namei(&ni))) 386 return error; 387 388 vp = ni.ni_vp; 389 390 if ((error = vn_rdwr(UIO_READ, vp, (caddr_t) &hdr, LINUX_AOUT_HDR_SIZE, 391 0, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, 392 &rem, p))) { 393 vrele(vp); 394 return error; 395 } 396 397 if (rem != 0) { 398 vrele(vp); 399 return ENOEXEC; 400 } 401 402 magic = LINUX_N_MAGIC(&hdr); 403 taddr = hdr.a_entry & (~(NBPG - 1)); 404 tsize = hdr.a_text; 405 daddr = taddr + tsize; 406 dsize = hdr.a_data + hdr.a_bss; 407 408 if ((hdr.a_text != 0 || hdr.a_data != 0) && vp->v_writecount != 0) { 409 vrele(vp); 410 return ETXTBSY; 411 } 412 vp->v_flag |= VTEXT; 413 414 vcset.evs_cnt = 0; 415 vcset.evs_used = 0; 416 417 NEW_VMCMD(&vcset, 418 magic == ZMAGIC ? vmcmd_map_readvn : vmcmd_map_pagedvn, 419 hdr.a_text + hdr.a_data, taddr, 420 vp, LINUX_N_TXTOFF(hdr, magic), 421 VM_PROT_READ|VM_PROT_EXECUTE|VM_PROT_WRITE); 422 423 baddr = roundup(daddr + hdr.a_data, NBPG); 424 bsize = daddr + dsize - baddr; 425 if (bsize > 0) { 426 NEW_VMCMD(&vcset, vmcmd_map_zero, bsize, baddr, 427 NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 428 } 429 430 for (i = 0; i < vcset.evs_used && !error; i++) { 431 struct exec_vmcmd *vcp; 432 433 vcp = &vcset.evs_cmds[i]; 434 error = (*vcp->ev_proc)(p, vcp); 435 } 436 437 kill_vmcmds(&vcset); 438 439 vrele(vp); 440 441 return error; 442 } 443 444 /* 445 * Execve(2). Just check the alternate emulation path, and pass it on 446 * to the NetBSD execve(). 447 */ 448 int 449 linux_execve(p, uap, retval) 450 struct proc *p; 451 struct linux_execve_args /* { 452 syscallarg(char *) path; 453 syscallarg(char **) argv; 454 syscallarg(char **) envp; 455 } */ *uap; 456 register_t *retval; 457 { 458 caddr_t sg; 459 460 sg = stackgap_init(); 461 CHECK_ALT_EXIST(p, &sg, SCARG(uap, path)); 462 463 return execve(p, uap, retval); 464 } 465