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