1 /* $NetBSD: boot.c,v 1.3 2001/05/31 08:55:19 mrg Exp $ */ 2 #define DEBUG 3 /* 4 * Copyright (c) 1997, 1999 Eduardo E. Horvath. All rights reserved. 5 * Copyright (c) 1997 Jason R. Thorpe. All rights reserved. 6 * Copyright (C) 1995, 1996 Wolfgang Solfrank. 7 * Copyright (C) 1995, 1996 TooLs GmbH. 8 * All rights reserved. 9 * 10 * ELF support derived from NetBSD/alpha's boot loader, written 11 * by Christopher G. Demetriou. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. All advertising materials mentioning features or use of this software 22 * must display the following acknowledgement: 23 * This product includes software developed by TooLs GmbH. 24 * 4. The name of TooLs GmbH may not be used to endorse or promote products 25 * derived from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 28 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 29 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 30 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 31 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 32 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 33 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 34 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 35 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 36 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * First try for the boot code 41 * 42 * Input syntax is: 43 * [promdev[{:|,}partition]]/[filename] [flags] 44 */ 45 46 #ifdef ELFSIZE 47 #undef ELFSIZE /* We use both. */ 48 #endif 49 50 #include <lib/libsa/stand.h> 51 #include <lib/libkern/libkern.h> 52 53 #include <sys/param.h> 54 #include <sys/exec.h> 55 #include <sys/exec_elf.h> 56 #include <sys/reboot.h> 57 #include <sys/disklabel.h> 58 #include <sys/boot_flag.h> 59 60 #include <machine/cpu.h> 61 62 #include "ofdev.h" 63 #include "openfirm.h" 64 65 #define MEG (1024*1024) 66 67 /* 68 * Boot device is derived from ROM provided information, or if there is none, 69 * this list is used in sequence, to find a kernel. 70 */ 71 char *kernels[] = { 72 "netbsd ", 73 "netbsd.gz ", 74 "netbsd.old ", 75 "netbsd.old.gz ", 76 "onetbsd ", 77 "onetbsd.gz ", 78 "vmunix ", 79 #ifdef notyet 80 "netbsd.pl ", 81 "netbsd.pl.gz ", 82 "netbsd.el ", 83 "netbsd.el.gz ", 84 #endif 85 NULL 86 }; 87 88 char *kernelname; 89 char bootdev[128]; 90 char bootfile[128]; 91 int boothowto; 92 int debug; 93 94 95 #ifdef SPARC_BOOT_ELF 96 int elf32_exec __P((int, Elf32_Ehdr *, u_int64_t *, void **, void **)); 97 int elf64_exec __P((int, Elf64_Ehdr *, u_int64_t *, void **, void **)); 98 #endif 99 100 #ifdef SPARC_BOOT_AOUT 101 int aout_exec __P((int, struct exec *, u_int64_t *, void **)); 102 #endif 103 104 #if 0 105 static void 106 prom2boot(dev) 107 char *dev; 108 { 109 char *cp, *lp = 0; 110 int handle; 111 char devtype[16]; 112 113 for (cp = dev; *cp; cp++) 114 if (*cp == ':') 115 lp = cp; 116 if (!lp) 117 lp = cp; 118 *lp = 0; 119 } 120 #endif 121 122 static void 123 parseargs(str, howtop) 124 char *str; 125 int *howtop; 126 { 127 char *cp; 128 int i; 129 130 /* Allow user to drop back to the PROM. */ 131 if (strcmp(str, "exit") == 0 || strcmp(str, "halt") == 0) 132 _rtt(); 133 134 /* Insert the kernel name if it is not there. */ 135 if (str[0] == 0 || str[0] == '-') { 136 /* Move args down the string */ 137 i=0; 138 for (cp = str + strlen(kernelname); str[i]; i++) 139 cp[i] = str[i]; 140 /* Copy over kernelname */ 141 for (i = 0; kernelname[i]; i++) 142 str[i] = kernelname[i]; 143 } 144 *howtop = 0; 145 for (cp = str; *cp; cp++) 146 if (*cp == ' ' || *cp == '-') 147 break; 148 if (!*cp) 149 return; 150 151 *cp++ = 0; 152 while (*cp) { 153 BOOT_FLAG(*cp, *howtop); 154 /* handle specialties */ 155 switch (*cp++) { 156 case 'd': 157 if (!debug) debug = 1; 158 break; 159 case 'D': 160 debug = 2; 161 break; 162 default: 163 break; 164 } 165 } 166 } 167 168 169 static void 170 chain(pentry, args, ssym, esym) 171 u_int64_t pentry; 172 char *args; 173 void *ssym; 174 void *esym; 175 { 176 extern char end[]; 177 void (*entry)(); 178 int l, machine_tag; 179 long newargs[3]; 180 181 entry = (void*)(long)pentry; 182 183 freeall(); 184 /* 185 * When we come in args consists of a pointer to the boot 186 * string. We need to fix it so it takes into account 187 * other params such as romp. 188 */ 189 190 /* 191 * Stash pointer to end of symbol table after the argument 192 * strings. 193 */ 194 l = strlen(args) + 1; 195 bcopy(&esym, args + l, sizeof(esym)); 196 l += sizeof(esym); 197 198 /* 199 * Tell the kernel we're an OpenFirmware system. 200 */ 201 #define SPARC_MACHINE_OPENFIRMWARE 0x44444230 202 machine_tag = SPARC_MACHINE_OPENFIRMWARE; 203 bcopy(&machine_tag, args + l, sizeof(machine_tag)); 204 l += sizeof(machine_tag); 205 206 /* 207 * Since we don't need the boot string (we can get it from /chosen) 208 * we won't pass it in. Just pass in esym and magic # 209 */ 210 newargs[0] = SPARC_MACHINE_OPENFIRMWARE; 211 newargs[1] = (long)esym; 212 newargs[2] = (long)ssym; 213 args = (char *)newargs; 214 l = sizeof(newargs); 215 216 #ifdef DEBUG 217 printf("chain: calling OF_chain(%x, %x, %x, %x, %x)\n", 218 (void *)RELOC, end - (char *)RELOC, entry, args, l); 219 #endif 220 /* if -D is set then pause in the PROM. */ 221 if (debug > 1) OF_enter(); 222 OF_chain((void *)RELOC, ((end - (char *)RELOC)+NBPG)%NBPG, entry, args, l); 223 panic("chain"); 224 } 225 226 int 227 loadfile(fd, args) 228 int fd; 229 char *args; 230 { 231 union { 232 #ifdef SPARC_BOOT_AOUT 233 struct exec aout; 234 #endif 235 #ifdef SPARC_BOOT_ELF 236 Elf32_Ehdr elf32; 237 Elf64_Ehdr elf64; 238 #endif 239 } hdr; 240 int rval; 241 u_int64_t entry = 0; 242 void *ssym; 243 void *esym; 244 245 rval = 1; 246 ssym = NULL; 247 esym = NULL; 248 249 /* Load the header. */ 250 #ifdef DEBUG 251 printf("loadfile: reading header\n"); 252 #endif 253 if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) { 254 printf("read header: %s\n", strerror(errno)); 255 goto err; 256 } 257 258 /* Determine file type, load kernel. */ 259 #ifdef SPARC_BOOT_AOUT 260 if (N_BADMAG(hdr.aout) == 0 && N_GETMID(hdr.aout) == MID_SPARC) { 261 rval = aout_exec(fd, &hdr.aout, &entry, &esym); 262 } else 263 #endif 264 #ifdef SPARC_BOOT_ELF 265 if (bcmp(hdr.elf32.e_ident, ELFMAG, SELFMAG) == 0 && 266 hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) { 267 rval = elf32_exec(fd, &hdr.elf32, &entry, &ssym, &esym); 268 } else 269 if (bcmp(hdr.elf64.e_ident, ELFMAG, SELFMAG) == 0 && 270 hdr.elf64.e_ident[EI_CLASS] == ELFCLASS64) { 271 rval = elf64_exec(fd, &hdr.elf64, &entry, &ssym, &esym); 272 } else 273 #endif 274 { 275 printf("unknown executable format\n"); 276 } 277 278 if (rval) 279 goto err; 280 281 printf(" start=0x%lx\n", (unsigned long)entry); 282 283 close(fd); 284 285 /* XXX this should be replaced w/ a mountroothook. */ 286 if (floppyboot) { 287 printf("Please insert root disk and press ENTER "); 288 getchar(); 289 printf("\n"); 290 } 291 292 chain(entry, args, ssym, esym); 293 /* NOTREACHED */ 294 295 err: 296 close(fd); 297 return (rval); 298 } 299 300 #ifdef SPARC_BOOT_AOUT 301 int 302 aout_exec(fd, hdr, entryp, esymp) 303 int fd; 304 struct exec *hdr; 305 u_int64_t *entryp; 306 void **esymp; 307 { 308 void *addr; 309 int n, *paddr; 310 311 #ifdef DEBUG 312 printf("auout_exec: "); 313 #endif 314 /* Display the load address (entry point) for a.out. */ 315 printf("Booting %s @ 0x%lx\n", opened_name, hdr->a_entry); 316 addr = (void *)(hdr->a_entry); 317 318 /* 319 * Determine memory needed for kernel and allocate it from 320 * the firmware. 321 */ 322 n = hdr->a_text + hdr->a_data + hdr->a_bss + hdr->a_syms + sizeof(int); 323 if ((paddr = OF_claim(addr, n, 0)) == (int *)-1) 324 panic("cannot claim memory"); 325 326 /* Load text. */ 327 lseek(fd, N_TXTOFF(*hdr), SEEK_SET); 328 printf("%lu", hdr->a_text); 329 if (read(fd, paddr, hdr->a_text) != hdr->a_text) { 330 printf("read text: %s\n", strerror(errno)); 331 return (1); 332 } 333 syncicache((void *)paddr, hdr->a_text); 334 335 /* Load data. */ 336 printf("+%lu", hdr->a_data); 337 if (read(fd, (void *)paddr + hdr->a_text, hdr->a_data) != hdr->a_data) { 338 printf("read data: %s\n", strerror(errno)); 339 return (1); 340 } 341 342 /* Zero BSS. */ 343 printf("+%lu", hdr->a_bss); 344 bzero((void *)paddr + hdr->a_text + hdr->a_data, hdr->a_bss); 345 346 /* Symbols. */ 347 *esymp = paddr; 348 paddr = (int *)((void *)paddr + hdr->a_text + hdr->a_data + hdr->a_bss); 349 *paddr++ = hdr->a_syms; 350 if (hdr->a_syms) { 351 printf(" [%lu", hdr->a_syms); 352 if (read(fd, paddr, hdr->a_syms) != hdr->a_syms) { 353 printf("read symbols: %s\n", strerror(errno)); 354 return (1); 355 } 356 paddr = (int *)((void *)paddr + hdr->a_syms); 357 if (read(fd, &n, sizeof(int)) != sizeof(int)) { 358 printf("read symbols: %s\n", strerror(errno)); 359 return (1); 360 } 361 if (OF_claim((void *)paddr, n + sizeof(int), 0) == (void *)-1) 362 panic("cannot claim memory"); 363 *paddr++ = n; 364 if (read(fd, paddr, n - sizeof(int)) != n - sizeof(int)) { 365 printf("read symbols: %s\n", strerror(errno)); 366 return (1); 367 } 368 printf("+%d]", n - sizeof(int)); 369 *esymp = paddr + (n - sizeof(int)); 370 } 371 372 *entryp = hdr->a_entry; 373 return (0); 374 } 375 #endif /* SPARC_BOOT_AOUT */ 376 377 #ifdef SPARC_BOOT_ELF 378 #if 1 379 /* New style */ 380 381 #ifdef ELFSIZE 382 #undef ELFSIZE 383 #endif 384 385 #define ELFSIZE 32 386 #include "elfXX_exec.c" 387 388 #undef ELFSIZE 389 #define ELFSIZE 64 390 #include "elfXX_exec.c" 391 392 #else 393 /* Old style */ 394 int 395 elf32_exec(fd, elf, entryp, ssymp, esymp) 396 int fd; 397 Elf32_Ehdr *elf; 398 u_int64_t *entryp; 399 void **ssymp; 400 void **esymp; 401 { 402 Elf32_Shdr *shp; 403 Elf32_Off off; 404 void *addr; 405 size_t size; 406 int i, first = 1; 407 long align; 408 int n; 409 410 /* 411 * Don't display load address for ELF; it's encoded in 412 * each section. 413 */ 414 #ifdef DEBUG 415 printf("elf_exec: "); 416 #endif 417 printf("Booting %s\n", opened_name); 418 419 for (i = 0; i < elf->e_phnum; i++) { 420 Elf32_Phdr phdr; 421 (void)lseek(fd, elf->e_phoff + sizeof(phdr) * i, SEEK_SET); 422 if (read(fd, (void *)&phdr, sizeof(phdr)) != sizeof(phdr)) { 423 printf("read phdr: %s\n", strerror(errno)); 424 return (1); 425 } 426 if (phdr.p_type != PT_LOAD || 427 (phdr.p_flags & (PF_W|PF_X)) == 0) 428 continue; 429 430 /* Read in segment. */ 431 printf("%s%lu@0x%lx", first ? "" : "+", phdr.p_filesz, 432 (u_long)phdr.p_vaddr); 433 (void)lseek(fd, phdr.p_offset, SEEK_SET); 434 435 /* 436 * If the segment's VA is aligned on a 4MB boundary, align its 437 * request 4MB aligned physical memory. Otherwise use default 438 * alignment. 439 */ 440 align = phdr.p_align; 441 if ((phdr.p_vaddr & (4*MEG-1)) == 0) 442 align = 4*MEG; 443 if (OF_claim((void *)phdr.p_vaddr, phdr.p_memsz, phdr.p_align) == 444 (void *)-1) 445 panic("cannot claim memory"); 446 if (read(fd, (void *)phdr.p_vaddr, phdr.p_filesz) != 447 phdr.p_filesz) { 448 printf("read segment: %s\n", strerror(errno)); 449 return (1); 450 } 451 syncicache((void *)phdr.p_vaddr, phdr.p_filesz); 452 453 /* Zero BSS. */ 454 if (phdr.p_filesz < phdr.p_memsz) { 455 printf("+%lu@0x%lx", phdr.p_memsz - phdr.p_filesz, 456 (u_long)(phdr.p_vaddr + phdr.p_filesz)); 457 bzero((void*)phdr.p_vaddr + phdr.p_filesz, 458 phdr.p_memsz - phdr.p_filesz); 459 } 460 first = 0; 461 } 462 463 printf(" \n"); 464 465 #if 1 /* I want to rethink this... --thorpej@netbsd.org */ 466 /* 467 * Compute the size of the symbol table. 468 */ 469 size = sizeof(Elf32_Ehdr) + (elf->e_shnum * sizeof(Elf32_Shdr)); 470 shp = addr = alloc(elf->e_shnum * sizeof(Elf32_Shdr)); 471 (void)lseek(fd, elf->e_shoff, SEEK_SET); 472 if (read(fd, addr, elf->e_shnum * sizeof(Elf32_Shdr)) != 473 elf->e_shnum * sizeof(Elf32_Shdr)) { 474 printf("read section headers: %s\n", strerror(errno)); 475 return (1); 476 } 477 for (i = 0; i < elf->e_shnum; i++, shp++) { 478 if (shp->sh_type == SHT_NULL) 479 continue; 480 if (shp->sh_type != SHT_SYMTAB 481 && shp->sh_type != SHT_STRTAB) { 482 shp->sh_offset = 0; 483 shp->sh_type = SHT_NOBITS; 484 continue; 485 } 486 size += shp->sh_size; 487 } 488 shp = addr; 489 490 /* 491 * Reserve memory for the symbols. 492 */ 493 if ((addr = OF_claim(0, size, NBPG)) == (void *)-1) 494 panic("no space for symbol table"); 495 496 /* 497 * Copy the headers. 498 */ 499 elf->e_phoff = 0; 500 elf->e_shoff = sizeof(Elf32_Ehdr); 501 elf->e_phentsize = 0; 502 elf->e_phnum = 0; 503 bcopy(elf, addr, sizeof(Elf32_Ehdr)); 504 bcopy(shp, addr + sizeof(Elf32_Ehdr), elf->e_shnum * sizeof(Elf32_Shdr)); 505 free(shp, elf->e_shnum * sizeof(Elf32_Shdr)); 506 *ssymp = addr; 507 508 /* 509 * Now load the symbol sections themselves. 510 */ 511 shp = addr + sizeof(Elf32_Ehdr); 512 addr += sizeof(Elf32_Ehdr) + (elf->e_shnum * sizeof(Elf32_Shdr)); 513 off = sizeof(Elf32_Ehdr) + (elf->e_shnum * sizeof(Elf32_Shdr)); 514 for (first = 1, i = 0; i < elf->e_shnum; i++, shp++) { 515 if (shp->sh_type == SHT_SYMTAB 516 || shp->sh_type == SHT_STRTAB) { 517 if (first) 518 printf("symbols @ 0x%lx ", (u_long)addr); 519 printf("%s%d", first ? "" : "+", shp->sh_size); 520 (void)lseek(fd, shp->sh_offset, SEEK_SET); 521 if (read(fd, addr, shp->sh_size) != shp->sh_size) { 522 printf("read symbols: %s\n", strerror(errno)); 523 return (1); 524 } 525 addr += (shp->sh_size+3)&(~3); 526 shp->sh_offset = off; 527 off += (shp->sh_size+3)&(~3); 528 first = 0; 529 } 530 } 531 *esymp = addr; 532 #endif /* 0 */ 533 534 *entryp = elf->e_entry; 535 return (0); 536 } 537 #endif 538 #endif /* SPARC_BOOT_ELF */ 539 540 void 541 main() 542 { 543 extern char bootprog_name[], bootprog_rev[], 544 bootprog_maker[], bootprog_date[]; 545 int chosen; 546 char bootline[512]; /* Should check size? */ 547 char *cp; 548 int i, fd; 549 550 /* Initialize kernelname */ 551 kernelname = kernels[0]; 552 553 printf(">> %s, Revision %s\n", bootprog_name, bootprog_rev); 554 printf(">> (%s, %s)\n", bootprog_maker, bootprog_date); 555 556 /* 557 * Get the boot arguments from Openfirmware 558 */ 559 if ((chosen = OF_finddevice("/chosen")) == -1 560 || OF_getprop(chosen, "bootpath", bootdev, sizeof bootdev) < 0 561 || OF_getprop(chosen, "bootargs", bootline, sizeof bootline) < 0) { 562 printf("Invalid Openfirmware environment\n"); 563 exit(); 564 } 565 /*prom2boot(bootdev);*/ 566 kernelname = kernels[0]; 567 parseargs(bootline, &boothowto); 568 for (i=0;;) { 569 kernelname = kernels[i]; 570 if (boothowto & RB_ASKNAME) { 571 printf("Boot: "); 572 gets(bootline); 573 parseargs(bootline, &boothowto); 574 } 575 if ((fd = open(bootline, 0)) >= 0) 576 break; 577 if (errno) 578 printf("open %s: %s\n", opened_name, strerror(errno)); 579 /* 580 * if we have are not in askname mode, and we aren't using the 581 * prom bootfile, try the next one (if it exits). otherwise, 582 * go into askname mode. 583 */ 584 if ((boothowto & RB_ASKNAME) == 0 && 585 i != -1 && kernels[++i]) { 586 printf(": trying %s...\n", kernels[i]); 587 } else { 588 printf("\n"); 589 boothowto |= RB_ASKNAME; 590 } 591 } 592 #ifdef __notyet__ 593 OF_setprop(chosen, "bootpath", opened_name, strlen(opened_name) + 1); 594 cp = bootline; 595 #else 596 strcpy(bootline, opened_name); 597 cp = bootline + strlen(bootline); 598 *cp++ = ' '; 599 #endif 600 *cp = '-'; 601 if (boothowto & RB_ASKNAME) 602 *++cp = 'a'; 603 if (boothowto & RB_SINGLE) 604 *++cp = 's'; 605 if (boothowto & RB_KDB) 606 *++cp = 'd'; 607 if (*cp == '-') 608 #ifdef __notyet__ 609 *cp = 0; 610 #else 611 *--cp = 0; 612 #endif 613 else 614 *++cp = 0; 615 #ifdef __notyet__ 616 OF_setprop(chosen, "bootargs", bootline, strlen(bootline) + 1); 617 #endif 618 /* XXX void, for now */ 619 #ifdef DEBUG 620 if (debug) 621 printf("main: Calling loadfile(fd, %s)\n", bootline); 622 #endif 623 (void)loadfile(fd, bootline); 624 625 _rtt(); 626 } 627