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