1 /* $NetBSD: boot.c,v 1.10 2005/12/11 12:19:08 christos 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 == ' ') 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 379 #ifdef ELFSIZE 380 #undef ELFSIZE 381 #endif 382 383 #define ELFSIZE 32 384 #include "elfXX_exec.c" 385 386 #undef ELFSIZE 387 #define ELFSIZE 64 388 #include "elfXX_exec.c" 389 390 #endif /* SPARC_BOOT_ELF */ 391 392 void 393 main() 394 { 395 extern char bootprog_name[], bootprog_rev[], 396 bootprog_maker[], bootprog_date[]; 397 int chosen; 398 char bootline[512]; /* Should check size? */ 399 char *cp; 400 int i, fd; 401 402 /* Initialize kernelname */ 403 kernelname = kernels[0]; 404 405 printf("\r>> %s, Revision %s\n", bootprog_name, bootprog_rev); 406 printf(">> (%s, %s)\n", bootprog_maker, bootprog_date); 407 408 /* 409 * Get the boot arguments from Openfirmware 410 */ 411 if ((chosen = OF_finddevice("/chosen")) == -1 412 || OF_getprop(chosen, "bootpath", bootdev, sizeof bootdev) < 0 413 || OF_getprop(chosen, "bootargs", bootline, sizeof bootline) < 0) { 414 printf("Invalid Openfirmware environment\n"); 415 exit(0); 416 } 417 /*prom2boot(bootdev);*/ 418 kernelname = kernels[0]; 419 parseargs(bootline, &boothowto); 420 for (i=0;;) { 421 kernelname = kernels[i]; 422 if (boothowto & RB_ASKNAME) { 423 printf("Boot: "); 424 gets(bootline); 425 parseargs(bootline, &boothowto); 426 } 427 if ((fd = open(bootline, 0)) >= 0) 428 break; 429 if (errno) 430 printf("open %s: %s\n", opened_name, strerror(errno)); 431 /* 432 * if we have are not in askname mode, and we aren't using the 433 * prom bootfile, try the next one (if it exits). otherwise, 434 * go into askname mode. 435 */ 436 if ((boothowto & RB_ASKNAME) == 0 && 437 i != -1 && kernels[i + 1]) { 438 printf(": trying %s...\n", kernels[++i]); 439 } else { 440 printf("\n"); 441 boothowto |= RB_ASKNAME; 442 } 443 } 444 #ifdef __notyet__ 445 OF_setprop(chosen, "bootpath", opened_name, strlen(opened_name) + 1); 446 cp = bootline; 447 #else 448 strcpy(bootline, opened_name); 449 cp = bootline + strlen(bootline); 450 *cp++ = ' '; 451 #endif 452 *cp = '-'; 453 if (boothowto & RB_ASKNAME) 454 *++cp = 'a'; 455 if (boothowto & RB_SINGLE) 456 *++cp = 's'; 457 if (boothowto & RB_KDB) 458 *++cp = 'd'; 459 if (*cp == '-') 460 #ifdef __notyet__ 461 *cp = 0; 462 #else 463 *--cp = 0; 464 #endif 465 else 466 *++cp = 0; 467 #ifdef __notyet__ 468 OF_setprop(chosen, "bootargs", bootline, strlen(bootline) + 1); 469 #endif 470 /* XXX void, for now */ 471 #ifdef DEBUG 472 if (debug) 473 printf("main: Calling loadfile(fd, %s)\n", bootline); 474 #endif 475 (void)loadfile(fd, bootline); 476 477 _rtt(); 478 } 479