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