1 /*- 2 * Copyright (c) 1998 Robert Nordier 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are freely 6 * permitted provided that the above copyright notice and this 7 * paragraph and the following disclaimer are duplicated in all 8 * such forms. 9 * 10 * This software is provided "AS IS" and without any express or 11 * implied warranties, including, without limitation, the implied 12 * warranties of merchantability and fitness for a particular 13 * purpose. 14 */ 15 16 #include <sys/cdefs.h> 17 __FBSDID("$FreeBSD$"); 18 19 #include <sys/param.h> 20 #include <sys/gpt.h> 21 #include <sys/dirent.h> 22 #include <sys/reboot.h> 23 24 #include <machine/bootinfo.h> 25 #include <machine/elf.h> 26 #include <machine/pc/bios.h> 27 #include <machine/psl.h> 28 29 #include <stdarg.h> 30 31 #include <a.out.h> 32 33 #include <btxv86.h> 34 35 #include "bootargs.h" 36 #include "lib.h" 37 #include "rbx.h" 38 #include "drv.h" 39 #include "util.h" 40 #include "cons.h" 41 #include "gpt.h" 42 #include "paths.h" 43 44 #define ARGS 0x900 45 #define NOPT 14 46 #define NDEV 3 47 #define MEM_BASE 0x12 48 #define MEM_EXT 0x15 49 50 #define DRV_HARD 0x80 51 #define DRV_MASK 0x7f 52 53 #define TYPE_AD 0 54 #define TYPE_DA 1 55 #define TYPE_MAXHARD TYPE_DA 56 #define TYPE_FD 2 57 58 extern uint32_t _end; 59 60 static const uuid_t freebsd_ufs_uuid = GPT_ENT_TYPE_FREEBSD_UFS; 61 static const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */ 62 static const unsigned char flags[NOPT] = { 63 RBX_DUAL, 64 RBX_SERIAL, 65 RBX_ASKNAME, 66 RBX_CDROM, 67 RBX_CONFIG, 68 RBX_KDB, 69 RBX_GDB, 70 RBX_MUTE, 71 RBX_NOINTR, 72 RBX_PAUSE, 73 RBX_QUIET, 74 RBX_DFLTROOT, 75 RBX_SINGLE, 76 RBX_VERBOSE 77 }; 78 uint32_t opts; 79 80 static const char *const dev_nm[NDEV] = {"ad", "da", "fd"}; 81 static const unsigned char dev_maj[NDEV] = {30, 4, 2}; 82 83 static struct dsk dsk; 84 static char kname[1024]; 85 static int comspeed = SIOSPD; 86 static struct bootinfo bootinfo; 87 #ifdef LOADER_GELI_SUPPORT 88 static struct geli_boot_args geliargs; 89 #endif 90 91 static vm_offset_t high_heap_base; 92 static uint32_t bios_basemem, bios_extmem, high_heap_size; 93 94 static struct bios_smap smap; 95 96 /* 97 * The minimum amount of memory to reserve in bios_extmem for the heap. 98 */ 99 #define HEAP_MIN (3 * 1024 * 1024) 100 101 static char *heap_next; 102 static char *heap_end; 103 104 void exit(int); 105 static void load(void); 106 static int parse_cmds(char *, int *); 107 static int dskread(void *, daddr_t, unsigned); 108 void *malloc(size_t n); 109 void free(void *ptr); 110 #ifdef LOADER_GELI_SUPPORT 111 static int vdev_read(void *vdev __unused, void *priv, off_t off, void *buf, 112 size_t bytes); 113 #endif 114 115 void * 116 malloc(size_t n) 117 { 118 char *p = heap_next; 119 if (p + n > heap_end) { 120 printf("malloc failure\n"); 121 for (;;) 122 ; 123 /* NOTREACHED */ 124 return (0); 125 } 126 heap_next += n; 127 return (p); 128 } 129 130 void 131 free(void *ptr) 132 { 133 134 return; 135 } 136 137 #include "ufsread.c" 138 #include "gpt.c" 139 #ifdef LOADER_GELI_SUPPORT 140 #include "geliboot.c" 141 static char gelipw[GELI_PW_MAXLEN]; 142 static struct keybuf *gelibuf; 143 #endif 144 145 static inline int 146 xfsread(ufs_ino_t inode, void *buf, size_t nbyte) 147 { 148 149 if ((size_t)fsread(inode, buf, nbyte) != nbyte) { 150 printf("Invalid %s\n", "format"); 151 return (-1); 152 } 153 return (0); 154 } 155 156 static void 157 bios_getmem(void) 158 { 159 uint64_t size; 160 161 /* Parse system memory map */ 162 v86.ebx = 0; 163 do { 164 v86.ctl = V86_FLAGS; 165 v86.addr = MEM_EXT; /* int 0x15 function 0xe820*/ 166 v86.eax = 0xe820; 167 v86.ecx = sizeof(struct bios_smap); 168 v86.edx = SMAP_SIG; 169 v86.es = VTOPSEG(&smap); 170 v86.edi = VTOPOFF(&smap); 171 v86int(); 172 if ((v86.efl & 1) || (v86.eax != SMAP_SIG)) 173 break; 174 /* look for a low-memory segment that's large enough */ 175 if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0) && 176 (smap.length >= (512 * 1024))) 177 bios_basemem = smap.length; 178 /* look for the first segment in 'extended' memory */ 179 if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0x100000)) { 180 bios_extmem = smap.length; 181 } 182 183 /* 184 * Look for the largest segment in 'extended' memory beyond 185 * 1MB but below 4GB. 186 */ 187 if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base > 0x100000) && 188 (smap.base < 0x100000000ull)) { 189 size = smap.length; 190 191 /* 192 * If this segment crosses the 4GB boundary, truncate it. 193 */ 194 if (smap.base + size > 0x100000000ull) 195 size = 0x100000000ull - smap.base; 196 197 if (size > high_heap_size) { 198 high_heap_size = size; 199 high_heap_base = smap.base; 200 } 201 } 202 } while (v86.ebx != 0); 203 204 /* Fall back to the old compatibility function for base memory */ 205 if (bios_basemem == 0) { 206 v86.ctl = 0; 207 v86.addr = 0x12; /* int 0x12 */ 208 v86int(); 209 210 bios_basemem = (v86.eax & 0xffff) * 1024; 211 } 212 213 /* Fall back through several compatibility functions for extended memory */ 214 if (bios_extmem == 0) { 215 v86.ctl = V86_FLAGS; 216 v86.addr = 0x15; /* int 0x15 function 0xe801*/ 217 v86.eax = 0xe801; 218 v86int(); 219 if (!(v86.efl & 1)) { 220 bios_extmem = ((v86.ecx & 0xffff) + ((v86.edx & 0xffff) * 64)) * 1024; 221 } 222 } 223 if (bios_extmem == 0) { 224 v86.ctl = 0; 225 v86.addr = 0x15; /* int 0x15 function 0x88*/ 226 v86.eax = 0x8800; 227 v86int(); 228 bios_extmem = (v86.eax & 0xffff) * 1024; 229 } 230 231 /* 232 * If we have extended memory and did not find a suitable heap 233 * region in the SMAP, use the last 3MB of 'extended' memory as a 234 * high heap candidate. 235 */ 236 if (bios_extmem >= HEAP_MIN && high_heap_size < HEAP_MIN) { 237 high_heap_size = HEAP_MIN; 238 high_heap_base = bios_extmem + 0x100000 - HEAP_MIN; 239 } 240 } 241 242 static int 243 gptinit(void) 244 { 245 246 if (gptread(&freebsd_ufs_uuid, &dsk, dmadat->secbuf) == -1) { 247 printf("%s: unable to load GPT\n", BOOTPROG); 248 return (-1); 249 } 250 if (gptfind(&freebsd_ufs_uuid, &dsk, dsk.part) == -1) { 251 printf("%s: no UFS partition was found\n", BOOTPROG); 252 return (-1); 253 } 254 #ifdef LOADER_GELI_SUPPORT 255 if (geli_taste(vdev_read, &dsk, (gpttable[curent].ent_lba_end - 256 gpttable[curent].ent_lba_start)) == 0) { 257 if (geli_havekey(&dsk) != 0 && geli_passphrase(&gelipw, 258 dsk.unit, 'p', curent + 1, &dsk) != 0) { 259 printf("%s: unable to decrypt GELI key\n", BOOTPROG); 260 return (-1); 261 } 262 } 263 #endif 264 265 dsk_meta = 0; 266 return (0); 267 } 268 269 int 270 main(void) 271 { 272 char cmd[512], cmdtmp[512]; 273 ssize_t sz; 274 int autoboot, dskupdated; 275 ufs_ino_t ino; 276 277 dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base); 278 279 bios_getmem(); 280 281 if (high_heap_size > 0) { 282 heap_end = PTOV(high_heap_base + high_heap_size); 283 heap_next = PTOV(high_heap_base); 284 } else { 285 heap_next = (char *)dmadat + sizeof(*dmadat); 286 heap_end = (char *)PTOV(bios_basemem); 287 } 288 289 v86.ctl = V86_FLAGS; 290 v86.efl = PSL_RESERVED_DEFAULT | PSL_I; 291 dsk.drive = *(uint8_t *)PTOV(ARGS); 292 dsk.type = dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD; 293 dsk.unit = dsk.drive & DRV_MASK; 294 dsk.part = -1; 295 dsk.start = 0; 296 bootinfo.bi_version = BOOTINFO_VERSION; 297 bootinfo.bi_size = sizeof(bootinfo); 298 bootinfo.bi_basemem = bios_basemem / 1024; 299 bootinfo.bi_extmem = bios_extmem / 1024; 300 bootinfo.bi_memsizes_valid++; 301 bootinfo.bi_bios_dev = dsk.drive; 302 303 #ifdef LOADER_GELI_SUPPORT 304 geli_init(); 305 #endif 306 /* Process configuration file */ 307 308 if (gptinit() != 0) 309 return (-1); 310 311 autoboot = 1; 312 *cmd = '\0'; 313 314 for (;;) { 315 *kname = '\0'; 316 if ((ino = lookup(PATH_CONFIG)) || 317 (ino = lookup(PATH_DOTCONFIG))) { 318 sz = fsread(ino, cmd, sizeof(cmd) - 1); 319 cmd[(sz < 0) ? 0 : sz] = '\0'; 320 } 321 if (*cmd != '\0') { 322 memcpy(cmdtmp, cmd, sizeof(cmdtmp)); 323 if (parse_cmds(cmdtmp, &dskupdated)) 324 break; 325 if (dskupdated && gptinit() != 0) 326 break; 327 if (!OPT_CHECK(RBX_QUIET)) 328 printf("%s: %s", PATH_CONFIG, cmd); 329 *cmd = '\0'; 330 } 331 332 if (autoboot && keyhit(3)) { 333 if (*kname == '\0') 334 memcpy(kname, PATH_LOADER, sizeof(PATH_LOADER)); 335 break; 336 } 337 autoboot = 0; 338 339 /* 340 * Try to exec stage 3 boot loader. If interrupted by a 341 * keypress, or in case of failure, try to load a kernel 342 * directly instead. 343 */ 344 if (*kname != '\0') 345 load(); 346 memcpy(kname, PATH_LOADER, sizeof(PATH_LOADER)); 347 load(); 348 memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL)); 349 load(); 350 gptbootfailed(&dsk); 351 if (gptfind(&freebsd_ufs_uuid, &dsk, -1) == -1) 352 break; 353 dsk_meta = 0; 354 } 355 356 /* Present the user with the boot2 prompt. */ 357 358 for (;;) { 359 if (!OPT_CHECK(RBX_QUIET)) { 360 printf("\nFreeBSD/x86 boot\n" 361 "Default: %u:%s(%up%u)%s\n" 362 "boot: ", 363 dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit, 364 dsk.part, kname); 365 } 366 if (ioctrl & IO_SERIAL) 367 sio_flush(); 368 *cmd = '\0'; 369 if (keyhit(0)) 370 getstr(cmd, sizeof(cmd)); 371 else if (!OPT_CHECK(RBX_QUIET)) 372 putchar('\n'); 373 if (parse_cmds(cmd, &dskupdated)) { 374 putchar('\a'); 375 continue; 376 } 377 if (dskupdated && gptinit() != 0) 378 continue; 379 load(); 380 } 381 /* NOTREACHED */ 382 } 383 384 /* XXX - Needed for btxld to link the boot2 binary; do not remove. */ 385 void 386 exit(int x) 387 { 388 } 389 390 static void 391 load(void) 392 { 393 union { 394 struct exec ex; 395 Elf32_Ehdr eh; 396 } hdr; 397 static Elf32_Phdr ep[2]; 398 static Elf32_Shdr es[2]; 399 caddr_t p; 400 ufs_ino_t ino; 401 uint32_t addr, x; 402 int fmt, i, j; 403 404 if (!(ino = lookup(kname))) { 405 if (!ls) { 406 printf("%s: No %s on %u:%s(%up%u)\n", BOOTPROG, 407 kname, dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit, 408 dsk.part); 409 } 410 return; 411 } 412 if (xfsread(ino, &hdr, sizeof(hdr))) 413 return; 414 if (N_GETMAGIC(hdr.ex) == ZMAGIC) 415 fmt = 0; 416 else if (IS_ELF(hdr.eh)) 417 fmt = 1; 418 else { 419 printf("Invalid %s\n", "format"); 420 return; 421 } 422 if (fmt == 0) { 423 addr = hdr.ex.a_entry & 0xffffff; 424 p = PTOV(addr); 425 fs_off = PAGE_SIZE; 426 if (xfsread(ino, p, hdr.ex.a_text)) 427 return; 428 p += roundup2(hdr.ex.a_text, PAGE_SIZE); 429 if (xfsread(ino, p, hdr.ex.a_data)) 430 return; 431 p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE); 432 bootinfo.bi_symtab = VTOP(p); 433 memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms)); 434 p += sizeof(hdr.ex.a_syms); 435 if (hdr.ex.a_syms) { 436 if (xfsread(ino, p, hdr.ex.a_syms)) 437 return; 438 p += hdr.ex.a_syms; 439 if (xfsread(ino, p, sizeof(int))) 440 return; 441 x = *(uint32_t *)p; 442 p += sizeof(int); 443 x -= sizeof(int); 444 if (xfsread(ino, p, x)) 445 return; 446 p += x; 447 } 448 } else { 449 fs_off = hdr.eh.e_phoff; 450 for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) { 451 if (xfsread(ino, ep + j, sizeof(ep[0]))) 452 return; 453 if (ep[j].p_type == PT_LOAD) 454 j++; 455 } 456 for (i = 0; i < 2; i++) { 457 p = PTOV(ep[i].p_paddr & 0xffffff); 458 fs_off = ep[i].p_offset; 459 if (xfsread(ino, p, ep[i].p_filesz)) 460 return; 461 } 462 p += roundup2(ep[1].p_memsz, PAGE_SIZE); 463 bootinfo.bi_symtab = VTOP(p); 464 if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { 465 fs_off = hdr.eh.e_shoff + sizeof(es[0]) * 466 (hdr.eh.e_shstrndx + 1); 467 if (xfsread(ino, &es, sizeof(es))) 468 return; 469 for (i = 0; i < 2; i++) { 470 memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size)); 471 p += sizeof(es[i].sh_size); 472 fs_off = es[i].sh_offset; 473 if (xfsread(ino, p, es[i].sh_size)) 474 return; 475 p += es[i].sh_size; 476 } 477 } 478 addr = hdr.eh.e_entry & 0xffffff; 479 } 480 bootinfo.bi_esymtab = VTOP(p); 481 bootinfo.bi_kernelname = VTOP(kname); 482 bootinfo.bi_bios_dev = dsk.drive; 483 #ifdef LOADER_GELI_SUPPORT 484 geliargs.size = sizeof(geliargs); 485 explicit_bzero(gelipw, sizeof(gelipw)); 486 gelibuf = malloc(sizeof(struct keybuf) + (GELI_MAX_KEYS * sizeof(struct keybuf_ent))); 487 geli_fill_keybuf(gelibuf); 488 geliargs.notapw = '\0'; 489 geliargs.keybuf_sentinel = KEYBUF_SENTINEL; 490 geliargs.keybuf = gelibuf; 491 #endif 492 __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), 493 MAKEBOOTDEV(dev_maj[dsk.type], dsk.part + 1, dsk.unit, 0xff), 494 KARGS_FLAGS_EXTARG, 0, 0, VTOP(&bootinfo) 495 #ifdef LOADER_GELI_SUPPORT 496 , geliargs 497 #endif 498 ); 499 } 500 501 static int 502 parse_cmds(char *cmdstr, int *dskupdated) 503 { 504 char *arg = cmdstr; 505 char *ep, *p, *q; 506 const char *cp; 507 unsigned int drv; 508 int c, i, j; 509 510 *dskupdated = 0; 511 while ((c = *arg++)) { 512 if (c == ' ' || c == '\t' || c == '\n') 513 continue; 514 for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++); 515 ep = p; 516 if (*p) 517 *p++ = 0; 518 if (c == '-') { 519 while ((c = *arg++)) { 520 if (c == 'P') { 521 if (*(uint8_t *)PTOV(0x496) & 0x10) { 522 cp = "yes"; 523 } else { 524 opts |= OPT_SET(RBX_DUAL) | OPT_SET(RBX_SERIAL); 525 cp = "no"; 526 } 527 printf("Keyboard: %s\n", cp); 528 continue; 529 } else if (c == 'S') { 530 j = 0; 531 while ((unsigned int)(i = *arg++ - '0') <= 9) 532 j = j * 10 + i; 533 if (j > 0 && i == -'0') { 534 comspeed = j; 535 break; 536 } 537 /* Fall through to error below ('S' not in optstr[]). */ 538 } 539 for (i = 0; c != optstr[i]; i++) 540 if (i == NOPT - 1) 541 return -1; 542 opts ^= OPT_SET(flags[i]); 543 } 544 ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) : 545 OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD; 546 if (ioctrl & IO_SERIAL) { 547 if (sio_init(115200 / comspeed) != 0) 548 ioctrl &= ~IO_SERIAL; 549 } 550 } else { 551 for (q = arg--; *q && *q != '('; q++); 552 if (*q) { 553 drv = -1; 554 if (arg[1] == ':') { 555 drv = *arg - '0'; 556 if (drv > 9) 557 return (-1); 558 arg += 2; 559 } 560 if (q - arg != 2) 561 return -1; 562 for (i = 0; arg[0] != dev_nm[i][0] || 563 arg[1] != dev_nm[i][1]; i++) 564 if (i == NDEV - 1) 565 return -1; 566 dsk.type = i; 567 arg += 3; 568 dsk.unit = *arg - '0'; 569 if (arg[1] != 'p' || dsk.unit > 9) 570 return -1; 571 arg += 2; 572 dsk.part = *arg - '0'; 573 if (dsk.part < 1 || dsk.part > 9) 574 return -1; 575 arg++; 576 if (arg[0] != ')') 577 return -1; 578 arg++; 579 if (drv == -1) 580 drv = dsk.unit; 581 dsk.drive = (dsk.type <= TYPE_MAXHARD 582 ? DRV_HARD : 0) + drv; 583 *dskupdated = 1; 584 } 585 if ((i = ep - arg)) { 586 if ((size_t)i >= sizeof(kname)) 587 return -1; 588 memcpy(kname, arg, i + 1); 589 } 590 } 591 arg = p; 592 } 593 return 0; 594 } 595 596 static int 597 dskread(void *buf, daddr_t lba, unsigned nblk) 598 { 599 int err; 600 601 err = drvread(&dsk, buf, lba + dsk.start, nblk); 602 603 #ifdef LOADER_GELI_SUPPORT 604 if (err == 0 && is_geli(&dsk) == 0) { 605 /* Decrypt */ 606 if (geli_read(&dsk, lba * DEV_BSIZE, buf, nblk * DEV_BSIZE)) 607 return (err); 608 } 609 #endif 610 611 return (err); 612 } 613 614 #ifdef LOADER_GELI_SUPPORT 615 /* 616 * Read function compartible with the ZFS callback, required to keep the GELI 617 * Implementation the same for both UFS and ZFS 618 */ 619 static int 620 vdev_read(void *vdev __unused, void *priv, off_t off, void *buf, size_t bytes) 621 { 622 char *p; 623 daddr_t lba; 624 unsigned int nb; 625 struct dsk *dskp = (struct dsk *) priv; 626 627 if ((off & (DEV_BSIZE - 1)) || (bytes & (DEV_BSIZE - 1))) 628 return (-1); 629 630 p = buf; 631 lba = off / DEV_BSIZE; 632 lba += dskp->start; 633 634 while (bytes > 0) { 635 nb = bytes / DEV_BSIZE; 636 if (nb > VBLKSIZE / DEV_BSIZE) 637 nb = VBLKSIZE / DEV_BSIZE; 638 if (drvread(dskp, dmadat->blkbuf, lba, nb)) 639 return (-1); 640 memcpy(p, dmadat->blkbuf, nb * DEV_BSIZE); 641 p += nb * DEV_BSIZE; 642 lba += nb; 643 bytes -= nb * DEV_BSIZE; 644 } 645 646 return (0); 647 } 648 #endif /* LOADER_GELI_SUPPORT */ 649