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/disklabel.h> 21 #include <sys/diskmbr.h> 22 #include <sys/dirent.h> 23 #include <sys/reboot.h> 24 25 #include <machine/bootinfo.h> 26 #include <machine/elf.h> 27 28 #include <stdarg.h> 29 30 #include <a.out.h> 31 32 #include <btxv86.h> 33 34 #include "boot2.h" 35 #include "lib.h" 36 #include "paths.h" 37 #include "rbx.h" 38 39 /* Define to 0 to omit serial support */ 40 #ifndef SERIAL 41 #define SERIAL 1 42 #endif 43 44 #define IO_KEYBOARD 1 45 #define IO_SERIAL 2 46 47 #if SERIAL 48 #define DO_KBD (ioctrl & IO_KEYBOARD) 49 #define DO_SIO (ioctrl & IO_SERIAL) 50 #else 51 #define DO_KBD (1) 52 #define DO_SIO (0) 53 #endif 54 55 #define SECOND 18 /* Circa that many ticks in a second. */ 56 57 #define ARGS 0x900 58 #define NOPT 14 59 #define NDEV 3 60 #define MEM_BASE 0x12 61 #define MEM_EXT 0x15 62 63 #define DRV_HARD 0x80 64 #define DRV_MASK 0x7f 65 66 #define TYPE_AD 0 67 #define TYPE_DA 1 68 #define TYPE_MAXHARD TYPE_DA 69 #define TYPE_FD 2 70 71 extern uint32_t _end; 72 73 static const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */ 74 static const unsigned char flags[NOPT] = { 75 RBX_DUAL, 76 RBX_SERIAL, 77 RBX_ASKNAME, 78 RBX_CDROM, 79 RBX_CONFIG, 80 RBX_KDB, 81 RBX_GDB, 82 RBX_MUTE, 83 RBX_NOINTR, 84 RBX_PAUSE, 85 RBX_QUIET, 86 RBX_DFLTROOT, 87 RBX_SINGLE, 88 RBX_VERBOSE 89 }; 90 91 static const char *const dev_nm[NDEV] = {"ad", "da", "fd"}; 92 static const unsigned char dev_maj[NDEV] = {30, 4, 2}; 93 94 static struct dsk { 95 unsigned drive; 96 unsigned type; 97 unsigned unit; 98 uint8_t slice; 99 uint8_t part; 100 unsigned start; 101 int init; 102 } dsk; 103 static char cmd[512], cmddup[512], knamebuf[1024]; 104 static const char *kname; 105 uint32_t opts; 106 static struct bootinfo bootinfo; 107 #if SERIAL 108 static int comspeed = SIOSPD; 109 static uint8_t ioctrl = IO_KEYBOARD; 110 #endif 111 112 int main(void); 113 void exit(int); 114 static void load(void); 115 static int parse(void); 116 static int dskread(void *, unsigned, unsigned); 117 static void printf(const char *,...); 118 static void putchar(int); 119 static int drvread(void *, unsigned, unsigned); 120 static int keyhit(unsigned); 121 static int xputc(int); 122 static int xgetc(int); 123 static inline int getc(int); 124 125 static void memcpy(void *, const void *, int); 126 static void 127 memcpy(void *dst, const void *src, int len) 128 { 129 const char *s; 130 char *d; 131 132 s = src; 133 d = dst; 134 135 while (len--) 136 *d++ = *s++; 137 } 138 139 static inline int 140 strcmp(const char *s1, const char *s2) 141 { 142 143 for (; *s1 == *s2 && *s1; s1++, s2++); 144 return ((unsigned char)*s1 - (unsigned char)*s2); 145 } 146 147 #define UFS_SMALL_CGBASE 148 #include "ufsread.c" 149 150 static int 151 xfsread(ufs_ino_t inode, void *buf, size_t nbyte) 152 { 153 154 if ((size_t)fsread(inode, buf, nbyte) != nbyte) { 155 printf("Invalid %s\n", "format"); 156 return (-1); 157 } 158 return (0); 159 } 160 161 static inline void 162 getstr(void) 163 { 164 char *s; 165 int c; 166 167 s = cmd; 168 for (;;) { 169 switch (c = xgetc(0)) { 170 case 0: 171 break; 172 case '\177': 173 case '\b': 174 if (s > cmd) { 175 s--; 176 printf("\b \b"); 177 } 178 break; 179 case '\n': 180 case '\r': 181 *s = 0; 182 return; 183 default: 184 if (s - cmd < sizeof(cmd) - 1) 185 *s++ = c; 186 putchar(c); 187 } 188 } 189 } 190 191 static inline void 192 putc(int c) 193 { 194 195 v86.addr = 0x10; 196 v86.eax = 0xe00 | (c & 0xff); 197 v86.ebx = 0x7; 198 v86int(); 199 } 200 201 int 202 main(void) 203 { 204 uint8_t autoboot; 205 ufs_ino_t ino; 206 size_t nbyte; 207 208 dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base); 209 v86.ctl = V86_FLAGS; 210 v86.efl = PSL_RESERVED_DEFAULT | PSL_I; 211 dsk.drive = *(uint8_t *)PTOV(ARGS); 212 dsk.type = dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD; 213 dsk.unit = dsk.drive & DRV_MASK; 214 dsk.slice = *(uint8_t *)PTOV(ARGS + 1) + 1; 215 bootinfo.bi_version = BOOTINFO_VERSION; 216 bootinfo.bi_size = sizeof(bootinfo); 217 218 /* Process configuration file */ 219 220 autoboot = 1; 221 222 if ((ino = lookup(PATH_CONFIG)) || 223 (ino = lookup(PATH_DOTCONFIG))) { 224 nbyte = fsread(ino, cmd, sizeof(cmd) - 1); 225 cmd[nbyte] = '\0'; 226 } 227 228 if (*cmd) { 229 memcpy(cmddup, cmd, sizeof(cmd)); 230 if (parse()) 231 autoboot = 0; 232 if (!OPT_CHECK(RBX_QUIET)) 233 printf("%s: %s", PATH_CONFIG, cmddup); 234 /* Do not process this command twice */ 235 *cmd = 0; 236 } 237 238 /* 239 * Try to exec stage 3 boot loader. If interrupted by a keypress, 240 * or in case of failure, try to load a kernel directly instead. 241 */ 242 243 if (!kname) { 244 kname = PATH_LOADER; 245 if (autoboot && !keyhit(3*SECOND)) { 246 load(); 247 kname = PATH_KERNEL; 248 } 249 } 250 251 /* Present the user with the boot2 prompt. */ 252 253 for (;;) { 254 if (!autoboot || !OPT_CHECK(RBX_QUIET)) 255 printf("\nFreeBSD/x86 boot\n" 256 "Default: %u:%s(%u,%c)%s\n" 257 "boot: ", 258 dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit, 259 'a' + dsk.part, kname); 260 if (DO_SIO) 261 sio_flush(); 262 if (!autoboot || keyhit(3*SECOND)) 263 getstr(); 264 else if (!autoboot || !OPT_CHECK(RBX_QUIET)) 265 putchar('\n'); 266 autoboot = 0; 267 if (parse()) 268 putchar('\a'); 269 else 270 load(); 271 } 272 } 273 274 /* XXX - Needed for btxld to link the boot2 binary; do not remove. */ 275 void 276 exit(int x) 277 { 278 279 } 280 281 static void 282 load(void) 283 { 284 union { 285 struct exec ex; 286 Elf32_Ehdr eh; 287 } hdr; 288 static Elf32_Phdr ep[2]; 289 static Elf32_Shdr es[2]; 290 caddr_t p; 291 ufs_ino_t ino; 292 uint32_t addr; 293 int k; 294 uint8_t i, j; 295 296 if (!(ino = lookup(kname))) { 297 if (!ls) 298 printf("No %s\n", kname); 299 return; 300 } 301 if (xfsread(ino, &hdr, sizeof(hdr))) 302 return; 303 304 if (N_GETMAGIC(hdr.ex) == ZMAGIC) { 305 addr = hdr.ex.a_entry & 0xffffff; 306 p = PTOV(addr); 307 fs_off = PAGE_SIZE; 308 if (xfsread(ino, p, hdr.ex.a_text)) 309 return; 310 p += roundup2(hdr.ex.a_text, PAGE_SIZE); 311 if (xfsread(ino, p, hdr.ex.a_data)) 312 return; 313 } else if (IS_ELF(hdr.eh)) { 314 fs_off = hdr.eh.e_phoff; 315 for (j = k = 0; k < hdr.eh.e_phnum && j < 2; k++) { 316 if (xfsread(ino, ep + j, sizeof(ep[0]))) 317 return; 318 if (ep[j].p_type == PT_LOAD) 319 j++; 320 } 321 for (i = 0; i < 2; i++) { 322 p = PTOV(ep[i].p_paddr & 0xffffff); 323 fs_off = ep[i].p_offset; 324 if (xfsread(ino, p, ep[i].p_filesz)) 325 return; 326 } 327 p += roundup2(ep[1].p_memsz, PAGE_SIZE); 328 bootinfo.bi_symtab = VTOP(p); 329 if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { 330 fs_off = hdr.eh.e_shoff + sizeof(es[0]) * 331 (hdr.eh.e_shstrndx + 1); 332 if (xfsread(ino, &es, sizeof(es))) 333 return; 334 for (i = 0; i < 2; i++) { 335 *(Elf32_Word *)p = es[i].sh_size; 336 p += sizeof(es[i].sh_size); 337 fs_off = es[i].sh_offset; 338 if (xfsread(ino, p, es[i].sh_size)) 339 return; 340 p += es[i].sh_size; 341 } 342 } 343 addr = hdr.eh.e_entry & 0xffffff; 344 bootinfo.bi_esymtab = VTOP(p); 345 } else { 346 printf("Invalid %s\n", "format"); 347 return; 348 } 349 350 bootinfo.bi_kernelname = VTOP(kname); 351 bootinfo.bi_bios_dev = dsk.drive; 352 __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), 353 MAKEBOOTDEV(dev_maj[dsk.type], dsk.slice, dsk.unit, dsk.part), 354 0, 0, 0, VTOP(&bootinfo)); 355 } 356 357 static int 358 parse() 359 { 360 char *arg, *ep, *p, *q; 361 const char *cp; 362 unsigned int drv; 363 int c, i, j; 364 size_t k; 365 366 arg = cmd; 367 368 while ((c = *arg++)) { 369 if (c == ' ' || c == '\t' || c == '\n') 370 continue; 371 for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++); 372 ep = p; 373 if (*p) 374 *p++ = 0; 375 if (c == '-') { 376 while ((c = *arg++)) { 377 if (c == 'P') { 378 if (*(uint8_t *)PTOV(0x496) & 0x10) { 379 cp = "yes"; 380 } else { 381 opts |= OPT_SET(RBX_DUAL) | 382 OPT_SET(RBX_SERIAL); 383 cp = "no"; 384 } 385 printf("Keyboard: %s\n", cp); 386 continue; 387 #if SERIAL 388 } else if (c == 'S') { 389 j = 0; 390 while ((u_int)(i = *arg++ - '0') <= 9) 391 j = j * 10 + i; 392 if (j > 0 && i == -'0') { 393 comspeed = j; 394 break; 395 } 396 /* 397 * Fall through to error below 398 * ('S' not in optstr[]). 399 */ 400 #endif 401 } 402 for (i = 0; c != optstr[i]; i++) 403 if (i == NOPT - 1) 404 return (-1); 405 opts ^= OPT_SET(flags[i]); 406 } 407 #if SERIAL 408 ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) : 409 OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD; 410 if (DO_SIO) { 411 if (sio_init(115200 / comspeed) != 0) 412 ioctrl &= ~IO_SERIAL; 413 } 414 #endif 415 } else { 416 for (q = arg--; *q && *q != '('; q++); 417 if (*q) { 418 drv = -1; 419 if (arg[1] == ':') { 420 drv = *arg - '0'; 421 if (drv > 9) 422 return (-1); 423 arg += 2; 424 } 425 if (q - arg != 2) 426 return (-1); 427 for (i = 0; arg[0] != dev_nm[i][0] || 428 arg[1] != dev_nm[i][1]; i++) 429 if (i == NDEV - 1) 430 return (-1); 431 dsk.type = i; 432 arg += 3; 433 dsk.unit = *arg - '0'; 434 if (arg[1] != ',' || dsk.unit > 9) 435 return (-1); 436 arg += 2; 437 dsk.slice = WHOLE_DISK_SLICE; 438 if (arg[1] == ',') { 439 dsk.slice = *arg - '0' + 1; 440 if (dsk.slice > NDOSPART + 1) 441 return (-1); 442 arg += 2; 443 } 444 if (arg[1] != ')') 445 return (-1); 446 dsk.part = *arg - 'a'; 447 if (dsk.part > 7) 448 return (-1); 449 arg += 2; 450 if (drv == -1) 451 drv = dsk.unit; 452 dsk.drive = (dsk.type <= TYPE_MAXHARD 453 ? DRV_HARD : 0) + drv; 454 dsk_meta = 0; 455 } 456 k = ep - arg; 457 if (k > 0) { 458 if (k >= sizeof(knamebuf)) 459 return (-1); 460 memcpy(knamebuf, arg, k + 1); 461 kname = knamebuf; 462 } 463 } 464 arg = p; 465 } 466 return (0); 467 } 468 469 static int 470 dskread(void *buf, unsigned lba, unsigned nblk) 471 { 472 struct dos_partition *dp; 473 struct disklabel *d; 474 char *sec; 475 unsigned i; 476 uint8_t sl; 477 const char *reason; 478 479 if (!dsk_meta) { 480 sec = dmadat->secbuf; 481 dsk.start = 0; 482 if (drvread(sec, DOSBBSECTOR, 1)) 483 return (-1); 484 dp = (void *)(sec + DOSPARTOFF); 485 sl = dsk.slice; 486 if (sl < BASE_SLICE) { 487 for (i = 0; i < NDOSPART; i++) 488 if (dp[i].dp_typ == DOSPTYP_386BSD && 489 (dp[i].dp_flag & 0x80 || sl < BASE_SLICE)) { 490 sl = BASE_SLICE + i; 491 if (dp[i].dp_flag & 0x80 || 492 dsk.slice == COMPATIBILITY_SLICE) 493 break; 494 } 495 if (dsk.slice == WHOLE_DISK_SLICE) 496 dsk.slice = sl; 497 } 498 if (sl != WHOLE_DISK_SLICE) { 499 if (sl != COMPATIBILITY_SLICE) 500 dp += sl - BASE_SLICE; 501 if (dp->dp_typ != DOSPTYP_386BSD) { 502 reason = "slice"; 503 goto error; 504 } 505 dsk.start = dp->dp_start; 506 } 507 if (drvread(sec, dsk.start + LABELSECTOR, 1)) 508 return (-1); 509 d = (void *)(sec + LABELOFFSET); 510 if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) { 511 if (dsk.part != RAW_PART) { 512 reason = "label"; 513 goto error; 514 } 515 } else { 516 if (!dsk.init) { 517 if (d->d_type == DTYPE_SCSI) 518 dsk.type = TYPE_DA; 519 dsk.init++; 520 } 521 if (dsk.part >= d->d_npartitions || 522 !d->d_partitions[dsk.part].p_size) { 523 reason = "partition"; 524 goto error; 525 } 526 dsk.start += d->d_partitions[dsk.part].p_offset; 527 dsk.start -= d->d_partitions[RAW_PART].p_offset; 528 } 529 } 530 return (drvread(buf, dsk.start + lba, nblk)); 531 error: 532 printf("Invalid %s\n", reason); 533 return (-1); 534 } 535 536 static void 537 printf(const char *fmt,...) 538 { 539 va_list ap; 540 static char buf[10]; 541 char *s; 542 unsigned u; 543 int c; 544 545 va_start(ap, fmt); 546 while ((c = *fmt++)) { 547 if (c == '%') { 548 c = *fmt++; 549 switch (c) { 550 case 'c': 551 putchar(va_arg(ap, int)); 552 continue; 553 case 's': 554 for (s = va_arg(ap, char *); *s; s++) 555 putchar(*s); 556 continue; 557 case 'u': 558 u = va_arg(ap, unsigned); 559 s = buf; 560 do 561 *s++ = '0' + u % 10U; 562 while (u /= 10U); 563 while (--s >= buf) 564 putchar(*s); 565 continue; 566 } 567 } 568 putchar(c); 569 } 570 va_end(ap); 571 return; 572 } 573 574 static void 575 putchar(int c) 576 { 577 578 if (c == '\n') 579 xputc('\r'); 580 xputc(c); 581 } 582 583 static int 584 drvread(void *buf, unsigned lba, unsigned nblk) 585 { 586 static unsigned c = 0x2d5c7c2f; 587 588 if (!OPT_CHECK(RBX_QUIET)) { 589 xputc(c = c << 8 | c >> 24); 590 xputc('\b'); 591 } 592 v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; 593 v86.addr = XREADORG; /* call to xread in boot1 */ 594 v86.es = VTOPSEG(buf); 595 v86.eax = lba; 596 v86.ebx = VTOPOFF(buf); 597 v86.ecx = lba >> 16; 598 v86.edx = nblk << 8 | dsk.drive; 599 v86int(); 600 v86.ctl = V86_FLAGS; 601 if (V86_CY(v86.efl)) { 602 printf("error %u lba %u\n", v86.eax >> 8 & 0xff, lba); 603 return (-1); 604 } 605 return (0); 606 } 607 608 static int 609 keyhit(unsigned ticks) 610 { 611 uint32_t t0, t1; 612 613 if (OPT_CHECK(RBX_NOINTR)) 614 return (0); 615 t0 = 0; 616 for (;;) { 617 if (xgetc(1)) 618 return (1); 619 t1 = *(uint32_t *)PTOV(0x46c); 620 if (!t0) 621 t0 = t1; 622 if ((uint32_t)(t1 - t0) >= ticks) 623 return (0); 624 } 625 } 626 627 static int 628 xputc(int c) 629 { 630 631 if (DO_KBD) 632 putc(c); 633 if (DO_SIO) 634 sio_putc(c); 635 return (c); 636 } 637 638 static int 639 getc(int fn) 640 { 641 642 v86.addr = 0x16; 643 v86.eax = fn << 8; 644 v86int(); 645 return (fn == 0 ? v86.eax & 0xff : !V86_ZR(v86.efl)); 646 } 647 648 static int 649 xgetc(int fn) 650 { 651 652 if (OPT_CHECK(RBX_NOINTR)) 653 return (0); 654 for (;;) { 655 if (DO_KBD && getc(1)) 656 return (fn ? 1 : getc(0)); 657 if (DO_SIO && sio_ischar()) 658 return (fn ? 1 : sio_getc()); 659 if (fn) 660 return (0); 661 } 662 } 663