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