1 /* $NetBSD: loadfile.c,v 1.10 2000/12/03 02:53:04 tsutsui Exp $ */ 2 /* $OpenBSD: loadfile.c,v 1.18 2008/06/26 05:42:20 ray Exp $ */ 3 4 /*- 5 * Copyright (c) 1997 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 10 * NASA Ames Research Center and by Christos Zoulas. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * Copyright (c) 1992, 1993 36 * The Regents of the University of California. All rights reserved. 37 * 38 * This code is derived from software contributed to Berkeley by 39 * Ralph Campbell. 40 * 41 * Redistribution and use in source and binary forms, with or without 42 * modification, are permitted provided that the following conditions 43 * are met: 44 * 1. Redistributions of source code must retain the above copyright 45 * notice, this list of conditions and the following disclaimer. 46 * 2. Redistributions in binary form must reproduce the above copyright 47 * notice, this list of conditions and the following disclaimer in the 48 * documentation and/or other materials provided with the distribution. 49 * 3. Neither the name of the University nor the names of its contributors 50 * may be used to endorse or promote products derived from this software 51 * without specific prior written permission. 52 * 53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 63 * SUCH DAMAGE. 64 * 65 * @(#)boot.c 8.1 (Berkeley) 6/10/93 66 */ 67 68 #ifdef _STANDALONE 69 #include <lib/libkern/libkern.h> 70 #include <lib/libsa/stand.h> 71 #else 72 #include <stdio.h> 73 #include <string.h> 74 #include <errno.h> 75 #include <stdlib.h> 76 #include <unistd.h> 77 #include <fcntl.h> 78 #include <err.h> 79 #endif 80 81 #include <sys/param.h> 82 #include <sys/exec.h> 83 84 #include "loadfile.h" 85 86 #ifdef BOOT_ECOFF 87 #include <sys/exec_ecoff.h> 88 static int coff_exec(int, struct ecoff_exechdr *, u_long *, int); 89 #endif 90 #ifdef BOOT_AOUT 91 /* #include <sys/exec_aout.h> done from <sys/exec.h> above */ 92 static int aout_exec(int, struct exec *, u_long *, int); 93 #endif 94 95 #ifdef BOOT_ELF 96 #include <sys/exec_elf.h> 97 #if defined(BOOT_ELF32) && defined(BOOT_ELF64) 98 /* 99 * Both defined, so elf32_exec() and elf64_exec() need to be separately 100 * created (can't do it by including loadfile_elf.c here). 101 */ 102 int elf32_exec(int, Elf32_Ehdr *, u_long *, int); 103 int elf64_exec(int, Elf64_Ehdr *, u_long *, int); 104 #else 105 #include "loadfile_elf.c" 106 #endif 107 #endif 108 109 /* 110 * Open 'filename', read in program and return -1 on error otherwise fd, 111 * with file still open. 112 * Also fills in marks. 113 */ 114 int 115 loadfile(const char *fname, u_long *marks, int flags) 116 { 117 union { 118 #ifdef BOOT_ECOFF 119 struct ecoff_exechdr coff; 120 #endif 121 #if defined(BOOT_ELF32) || (defined(BOOT_ELF) && ELFSIZE == 32) 122 Elf32_Ehdr elf32; 123 #endif 124 #if defined(BOOT_ELF64) || (defined(BOOT_ELF) && ELFSIZE == 64) 125 Elf64_Ehdr elf64; 126 #endif 127 #ifdef BOOT_AOUT 128 struct exec aout; 129 #endif 130 131 } hdr; 132 ssize_t nr; 133 int fd, rval; 134 135 /* Open the file. */ 136 if ((fd = open(fname, 0)) < 0) { 137 WARN(("open %s", fname ? fname : "<default>")); 138 return -1; 139 } 140 141 /* Read the exec header. */ 142 if ((nr = read(fd, &hdr, sizeof(hdr))) != sizeof(hdr)) { 143 WARN(("read header")); 144 goto err; 145 } 146 147 #ifdef BOOT_ECOFF 148 if (!ECOFF_BADMAG(&hdr.coff)) { 149 rval = coff_exec(fd, &hdr.coff, marks, flags); 150 } else 151 #endif 152 #if defined(BOOT_ELF32) || (defined(BOOT_ELF) && ELFSIZE == 32) 153 if (memcmp(hdr.elf32.e_ident, ELFMAG, SELFMAG) == 0 && 154 hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) { 155 rval = elf32_exec(fd, &hdr.elf32, marks, flags); 156 } else 157 #endif 158 #if defined(BOOT_ELF64) || (defined(BOOT_ELF) && ELFSIZE == 64) 159 if (memcmp(hdr.elf64.e_ident, ELFMAG, SELFMAG) == 0 && 160 hdr.elf64.e_ident[EI_CLASS] == ELFCLASS64) { 161 rval = elf64_exec(fd, &hdr.elf64, marks, flags); 162 } else 163 #endif 164 #ifdef BOOT_AOUT 165 if (OKMAGIC(N_GETMAGIC(hdr.aout)) 166 #ifndef NO_MID_CHECK 167 && N_GETMID(hdr.aout) == MID_MACHINE 168 #endif 169 ) { 170 rval = aout_exec(fd, &hdr.aout, marks, flags); 171 } else 172 #endif 173 { 174 rval = 1; 175 errno = EFTYPE; 176 WARN(("%s", fname ? fname : "<default>")); 177 } 178 179 if (rval == 0) { 180 PROGRESS(("=0x%lx\n", marks[MARK_END] - marks[MARK_START])); 181 return fd; 182 } 183 err: 184 (void)close(fd); 185 return -1; 186 } 187 188 #ifdef BOOT_ECOFF 189 static int 190 coff_exec(int fd, struct ecoff_exechdr *coff, u_long *marks, int flags) 191 { 192 paddr_t offset = marks[MARK_START]; 193 paddr_t minp = ~0, maxp = 0, pos; 194 195 /* Read in text. */ 196 if (lseek(fd, ECOFF_TXTOFF(coff), SEEK_SET) == -1) { 197 WARN(("lseek text")); 198 return 1; 199 } 200 201 if (coff->a.tsize != 0) { 202 if (flags & LOAD_TEXT) { 203 PROGRESS(("%lu", coff->a.tsize)); 204 if (READ(fd, coff->a.text_start, coff->a.tsize) != 205 coff->a.tsize) { 206 return 1; 207 } 208 } 209 else { 210 if (lseek(fd, coff->a.tsize, SEEK_CUR) == -1) { 211 WARN(("read text")); 212 return 1; 213 } 214 } 215 if (flags & (COUNT_TEXT|LOAD_TEXT)) { 216 pos = coff->a.text_start; 217 if (minp > pos) 218 minp = pos; 219 pos += coff->a.tsize; 220 if (maxp < pos) 221 maxp = pos; 222 } 223 } 224 225 /* Read in data. */ 226 if (coff->a.dsize != 0) { 227 if (flags & LOAD_DATA) { 228 PROGRESS(("+%lu", coff->a.dsize)); 229 if (READ(fd, coff->a.data_start, coff->a.dsize) != 230 coff->a.dsize) { 231 WARN(("read data")); 232 return 1; 233 } 234 } 235 if (flags & (COUNT_DATA|LOAD_DATA)) { 236 pos = coff->a.data_start; 237 if (minp > pos) 238 minp = pos; 239 pos += coff->a.dsize; 240 if (maxp < pos) 241 maxp = pos; 242 } 243 } 244 245 /* Zero out bss. */ 246 if (coff->a.bsize != 0) { 247 if (flags & LOAD_BSS) { 248 PROGRESS(("+%lu", coff->a.bsize)); 249 BZERO(coff->a.bss_start, coff->a.bsize); 250 } 251 if (flags & (COUNT_BSS|LOAD_BSS)) { 252 pos = coff->a.bss_start; 253 if (minp > pos) 254 minp = pos; 255 pos = coff->a.bsize; 256 if (maxp < pos) 257 maxp = pos; 258 } 259 } 260 261 marks[MARK_START] = LOADADDR(minp); 262 marks[MARK_ENTRY] = LOADADDR(coff->a.entry); 263 marks[MARK_NSYM] = 1; /* XXX: Kernel needs >= 0 */ 264 marks[MARK_SYM] = LOADADDR(maxp); 265 marks[MARK_END] = LOADADDR(maxp); 266 return 0; 267 } 268 #endif /* BOOT_ECOFF */ 269 270 #ifdef BOOT_AOUT 271 static int 272 aout_exec(int fd, struct exec *x, u_long *marks, int flags) 273 { 274 u_long entry = x->a_entry; 275 paddr_t aoutp = 0; 276 paddr_t minp, maxp; 277 int cc; 278 paddr_t offset = marks[MARK_START]; 279 u_long magic = N_GETMAGIC(*x); 280 int sub; 281 282 /* In OMAGIC and NMAGIC, exec header isn't part of text segment */ 283 if (magic == OMAGIC || magic == NMAGIC) 284 sub = 0; 285 else 286 sub = sizeof(*x); 287 288 minp = maxp = ALIGNENTRY(entry); 289 290 if (lseek(fd, sizeof(*x), SEEK_SET) == -1) { 291 WARN(("lseek text")); 292 return 1; 293 } 294 295 /* 296 * Leave a copy of the exec header before the text. 297 * The kernel may use this to verify that the 298 * symbols were loaded by this boot program. 299 */ 300 if (magic == OMAGIC || magic == NMAGIC) { 301 if (flags & LOAD_HDR && maxp >= sizeof(*x)) 302 BCOPY(x, maxp - sizeof(*x), sizeof(*x)); 303 } 304 else { 305 if (flags & LOAD_HDR) 306 BCOPY(x, maxp, sizeof(*x)); 307 if (flags & (LOAD_HDR|COUNT_HDR)) { 308 minp += sizeof(*x); 309 maxp += sizeof(*x); 310 } 311 } 312 313 /* 314 * Read in the text segment. 315 */ 316 if (flags & LOAD_TEXT) { 317 PROGRESS(("%d", x->a_text)); 318 319 if (READ(fd, maxp, x->a_text - sub) != x->a_text - sub) { 320 WARN(("read text")); 321 return 1; 322 } 323 } else { 324 if (lseek(fd, x->a_text - sub, SEEK_CUR) == -1) { 325 WARN(("seek text")); 326 return 1; 327 } 328 } 329 if (flags & (LOAD_TEXT|COUNT_TEXT)) 330 maxp += x->a_text - sub; 331 332 /* 333 * Provide alignment if required 334 */ 335 if (magic == ZMAGIC || magic == NMAGIC) { 336 int size = -(unsigned int)maxp & (__LDPGSZ - 1); 337 338 if (flags & LOAD_TEXTA) { 339 PROGRESS(("/%d", size)); 340 BZERO(maxp, size); 341 } 342 343 if (flags & (LOAD_TEXTA|COUNT_TEXTA)) 344 maxp += size; 345 } 346 347 /* 348 * Read in the data segment. 349 */ 350 if (flags & LOAD_DATA) { 351 PROGRESS(("+%d", x->a_data)); 352 353 if (READ(fd, maxp, x->a_data) != x->a_data) { 354 WARN(("read data")); 355 return 1; 356 } 357 } 358 else { 359 if (lseek(fd, x->a_data, SEEK_CUR) == -1) { 360 WARN(("seek data")); 361 return 1; 362 } 363 } 364 if (flags & (LOAD_DATA|COUNT_DATA)) 365 maxp += x->a_data; 366 367 /* 368 * Zero out the BSS section. 369 * (Kernel doesn't care, but do it anyway.) 370 */ 371 if (flags & LOAD_BSS) { 372 PROGRESS(("+%d", x->a_bss)); 373 374 BZERO(maxp, x->a_bss); 375 } 376 377 if (flags & (LOAD_BSS|COUNT_BSS)) 378 maxp += x->a_bss; 379 380 /* 381 * Read in the symbol table and strings. 382 * (Always set the symtab size word.) 383 */ 384 if (flags & LOAD_SYM) 385 BCOPY(&x->a_syms, maxp, sizeof(x->a_syms)); 386 387 if (flags & (LOAD_SYM|COUNT_SYM)) { 388 maxp += sizeof(x->a_syms); 389 aoutp = maxp; 390 } 391 392 if (x->a_syms > 0) { 393 /* Symbol table and string table length word. */ 394 395 if (flags & LOAD_SYM) { 396 PROGRESS(("+[%d", x->a_syms)); 397 398 if (READ(fd, maxp, x->a_syms) != x->a_syms) { 399 WARN(("read symbols")); 400 return 1; 401 } 402 } else { 403 if (lseek(fd, x->a_syms, SEEK_CUR) == -1) { 404 WARN(("seek symbols")); 405 return 1; 406 } 407 } 408 if (flags & (LOAD_SYM|COUNT_SYM)) 409 maxp += x->a_syms; 410 411 if (read(fd, &cc, sizeof(cc)) != sizeof(cc)) { 412 WARN(("read string table")); 413 return 1; 414 } 415 416 if (flags & LOAD_SYM) { 417 BCOPY(&cc, maxp, sizeof(cc)); 418 419 /* String table. Length word includes itself. */ 420 421 PROGRESS(("+%d]", cc)); 422 } 423 if (flags & (LOAD_SYM|COUNT_SYM)) 424 maxp += sizeof(cc); 425 426 cc -= sizeof(int); 427 if (cc <= 0) { 428 WARN(("symbol table too short")); 429 return 1; 430 } 431 432 if (flags & LOAD_SYM) { 433 if (READ(fd, maxp, cc) != cc) { 434 WARN(("read strings")); 435 return 1; 436 } 437 } else { 438 if (lseek(fd, cc, SEEK_CUR) == -1) { 439 WARN(("seek strings")); 440 return 1; 441 } 442 } 443 if (flags & (LOAD_SYM|COUNT_SYM)) 444 maxp += cc; 445 } 446 447 marks[MARK_START] = LOADADDR(minp); 448 marks[MARK_ENTRY] = LOADADDR(entry); 449 marks[MARK_NSYM] = x->a_syms; 450 marks[MARK_SYM] = LOADADDR(aoutp); 451 marks[MARK_END] = LOADADDR(maxp); 452 return 0; 453 } 454 #endif /* BOOT_AOUT */ 455