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