1 /* $NetBSD: loadfile.c,v 1.10 2000/12/03 02:53:04 tsutsui Exp $ */ 2 /* $OpenBSD: loadfile.c,v 1.6 2003/06/02 23:28:09 millert 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 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the NetBSD 23 * Foundation, Inc. and its contributors. 24 * 4. Neither the name of The NetBSD Foundation nor the names of its 25 * contributors may be used to endorse or promote products derived 26 * from this software without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 29 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 32 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38 * POSSIBILITY OF SUCH DAMAGE. 39 */ 40 41 /* 42 * Copyright (c) 1992, 1993 43 * The Regents of the University of California. All rights reserved. 44 * 45 * This code is derived from software contributed to Berkeley by 46 * Ralph Campbell. 47 * 48 * Redistribution and use in source and binary forms, with or without 49 * modification, are permitted provided that the following conditions 50 * are met: 51 * 1. Redistributions of source code must retain the above copyright 52 * notice, this list of conditions and the following disclaimer. 53 * 2. Redistributions in binary form must reproduce the above copyright 54 * notice, this list of conditions and the following disclaimer in the 55 * documentation and/or other materials provided with the distribution. 56 * 3. Neither the name of the University nor the names of its contributors 57 * may be used to endorse or promote products derived from this software 58 * without specific prior written permission. 59 * 60 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 61 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 62 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 63 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 64 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 65 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 66 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 67 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 68 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 69 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 70 * SUCH DAMAGE. 71 * 72 * @(#)boot.c 8.1 (Berkeley) 6/10/93 73 */ 74 75 #ifdef _STANDALONE 76 #include <lib/libkern/libkern.h> 77 #include <lib/libsa/stand.h> 78 #else 79 #include <stdio.h> 80 #include <string.h> 81 #include <errno.h> 82 #include <stdlib.h> 83 #include <unistd.h> 84 #include <fcntl.h> 85 #include <err.h> 86 #endif 87 88 #include <sys/param.h> 89 #include <sys/exec.h> 90 91 #include "loadfile.h" 92 93 #ifdef BOOT_ECOFF 94 #include <sys/exec_ecoff.h> 95 static int coff_exec(int, struct ecoff_exechdr *, u_long *, int); 96 #endif 97 #ifdef BOOT_ELF 98 #include <sys/exec_elf.h> 99 static int elf_exec(int, Elf_Ehdr *, u_long *, int); 100 #endif 101 #ifdef BOOT_AOUT 102 #include <sys/exec_aout.h> 103 static int aout_exec(int, struct exec *, u_long *, int); 104 #endif 105 106 /* 107 * Open 'filename', read in program and and return 0 if ok 1 on error. 108 * Fill in marks 109 */ 110 int 111 loadfile(fname, marks, flags) 112 const char *fname; 113 u_long *marks; 114 int flags; 115 { 116 union { 117 #ifdef BOOT_ECOFF 118 struct ecoff_exechdr coff; 119 #endif 120 #ifdef BOOT_ELF 121 Elf_Ehdr elf; 122 #endif 123 #ifdef BOOT_AOUT 124 struct exec aout; 125 #endif 126 127 } hdr; 128 ssize_t nr; 129 int fd, rval; 130 131 /* Open the file. */ 132 if ((fd = open(fname, 0)) < 0) { 133 WARN(("open %s", fname ? fname : "<default>")); 134 return -1; 135 } 136 137 /* Read the exec header. */ 138 if ((nr = read(fd, &hdr, sizeof(hdr))) != sizeof(hdr)) { 139 WARN(("read header")); 140 goto err; 141 } 142 143 #ifdef BOOT_ECOFF 144 if (!ECOFF_BADMAG(&hdr.coff)) { 145 rval = coff_exec(fd, &hdr.coff, marks, flags); 146 } else 147 #endif 148 #ifdef BOOT_ELF 149 if (memcmp(hdr.elf.e_ident, ELFMAG, SELFMAG) == 0 && 150 hdr.elf.e_ident[EI_CLASS] == ELFCLASS) { 151 rval = elf_exec(fd, &hdr.elf, marks, flags); 152 } else 153 #endif 154 #ifdef BOOT_AOUT 155 if (OKMAGIC(N_GETMAGIC(hdr.aout)) 156 #ifndef NO_MID_CHECK 157 && N_GETMID(hdr.aout) == MID_MACHINE 158 #endif 159 ) { 160 rval = aout_exec(fd, &hdr.aout, marks, flags); 161 } else 162 #endif 163 { 164 rval = 1; 165 errno = EFTYPE; 166 WARN(("%s", fname ? fname : "<default>")); 167 } 168 169 if (rval == 0) { 170 PROGRESS(("=0x%lx\n", marks[MARK_END] - marks[MARK_START])); 171 return fd; 172 } 173 err: 174 (void)close(fd); 175 return -1; 176 } 177 178 #ifdef BOOT_ECOFF 179 static int 180 coff_exec(fd, coff, marks, flags) 181 int fd; 182 struct ecoff_exechdr *coff; 183 u_long *marks; 184 int flags; 185 { 186 paddr_t offset = marks[MARK_START]; 187 paddr_t minp = ~0, maxp = 0, pos; 188 189 /* Read in text. */ 190 if (lseek(fd, ECOFF_TXTOFF(coff), SEEK_SET) == -1) { 191 WARN(("lseek text")); 192 return 1; 193 } 194 195 if (coff->a.tsize != 0) { 196 if (flags & LOAD_TEXT) { 197 PROGRESS(("%lu", coff->a.tsize)); 198 if (READ(fd, coff->a.text_start, coff->a.tsize) != 199 coff->a.tsize) { 200 return 1; 201 } 202 } 203 else { 204 if (lseek(fd, coff->a.tsize, SEEK_CUR) == -1) { 205 WARN(("read text")); 206 return 1; 207 } 208 } 209 if (flags & (COUNT_TEXT|LOAD_TEXT)) { 210 pos = coff->a.text_start; 211 if (minp > pos) 212 minp = pos; 213 pos += coff->a.tsize; 214 if (maxp < pos) 215 maxp = pos; 216 } 217 } 218 219 /* Read in data. */ 220 if (coff->a.dsize != 0) { 221 if (flags & LOAD_DATA) { 222 PROGRESS(("+%lu", coff->a.dsize)); 223 if (READ(fd, coff->a.data_start, coff->a.dsize) != 224 coff->a.dsize) { 225 WARN(("read data")); 226 return 1; 227 } 228 } 229 if (flags & (COUNT_DATA|LOAD_DATA)) { 230 pos = coff->a.data_start; 231 if (minp > pos) 232 minp = pos; 233 pos += coff->a.dsize; 234 if (maxp < pos) 235 maxp = pos; 236 } 237 } 238 239 /* Zero out bss. */ 240 if (coff->a.bsize != 0) { 241 if (flags & LOAD_BSS) { 242 PROGRESS(("+%lu", coff->a.bsize)); 243 BZERO(coff->a.bss_start, coff->a.bsize); 244 } 245 if (flags & (COUNT_BSS|LOAD_BSS)) { 246 pos = coff->a.bss_start; 247 if (minp > pos) 248 minp = pos; 249 pos = coff->a.bsize; 250 if (maxp < pos) 251 maxp = pos; 252 } 253 } 254 255 marks[MARK_START] = LOADADDR(minp); 256 marks[MARK_ENTRY] = LOADADDR(coff->a.entry); 257 marks[MARK_NSYM] = 1; /* XXX: Kernel needs >= 0 */ 258 marks[MARK_SYM] = LOADADDR(maxp); 259 marks[MARK_END] = LOADADDR(maxp); 260 return 0; 261 } 262 #endif /* BOOT_ECOFF */ 263 264 #ifdef BOOT_ELF 265 static int 266 elf_exec(fd, elf, marks, flags) 267 int fd; 268 Elf_Ehdr *elf; 269 u_long *marks; 270 int flags; 271 { 272 Elf_Shdr *shp; 273 Elf_Off off; 274 int i; 275 size_t sz; 276 int first; 277 int havesyms; 278 paddr_t minp = ~0, maxp = 0, pos = 0; 279 paddr_t offset = marks[MARK_START], shpp, elfp; 280 281 for (first = 1, i = 0; i < elf->e_phnum; i++) { 282 Elf_Phdr phdr; 283 if (lseek(fd, elf->e_phoff + sizeof(phdr) * i, SEEK_SET) 284 == -1) { 285 WARN(("lseek phdr")); 286 return 1; 287 } 288 if (read(fd, (void *)&phdr, sizeof(phdr)) != sizeof(phdr)) { 289 WARN(("read phdr")); 290 return 1; 291 } 292 if (phdr.p_type != PT_LOAD || 293 (phdr.p_flags & (PF_W|PF_X)) == 0) 294 continue; 295 296 #define IS_TEXT(p) (p.p_flags & PF_X) 297 #define IS_DATA(p) (p.p_flags & PF_W) 298 #define IS_BSS(p) (p.p_filesz < p.p_memsz) 299 /* 300 * XXX: Assume first address is lowest 301 */ 302 if ((IS_TEXT(phdr) && (flags & LOAD_TEXT)) || 303 (IS_DATA(phdr) && (flags & LOAD_DATA))) { 304 305 /* Read in segment. */ 306 PROGRESS(("%s%lu", first ? "" : "+", 307 (u_long)phdr.p_filesz)); 308 309 if (lseek(fd, phdr.p_offset, SEEK_SET) == -1) { 310 WARN(("lseek text")); 311 return 1; 312 } 313 if (READ(fd, phdr.p_vaddr, phdr.p_filesz) != 314 phdr.p_filesz) { 315 WARN(("read text")); 316 return 1; 317 } 318 first = 0; 319 320 } 321 if ((IS_TEXT(phdr) && (flags & (LOAD_TEXT|COUNT_TEXT))) || 322 (IS_DATA(phdr) && (flags & (LOAD_DATA|COUNT_TEXT)))) { 323 pos = phdr.p_vaddr; 324 if (minp > pos) 325 minp = pos; 326 pos += phdr.p_filesz; 327 if (maxp < pos) 328 maxp = pos; 329 } 330 331 /* Zero out bss. */ 332 if (IS_BSS(phdr) && (flags & LOAD_BSS)) { 333 PROGRESS(("+%lu", 334 (u_long)(phdr.p_memsz - phdr.p_filesz))); 335 BZERO((phdr.p_vaddr + phdr.p_filesz), 336 phdr.p_memsz - phdr.p_filesz); 337 } 338 if (IS_BSS(phdr) && (flags & (LOAD_BSS|COUNT_BSS))) { 339 pos += phdr.p_memsz - phdr.p_filesz; 340 if (maxp < pos) 341 maxp = pos; 342 } 343 } 344 345 /* 346 * Copy the ELF and section headers. 347 */ 348 elfp = maxp = roundup(maxp, sizeof(long)); 349 if (flags & (LOAD_HDR|COUNT_HDR)) 350 maxp += sizeof(Elf_Ehdr); 351 352 if (flags & (LOAD_SYM|COUNT_SYM)) { 353 if (lseek(fd, elf->e_shoff, SEEK_SET) == -1) { 354 WARN(("lseek section headers")); 355 return 1; 356 } 357 sz = elf->e_shnum * sizeof(Elf_Shdr); 358 shp = ALLOC(sz); 359 360 if (read(fd, shp, sz) != sz) { 361 WARN(("read section headers")); 362 return 1; 363 } 364 365 shpp = maxp; 366 maxp += roundup(sz, sizeof(long)); 367 368 /* 369 * Now load the symbol sections themselves. Make sure the 370 * sections are aligned. Don't bother with string tables if 371 * there are no symbol sections. 372 */ 373 off = roundup((sizeof(Elf_Ehdr) + sz), sizeof(long)); 374 375 for (havesyms = i = 0; i < elf->e_shnum; i++) 376 if (shp[i].sh_type == SHT_SYMTAB) 377 havesyms = 1; 378 379 for (first = 1, i = 0; i < elf->e_shnum; i++) { 380 if (shp[i].sh_type == SHT_SYMTAB || 381 shp[i].sh_type == SHT_STRTAB) { 382 if (havesyms && (flags & LOAD_SYM)) { 383 PROGRESS(("%s%ld", first ? " [" : "+", 384 (u_long)shp[i].sh_size)); 385 if (lseek(fd, shp[i].sh_offset, 386 SEEK_SET) == -1) { 387 WARN(("lseek symbols")); 388 FREE(shp, sz); 389 return 1; 390 } 391 if (READ(fd, maxp, shp[i].sh_size) != 392 shp[i].sh_size) { 393 WARN(("read symbols")); 394 FREE(shp, sz); 395 return 1; 396 } 397 } 398 maxp += roundup(shp[i].sh_size, 399 sizeof(long)); 400 shp[i].sh_offset = off; 401 off += roundup(shp[i].sh_size, sizeof(long)); 402 first = 0; 403 } 404 } 405 if (flags & LOAD_SYM) { 406 BCOPY(shp, shpp, sz); 407 408 if (havesyms && first == 0) 409 PROGRESS(("]")); 410 } 411 FREE(shp, sz); 412 } 413 414 /* 415 * Frob the copied ELF header to give information relative 416 * to elfp. 417 */ 418 if (flags & LOAD_HDR) { 419 elf->e_phoff = 0; 420 elf->e_shoff = sizeof(Elf_Ehdr); 421 elf->e_phentsize = 0; 422 elf->e_phnum = 0; 423 BCOPY(elf, elfp, sizeof(*elf)); 424 } 425 426 marks[MARK_START] = LOADADDR(minp); 427 marks[MARK_ENTRY] = LOADADDR(elf->e_entry); 428 marks[MARK_NSYM] = 1; /* XXX: Kernel needs >= 0 */ 429 marks[MARK_SYM] = LOADADDR(elfp); 430 marks[MARK_END] = LOADADDR(maxp); 431 return 0; 432 } 433 #endif /* BOOT_ELF */ 434 435 #ifdef BOOT_AOUT 436 static int 437 aout_exec(fd, x, marks, flags) 438 int fd; 439 struct exec *x; 440 u_long *marks; 441 int flags; 442 { 443 u_long entry = x->a_entry; 444 paddr_t aoutp = 0; 445 paddr_t minp, maxp; 446 int cc; 447 paddr_t offset = marks[MARK_START]; 448 u_long magic = N_GETMAGIC(*x); 449 int sub; 450 451 /* In OMAGIC and NMAGIC, exec header isn't part of text segment */ 452 if (magic == OMAGIC || magic == NMAGIC) 453 sub = 0; 454 else 455 sub = sizeof(*x); 456 457 minp = maxp = ALIGNENTRY(entry); 458 459 if (lseek(fd, sizeof(*x), SEEK_SET) == -1) { 460 WARN(("lseek text")); 461 return 1; 462 } 463 464 /* 465 * Leave a copy of the exec header before the text. 466 * The kernel may use this to verify that the 467 * symbols were loaded by this boot program. 468 */ 469 if (magic == OMAGIC || magic == NMAGIC) { 470 if (flags & LOAD_HDR && maxp >= sizeof(*x)) 471 BCOPY(x, maxp - sizeof(*x), sizeof(*x)); 472 } 473 else { 474 if (flags & LOAD_HDR) 475 BCOPY(x, maxp, sizeof(*x)); 476 if (flags & (LOAD_HDR|COUNT_HDR)) 477 maxp += sizeof(*x); 478 } 479 480 /* 481 * Read in the text segment. 482 */ 483 if (flags & LOAD_TEXT) { 484 PROGRESS(("%ld", x->a_text)); 485 486 if (READ(fd, maxp, x->a_text - sub) != x->a_text - sub) { 487 WARN(("read text")); 488 return 1; 489 } 490 } else { 491 if (lseek(fd, x->a_text - sub, SEEK_CUR) == -1) { 492 WARN(("seek text")); 493 return 1; 494 } 495 } 496 if (flags & (LOAD_TEXT|COUNT_TEXT)) 497 maxp += x->a_text - sub; 498 499 /* 500 * Provide alignment if required 501 */ 502 if (magic == ZMAGIC || magic == NMAGIC) { 503 int size = -(unsigned int)maxp & (__LDPGSZ - 1); 504 505 if (flags & LOAD_TEXTA) { 506 PROGRESS(("/%d", size)); 507 BZERO(maxp, size); 508 } 509 510 if (flags & (LOAD_TEXTA|COUNT_TEXTA)) 511 maxp += size; 512 } 513 514 /* 515 * Read in the data segment. 516 */ 517 if (flags & LOAD_DATA) { 518 PROGRESS(("+%ld", x->a_data)); 519 520 if (READ(fd, maxp, x->a_data) != x->a_data) { 521 WARN(("read data")); 522 return 1; 523 } 524 } 525 else { 526 if (lseek(fd, x->a_data, SEEK_CUR) == -1) { 527 WARN(("seek data")); 528 return 1; 529 } 530 } 531 if (flags & (LOAD_DATA|COUNT_DATA)) 532 maxp += x->a_data; 533 534 /* 535 * Zero out the BSS section. 536 * (Kernel doesn't care, but do it anyway.) 537 */ 538 if (flags & LOAD_BSS) { 539 PROGRESS(("+%ld", x->a_bss)); 540 541 BZERO(maxp, x->a_bss); 542 } 543 544 if (flags & (LOAD_BSS|COUNT_BSS)) 545 maxp += x->a_bss; 546 547 /* 548 * Read in the symbol table and strings. 549 * (Always set the symtab size word.) 550 */ 551 if (flags & LOAD_SYM) 552 BCOPY(&x->a_syms, maxp, sizeof(x->a_syms)); 553 554 if (flags & (LOAD_SYM|COUNT_SYM)) { 555 maxp += sizeof(x->a_syms); 556 aoutp = maxp; 557 } 558 559 if (x->a_syms > 0) { 560 /* Symbol table and string table length word. */ 561 562 if (flags & LOAD_SYM) { 563 PROGRESS(("+[%ld", x->a_syms)); 564 565 if (READ(fd, maxp, x->a_syms) != x->a_syms) { 566 WARN(("read symbols")); 567 return 1; 568 } 569 } else { 570 if (lseek(fd, x->a_syms, SEEK_CUR) == -1) { 571 WARN(("seek symbols")); 572 return 1; 573 } 574 } 575 if (flags & (LOAD_SYM|COUNT_SYM)) 576 maxp += x->a_syms; 577 578 if (read(fd, &cc, sizeof(cc)) != sizeof(cc)) { 579 WARN(("read string table")); 580 return 1; 581 } 582 583 if (flags & LOAD_SYM) { 584 BCOPY(&cc, maxp, sizeof(cc)); 585 586 /* String table. Length word includes itself. */ 587 588 PROGRESS(("+%d]", cc)); 589 } 590 if (flags & (LOAD_SYM|COUNT_SYM)) 591 maxp += sizeof(cc); 592 593 cc -= sizeof(int); 594 if (cc <= 0) { 595 WARN(("symbol table too short")); 596 return 1; 597 } 598 599 if (flags & LOAD_SYM) { 600 if (READ(fd, maxp, cc) != cc) { 601 WARN(("read strings")); 602 return 1; 603 } 604 } else { 605 if (lseek(fd, cc, SEEK_CUR) == -1) { 606 WARN(("seek strings")); 607 return 1; 608 } 609 } 610 if (flags & (LOAD_SYM|COUNT_SYM)) 611 maxp += cc; 612 } 613 614 marks[MARK_START] = LOADADDR(minp); 615 marks[MARK_ENTRY] = LOADADDR(entry); 616 marks[MARK_NSYM] = x->a_syms; 617 marks[MARK_SYM] = LOADADDR(aoutp); 618 marks[MARK_END] = LOADADDR(maxp); 619 return 0; 620 } 621 #endif /* BOOT_AOUT */ 622