1 /* $OpenBSD: boot.c,v 1.38 2021/10/26 10:45:55 patrick Exp $ */ 2 /* $NetBSD: boot.c,v 1.3 2001/05/31 08:55:19 mrg Exp $ */ 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 #define ELFSIZE 64 47 48 #include <lib/libsa/stand.h> 49 #include <lib/libkern/funcs.h> 50 51 #include <sys/param.h> 52 #include <sys/exec.h> 53 #include <sys/exec_elf.h> 54 #include <sys/reboot.h> 55 #include <sys/disklabel.h> 56 57 #include <machine/cpu.h> 58 #include <lib/libsa/arc4.h> 59 60 #ifdef SOFTRAID 61 #include <sys/param.h> 62 #include <sys/queue.h> 63 #include <dev/biovar.h> 64 #include <dev/softraidvar.h> 65 #include <lib/libsa/softraid.h> 66 67 #include "disk.h" 68 #include "softraid_sparc64.h" 69 #endif 70 71 #include "ofdev.h" 72 #include "openfirm.h" 73 74 #ifdef BOOT_DEBUG 75 uint32_t boot_debug = 0 76 /* | BOOT_D_OFDEV */ 77 /* | BOOT_D_OFNET */ 78 ; 79 #endif 80 81 #define MEG (1024*1024) 82 83 /* 84 * Boot device is derived from ROM provided information, or if there is none, 85 * this list is used in sequence, to find a kernel. 86 */ 87 char *kernels[] = { 88 "bsd", 89 NULL 90 }; 91 92 char bootdev[128]; 93 extern char bootfile[128]; 94 int boothowto; 95 int debug; 96 97 char rnddata[BOOTRANDOM_MAX]; 98 struct rc4_ctx randomctx; 99 100 int elf64_exec(int, Elf64_Ehdr *, u_int64_t *, void **, void **); 101 102 /* 103 * parse: 104 * [kernel-name] [-options] 105 * leave kernel-name in passed-in string 106 * put options into *howtop 107 * return -1 iff syntax error (no - before options) 108 */ 109 110 static int 111 parseargs(char *str, int *howtop) 112 { 113 char *cp; 114 int i; 115 116 *howtop = 0; 117 cp = str; 118 while (*cp == ' ') 119 ++cp; 120 if (*cp != '-') { 121 while (*cp && *cp != ' ') 122 *str++ = *cp++; 123 while (*cp == ' ') 124 ++cp; 125 } 126 /* 127 * Note that, if only options have been passed, without a kernel 128 * name, str == cp and options will be ignored at the boot blocks 129 * level. 130 * This a feature intended to make `boot -a' behave as intended. 131 * If you want the bootblocks to handle arguments explicitly, a 132 * kernel filename needs to be provided (as in `boot bsd -a'). 133 */ 134 *str = 0; 135 switch (*cp) { 136 default: 137 printf("boot options string <%s> must start with -\n", cp); 138 return -1; 139 case 0: 140 return 0; 141 case '-': 142 break; 143 } 144 145 ++cp; 146 while (*cp) { 147 switch (*cp++) { 148 case 'a': 149 *howtop |= RB_ASKNAME; 150 break; 151 case 'd': 152 if (!debug) debug = 1; 153 break; 154 case 'D': 155 debug = 2; 156 break; 157 } 158 } 159 return 0; 160 } 161 162 163 static void 164 chain(u_int64_t pentry, char *args, void *ssym, void *esym) 165 { 166 extern char end[]; 167 void (*entry)(); 168 int l, machine_tag; 169 long newargs[3]; 170 171 entry = (void *)(long)pentry; 172 173 /* 174 * When we come in args consists of a pointer to the boot 175 * string. We need to fix it so it takes into account 176 * other params such as romp. 177 */ 178 179 /* 180 * Stash pointer to end of symbol table after the argument 181 * strings. 182 */ 183 l = strlen(args) + 1; 184 bcopy(&esym, args + l, sizeof(esym)); 185 l += sizeof(esym); 186 187 /* 188 * Tell the kernel we're an OpenFirmware system. 189 */ 190 #define SPARC_MACHINE_OPENFIRMWARE 0x44444230 191 machine_tag = SPARC_MACHINE_OPENFIRMWARE; 192 bcopy(&machine_tag, args + l, sizeof(machine_tag)); 193 l += sizeof(machine_tag); 194 195 /* 196 * Since we don't need the boot string (we can get it from /chosen) 197 * we won't pass it in. Just pass in esym and magic # 198 */ 199 newargs[0] = SPARC_MACHINE_OPENFIRMWARE; 200 newargs[1] = (long)esym; 201 newargs[2] = (long)ssym; 202 args = (char *)newargs; 203 l = sizeof(newargs); 204 205 #ifdef DEBUG 206 printf("chain: calling OF_chain(%x, %x, %x, %x, %x)\n", 207 (void *)RELOC, end - (char *)RELOC, entry, args, l); 208 #endif 209 /* if -D is set then pause in the PROM. */ 210 if (debug > 1) OF_enter(); 211 OF_chain((void *)RELOC, ((end - (char *)RELOC)+PAGE_SIZE)%PAGE_SIZE, 212 entry, args, l); 213 panic("chain"); 214 } 215 216 int 217 loadfile(int fd, char *args) 218 { 219 union { 220 Elf64_Ehdr elf64; 221 } hdr; 222 int rval; 223 u_int64_t entry = 0; 224 void *ssym; 225 void *esym; 226 227 ssym = NULL; 228 esym = NULL; 229 230 /* Load the header. */ 231 #ifdef DEBUG 232 printf("loadfile: reading header\n"); 233 #endif 234 if ((rval = read(fd, &hdr, sizeof(hdr))) != sizeof(hdr)) { 235 if (rval == -1) 236 printf("read header: %s\n", strerror(errno)); 237 else 238 printf("read header: short read (only %d of %d)\n", 239 rval, sizeof(hdr)); 240 rval = 1; 241 goto err; 242 } 243 244 /* Determine file type, load kernel. */ 245 if (bcmp(hdr.elf64.e_ident, ELFMAG, SELFMAG) == 0 && 246 hdr.elf64.e_ident[EI_CLASS] == ELFCLASS64) { 247 printf("Booting %s\n", opened_name); 248 rval = elf64_exec(fd, &hdr.elf64, &entry, &ssym, &esym); 249 } else { 250 rval = 1; 251 printf("unknown executable format\n"); 252 } 253 254 if (rval) 255 goto err; 256 257 printf(" start=0x%lx\n", (unsigned long)entry); 258 259 close(fd); 260 261 #ifdef SOFTRAID 262 if (bootdev_dip) 263 OF_close(bootdev_dip->sr_handle); 264 sr_clear_keys(); 265 #endif 266 chain(entry, args, ssym, esym); 267 /* NOTREACHED */ 268 269 err: 270 close(fd); 271 return (rval); 272 } 273 274 static int 275 upgrade(void) 276 { 277 struct stat sb; 278 279 if (stat("/bsd.upgrade", &sb) < 0) 280 return 0; 281 return 1; 282 } 283 284 int 285 loadrandom(char *path, char *buf, size_t buflen) 286 { 287 struct stat sb; 288 int fd, i, error = 0; 289 290 fd = open(path, O_RDONLY); 291 if (fd == -1) 292 return -1; 293 if (fstat(fd, &sb) == -1) { 294 error = -1; 295 goto done; 296 } 297 if (read(fd, buf, buflen) != buflen) { 298 error = -1; 299 goto done; 300 } 301 if (sb.st_mode & S_ISTXT) { 302 printf("NOTE: random seed is being reused.\n"); 303 error = -1; 304 goto done; 305 } 306 fchmod(fd, sb.st_mode | S_ISTXT); 307 done: 308 close(fd); 309 return (error); 310 } 311 312 #ifdef SOFTRAID 313 /* Set bootdev_dip to the softraid boot volume, if specified. */ 314 static int 315 srbootdev(const char *bootline) 316 { 317 struct sr_boot_volume *bv; 318 int unit; 319 320 bootdev_dip = NULL; 321 322 /* 323 * Look for softraid disks in bootline. 324 * E.g. 'sr0', 'sr0:bsd', or 'sr0a:/bsd' 325 */ 326 if (bootline[0] == 's' && bootline[1] == 'r' && 327 '0' <= bootline[2] && bootline[2] <= '9') { 328 unit = bootline[2] - '0'; 329 330 /* Create a fake diskinfo for this softraid volume. */ 331 SLIST_FOREACH(bv, &sr_volumes, sbv_link) 332 if (bv->sbv_unit == unit) 333 break; 334 if (bv == NULL) { 335 printf("Unknown device: sr%d\n", unit); 336 return ENODEV; 337 } 338 339 if ((bv->sbv_flags & BIOC_SCBOOTABLE) == 0) { 340 printf("device sr%d is not bootable\n", unit); 341 return ENODEV; 342 } 343 344 if (bv->sbv_level == 'C' && bv->sbv_keys == NULL) 345 if (sr_crypto_unlock_volume(bv) != 0) 346 return EPERM; 347 348 if (bv->sbv_diskinfo == NULL) { 349 struct sr_boot_chunk *bc; 350 struct diskinfo *dip, *bc_dip; 351 int sr_handle; 352 353 /* All reads will come from the boot chunk. */ 354 bc = sr_vol_boot_chunk(bv); 355 if (bc == NULL) 356 return ENXIO; 357 bc_dip = (struct diskinfo *)bc->sbc_diskinfo; 358 sr_handle = OF_open(bc_dip->path); 359 if (sr_handle == -1) 360 return EIO; 361 362 dip = alloc(sizeof(struct diskinfo)); 363 bzero(dip, sizeof(*dip)); 364 dip->sr_vol = bv; 365 dip->sr_handle = sr_handle; 366 bv->sbv_diskinfo = dip; 367 } 368 369 /* strategy() and devopen() will use bootdev_dip */ 370 bootdev_dip = bv->sbv_diskinfo; 371 372 /* Attempt to read disklabel. */ 373 bv->sbv_part = 'c'; 374 if (sr_getdisklabel(bv, &bootdev_dip->disklabel)) { 375 OF_close(bootdev_dip->sr_handle); 376 free(bv->sbv_diskinfo, sizeof(struct diskinfo)); 377 bv->sbv_diskinfo = NULL; 378 bootdev_dip = NULL; 379 return ERDLAB; 380 } 381 } 382 383 return 0; 384 } 385 #endif 386 387 int 388 main(void) 389 { 390 extern char version[]; 391 int chosen; 392 char bootline[512]; /* Should check size? */ 393 char *cp; 394 int i, fd; 395 #ifdef SOFTRAID 396 int err; 397 #endif 398 char **bootlp; 399 char *just_bootline[2]; 400 401 printf(">> OpenBSD BOOT %s\n", version); 402 403 /* 404 * Get the boot arguments from Openfirmware 405 */ 406 if ((chosen = OF_finddevice("/chosen")) == -1 || 407 OF_getprop(chosen, "bootpath", bootdev, sizeof bootdev) < 0 || 408 OF_getprop(chosen, "bootargs", bootline, sizeof bootline) < 0) { 409 printf("Invalid Openfirmware environment\n"); 410 exit(); 411 } 412 413 #ifdef SOFTRAID 414 diskprobe(); 415 srprobe(); 416 err = srbootdev(bootline); 417 if (err) { 418 printf("Cannot boot from softraid: %s\n", strerror(err)); 419 _rtt(); 420 } 421 #endif 422 423 /* 424 * case 1: boot net -a 425 * -> getln loop 426 * case 2: boot net kernel [options] 427 * -> boot kernel, getln loop 428 * case 3: boot net [options] 429 * -> iterate boot list, getln loop 430 */ 431 432 bootlp = kernels; 433 if (parseargs(bootline, &boothowto) == -1 || 434 (boothowto & RB_ASKNAME)) { 435 bootlp = 0; 436 } else if (*bootline) { 437 just_bootline[0] = bootline; 438 just_bootline[1] = 0; 439 bootlp = just_bootline; 440 } 441 if (bootlp == kernels && upgrade()) { 442 just_bootline[0] = "/bsd.upgrade"; 443 just_bootline[1] = 0; 444 bootlp = just_bootline; 445 printf("upgrade detected: switching to %s\n", *bootlp); 446 } 447 for (;;) { 448 if (bootlp) { 449 cp = *bootlp++; 450 if (!cp) { 451 printf("\n"); 452 bootlp = 0; 453 kernels[0] = 0; /* no more iteration */ 454 } else if (cp != bootline) { 455 printf("Trying %s...\n", cp); 456 if (strlcpy(bootline, cp, sizeof bootline) 457 >= sizeof bootline) { 458 printf("bootargs too long: %s\n", 459 bootline); 460 _rtt(); 461 } 462 } 463 } 464 if (!bootlp) { 465 printf("Boot: "); 466 getln(bootline, sizeof bootline); 467 if (parseargs(bootline, &boothowto) == -1) 468 continue; 469 if (!*bootline) { 470 bootlp = kernels; 471 continue; 472 } 473 if (strcmp(bootline, "exit") == 0 || 474 strcmp(bootline, "halt") == 0) { 475 _rtt(); 476 } 477 } 478 if (loadrandom(BOOTRANDOM, rnddata, sizeof(rnddata)) == 0) 479 boothowto |= RB_GOODRANDOM; 480 481 rc4_keysetup(&randomctx, rnddata, sizeof rnddata); 482 rc4_skip(&randomctx, 1536); 483 484 if ((fd = open(bootline, O_RDONLY)) < 0) { 485 printf("open %s: %s\n", opened_name, strerror(errno)); 486 continue; 487 } 488 /* XXX void, for now */ 489 #ifdef DEBUG 490 if (debug) 491 printf("main: Calling loadfile(fd, %s)\n", opened_name); 492 #endif 493 (void)loadfile(fd, opened_name); 494 } 495 return 0; 496 } 497