gptboot.c revision 40325
1219820Sjeff/* 2219820Sjeff * Copyright (c) 1998 Robert Nordier 3219820Sjeff * All rights reserved. 4219820Sjeff * 5270710Shselasky * Redistribution and use in source and binary forms are freely 6219820Sjeff * permitted provided that the above copyright notice and this 7219820Sjeff * paragraph and the following disclaimer are duplicated in all 8219820Sjeff * such forms. 9219820Sjeff * 10219820Sjeff * This software is provided "AS IS" and without any express or 11219820Sjeff * implied warranties, including, without limitation, the implied 12219820Sjeff * warranties of merchantability and fitness for a particular 13219820Sjeff * purpose. 14219820Sjeff */ 15219820Sjeff 16219820Sjeff/* 17219820Sjeff * $Id: boot2.c,v 1.5 1998/10/13 23:00:47 rnordier Exp $ 18219820Sjeff */ 19219820Sjeff 20219820Sjeff#include <sys/param.h> 21219820Sjeff#include <sys/reboot.h> 22219820Sjeff#include <sys/diskslice.h> 23219820Sjeff#include <sys/disklabel.h> 24219820Sjeff#include <sys/dirent.h> 25219820Sjeff#include <machine/bootinfo.h> 26219820Sjeff 27219820Sjeff#include <ufs/ffs/fs.h> 28289644Shselasky#include <ufs/ufs/dinode.h> 29289644Shselasky 30219820Sjeff#include <stdarg.h> 31219820Sjeff 32219820Sjeff#include <a.out.h> 33219820Sjeff#include <elf.h> 34219820Sjeff 35219820Sjeff#include <btxv86.h> 36289576Shselasky 37289576Shselasky#define RBX_ASKNAME 0x0 /* -a */ 38270710Shselasky#define RBX_SINGLE 0x1 /* -s */ 39270710Shselasky#define RBX_DFLTROOT 0x5 /* -r */ 40270710Shselasky#define RBX_KDB 0x6 /* -d */ 41270710Shselasky#define RBX_CONFIG 0xa /* -c */ 42270710Shselasky#define RBX_VERBOSE 0xb /* -v */ 43270710Shselasky#define RBX_CDROM 0xd /* -C */ 44219820Sjeff#define RBX_GDB 0xf /* -g */ 45270710Shselasky 46#define PATH_CONFIG "/boot.config" 47#define PATH_BOOT3 "/boot/loader" 48#define PATH_KERNEL "/kernel" 49#define PATH_HELP "boot.help" 50 51#define ARGS 0x800 52#define NOPT 8 53#define BSIZEMAX 8192 54#define NDEV 5 55#define MEM_BASE 0x12 56#define MEM_EXT 0x15 57#define V86_CY(x) ((x) & 1) 58#define V86_ZR(x) ((x) & 0x40) 59 60#define DRV_HARD 0x80 61#define DRV_MASK 0x7f 62 63#define MAJ_WD 0 64#define MAJ_WFD 1 65#define MAJ_FD 2 66#define MAJ_DA 4 67 68extern uint32_t _end; 69 70static const char optstr[NOPT] = "aCcdgrsv"; 71static const unsigned char flags[NOPT] = { 72 RBX_ASKNAME, 73 RBX_CDROM, 74 RBX_CONFIG, 75 RBX_KDB, 76 RBX_GDB, 77 RBX_DFLTROOT, 78 RBX_SINGLE, 79 RBX_VERBOSE 80}; 81 82static const char *const dev_nm[] = {"wd", " ", "fd", " ", "da"}; 83 84static struct dsk { 85 unsigned drive; 86 unsigned type; 87 unsigned unit; 88 unsigned slice; 89 unsigned part; 90 unsigned start; 91 int init; 92 int meta; 93} dsk; 94static char cmd[512]; 95static char kname[1024]; 96static char help[2048]; 97static uint32_t opts; 98static struct bootinfo bootinfo; 99static int ls; 100static uint32_t fs_off; 101 102void exit(int); 103static void load(const char *); 104static int parse(char *); 105static void readfile(const char *, void *, size_t); 106static ino_t lookup(const char *); 107static int fsfind(const char *, ino_t *); 108static int xfsread(ino_t, void *, size_t); 109static ssize_t fsread(ino_t, void *, size_t); 110static int dskread(void *, unsigned, unsigned); 111static int printf(const char *,...); 112static void getstr(char *, int); 113static int putchar(int); 114static int getchar(void); 115static void *memcpy(void *, const void *, size_t); 116static int strcmp(const char *, const char *); 117static void *malloc(size_t); 118static uint32_t memsize(int); 119static uint32_t drvinfo(int); 120static int drvread(void *, unsigned, unsigned); 121static int keyhit(unsigned); 122static int putch(int); 123static int getch(void); 124 125int 126main(void) 127{ 128 int autoboot, helpon, i; 129 130 v86.ctl = V86_FLAGS; 131 dsk.drive = *(uint8_t *)PTOV(ARGS); 132 dsk.type = dsk.drive & DRV_HARD ? MAJ_WD : MAJ_FD; 133 dsk.unit = dsk.drive & DRV_MASK; 134 dsk.slice = *(uint8_t *)PTOV(ARGS + 1) + 1; 135 bootinfo.bi_version = BOOTINFO_VERSION; 136 bootinfo.bi_size = sizeof(bootinfo); 137 bootinfo.bi_basemem = memsize(MEM_BASE); 138 bootinfo.bi_extmem = memsize(MEM_EXT); 139 bootinfo.bi_memsizes_valid++; 140 for (i = 0; i < N_BIOS_GEOM; i++) 141 bootinfo.bi_bios_geom[i] = drvinfo(i); 142 autoboot = 2; 143 helpon = 1; 144 readfile(PATH_CONFIG, cmd, sizeof(cmd)); 145 if (parse(cmd)) 146 autoboot = 0; 147 else if (!*kname) { 148 if (autoboot == 2) { 149 memcpy(kname, PATH_BOOT3, sizeof(PATH_BOOT3)); 150 if (!keyhit(0x37)) { 151 load(kname); 152 autoboot = 1; 153 } 154 } 155 if (autoboot == 1) 156 memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL)); 157 } 158 readfile(PATH_HELP, help, sizeof(help)); 159 for (;;) { 160 printf(" \n>> FreeBSD/i386 BOOT\n" 161 "Default: %u:%s(%u,%c)%s\n" 162 "%s" 163 "boot: ", 164 dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit, 165 'a' + dsk.part, kname, helpon ? help : ""); 166 if (!autoboot || keyhit(0x5a)) 167 getstr(cmd, sizeof(cmd)); 168 autoboot = helpon = 0; 169 if (parse(cmd)) 170 helpon = 1; 171 else 172 load(kname); 173 } 174} 175 176void 177exit(int x) 178{ 179} 180 181static void 182load(const char *fname) 183{ 184 union { 185 struct exec ex; 186 Elf32_Ehdr eh; 187 } hdr; 188 Elf32_Phdr ep[2]; 189 Elf32_Shdr es[2]; 190 caddr_t p; 191 ino_t ino; 192 uint32_t addr, x; 193 int fmt, i, j; 194 195 if (!(ino = lookup(fname))) { 196 if (!ls) 197 printf("No %s\n", fname); 198 return; 199 } 200 if (xfsread(ino, &hdr, sizeof(hdr))) 201 return; 202 if (N_GETMAGIC(hdr.ex) == ZMAGIC) 203 fmt = 0; 204 else if (IS_ELF(hdr.eh)) 205 fmt = 1; 206 else { 207 printf("Invalid %s\n", "format"); 208 return; 209 } 210 if (fmt == 0) { 211 addr = hdr.ex.a_entry & 0xffffff; 212 p = PTOV(addr); 213 printf("%s=0x%x ", "text", (unsigned)hdr.ex.a_text); 214 fs_off = PAGE_SIZE; 215 if (xfsread(ino, p, hdr.ex.a_text)) 216 return; 217 p += roundup2(hdr.ex.a_text, PAGE_SIZE); 218 printf("%s=0x%x ", "data", (unsigned)hdr.ex.a_data); 219 if (xfsread(ino, p, hdr.ex.a_data)) 220 return; 221 p += hdr.ex.a_data; 222 printf("%s=0x%x ", "bss", (unsigned)hdr.ex.a_bss); 223 p += roundup2(hdr.ex.a_bss, PAGE_SIZE); 224 bootinfo.bi_symtab = VTOP(p); 225 memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms)); 226 p += sizeof(hdr.ex.a_syms); 227 printf("symbols=["); 228 printf("+0x%x", (unsigned)hdr.ex.a_syms); 229 if (hdr.ex.a_syms) { 230 if (xfsread(ino, p, hdr.ex.a_syms)) 231 return; 232 p += hdr.ex.a_syms; 233 if (xfsread(ino, p, sizeof(int))) 234 return; 235 x = *(uint32_t *)p; 236 p += sizeof(int); 237 x -= sizeof(int); 238 printf("+0x%x", x); 239 if (xfsread(ino, p, x)) 240 return; 241 p += x; 242 } 243 } else { 244 fs_off = hdr.eh.e_phoff; 245 for (j = i = 0; i < hdr.eh.e_phoff && j < 2; i++) { 246 if (xfsread(ino, ep + j, sizeof(ep[0]))) 247 return; 248 if (ep[j].p_type == PT_LOAD) 249 j++; 250 } 251 for (i = 0; i < 2; i++) { 252 p = PTOV(ep[i].p_paddr & 0xffffff); 253 printf("%s=0x%x ", !i ? "text" : "data", ep[i].p_filesz); 254 fs_off = ep[i].p_offset; 255 if (xfsread(ino, p, ep[i].p_filesz)) 256 return; 257 } 258 printf("%s=0x%x ", "bss", ep[1].p_memsz - ep[1].p_filesz); 259 p += roundup2(ep[1].p_memsz, PAGE_SIZE); 260 bootinfo.bi_symtab = VTOP(p); 261 printf("symbols=["); 262 if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { 263 fs_off = hdr.eh.e_shoff + sizeof(es[0]) * 264 (hdr.eh.e_shstrndx + 1); 265 if (xfsread(ino, &es, sizeof(es))) 266 return; 267 for (i = 0; i < 2; i++) { 268 memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size)); 269 p += sizeof(es[i].sh_size); 270 printf("+0x%x", es[i].sh_size); 271 fs_off = es[i].sh_offset; 272 if (xfsread(ino, p, es[i].sh_size)) 273 return; 274 p += es[i].sh_size; 275 } 276 } 277 addr = hdr.eh.e_entry & 0xffffff; 278 } 279 bootinfo.bi_esymtab = VTOP(p); 280 printf("]\nentry=0x%x\n", addr); 281 bootinfo.bi_kernelname = VTOP(fname); 282 __exec((caddr_t)addr, RB_BOOTINFO | opts, 283 MAKEBOOTDEV(dsk.type, 0, dsk.slice, dsk.unit, dsk.part), 284 0, 0, 0, VTOP(&bootinfo)); 285} 286 287static int 288parse(char *arg) 289{ 290 char *p, *q; 291 int drv, c, i; 292 293 while ((c = *arg++)) { 294 if (c == ' ') 295 continue; 296 for (p = arg; *p && *p != '\n' && *p != ' '; p++); 297 if (*p) 298 *p++ = 0; 299 if (c == '-') 300 while ((c = *arg++)) { 301 for (i = 0; c != optstr[i]; i++) 302 if (i == NOPT - 1) 303 return -1; 304 opts |= 1 << flags[i]; 305 } 306 else { 307 for (q = arg--; *q && *q != '('; q++); 308 if (*q) { 309 drv = -1; 310 if (arg[1] == ':') { 311 if (*arg < '0' || *arg > '9') 312 return -1; 313 drv = *arg - '0'; 314 arg += 2; 315 } 316 if (q - arg != 2) 317 return -1; 318 for (i = 0; arg[0] != dev_nm[i][0] || 319 arg[1] != dev_nm[i][1]; i++) 320 if (i == NDEV - 1) 321 return -1; 322 dsk.type = i; 323 arg += 3; 324 if (arg[1] != ',' || *arg < '0' || *arg > '9') 325 return -1; 326 dsk.unit = *arg - '0'; 327 arg += 2; 328 dsk.slice = WHOLE_DISK_SLICE; 329 if (arg[1] == ',') { 330 if (*arg < '0' || *arg > '0' + NDOSPART) 331 return -1; 332 if ((dsk.slice = *arg - '0')) 333 dsk.slice++; 334 arg += 2; 335 } 336 if (arg[1] != ')' || *arg < 'a' || *arg > 'p') 337 return -1; 338 dsk.part = *arg - 'a'; 339 arg += 2; 340 if (drv == -1) 341 drv = dsk.unit; 342 dsk.drive = (dsk.type == MAJ_WD || 343 dsk.type == MAJ_DA ? DRV_HARD : 0) + drv; 344 dsk.meta = 0; 345 fsread(0, NULL, 0); 346 } 347 if ((i = p - arg - !*(p - 1))) { 348 if (i >= sizeof(kname)) 349 return -1; 350 memcpy(kname, arg, i + 1); 351 } 352 } 353 arg = p; 354 } 355 return 0; 356} 357 358static void 359readfile(const char *fname, void *buf, size_t size) 360{ 361 ino_t ino; 362 363 if ((ino = lookup(fname))) 364 fsread(ino, buf, size); 365} 366 367static ino_t 368lookup(const char *path) 369{ 370 char name[MAXNAMLEN + 1]; 371 const char *s; 372 ino_t ino; 373 ssize_t n; 374 int dt; 375 376 ino = ROOTINO; 377 dt = DT_DIR; 378 for (;;) { 379 if (*path == '/') 380 path++; 381 if (!*path) 382 break; 383 for (s = path; *s && *s != '/'; s++); 384 if ((n = s - path) > MAXNAMLEN) 385 return 0; 386 ls = *path == '?' && n == 1 && !*s; 387 memcpy(name, path, n); 388 name[n] = 0; 389 if ((dt = fsfind(name, &ino)) <= 0) 390 break; 391 path = s; 392 } 393 return dt == DT_REG ? ino : 0; 394} 395 396static int 397fsfind(const char *name, ino_t * ino) 398{ 399 char buf[DEV_BSIZE]; 400 struct dirent *d; 401 char *s; 402 ssize_t n; 403 404 fs_off = 0; 405 while ((n = fsread(*ino, buf, DEV_BSIZE)) > 0) 406 for (s = buf; s < buf + DEV_BSIZE;) { 407 d = (void *)s; 408 if (ls) 409 printf("%s ", d->d_name); 410 else if (!strcmp(name, d->d_name)) { 411 *ino = d->d_fileno; 412 return d->d_type; 413 } 414 s += d->d_reclen; 415 } 416 if (n != -1 && ls) 417 putchar('\n'); 418 return 0; 419} 420 421static int 422xfsread(ino_t inode, void *buf, size_t nbyte) 423{ 424 if (fsread(inode, buf, nbyte) != nbyte) { 425 printf("Invalid %s\n", "format"); 426 return -1; 427 } 428 return 0; 429} 430 431static ssize_t 432fsread(ino_t inode, void *buf, size_t nbyte) 433{ 434 static struct fs fs; 435 static struct dinode din; 436 static char *blkbuf; 437 static ufs_daddr_t *indbuf; 438 static ino_t inomap; 439 static ufs_daddr_t blkmap, indmap; 440 static unsigned fsblks; 441 char *s; 442 ufs_daddr_t lbn, addr; 443 size_t n, nb, off; 444 445 if (!dsk.meta) { 446 if (!blkbuf) 447 blkbuf = malloc(BSIZEMAX); 448 inomap = 0; 449 if (dskread(blkbuf, SBOFF / DEV_BSIZE, SBSIZE / DEV_BSIZE)) 450 return -1; 451 memcpy(&fs, blkbuf, sizeof(fs)); 452 if (fs.fs_magic != FS_MAGIC) { 453 printf("Not ufs\n"); 454 return -1; 455 } 456 fsblks = fs.fs_bsize >> DEV_BSHIFT; 457 dsk.meta = 1; 458 } 459 if (!inode) 460 return 0; 461 if (inomap != inode) { 462 if (dskread(blkbuf, fsbtodb(&fs, ino_to_fsba(&fs, inode)), 463 fsblks)) 464 return -1; 465 din = ((struct dinode *)blkbuf)[inode % INOPB(&fs)]; 466 inomap = inode; 467 fs_off = 0; 468 blkmap = indmap = 0; 469 } 470 s = buf; 471 if (nbyte > (n = din.di_size - fs_off)) 472 nbyte = n; 473 nb = nbyte; 474 while (nb) { 475 lbn = lblkno(&fs, fs_off); 476 if (lbn < NDADDR) 477 addr = din.di_db[lbn]; 478 else { 479 if (indmap != din.di_ib[0]) { 480 if (!indbuf) 481 indbuf = malloc(BSIZEMAX); 482 if (dskread(indbuf, fsbtodb(&fs, din.di_ib[0]), 483 fsblks)) 484 return -1; 485 indmap = din.di_ib[0]; 486 } 487 addr = indbuf[(lbn - NDADDR) % NINDIR(&fs)]; 488 } 489 n = dblksize(&fs, &din, lbn); 490 if (blkmap != addr) { 491 if (dskread(blkbuf, fsbtodb(&fs, addr), n >> DEV_BSHIFT)) 492 return -1; 493 blkmap = addr; 494 } 495 off = blkoff(&fs, fs_off); 496 n -= off; 497 if (n > nb) 498 n = nb; 499 memcpy(s, blkbuf + off, n); 500 s += n; 501 fs_off += n; 502 nb -= n; 503 } 504 return nbyte; 505} 506 507static int 508dskread(void *buf, unsigned lba, unsigned nblk) 509{ 510 static char *sec; 511 struct dos_partition *dp; 512 struct disklabel *d; 513 unsigned sl, i; 514 515 if (!dsk.meta) { 516 if (!sec) 517 sec = malloc(DEV_BSIZE); 518 dsk.start = 0; 519 if (drvread(sec, DOSBBSECTOR, 1)) 520 return -1; 521 dp = (void *)(sec + DOSPARTOFF); 522 sl = dsk.slice; 523 if (sl < BASE_SLICE) { 524 for (i = 0; i < NDOSPART; i++) 525 if (dp[i].dp_typ == DOSPTYP_386BSD && 526 (dp[i].dp_flag & 0x80 || sl < BASE_SLICE)) { 527 sl = BASE_SLICE + i; 528 if (dp[i].dp_flag & 0x80 || 529 dsk.slice == COMPATIBILITY_SLICE) 530 break; 531 } 532 if (dsk.slice == WHOLE_DISK_SLICE) 533 dsk.slice = sl; 534 } 535 if (sl != WHOLE_DISK_SLICE) { 536 if (sl != COMPATIBILITY_SLICE) 537 dp += sl - BASE_SLICE; 538 if (dp->dp_typ != DOSPTYP_386BSD) { 539 printf("Invalid %s\n", "slice"); 540 return -1; 541 } 542 dsk.start = dp->dp_start; 543 } 544 if (drvread(sec, dsk.start + LABELSECTOR, 1)) 545 return -1; 546 d = (void *)(sec + LABELOFFSET); 547 if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) { 548 if (dsk.part != RAW_PART) { 549 printf("Invalid %s\n", "label"); 550 return -1; 551 } 552 } else { 553 if (!dsk.init) { 554 if (d->d_type == DTYPE_SCSI) 555 dsk.type = MAJ_DA; 556 dsk.init++; 557 } 558 if (dsk.part >= d->d_npartitions) { 559 printf("Invalid %s\n", "partition"); 560 return -1; 561 } 562 dsk.start = d->d_partitions[dsk.part].p_offset; 563 } 564 } 565 return drvread(buf, dsk.start + lba, nblk); 566} 567 568static int 569printf(const char *fmt,...) 570{ 571 static const char digits[16] = "0123456789abcdef"; 572 va_list ap; 573 char buf[10]; 574 char *s; 575 unsigned r, u; 576 int c; 577 578 va_start(ap, fmt); 579 while ((c = *fmt++)) { 580 if (c == '%') { 581 c = *fmt++; 582 switch (c) { 583 case 'c': 584 putchar(va_arg(ap, int)); 585 continue; 586 case 's': 587 for (s = va_arg(ap, char *); *s; s++) 588 putchar(*s); 589 continue; 590 case 'u': 591 case 'x': 592 r = c == 'u' ? 10U : 16U; 593 u = va_arg(ap, unsigned); 594 s = buf; 595 do 596 *s++ = digits[u % r]; 597 while (u /= r); 598 while (--s >= buf) 599 putchar(*s); 600 continue; 601 } 602 } 603 putchar(c); 604 } 605 va_end(ap); 606 return 0; 607} 608 609static void 610getstr(char *str, int size) 611{ 612 char *s; 613 int c; 614 615 s = str; 616 do { 617 switch (c = getchar()) { 618 case '\b': 619 if (s > str) 620 s--; 621 break; 622 case '\n': 623 *s = 0; 624 break; 625 default: 626 if (s - str < size - 1) 627 *s++ = c; 628 } 629 putchar(c); 630 } while (c != '\n'); 631} 632 633static int 634putchar(int c) 635{ 636 if (c == '\n') 637 putch('\r'); 638 return putch(c); 639} 640 641static int 642getchar(void) 643{ 644 int c; 645 646 c = getch(); 647 if (c == '\r') 648 c = '\n'; 649 return c; 650} 651 652static void * 653memcpy(void *dst, const void *src, size_t size) 654{ 655 const char *s; 656 char *d; 657 658 for (d = dst, s = src; size; size--) 659 *d++ = *s++; 660 return dst; 661} 662 663static int 664strcmp(const char *s1, const char *s2) 665{ 666 for (; *s1 == *s2 && *s1; s1++, s2++); 667 return (u_char)*s1 - (u_char)*s2; 668} 669 670static void * 671malloc(size_t size) 672{ 673 static uint32_t next; 674 void *p; 675 676 if (!next) 677 next = roundup2(__base + _end, 0x10000) - __base; 678 p = (void *)next; 679 next += size; 680 return p; 681} 682 683static uint32_t 684memsize(int type) 685{ 686 v86.addr = type; 687 v86.eax = 0x8800; 688 v86int(); 689 return v86.eax; 690} 691 692static uint32_t 693drvinfo(int drive) 694{ 695 v86.addr = 0x13; 696 v86.eax = 0x800; 697 v86.edx = DRV_HARD + drive; 698 v86int(); 699 if (V86_CY(v86.efl)) 700 return 0x4f010f; 701 return ((v86.ecx & 0xc0) << 18) | ((v86.ecx & 0xff00) << 8) | 702 (v86.edx & 0xff00) | (v86.ecx & 0x3f); 703} 704 705static int 706drvread(void *buf, unsigned lba, unsigned nblk) 707{ 708 static unsigned c = 0x2d5c7c2f; 709 710 printf("%c\b", c = c << 8 | c >> 24); 711 v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; 712 v86.addr = 0x604; 713 v86.eax = nblk; 714 v86.ebx = VTOPSEG(buf) << 16 | VTOPOFF(buf); 715 v86.ecx = lba; 716 v86.edx = 0x100 | dsk.drive; 717 v86int(); 718 v86.ctl = V86_FLAGS; 719 if (V86_CY(v86.efl)) { 720 printf("Disk error 0x%x (lba=0x%x)\n", v86.eax >> 8 & 0xff, 721 lba); 722 return -1; 723 } 724 return 0; 725} 726 727static int 728keyhit(unsigned ticks) 729{ 730 uint32_t t0, t1; 731 732 t0 = 0; 733 for (;;) { 734 v86.addr = 0x16; 735 v86.eax = 0x100; 736 v86int(); 737 if (!V86_ZR(v86.efl)) 738 return 1; 739 t1 = *(uint32_t *)PTOV(0x46c); 740 if (!t0) 741 t0 = t1; 742 if (t1 < t0 || t1 >= t0 + ticks) 743 return 0; 744 } 745} 746 747static int 748putch(int c) 749{ 750 v86.addr = 0x10; 751 v86.eax = 0xe00 | (c & 0xff); 752 v86.ebx = 0x7; 753 v86int(); 754 return c; 755} 756 757static int 758getch(void) 759{ 760 v86.addr = 0x16; 761 v86.eax = 0; 762 v86int(); 763 return v86.eax & 0xff; 764} 765