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