1 /* $NetBSD: netbsd32_exec_aout.c,v 1.15 2003/06/29 22:29:37 fvdl Exp $ */ 2 /* from: NetBSD: exec_aout.c,v 1.15 1996/09/26 23:34:46 cgd Exp */ 3 4 /* 5 * Copyright (c) 1998, 2001 Matthew R. Green. 6 * Copyright (c) 1993, 1994 Christopher G. Demetriou 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by Christopher G. Demetriou. 20 * 4. The name of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include <sys/cdefs.h> 36 __KERNEL_RCSID(0, "$NetBSD: netbsd32_exec_aout.c,v 1.15 2003/06/29 22:29:37 fvdl Exp $"); 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/proc.h> 41 #include <sys/malloc.h> 42 #include <sys/vnode.h> 43 #include <sys/exec.h> 44 #include <sys/exec_aout.h> 45 #include <sys/resourcevar.h> 46 #include <sys/signal.h> 47 #include <sys/signalvar.h> 48 49 #include <compat/netbsd32/netbsd32.h> 50 #ifndef EXEC_AOUT 51 #define EXEC_AOUT 52 #endif 53 #include <compat/netbsd32/netbsd32_exec.h> 54 55 #include <machine/frame.h> 56 #include <machine/netbsd32_machdep.h> 57 58 int netbsd32_copyinargs __P((struct exec_package *, struct ps_strings *, 59 void *, size_t, const void *, const void *)); 60 61 int netbsd32_exec_aout_setup_stack __P((struct proc *p, 62 struct exec_package *epp)); 63 64 /* 65 * exec_netbsd32_makecmds(): Check if it's an netbsd32 a.out format 66 * executable. 67 * 68 * Given a proc pointer and an exec package pointer, see if the referent 69 * of the epp is in netbsd32 a.out format. Check 'standard' magic 70 * numbers for this architecture. 71 * 72 * This function, in the former case, or the hook, in the latter, is 73 * responsible for creating a set of vmcmds which can be used to build 74 * the process's vm space and inserting them into the exec package. 75 */ 76 77 int 78 exec_netbsd32_makecmds(p, epp) 79 struct proc *p; 80 struct exec_package *epp; 81 { 82 netbsd32_u_long midmag, magic; 83 u_short mid; 84 int error; 85 struct netbsd32_exec *execp = epp->ep_hdr; 86 87 if (epp->ep_hdrvalid < sizeof(struct netbsd32_exec)) 88 return ENOEXEC; 89 90 midmag = (netbsd32_u_long)ntohl(execp->a_midmag); 91 mid = (midmag >> 16) & 0x3ff; 92 magic = midmag & 0xffff; 93 94 midmag = mid << 16 | magic; 95 96 switch (midmag) { 97 case (MID_SPARC << 16) | ZMAGIC: 98 error = netbsd32_exec_aout_prep_zmagic(p, epp); 99 break; 100 case (MID_SPARC << 16) | NMAGIC: 101 error = netbsd32_exec_aout_prep_nmagic(p, epp); 102 break; 103 case (MID_SPARC << 16) | OMAGIC: 104 error = netbsd32_exec_aout_prep_omagic(p, epp); 105 break; 106 default: 107 /* Invalid magic */ 108 error = ENOEXEC; 109 break; 110 } 111 112 if (error == 0) { 113 /* set up our emulation information */ 114 epp->ep_flags |= EXEC_32; 115 } else 116 kill_vmcmds(&epp->ep_vmcmds); 117 118 return error; 119 } 120 121 /* 122 * netbsd32_exec_aout_prep_zmagic(): Prepare a 'native' ZMAGIC binary's 123 * exec package 124 * 125 * First, set of the various offsets/lengths in the exec package. 126 * 127 * Then, mark the text image busy (so it can be demand paged) or error 128 * out if this is not possible. Finally, set up vmcmds for the 129 * text, data, bss, and stack segments. 130 */ 131 132 int 133 netbsd32_exec_aout_prep_zmagic(p, epp) 134 struct proc *p; 135 struct exec_package *epp; 136 { 137 struct netbsd32_exec *execp = epp->ep_hdr; 138 int error; 139 140 epp->ep_taddr = AOUT_LDPGSZ; 141 epp->ep_tsize = execp->a_text; 142 epp->ep_daddr = epp->ep_taddr + execp->a_text; 143 epp->ep_dsize = execp->a_data + execp->a_bss; 144 epp->ep_entry = execp->a_entry; 145 epp->ep_vm_minaddr = VM_MIN_ADDRESS; 146 epp->ep_vm_maxaddr = VM_MAXUSER_ADDRESS32; 147 148 error = vn_marktext(epp->ep_vp); 149 if (error) 150 return (error); 151 152 /* set up command for text segment */ 153 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_text, 154 epp->ep_taddr, epp->ep_vp, 0, VM_PROT_READ|VM_PROT_EXECUTE); 155 156 /* set up command for data segment */ 157 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_data, 158 epp->ep_daddr, epp->ep_vp, execp->a_text, 159 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 160 161 /* set up command for bss segment */ 162 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, execp->a_bss, 163 epp->ep_daddr + execp->a_data, NULLVP, 0, 164 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 165 166 return netbsd32_exec_aout_setup_stack(p, epp); 167 } 168 169 /* 170 * netbsd32_exec_aout_prep_nmagic(): Prepare a 'native' NMAGIC binary's 171 * exec package 172 */ 173 174 int 175 netbsd32_exec_aout_prep_nmagic(p, epp) 176 struct proc *p; 177 struct exec_package *epp; 178 { 179 struct netbsd32_exec *execp = epp->ep_hdr; 180 long bsize, baddr; 181 182 epp->ep_taddr = AOUT_LDPGSZ; 183 epp->ep_tsize = execp->a_text; 184 epp->ep_daddr = roundup(epp->ep_taddr + execp->a_text, AOUT_LDPGSZ); 185 epp->ep_dsize = execp->a_data + execp->a_bss; 186 epp->ep_entry = execp->a_entry; 187 epp->ep_vm_minaddr = VM_MIN_ADDRESS; 188 epp->ep_vm_maxaddr = VM_MAXUSER_ADDRESS32; 189 190 /* set up command for text segment */ 191 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_text, 192 epp->ep_taddr, epp->ep_vp, sizeof(struct netbsd32_exec), 193 VM_PROT_READ|VM_PROT_EXECUTE); 194 195 /* set up command for data segment */ 196 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_data, 197 epp->ep_daddr, epp->ep_vp, execp->a_text + sizeof(struct netbsd32_exec), 198 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 199 200 /* set up command for bss segment */ 201 baddr = roundup(epp->ep_daddr + execp->a_data, PAGE_SIZE); 202 bsize = epp->ep_daddr + epp->ep_dsize - baddr; 203 if (bsize > 0) 204 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr, 205 NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 206 207 return netbsd32_exec_aout_setup_stack(p, epp); 208 } 209 210 /* 211 * netbsd32_exec_aout_prep_omagic(): Prepare a 'native' OMAGIC binary's 212 * exec package 213 */ 214 215 int 216 netbsd32_exec_aout_prep_omagic(p, epp) 217 struct proc *p; 218 struct exec_package *epp; 219 { 220 struct netbsd32_exec *execp = epp->ep_hdr; 221 long dsize, bsize, baddr; 222 223 epp->ep_taddr = AOUT_LDPGSZ; 224 epp->ep_tsize = execp->a_text; 225 epp->ep_daddr = epp->ep_taddr + execp->a_text; 226 epp->ep_dsize = execp->a_data + execp->a_bss; 227 epp->ep_entry = execp->a_entry; 228 epp->ep_vm_minaddr = VM_MIN_ADDRESS; 229 epp->ep_vm_maxaddr = VM_MAXUSER_ADDRESS32; 230 231 /* set up command for text and data segments */ 232 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, 233 execp->a_text + execp->a_data, epp->ep_taddr, epp->ep_vp, 234 sizeof(struct netbsd32_exec), VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 235 236 /* set up command for bss segment */ 237 baddr = roundup(epp->ep_daddr + execp->a_data, PAGE_SIZE); 238 bsize = epp->ep_daddr + epp->ep_dsize - baddr; 239 if (bsize > 0) 240 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr, 241 NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 242 243 /* 244 * Make sure (# of pages) mapped above equals (vm_tsize + vm_dsize); 245 * obreak(2) relies on this fact. Both `vm_tsize' and `vm_dsize' are 246 * computed (in execve(2)) by rounding *up* `ep_tsize' and `ep_dsize' 247 * respectively to page boundaries. 248 * Compensate `ep_dsize' for the amount of data covered by the last 249 * text page. 250 */ 251 dsize = epp->ep_dsize + execp->a_text - roundup(execp->a_text, 252 PAGE_SIZE); 253 epp->ep_dsize = (dsize > 0) ? dsize : 0; 254 return netbsd32_exec_aout_setup_stack(p, epp); 255 } 256 257 /* 258 * netbsd32_exec_aout_setup_stack(): Set up the stack segment for an a.out 259 * executable. 260 * 261 * Note that the ep_ssize parameter must be set to be the current stack 262 * limit; this is adjusted in the body of execve() to yield the 263 * appropriate stack segment usage once the argument length is 264 * calculated. 265 * 266 * This function returns an int for uniformity with other (future) formats' 267 * stack setup functions. They might have errors to return. 268 */ 269 int 270 netbsd32_exec_aout_setup_stack(struct proc *p, struct exec_package *epp) 271 { 272 273 epp->ep_maxsaddr = USRSTACK32 - MAXSSIZ; 274 epp->ep_minsaddr = USRSTACK32; 275 epp->ep_ssize = p->p_rlimit[RLIMIT_STACK].rlim_cur; 276 277 /* 278 * set up commands for stack. note that this takes *two*, one to 279 * map the part of the stack which we can access, and one to map 280 * the part which we can't. 281 * 282 * arguably, it could be made into one, but that would require the 283 * addition of another mapping proc, which is unnecessary 284 * 285 * note that in memory, things assumed to be: 0 ... ep_maxsaddr 286 * <stack> ep_minsaddr 287 */ 288 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, 289 ((epp->ep_minsaddr - epp->ep_ssize) - epp->ep_maxsaddr), 290 epp->ep_maxsaddr, NULLVP, 0, VM_PROT_NONE); 291 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, epp->ep_ssize, 292 (epp->ep_minsaddr - epp->ep_ssize), NULLVP, 0, 293 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 294 295 return 0; 296 } 297