1 /* $NetBSD: m68k4k_exec.c,v 1.21 2008/11/21 19:55:38 he Exp $ */ 2 3 /* 4 * Copyright (c) 1993, 1994 Christopher G. Demetriou 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 by Christopher G. Demetriou. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Exec glue to provide compatibility with older NetBSD m68k4k exectuables. 35 * 36 * Taken directly from kern/exec_aout.c and frobbed to map text and 37 * data as m68k4k executables expect. 38 * 39 * This module only works on machines with PAGE_SIZE == 4096. It's not clear 40 * that making it work on other machines is worth the trouble. 41 */ 42 43 #include <sys/cdefs.h> 44 __KERNEL_RCSID(0, "$NetBSD: m68k4k_exec.c,v 1.21 2008/11/21 19:55:38 he Exp $"); 45 46 #if !defined(__m68k__) 47 #error YOU GOTTA BE KIDDING! 48 #endif 49 50 #include <sys/param.h> 51 #include <sys/systm.h> 52 #include <sys/proc.h> 53 #include <sys/malloc.h> 54 #include <sys/module.h> 55 #include <sys/vnode.h> 56 #include <sys/exec.h> 57 #include <sys/resourcevar.h> 58 59 #include <compat/m68k4k/m68k4k_exec.h> 60 61 #ifdef COREDUMP 62 #define DEP "coredump" 63 #else 64 #define DEP NULL 65 #endif 66 67 MODULE(MODULE_CLASS_MISC, exec_m68k4k, DEP); 68 69 static struct execsw exec_m68k4k_execsw[] = { 70 { sizeof(struct exec), 71 exec_m68k4k_makecmds, 72 { NULL }, 73 &emul_netbsd, 74 EXECSW_PRIO_ANY, 75 0, 76 copyargs, 77 NULL, 78 coredump_netbsd, 79 exec_setup_stack }, 80 }; 81 82 static int 83 exec_m68k4k_modcmd(modcmd_t cmd, void *arg) 84 { 85 86 switch (cmd) { 87 case MODULE_CMD_INIT: 88 return exec_add(exec_m68k4k_execsw, 89 __arraycount(exec_m68k4k_execsw)); 90 91 case MODULE_CMD_FINI: 92 return exec_remove(exec_m68k4k_execsw, 93 __arraycount(exec_m68k4k_execsw)); 94 95 default: 96 return ENOTTY; 97 } 98 } 99 100 int exec_m68k4k_prep_zmagic(struct lwp *, struct exec_package *); 101 int exec_m68k4k_prep_nmagic(struct lwp *, struct exec_package *); 102 int exec_m68k4k_prep_omagic(struct lwp *, struct exec_package *); 103 104 /* 105 * exec_m68k4k_makecmds(): Check if it's an a.out-format executable 106 * with an m68k4k magic number. 107 * 108 * Given a proc pointer and an exec package pointer, see if the referent 109 * of the epp is in a.out format. Just check 'standard' magic numbers for 110 * this architecture. 111 * 112 * This function, in the former case, or the hook, in the latter, is 113 * responsible for creating a set of vmcmds which can be used to build 114 * the process's vm space and inserting them into the exec package. 115 */ 116 117 int 118 exec_m68k4k_makecmds(struct lwp *l, struct exec_package *epp) 119 { 120 u_long midmag, magic; 121 u_short mid; 122 int error; 123 struct exec *execp = epp->ep_hdr; 124 125 /* See note above... */ 126 if (M68K4K_LDPGSZ != PAGE_SIZE) 127 return ENOEXEC; 128 129 if (epp->ep_hdrvalid < sizeof(struct exec)) 130 return ENOEXEC; 131 132 midmag = ntohl(execp->a_midmag); 133 mid = (midmag >> 16) & 0x3ff; 134 magic = midmag & 0xffff; 135 136 midmag = mid << 16 | magic; 137 138 switch (midmag) { 139 case (MID_M68K4K << 16) | ZMAGIC: 140 error = exec_m68k4k_prep_zmagic(l, epp); 141 break; 142 case (MID_M68K4K << 16) | NMAGIC: 143 error = exec_m68k4k_prep_nmagic(l, epp); 144 break; 145 case (MID_M68K4K << 16) | OMAGIC: 146 error = exec_m68k4k_prep_omagic(l, epp); 147 break; 148 default: 149 error = ENOEXEC; 150 } 151 152 if (error) 153 kill_vmcmds(&epp->ep_vmcmds); 154 155 return error; 156 } 157 158 /* 159 * exec_m68k4k_prep_zmagic(): Prepare an m68k4k ZMAGIC binary's exec package 160 * 161 * First, set of the various offsets/lengths in the exec package. 162 * 163 * Then, mark the text image busy (so it can be demand paged) or error 164 * out if this is not possible. Finally, set up vmcmds for the 165 * text, data, bss, and stack segments. 166 */ 167 168 int 169 exec_m68k4k_prep_zmagic(struct lwp *l, struct exec_package *epp) 170 { 171 struct exec *execp = epp->ep_hdr; 172 int error; 173 174 epp->ep_taddr = M68K4K_USRTEXT; 175 epp->ep_tsize = execp->a_text; 176 epp->ep_daddr = epp->ep_taddr + execp->a_text; 177 epp->ep_dsize = execp->a_data + execp->a_bss; 178 epp->ep_entry = execp->a_entry; 179 180 error = vn_marktext(epp->ep_vp); 181 if (error) 182 return (error); 183 184 /* set up command for text segment */ 185 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_text, 186 epp->ep_taddr, epp->ep_vp, 0, VM_PROT_READ|VM_PROT_EXECUTE); 187 188 /* set up command for data segment */ 189 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_data, 190 epp->ep_daddr, epp->ep_vp, execp->a_text, 191 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 192 193 /* set up command for bss segment */ 194 if (execp->a_bss) 195 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, execp->a_bss, 196 epp->ep_daddr + execp->a_data, NULLVP, 0, 197 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 198 199 return (*epp->ep_esch->es_setup_stack)(l, epp); 200 } 201 202 /* 203 * exec_m68k4k_prep_nmagic(): Prepare a m68k4k NMAGIC binary's exec package 204 */ 205 206 int 207 exec_m68k4k_prep_nmagic(struct lwp *l, struct exec_package *epp) 208 { 209 struct exec *execp = epp->ep_hdr; 210 long bsize, baddr; 211 212 epp->ep_taddr = M68K4K_USRTEXT; 213 epp->ep_tsize = execp->a_text; 214 epp->ep_daddr = roundup(epp->ep_taddr + execp->a_text, 215 M68K4K_LDPGSZ); 216 epp->ep_dsize = execp->a_data + execp->a_bss; 217 epp->ep_entry = execp->a_entry; 218 219 /* set up command for text segment */ 220 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_text, 221 epp->ep_taddr, epp->ep_vp, sizeof(struct exec), 222 VM_PROT_READ|VM_PROT_EXECUTE); 223 224 /* set up command for data segment */ 225 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_data, 226 epp->ep_daddr, epp->ep_vp, execp->a_text + sizeof(struct exec), 227 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 228 229 /* set up command for bss segment */ 230 baddr = roundup(epp->ep_daddr + execp->a_data, PAGE_SIZE); 231 bsize = epp->ep_daddr + epp->ep_dsize - baddr; 232 if (bsize > 0) 233 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr, 234 NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 235 236 return (*epp->ep_esch->es_setup_stack)(l, epp); 237 } 238 239 /* 240 * exec_m68k4k_prep_omagic(): Prepare a m68k4k OMAGIC binary's exec package 241 */ 242 243 int 244 exec_m68k4k_prep_omagic(struct lwp *l, struct exec_package *epp) 245 { 246 struct exec *execp = epp->ep_hdr; 247 long dsize, bsize, baddr; 248 249 epp->ep_taddr = M68K4K_USRTEXT; 250 epp->ep_tsize = execp->a_text; 251 epp->ep_daddr = epp->ep_taddr + execp->a_text; 252 epp->ep_dsize = execp->a_data + execp->a_bss; 253 epp->ep_entry = execp->a_entry; 254 255 /* set up command for text and data segments */ 256 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, 257 execp->a_text + execp->a_data, epp->ep_taddr, epp->ep_vp, 258 sizeof(struct exec), VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 259 260 /* set up command for bss segment */ 261 baddr = roundup(epp->ep_daddr + execp->a_data, PAGE_SIZE); 262 bsize = epp->ep_daddr + epp->ep_dsize - baddr; 263 if (bsize > 0) 264 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr, 265 NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 266 267 /* 268 * Make sure (# of pages) mapped above equals (vm_tsize + vm_dsize); 269 * obreak(2) relies on this fact. Both `vm_tsize' and `vm_dsize' are 270 * computed (in execve(2)) by rounding *up* `ep_tsize' and `ep_dsize' 271 * respectively to page boundaries. 272 * Compensate `ep_dsize' for the amount of data covered by the last 273 * text page. 274 */ 275 dsize = epp->ep_dsize + execp->a_text - roundup(execp->a_text, 276 PAGE_SIZE); 277 epp->ep_dsize = (dsize > 0) ? dsize : 0; 278 return (*epp->ep_esch->es_setup_stack)(l, epp); 279 } 280