1 /* $NetBSD: loadfile.c,v 1.10 2000/12/03 02:53:04 tsutsui 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 #ifndef NO_MID_CHECK 160 && N_GETMID(hdr.aout) == MID_MACHINE 161 #endif 162 ) { 163 rval = aout_exec(fd, &hdr.aout, marks, flags); 164 } else 165 #endif 166 { 167 rval = 1; 168 errno = EFTYPE; 169 WARN(("%s", fname ? fname : "<default>")); 170 } 171 172 if (rval == 0) { 173 PROGRESS(("=0x%lx\n", marks[MARK_END] - marks[MARK_START])); 174 return fd; 175 } 176 err: 177 (void)close(fd); 178 return -1; 179 } 180 181 #ifdef BOOT_ECOFF 182 static int 183 coff_exec(fd, coff, marks, flags) 184 int fd; 185 struct ecoff_exechdr *coff; 186 u_long *marks; 187 int flags; 188 { 189 paddr_t offset = marks[MARK_START]; 190 paddr_t minp = ~0, maxp = 0, pos; 191 192 /* Read in text. */ 193 if (lseek(fd, ECOFF_TXTOFF(coff), SEEK_SET) == -1) { 194 WARN(("lseek text")); 195 return 1; 196 } 197 198 if (coff->a.tsize != 0) { 199 if (flags & LOAD_TEXT) { 200 PROGRESS(("%lu", coff->a.tsize)); 201 if (READ(fd, coff->a.text_start, coff->a.tsize) != 202 coff->a.tsize) { 203 return 1; 204 } 205 } 206 else { 207 if (lseek(fd, coff->a.tsize, SEEK_CUR) == -1) { 208 WARN(("read text")); 209 return 1; 210 } 211 } 212 if (flags & (COUNT_TEXT|LOAD_TEXT)) { 213 pos = coff->a.text_start; 214 if (minp > pos) 215 minp = pos; 216 pos += coff->a.tsize; 217 if (maxp < pos) 218 maxp = pos; 219 } 220 } 221 222 /* Read in data. */ 223 if (coff->a.dsize != 0) { 224 if (flags & LOAD_DATA) { 225 PROGRESS(("+%lu", coff->a.dsize)); 226 if (READ(fd, coff->a.data_start, coff->a.dsize) != 227 coff->a.dsize) { 228 WARN(("read data")); 229 return 1; 230 } 231 } 232 if (flags & (COUNT_DATA|LOAD_DATA)) { 233 pos = coff->a.data_start; 234 if (minp > pos) 235 minp = pos; 236 pos += coff->a.dsize; 237 if (maxp < pos) 238 maxp = pos; 239 } 240 } 241 242 /* Zero out bss. */ 243 if (coff->a.bsize != 0) { 244 if (flags & LOAD_BSS) { 245 PROGRESS(("+%lu", coff->a.bsize)); 246 BZERO(coff->a.bss_start, coff->a.bsize); 247 } 248 if (flags & (COUNT_BSS|LOAD_BSS)) { 249 pos = coff->a.bss_start; 250 if (minp > pos) 251 minp = pos; 252 pos = coff->a.bsize; 253 if (maxp < pos) 254 maxp = pos; 255 } 256 } 257 258 marks[MARK_START] = LOADADDR(minp); 259 marks[MARK_ENTRY] = LOADADDR(coff->a.entry); 260 marks[MARK_NSYM] = 1; /* XXX: Kernel needs >= 0 */ 261 marks[MARK_SYM] = LOADADDR(maxp); 262 marks[MARK_END] = LOADADDR(maxp); 263 return 0; 264 } 265 #endif /* BOOT_ECOFF */ 266 267 #ifdef BOOT_ELF 268 static int 269 elf_exec(fd, elf, marks, flags) 270 int fd; 271 Elf_Ehdr *elf; 272 u_long *marks; 273 int flags; 274 { 275 Elf_Shdr *shp; 276 Elf_Off off; 277 int i; 278 size_t sz; 279 int first; 280 int havesyms; 281 paddr_t minp = ~0, maxp = 0, pos; 282 paddr_t offset = marks[MARK_START], shpp, elfp; 283 284 for (first = 1, i = 0; i < elf->e_phnum; i++) { 285 Elf_Phdr phdr; 286 if (lseek(fd, elf->e_phoff + sizeof(phdr) * i, SEEK_SET) 287 == -1) { 288 WARN(("lseek phdr")); 289 return 1; 290 } 291 if (read(fd, (void *)&phdr, sizeof(phdr)) != sizeof(phdr)) { 292 WARN(("read phdr")); 293 return 1; 294 } 295 if (phdr.p_type != PT_LOAD || 296 (phdr.p_flags & (PF_W|PF_X)) == 0) 297 continue; 298 299 #define IS_TEXT(p) (p.p_flags & PF_X) 300 #define IS_DATA(p) (p.p_flags & PF_W) 301 #define IS_BSS(p) (p.p_filesz < p.p_memsz) 302 /* 303 * XXX: Assume first address is lowest 304 */ 305 if ((IS_TEXT(phdr) && (flags & LOAD_TEXT)) || 306 (IS_DATA(phdr) && (flags & LOAD_DATA))) { 307 308 /* Read in segment. */ 309 PROGRESS(("%s%lu", first ? "" : "+", 310 (u_long)phdr.p_filesz)); 311 312 if (lseek(fd, phdr.p_offset, SEEK_SET) == -1) { 313 WARN(("lseek text")); 314 return 1; 315 } 316 if (READ(fd, phdr.p_vaddr, phdr.p_filesz) != 317 phdr.p_filesz) { 318 WARN(("read text")); 319 return 1; 320 } 321 first = 0; 322 323 } 324 if ((IS_TEXT(phdr) && (flags & (LOAD_TEXT|COUNT_TEXT))) || 325 (IS_DATA(phdr) && (flags & (LOAD_DATA|COUNT_TEXT)))) { 326 pos = phdr.p_vaddr; 327 if (minp > pos) 328 minp = pos; 329 pos += phdr.p_filesz; 330 if (maxp < pos) 331 maxp = pos; 332 } 333 334 /* Zero out bss. */ 335 if (IS_BSS(phdr) && (flags & LOAD_BSS)) { 336 PROGRESS(("+%lu", 337 (u_long)(phdr.p_memsz - phdr.p_filesz))); 338 BZERO((phdr.p_vaddr + phdr.p_filesz), 339 phdr.p_memsz - phdr.p_filesz); 340 } 341 if (IS_BSS(phdr) && (flags & (LOAD_BSS|COUNT_BSS))) { 342 pos += phdr.p_memsz - phdr.p_filesz; 343 if (maxp < pos) 344 maxp = pos; 345 } 346 } 347 348 /* 349 * Copy the ELF and section headers. 350 */ 351 maxp = roundup(maxp, sizeof(long)); 352 if (flags & (LOAD_HDR|COUNT_HDR)) { 353 elfp = maxp; 354 maxp += sizeof(Elf_Ehdr); 355 } 356 357 if (flags & (LOAD_SYM|COUNT_SYM)) { 358 if (lseek(fd, elf->e_shoff, SEEK_SET) == -1) { 359 WARN(("lseek section headers")); 360 return 1; 361 } 362 sz = elf->e_shnum * sizeof(Elf_Shdr); 363 364 shp = ALLOC(sz); 365 366 if (read(fd, shp, sz) != sz) { 367 WARN(("read section headers")); 368 return 1; 369 } 370 371 shpp = maxp; 372 maxp += roundup(sz, sizeof(long)); 373 374 /* 375 * Now load the symbol sections themselves. Make sure the 376 * sections are aligned. Don't bother with string tables if 377 * there are no symbol sections. 378 */ 379 off = roundup((sizeof(Elf_Ehdr) + sz), sizeof(long)); 380 381 for (havesyms = i = 0; i < elf->e_shnum; i++) 382 if (shp[i].sh_type == SHT_SYMTAB) 383 havesyms = 1; 384 385 for (first = 1, i = 0; i < elf->e_shnum; i++) { 386 if (shp[i].sh_type == SHT_SYMTAB || 387 shp[i].sh_type == SHT_STRTAB) { 388 if (havesyms && (flags & LOAD_SYM)) { 389 PROGRESS(("%s%ld", first ? " [" : "+", 390 (u_long)shp[i].sh_size)); 391 if (lseek(fd, shp[i].sh_offset, 392 SEEK_SET) == -1) { 393 WARN(("lseek symbols")); 394 FREE(shp, sz); 395 return 1; 396 } 397 if (READ(fd, maxp, shp[i].sh_size) != 398 shp[i].sh_size) { 399 WARN(("read symbols")); 400 FREE(shp, sz); 401 return 1; 402 } 403 } 404 maxp += roundup(shp[i].sh_size, 405 sizeof(long)); 406 shp[i].sh_offset = off; 407 off += roundup(shp[i].sh_size, sizeof(long)); 408 first = 0; 409 } 410 } 411 if (flags & LOAD_SYM) { 412 BCOPY(shp, shpp, sz); 413 FREE(shp, sz); 414 415 if (havesyms && first == 0) 416 PROGRESS(("]")); 417 } 418 } 419 420 /* 421 * Frob the copied ELF header to give information relative 422 * to elfp. 423 */ 424 if (flags & LOAD_HDR) { 425 elf->e_phoff = 0; 426 elf->e_shoff = sizeof(Elf_Ehdr); 427 elf->e_phentsize = 0; 428 elf->e_phnum = 0; 429 BCOPY(elf, elfp, sizeof(*elf)); 430 } 431 432 marks[MARK_START] = LOADADDR(minp); 433 marks[MARK_ENTRY] = LOADADDR(elf->e_entry); 434 marks[MARK_NSYM] = 1; /* XXX: Kernel needs >= 0 */ 435 marks[MARK_SYM] = LOADADDR(elfp); 436 marks[MARK_END] = LOADADDR(maxp); 437 return 0; 438 } 439 #endif /* BOOT_ELF */ 440 441 #ifdef BOOT_AOUT 442 static int 443 aout_exec(fd, x, marks, flags) 444 int fd; 445 struct exec *x; 446 u_long *marks; 447 int flags; 448 { 449 u_long entry = x->a_entry; 450 paddr_t aoutp = 0; 451 paddr_t minp, maxp; 452 int cc; 453 paddr_t offset = marks[MARK_START]; 454 u_long magic = N_GETMAGIC(*x); 455 int sub; 456 457 /* In OMAGIC and NMAGIC, exec header isn't part of text segment */ 458 if (magic == OMAGIC || magic == NMAGIC) 459 sub = 0; 460 else 461 sub = sizeof(*x); 462 463 minp = maxp = ALIGNENTRY(entry); 464 465 if (lseek(fd, sizeof(*x), SEEK_SET) == -1) { 466 WARN(("lseek text")); 467 return 1; 468 } 469 470 /* 471 * Leave a copy of the exec header before the text. 472 * The kernel may use this to verify that the 473 * symbols were loaded by this boot program. 474 */ 475 if (magic == OMAGIC || magic == NMAGIC) { 476 if (flags & LOAD_HDR && maxp >= sizeof(*x)) 477 BCOPY(x, maxp - sizeof(*x), sizeof(*x)); 478 } 479 else { 480 if (flags & LOAD_HDR) 481 BCOPY(x, maxp, sizeof(*x)); 482 if (flags & (LOAD_HDR|COUNT_HDR)) 483 maxp += sizeof(*x); 484 } 485 486 /* 487 * Read in the text segment. 488 */ 489 if (flags & LOAD_TEXT) { 490 PROGRESS(("%ld", x->a_text)); 491 492 if (READ(fd, maxp, x->a_text - sub) != x->a_text - sub) { 493 WARN(("read text")); 494 return 1; 495 } 496 } else { 497 if (lseek(fd, x->a_text - sub, SEEK_CUR) == -1) { 498 WARN(("seek text")); 499 return 1; 500 } 501 } 502 if (flags & (LOAD_TEXT|COUNT_TEXT)) 503 maxp += x->a_text - sub; 504 505 /* 506 * Provide alignment if required 507 */ 508 if (magic == ZMAGIC || magic == NMAGIC) { 509 int size = -(unsigned int)maxp & (__LDPGSZ - 1); 510 511 if (flags & LOAD_TEXTA) { 512 PROGRESS(("/%d", size)); 513 BZERO(maxp, size); 514 } 515 516 if (flags & (LOAD_TEXTA|COUNT_TEXTA)) 517 maxp += size; 518 } 519 520 /* 521 * Read in the data segment. 522 */ 523 if (flags & LOAD_DATA) { 524 PROGRESS(("+%ld", x->a_data)); 525 526 if (READ(fd, maxp, x->a_data) != x->a_data) { 527 WARN(("read data")); 528 return 1; 529 } 530 } 531 else { 532 if (lseek(fd, x->a_data, SEEK_CUR) == -1) { 533 WARN(("seek data")); 534 return 1; 535 } 536 } 537 if (flags & (LOAD_DATA|COUNT_DATA)) 538 maxp += x->a_data; 539 540 /* 541 * Zero out the BSS section. 542 * (Kernel doesn't care, but do it anyway.) 543 */ 544 if (flags & LOAD_BSS) { 545 PROGRESS(("+%ld", x->a_bss)); 546 547 BZERO(maxp, x->a_bss); 548 } 549 550 if (flags & (LOAD_BSS|COUNT_BSS)) 551 maxp += x->a_bss; 552 553 /* 554 * Read in the symbol table and strings. 555 * (Always set the symtab size word.) 556 */ 557 if (flags & LOAD_SYM) 558 BCOPY(&x->a_syms, maxp, sizeof(x->a_syms)); 559 560 if (flags & (LOAD_SYM|COUNT_SYM)) { 561 maxp += sizeof(x->a_syms); 562 aoutp = maxp; 563 } 564 565 if (x->a_syms > 0) { 566 /* Symbol table and string table length word. */ 567 568 if (flags & LOAD_SYM) { 569 PROGRESS(("+[%ld", x->a_syms)); 570 571 if (READ(fd, maxp, x->a_syms) != x->a_syms) { 572 WARN(("read symbols")); 573 return 1; 574 } 575 } else { 576 if (lseek(fd, x->a_syms, SEEK_CUR) == -1) { 577 WARN(("seek symbols")); 578 return 1; 579 } 580 } 581 if (flags & (LOAD_SYM|COUNT_SYM)) 582 maxp += x->a_syms; 583 584 if (read(fd, &cc, sizeof(cc)) != sizeof(cc)) { 585 WARN(("read string table")); 586 return 1; 587 } 588 589 if (flags & LOAD_SYM) { 590 BCOPY(&cc, maxp, sizeof(cc)); 591 592 /* String table. Length word includes itself. */ 593 594 PROGRESS(("+%d]", cc)); 595 } 596 if (flags & (LOAD_SYM|COUNT_SYM)) 597 maxp += sizeof(cc); 598 599 cc -= sizeof(int); 600 if (cc <= 0) { 601 WARN(("symbol table too short")); 602 return 1; 603 } 604 605 if (flags & LOAD_SYM) { 606 if (READ(fd, maxp, cc) != cc) { 607 WARN(("read strings")); 608 return 1; 609 } 610 } else { 611 if (lseek(fd, cc, SEEK_CUR) == -1) { 612 WARN(("seek strings")); 613 return 1; 614 } 615 } 616 if (flags & (LOAD_SYM|COUNT_SYM)) 617 maxp += cc; 618 } 619 620 marks[MARK_START] = LOADADDR(minp); 621 marks[MARK_ENTRY] = LOADADDR(entry); 622 marks[MARK_NSYM] = x->a_syms; 623 marks[MARK_SYM] = LOADADDR(aoutp); 624 marks[MARK_END] = LOADADDR(maxp); 625 return 0; 626 } 627 #endif /* BOOT_AOUT */ 628