1 /* $NetBSD: loadfile.c,v 1.7 1999/12/29 11:08:02 hannken Exp $ */ 2 3 /*- 4 * Copyright (c) 1997 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center and by Christos Zoulas. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 /* 41 * Copyright (c) 1992, 1993 42 * The Regents of the University of California. All rights reserved. 43 * 44 * This code is derived from software contributed to Berkeley by 45 * Ralph Campbell. 46 * 47 * Redistribution and use in source and binary forms, with or without 48 * modification, are permitted provided that the following conditions 49 * are met: 50 * 1. Redistributions of source code must retain the above copyright 51 * notice, this list of conditions and the following disclaimer. 52 * 2. Redistributions in binary form must reproduce the above copyright 53 * notice, this list of conditions and the following disclaimer in the 54 * documentation and/or other materials provided with the distribution. 55 * 3. All advertising materials mentioning features or use of this software 56 * must display the following acknowledgement: 57 * This product includes software developed by the University of 58 * California, Berkeley and its contributors. 59 * 4. Neither the name of the University nor the names of its contributors 60 * may be used to endorse or promote products derived from this software 61 * without specific prior written permission. 62 * 63 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 64 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 65 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 66 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 67 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 68 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 69 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 70 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 71 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 72 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 73 * SUCH DAMAGE. 74 * 75 * @(#)boot.c 8.1 (Berkeley) 6/10/93 76 */ 77 78 #ifdef _STANDALONE 79 #include <lib/libsa/stand.h> 80 #include <lib/libkern/libkern.h> 81 #else 82 #include <stdio.h> 83 #include <string.h> 84 #include <errno.h> 85 #include <stdlib.h> 86 #include <unistd.h> 87 #include <fcntl.h> 88 #include <err.h> 89 #endif 90 91 #include <sys/param.h> 92 #include <sys/exec.h> 93 94 #include "loadfile.h" 95 96 #ifdef BOOT_ECOFF 97 #include <sys/exec_ecoff.h> 98 static int coff_exec __P((int, struct ecoff_exechdr *, u_long *, int)); 99 #endif 100 #ifdef BOOT_ELF 101 #include <sys/exec_elf.h> 102 static int elf_exec __P((int, Elf_Ehdr *, u_long *, int)); 103 #endif 104 #ifdef BOOT_AOUT 105 #include <sys/exec_aout.h> 106 static int aout_exec __P((int, struct exec *, u_long *, int)); 107 #endif 108 109 /* 110 * Open 'filename', read in program and and return 0 if ok 1 on error. 111 * Fill in marks 112 */ 113 int 114 loadfile(fname, marks, flags) 115 const char *fname; 116 u_long *marks; 117 int flags; 118 { 119 union { 120 #ifdef BOOT_ECOFF 121 struct ecoff_exechdr coff; 122 #endif 123 #ifdef BOOT_ELF 124 Elf_Ehdr elf; 125 #endif 126 #ifdef BOOT_AOUT 127 struct exec aout; 128 #endif 129 130 } hdr; 131 ssize_t nr; 132 int fd, rval; 133 134 /* Open the file. */ 135 if ((fd = open(fname, 0)) < 0) { 136 WARN(("open %s", fname ? fname : "<default>")); 137 return -1; 138 } 139 140 /* Read the exec header. */ 141 if ((nr = read(fd, &hdr, sizeof(hdr))) != sizeof(hdr)) { 142 WARN(("read header")); 143 goto err; 144 } 145 146 #ifdef BOOT_ECOFF 147 if (!ECOFF_BADMAG(&hdr.coff)) { 148 rval = coff_exec(fd, &hdr.coff, marks, flags); 149 } else 150 #endif 151 #ifdef BOOT_ELF 152 if (memcmp(hdr.elf.e_ident, ELFMAG, SELFMAG) == 0 && 153 hdr.elf.e_ident[EI_CLASS] == ELFCLASS) { 154 rval = elf_exec(fd, &hdr.elf, marks, flags); 155 } else 156 #endif 157 #ifdef BOOT_AOUT 158 if (OKMAGIC(N_GETMAGIC(hdr.aout)) && 159 N_GETMID(hdr.aout) == MID_MACHINE) { 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; 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 maxp = roundup(maxp, sizeof(long)); 349 if (flags & (LOAD_HDR|COUNT_HDR)) { 350 elfp = maxp; 351 maxp += sizeof(Elf_Ehdr); 352 } 353 354 if (flags & (LOAD_SYM|COUNT_SYM)) { 355 if (lseek(fd, elf->e_shoff, SEEK_SET) == -1) { 356 WARN(("lseek section headers")); 357 return 1; 358 } 359 sz = elf->e_shnum * sizeof(Elf_Shdr); 360 361 shp = ALLOC(sz); 362 363 if (read(fd, shp, sz) != sz) { 364 WARN(("read section headers")); 365 return 1; 366 } 367 368 shpp = maxp; 369 maxp += roundup(sz, sizeof(long)); 370 371 /* 372 * Now load the symbol sections themselves. Make sure the 373 * sections are aligned. Don't bother with string tables if 374 * there are no symbol sections. 375 */ 376 off = roundup((sizeof(Elf_Ehdr) + sz), sizeof(long)); 377 378 for (havesyms = i = 0; i < elf->e_shnum; i++) 379 if (shp[i].sh_type == SHT_SYMTAB) 380 havesyms = 1; 381 382 for (first = 1, i = 0; i < elf->e_shnum; i++) { 383 if (shp[i].sh_type == SHT_SYMTAB || 384 shp[i].sh_type == SHT_STRTAB) { 385 if (havesyms && (flags & LOAD_SYM)) { 386 PROGRESS(("%s%ld", first ? " [" : "+", 387 (u_long)shp[i].sh_size)); 388 if (lseek(fd, shp[i].sh_offset, 389 SEEK_SET) == -1) { 390 WARN(("lseek symbols")); 391 FREE(shp, sz); 392 return 1; 393 } 394 if (READ(fd, maxp, shp[i].sh_size) != 395 shp[i].sh_size) { 396 WARN(("read symbols")); 397 FREE(shp, sz); 398 return 1; 399 } 400 } 401 maxp += roundup(shp[i].sh_size, 402 sizeof(long)); 403 shp[i].sh_offset = off; 404 off += roundup(shp[i].sh_size, sizeof(long)); 405 first = 0; 406 } 407 } 408 if (flags & LOAD_SYM) { 409 BCOPY(shp, shpp, sz); 410 FREE(shp, sz); 411 412 if (first == 0) 413 PROGRESS(("]")); 414 } 415 } 416 417 /* 418 * Frob the copied ELF header to give information relative 419 * to elfp. 420 */ 421 if (flags & LOAD_HDR) { 422 elf->e_phoff = 0; 423 elf->e_shoff = sizeof(Elf_Ehdr); 424 elf->e_phentsize = 0; 425 elf->e_phnum = 0; 426 BCOPY(elf, elfp, sizeof(*elf)); 427 } 428 429 marks[MARK_START] = LOADADDR(minp); 430 marks[MARK_ENTRY] = LOADADDR(elf->e_entry); 431 marks[MARK_NSYM] = 1; /* XXX: Kernel needs >= 0 */ 432 marks[MARK_SYM] = LOADADDR(elfp); 433 marks[MARK_END] = LOADADDR(maxp); 434 return 0; 435 } 436 #endif /* BOOT_ELF */ 437 438 #ifdef BOOT_AOUT 439 static int 440 aout_exec(fd, x, marks, flags) 441 int fd; 442 struct exec *x; 443 u_long *marks; 444 int flags; 445 { 446 u_long entry = x->a_entry; 447 paddr_t aoutp = 0; 448 paddr_t minp, maxp; 449 int cc; 450 paddr_t offset = marks[MARK_START]; 451 u_long magic = N_GETMAGIC(*x); 452 int sub; 453 454 /* In OMAGIC and NMAGIC, exec header isn't part of text segment */ 455 if (magic == OMAGIC || magic == NMAGIC) 456 sub = 0; 457 else 458 sub = sizeof(*x); 459 460 minp = maxp = ALIGNENTRY(entry); 461 462 if (lseek(fd, sizeof(*x), SEEK_SET) == -1) { 463 WARN(("lseek text")); 464 return 1; 465 } 466 467 /* 468 * Leave a copy of the exec header before the text. 469 * The kernel may use this to verify that the 470 * symbols were loaded by this boot program. 471 */ 472 if (magic == OMAGIC || magic == NMAGIC) { 473 if (flags & LOAD_HDR) 474 BCOPY(x, maxp - sizeof(*x), sizeof(*x)); 475 } 476 else { 477 if (flags & LOAD_HDR) 478 BCOPY(x, maxp, sizeof(*x)); 479 if (flags & (LOAD_HDR|COUNT_HDR)) 480 maxp += sizeof(*x); 481 } 482 483 /* 484 * Read in the text segment. 485 */ 486 if (flags & LOAD_TEXT) { 487 PROGRESS(("%ld", x->a_text)); 488 489 if (READ(fd, maxp, x->a_text - sub) != x->a_text - sub) { 490 WARN(("read text")); 491 return 1; 492 } 493 } else { 494 if (lseek(fd, x->a_text - sub, SEEK_CUR) == -1) { 495 WARN(("seek text")); 496 return 1; 497 } 498 } 499 if (flags & (LOAD_TEXT|COUNT_TEXT)) 500 maxp += x->a_text - sub; 501 502 /* 503 * Provide alignment if required 504 */ 505 if (magic == ZMAGIC || magic == NMAGIC) { 506 int size = -(unsigned int)maxp & (__LDPGSZ - 1); 507 508 if (flags & LOAD_TEXTA) { 509 PROGRESS(("/%d", size)); 510 BZERO(maxp, size); 511 } 512 513 if (flags & (LOAD_TEXTA|COUNT_TEXTA)) 514 maxp += size; 515 } 516 517 /* 518 * Read in the data segment. 519 */ 520 if (flags & LOAD_DATA) { 521 PROGRESS(("+%ld", x->a_data)); 522 523 if (READ(fd, maxp, x->a_data) != x->a_data) { 524 WARN(("read data")); 525 return 1; 526 } 527 } 528 else { 529 if (lseek(fd, x->a_data, SEEK_CUR) == -1) { 530 WARN(("seek data")); 531 return 1; 532 } 533 } 534 if (flags & (LOAD_DATA|COUNT_DATA)) 535 maxp += x->a_data; 536 537 /* 538 * Zero out the BSS section. 539 * (Kernel doesn't care, but do it anyway.) 540 */ 541 if (flags & LOAD_BSS) { 542 PROGRESS(("+%ld", x->a_bss)); 543 544 BZERO(maxp, x->a_bss); 545 } 546 547 if (flags & (LOAD_BSS|COUNT_BSS)) 548 maxp += x->a_bss; 549 550 /* 551 * Read in the symbol table and strings. 552 * (Always set the symtab size word.) 553 */ 554 if (flags & LOAD_SYM) 555 BCOPY(&x->a_syms, maxp, sizeof(x->a_syms)); 556 557 if (flags & (LOAD_SYM|COUNT_SYM)) { 558 maxp += sizeof(x->a_syms); 559 aoutp = maxp; 560 } 561 562 if (x->a_syms > 0) { 563 /* Symbol table and string table length word. */ 564 565 if (flags & LOAD_SYM) { 566 PROGRESS(("+[%ld", x->a_syms)); 567 568 if (READ(fd, maxp, x->a_syms) != x->a_syms) { 569 WARN(("read symbols")); 570 return 1; 571 } 572 } else { 573 if (lseek(fd, x->a_syms, SEEK_CUR) == -1) { 574 WARN(("seek symbols")); 575 return 1; 576 } 577 } 578 if (flags & (LOAD_SYM|COUNT_SYM)) 579 maxp += x->a_syms; 580 581 if (read(fd, &cc, sizeof(cc)) != sizeof(cc)) { 582 WARN(("read string table")); 583 return 1; 584 } 585 586 if (flags & LOAD_SYM) { 587 BCOPY(&cc, maxp, sizeof(cc)); 588 589 /* String table. Length word includes itself. */ 590 591 PROGRESS(("+%d]", cc)); 592 } 593 if (flags & (LOAD_SYM|COUNT_SYM)) 594 maxp += sizeof(cc); 595 596 cc -= sizeof(int); 597 if (cc <= 0) { 598 WARN(("symbol table too short")); 599 return 1; 600 } 601 602 if (flags & LOAD_SYM) { 603 if (READ(fd, maxp, cc) != cc) { 604 WARN(("read strings")); 605 return 1; 606 } 607 } else { 608 if (lseek(fd, cc, SEEK_CUR) == -1) { 609 WARN(("seek strings")); 610 return 1; 611 } 612 } 613 if (flags & (LOAD_SYM|COUNT_SYM)) 614 maxp += cc; 615 } 616 617 marks[MARK_START] = LOADADDR(minp); 618 marks[MARK_ENTRY] = LOADADDR(entry); 619 marks[MARK_NSYM] = x->a_syms; 620 marks[MARK_SYM] = LOADADDR(aoutp); 621 marks[MARK_END] = LOADADDR(maxp); 622 return 0; 623 } 624 #endif /* BOOT_AOUT */ 625