1/*- 2 * Copyright (c) 2008-2009 TAKAHASHI Yoshihiro 3 * Copyright (c) 1998 Robert Nordier 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms are freely 7 * permitted provided that the above copyright notice and this 8 * paragraph and the following disclaimer are duplicated in all 9 * such forms. 10 * 11 * This software is provided "AS IS" and without any express or 12 * implied warranties, including, without limitation, the implied 13 * warranties of merchantability and fitness for a particular 14 * purpose. 15 */ 16 17#include <sys/cdefs.h> 18__FBSDID("$FreeBSD$"); 19 20#include <sys/param.h> 21#include <sys/disklabel.h> 22#include <sys/diskpc98.h> 23#include <sys/dirent.h> 24#include <sys/reboot.h> 25 26#include <machine/bootinfo.h> 27#include <machine/cpufunc.h> 28#include <machine/elf.h> 29 30#include <stdarg.h> 31 32#include <a.out.h> 33 34#include <btxv86.h> 35 36#include "boot2.h" 37#include "lib.h" 38 39#define IO_KEYBOARD 1 40#define IO_SERIAL 2 41 42#define SECOND 1 /* Circa that many ticks in a second. */ 43 44#define RBX_ASKNAME 0x0 /* -a */ 45#define RBX_SINGLE 0x1 /* -s */ 46/* 0x2 is reserved for log2(RB_NOSYNC). */ 47/* 0x3 is reserved for log2(RB_HALT). */ 48/* 0x4 is reserved for log2(RB_INITNAME). */ 49#define RBX_DFLTROOT 0x5 /* -r */ 50#define RBX_KDB 0x6 /* -d */ 51/* 0x7 is reserved for log2(RB_RDONLY). */ 52/* 0x8 is reserved for log2(RB_DUMP). */ 53/* 0x9 is reserved for log2(RB_MINIROOT). */ 54#define RBX_CONFIG 0xa /* -c */ 55#define RBX_VERBOSE 0xb /* -v */ 56#define RBX_SERIAL 0xc /* -h */ 57#define RBX_CDROM 0xd /* -C */ 58/* 0xe is reserved for log2(RB_POWEROFF). */ 59#define RBX_GDB 0xf /* -g */ 60#define RBX_MUTE 0x10 /* -m */ 61/* 0x11 is reserved for log2(RB_SELFTEST). */ 62/* 0x12 is reserved for boot programs. */ 63/* 0x13 is reserved for boot programs. */ 64#define RBX_PAUSE 0x14 /* -p */ 65#define RBX_QUIET 0x15 /* -q */ 66#define RBX_NOINTR 0x1c /* -n */ 67/* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */ 68#define RBX_DUAL 0x1d /* -D */ 69/* 0x1f is reserved for log2(RB_BOOTINFO). */ 70 71/* pass: -a, -s, -r, -d, -c, -v, -h, -C, -g, -m, -p, -D */ 72#define RBX_MASK (OPT_SET(RBX_ASKNAME) | OPT_SET(RBX_SINGLE) | \ 73 OPT_SET(RBX_DFLTROOT) | OPT_SET(RBX_KDB ) | \ 74 OPT_SET(RBX_CONFIG) | OPT_SET(RBX_VERBOSE) | \ 75 OPT_SET(RBX_SERIAL) | OPT_SET(RBX_CDROM) | \ 76 OPT_SET(RBX_GDB ) | OPT_SET(RBX_MUTE) | \ 77 OPT_SET(RBX_PAUSE) | OPT_SET(RBX_DUAL)) 78 79#define PATH_DOTCONFIG "/boot.config" 80#define PATH_CONFIG "/boot/config" 81#define PATH_BOOT3 "/boot/loader" 82#define PATH_KERNEL "/boot/kernel/kernel" 83 84#define ARGS 0x900 85#define NOPT 14 86#define NDEV 3 87 88#define DRV_DISK 0xf0 89#define DRV_UNIT 0x0f 90 91#define TYPE_AD 0 92#define TYPE_DA 1 93#define TYPE_FD 2 94 95#define OPT_SET(opt) (1 << (opt)) 96#define OPT_CHECK(opt) ((opts) & OPT_SET(opt)) 97 98extern uint32_t _end; 99 100static const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */ 101static const unsigned char flags[NOPT] = { 102 RBX_DUAL, 103 RBX_SERIAL, 104 RBX_ASKNAME, 105 RBX_CDROM, 106 RBX_CONFIG, 107 RBX_KDB, 108 RBX_GDB, 109 RBX_MUTE, 110 RBX_NOINTR, 111 RBX_PAUSE, 112 RBX_QUIET, 113 RBX_DFLTROOT, 114 RBX_SINGLE, 115 RBX_VERBOSE 116}; 117 118static const char *const dev_nm[NDEV] = {"ad", "da", "fd"}; 119static const unsigned char dev_maj[NDEV] = {30, 4, 2}; 120static const unsigned char dev_daua[NDEV] = {0x80, 0xa0, 0x90}; 121 122static struct dsk { 123 unsigned daua; 124 unsigned type; 125 unsigned disk; 126 unsigned unit; 127 unsigned head; 128 unsigned sec; 129 uint8_t slice; 130 uint8_t part; 131 unsigned start; 132} dsk; 133static char cmd[512], cmddup[512], knamebuf[1024]; 134static const char *kname; 135static uint32_t opts; 136static int comspeed = SIOSPD; 137static struct bootinfo bootinfo; 138static uint8_t ioctrl = IO_KEYBOARD; 139 140void exit(int); 141static void load(void); 142static int parse(void); 143static int dskread(void *, unsigned, unsigned); 144static void printf(const char *,...); 145static void putchar(int); 146static int drvread(void *, unsigned); 147static int keyhit(unsigned); 148static int xputc(int); 149static int xgetc(int); 150static inline int getc(int); 151 152static void memcpy(void *, const void *, int); 153static void 154memcpy(void *dst, const void *src, int len) 155{ 156 const char *s = src; 157 char *d = dst; 158 159 while (len--) 160 *d++ = *s++; 161} 162 163static inline int 164strcmp(const char *s1, const char *s2) 165{ 166 for (; *s1 == *s2 && *s1; s1++, s2++); 167 return (unsigned char)*s1 - (unsigned char)*s2; 168} 169 170#define UFS_SMALL_CGBASE 171#include "ufsread.c" 172 173static inline int 174xfsread(ufs_ino_t inode, void *buf, size_t nbyte) 175{ 176 if ((size_t)fsread(inode, buf, nbyte) != nbyte) { 177 printf("Invalid %s\n", "format"); 178 return -1; 179 } 180 return 0; 181} 182 183static inline void 184getstr(void) 185{ 186 char *s; 187 int c; 188 189 s = cmd; 190 for (;;) { 191 switch (c = xgetc(0)) { 192 case 0: 193 break; 194 case '\177': 195 case '\b': 196 if (s > cmd) { 197 s--; 198 printf("\b \b"); 199 } 200 break; 201 case '\n': 202 case '\r': 203 *s = 0; 204 return; 205 default: 206 if (s - cmd < sizeof(cmd) - 1) 207 *s++ = c; 208 putchar(c); 209 } 210 } 211} 212 213static inline void 214putc(int c) 215{ 216 217 v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; 218 v86.addr = PUTCORG; /* call to putc in boot1 */ 219 v86.eax = c; 220 v86int(); 221 v86.ctl = V86_FLAGS; 222} 223 224static inline int 225is_scsi_hd(void) 226{ 227 228 if ((*(u_char *)PTOV(0x482) >> dsk.unit) & 0x01) 229 return 1; 230 231 return 0; 232} 233 234static inline void 235fix_sector_size(void) 236{ 237 u_char *p; 238 239 p = (u_char *)PTOV(0x460 + dsk.unit * 4); /* SCSI equipment parameter */ 240 241 if ((p[0] & 0x1f) == 7) { /* SCSI MO */ 242 if (!(p[3] & 0x30)) { /* 256B / sector */ 243 p[3] |= 0x10; /* forced set 512B / sector */ 244 p[3 + 0xa1000] |= 0x10; 245 } 246 } 247} 248 249static inline uint32_t 250get_diskinfo(void) 251{ 252 253 if (dsk.disk == 0x30) { /* 1440KB FD */ 254 /* 80 cylinders, 2 heads, 18 sectors */ 255 return (80 << 16) | (2 << 8) | 18; 256 } else if (dsk.disk == 0x90) { /* 1200KB FD */ 257 /* 80 cylinders, 2 heads, 15 sectors */ 258 return (80 << 16) | (2 << 8) | 15; 259 } else if (dsk.disk == 0x80 || is_scsi_hd()) { /* IDE or SCSI HDD */ 260 v86.addr = 0x1b; 261 v86.eax = 0x8400 | dsk.daua; 262 v86int(); 263 return (v86.ecx << 16) | v86.edx; 264 } 265 266 /* SCSI MO or CD */ 267 fix_sector_size(); /* SCSI MO */ 268 269 /* other SCSI devices */ 270 return (65535 << 16) | (8 << 8) | 32; 271} 272 273static void 274set_dsk(void) 275{ 276 uint32_t di; 277 278 di = get_diskinfo(); 279 280 dsk.head = (di >> 8) & 0xff; 281 dsk.sec = di & 0xff; 282 dsk.start = 0; 283} 284 285#ifdef GET_BIOSGEOM 286static uint32_t 287bd_getbigeom(int bunit) 288{ 289 int hds = 0; 290 int unit = 0x80; /* IDE HDD */ 291 u_int addr = 0x55d; 292 293 while (unit < 0xa7) { 294 if (*(u_char *)PTOV(addr) & (1 << (unit & 0x0f))) 295 if (hds++ == bunit) 296 break; 297 298 if (unit >= 0xA0) { 299 int media = ((unsigned *)PTOV(0x460))[unit & 0x0F] & 0x1F; 300 301 if (media == 7 && hds++ == bunit) /* SCSI MO */ 302 return(0xFFFE0820); /* C:65535 H:8 S:32 */ 303 } 304 if (++unit == 0x84) { 305 unit = 0xA0; /* SCSI HDD */ 306 addr = 0x482; 307 } 308 } 309 if (unit == 0xa7) 310 return 0x4F020F; /* 1200KB FD C:80 H:2 S:15 */ 311 v86.addr = 0x1b; 312 v86.eax = 0x8400 | unit; 313 v86int(); 314 if (v86.efl & 0x1) 315 return 0x4F020F; /* 1200KB FD C:80 H:2 S:15 */ 316 return ((v86.ecx & 0xffff) << 16) | (v86.edx & 0xffff); 317} 318#endif 319 320static int 321check_slice(void) 322{ 323 struct pc98_partition *dp; 324 char *sec; 325 unsigned i, cyl; 326 327 sec = dmadat->secbuf; 328 cyl = *(uint16_t *)PTOV(ARGS); 329 set_dsk(); 330 331 if (dsk.type == TYPE_FD) 332 return (WHOLE_DISK_SLICE); 333 if (drvread(sec, PC98_BBSECTOR)) 334 return (WHOLE_DISK_SLICE); /* Read error */ 335 dp = (void *)(sec + PC98_PARTOFF); 336 for (i = 0; i < PC98_NPARTS; i++) { 337 if (dp[i].dp_mid == DOSMID_386BSD) { 338 if (dp[i].dp_scyl <= cyl && cyl <= dp[i].dp_ecyl) 339 return (BASE_SLICE + i); 340 } 341 } 342 343 return (WHOLE_DISK_SLICE); 344} 345 346int 347main(void) 348{ 349#ifdef GET_BIOSGEOM 350 int i; 351#endif 352 uint8_t autoboot; 353 ufs_ino_t ino; 354 size_t nbyte; 355 356 dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base); 357 v86.ctl = V86_FLAGS; 358 v86.efl = PSL_RESERVED_DEFAULT | PSL_I; 359 dsk.daua = *(uint8_t *)PTOV(0x584); 360 dsk.disk = dsk.daua & DRV_DISK; 361 dsk.unit = dsk.daua & DRV_UNIT; 362 if (dsk.disk == 0x80) 363 dsk.type = TYPE_AD; 364 else if (dsk.disk == 0xa0) 365 dsk.type = TYPE_DA; 366 else /* if (dsk.disk == 0x30 || dsk.disk == 0x90) */ 367 dsk.type = TYPE_FD; 368 dsk.slice = check_slice(); 369#ifdef GET_BIOSGEOM 370 for (i = 0; i < N_BIOS_GEOM; i++) 371 bootinfo.bi_bios_geom[i] = bd_getbigeom(i); 372#endif 373 bootinfo.bi_version = BOOTINFO_VERSION; 374 bootinfo.bi_size = sizeof(bootinfo); 375 376 /* Process configuration file */ 377 378 autoboot = 1; 379 380 if ((ino = lookup(PATH_CONFIG)) || 381 (ino = lookup(PATH_DOTCONFIG))) { 382 nbyte = fsread(ino, cmd, sizeof(cmd) - 1); 383 cmd[nbyte] = '\0'; 384 } 385 386 if (*cmd) { 387 memcpy(cmddup, cmd, sizeof(cmd)); 388 if (parse()) 389 autoboot = 0; 390 if (!OPT_CHECK(RBX_QUIET)) 391 printf("%s: %s", PATH_CONFIG, cmddup); 392 /* Do not process this command twice */ 393 *cmd = 0; 394 } 395 396 /* 397 * Try to exec stage 3 boot loader. If interrupted by a keypress, 398 * or in case of failure, try to load a kernel directly instead. 399 */ 400 401 if (!kname) { 402 kname = PATH_BOOT3; 403 if (autoboot && !keyhit(3*SECOND)) { 404 load(); 405 kname = PATH_KERNEL; 406 } 407 } 408 409 /* Present the user with the boot2 prompt. */ 410 411 for (;;) { 412 if (!autoboot || !OPT_CHECK(RBX_QUIET)) 413 printf("\nFreeBSD/pc98 boot\n" 414 "Default: %u:%s(%u,%c)%s\n" 415 "boot: ", 416 dsk.unit, dev_nm[dsk.type], dsk.unit, 417 'a' + dsk.part, kname); 418 if (ioctrl & IO_SERIAL) 419 sio_flush(); 420 if (!autoboot || keyhit(3*SECOND)) 421 getstr(); 422 else if (!autoboot || !OPT_CHECK(RBX_QUIET)) 423 putchar('\n'); 424 autoboot = 0; 425 if (parse()) 426 putchar('\a'); 427 else 428 load(); 429 } 430} 431 432/* XXX - Needed for btxld to link the boot2 binary; do not remove. */ 433void 434exit(int x) 435{ 436} 437 438static void 439load(void) 440{ 441 union { 442 struct exec ex; 443 Elf32_Ehdr eh; 444 } hdr; 445 static Elf32_Phdr ep[2]; 446 static Elf32_Shdr es[2]; 447 caddr_t p; 448 ufs_ino_t ino; 449 uint32_t addr; 450 int i, j; 451 452 if (!(ino = lookup(kname))) { 453 if (!ls) 454 printf("No %s\n", kname); 455 return; 456 } 457 if (xfsread(ino, &hdr, sizeof(hdr))) 458 return; 459 460 if (N_GETMAGIC(hdr.ex) == ZMAGIC) { 461 addr = hdr.ex.a_entry & 0xffffff; 462 p = PTOV(addr); 463 fs_off = PAGE_SIZE; 464 if (xfsread(ino, p, hdr.ex.a_text)) 465 return; 466 p += roundup2(hdr.ex.a_text, PAGE_SIZE); 467 if (xfsread(ino, p, hdr.ex.a_data)) 468 return; 469 } else if (IS_ELF(hdr.eh)) { 470 fs_off = hdr.eh.e_phoff; 471 for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) { 472 if (xfsread(ino, ep + j, sizeof(ep[0]))) 473 return; 474 if (ep[j].p_type == PT_LOAD) 475 j++; 476 } 477 for (i = 0; i < 2; i++) { 478 p = PTOV(ep[i].p_paddr & 0xffffff); 479 fs_off = ep[i].p_offset; 480 if (xfsread(ino, p, ep[i].p_filesz)) 481 return; 482 } 483 p += roundup2(ep[1].p_memsz, PAGE_SIZE); 484 bootinfo.bi_symtab = VTOP(p); 485 if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { 486 fs_off = hdr.eh.e_shoff + sizeof(es[0]) * 487 (hdr.eh.e_shstrndx + 1); 488 if (xfsread(ino, &es, sizeof(es))) 489 return; 490 for (i = 0; i < 2; i++) { 491 *(Elf32_Word *)p = es[i].sh_size; 492 p += sizeof(es[i].sh_size); 493 fs_off = es[i].sh_offset; 494 if (xfsread(ino, p, es[i].sh_size)) 495 return; 496 p += es[i].sh_size; 497 } 498 } 499 addr = hdr.eh.e_entry & 0xffffff; 500 bootinfo.bi_esymtab = VTOP(p); 501 } else { 502 printf("Invalid %s\n", "format"); 503 return; 504 } 505 506 bootinfo.bi_kernelname = VTOP(kname); 507 bootinfo.bi_bios_dev = dsk.daua; 508 __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), 509 MAKEBOOTDEV(dev_maj[dsk.type], dsk.slice, dsk.unit, dsk.part), 510 0, 0, 0, VTOP(&bootinfo)); 511} 512 513static int 514parse() 515{ 516 char *arg = cmd; 517 char *ep, *p, *q; 518 const char *cp; 519 unsigned int drv; 520 int c, i, j; 521 522 while ((c = *arg++)) { 523 if (c == ' ' || c == '\t' || c == '\n') 524 continue; 525 for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++); 526 ep = p; 527 if (*p) 528 *p++ = 0; 529 if (c == '-') { 530 while ((c = *arg++)) { 531 if (c == 'P') { 532 if (*(uint8_t *)PTOV(0x481) & 0x48) { 533 cp = "yes"; 534 } else { 535 opts |= OPT_SET(RBX_DUAL) | OPT_SET(RBX_SERIAL); 536 cp = "no"; 537 } 538 printf("Keyboard: %s\n", cp); 539 continue; 540 } else if (c == 'S') { 541 j = 0; 542 while ((unsigned int)(i = *arg++ - '0') <= 9) 543 j = j * 10 + i; 544 if (j > 0 && i == -'0') { 545 comspeed = j; 546 break; 547 } 548 /* Fall through to error below ('S' not in optstr[]). */ 549 } 550 for (i = 0; c != optstr[i]; i++) 551 if (i == NOPT - 1) 552 return -1; 553 opts ^= OPT_SET(flags[i]); 554 } 555 ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) : 556 OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD; 557 if (ioctrl & IO_SERIAL) { 558 if (sio_init(115200 / comspeed) != 0) 559 ioctrl &= ~IO_SERIAL; 560 } 561 } else { 562 for (q = arg--; *q && *q != '('; q++); 563 if (*q) { 564 drv = -1; 565 if (arg[1] == ':') { 566 drv = *arg - '0'; 567 if (drv > 9) 568 return (-1); 569 arg += 2; 570 } 571 if (q - arg != 2) 572 return -1; 573 for (i = 0; arg[0] != dev_nm[i][0] || 574 arg[1] != dev_nm[i][1]; i++) 575 if (i == NDEV - 1) 576 return -1; 577 dsk.type = i; 578 arg += 3; 579 dsk.unit = *arg - '0'; 580 if (arg[1] != ',' || dsk.unit > 9) 581 return -1; 582 arg += 2; 583 dsk.slice = WHOLE_DISK_SLICE; 584 if (arg[1] == ',') { 585 dsk.slice = *arg - '0' + 1; 586 if (dsk.slice > PC98_NPARTS + 1) 587 return -1; 588 arg += 2; 589 } 590 if (arg[1] != ')') 591 return -1; 592 dsk.part = *arg - 'a'; 593 if (dsk.part > 7) 594 return (-1); 595 arg += 2; 596 if (drv == -1) 597 drv = dsk.unit; 598 dsk.disk = dev_daua[dsk.type]; 599 dsk.daua = dsk.disk | dsk.unit; 600 dsk_meta = 0; 601 } 602 if ((i = ep - arg)) { 603 if ((size_t)i >= sizeof(knamebuf)) 604 return -1; 605 memcpy(knamebuf, arg, i + 1); 606 kname = knamebuf; 607 } 608 } 609 arg = p; 610 } 611 return 0; 612} 613 614static int 615dskread(void *buf, unsigned lba, unsigned nblk) 616{ 617 struct pc98_partition *dp; 618 struct disklabel *d; 619 char *sec; 620 unsigned i; 621 uint8_t sl; 622 u_char *p; 623 624 if (!dsk_meta) { 625 sec = dmadat->secbuf; 626 set_dsk(); 627 if (dsk.type == TYPE_FD) 628 goto unsliced; 629 if (drvread(sec, PC98_BBSECTOR)) 630 return -1; 631 dp = (void *)(sec + PC98_PARTOFF); 632 sl = dsk.slice; 633 if (sl < BASE_SLICE) { 634 for (i = 0; i < PC98_NPARTS; i++) 635 if (dp[i].dp_mid == DOSMID_386BSD) { 636 sl = BASE_SLICE + i; 637 break; 638 } 639 dsk.slice = sl; 640 } 641 if (sl != WHOLE_DISK_SLICE) { 642 dp += sl - BASE_SLICE; 643 if (dp->dp_mid != DOSMID_386BSD) { 644 printf("Invalid %s\n", "slice"); 645 return -1; 646 } 647 dsk.start = dp->dp_scyl * dsk.head * dsk.sec + 648 dp->dp_shd * dsk.sec + dp->dp_ssect; 649 } 650 if (drvread(sec, dsk.start + LABELSECTOR)) 651 return -1; 652 d = (void *)(sec + LABELOFFSET); 653 if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) { 654 if (dsk.part != RAW_PART) { 655 printf("Invalid %s\n", "label"); 656 return -1; 657 } 658 } else { 659 if (dsk.part >= d->d_npartitions || 660 !d->d_partitions[dsk.part].p_size) { 661 printf("Invalid %s\n", "partition"); 662 return -1; 663 } 664 dsk.start += d->d_partitions[dsk.part].p_offset; 665 dsk.start -= d->d_partitions[RAW_PART].p_offset; 666 } 667 unsliced: ; 668 } 669 for (p = buf; nblk; p += 512, lba++, nblk--) { 670 if ((i = drvread(p, dsk.start + lba))) 671 return i; 672 } 673 return 0; 674} 675 676static void 677printf(const char *fmt,...) 678{ 679 va_list ap; 680 static char buf[10]; 681 char *s; 682 unsigned u; 683 int c; 684 685 va_start(ap, fmt); 686 while ((c = *fmt++)) { 687 if (c == '%') { 688 c = *fmt++; 689 switch (c) { 690 case 'c': 691 putchar(va_arg(ap, int)); 692 continue; 693 case 's': 694 for (s = va_arg(ap, char *); *s; s++) 695 putchar(*s); 696 continue; 697 case 'u': 698 u = va_arg(ap, unsigned); 699 s = buf; 700 do 701 *s++ = '0' + u % 10U; 702 while (u /= 10U); 703 while (--s >= buf) 704 putchar(*s); 705 continue; 706 } 707 } 708 putchar(c); 709 } 710 va_end(ap); 711 return; 712} 713 714static void 715putchar(int c) 716{ 717 if (c == '\n') 718 xputc('\r'); 719 xputc(c); 720} 721 722static int 723drvread(void *buf, unsigned lba) 724{ 725 static unsigned c = 0x2d5c7c2f; 726 unsigned bpc, x, cyl, head, sec; 727 728 bpc = dsk.sec * dsk.head; 729 cyl = lba / bpc; 730 x = lba % bpc; 731 head = x / dsk.sec; 732 sec = x % dsk.sec; 733 734 if (!OPT_CHECK(RBX_QUIET)) 735 printf("%c\b", c = c << 8 | c >> 24); 736 v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; 737 v86.addr = READORG; /* call to read in boot1 */ 738 v86.ecx = cyl; 739 v86.edx = (head << 8) | sec; 740 v86.edi = lba; 741 v86.ebx = 512; 742 v86.es = VTOPSEG(buf); 743 v86.ebp = VTOPOFF(buf); 744 v86int(); 745 v86.ctl = V86_FLAGS; 746 if (V86_CY(v86.efl)) { 747 printf("error %u c/h/s %u/%u/%u lba %u\n", v86.eax >> 8 & 0xff, 748 cyl, head, sec, lba); 749 return -1; 750 } 751 return 0; 752} 753 754static inline void 755delay(void) 756{ 757 int i; 758 759 i = 800; 760 do { 761 outb(0x5f, 0); /* about 600ns */ 762 } while (--i >= 0); 763} 764 765static int 766keyhit(unsigned sec) 767{ 768 unsigned i; 769 770 if (OPT_CHECK(RBX_NOINTR)) 771 return 0; 772 for (i = 0; i < sec * 1000; i++) { 773 if (xgetc(1)) 774 return 1; 775 delay(); 776 } 777 return 0; 778} 779 780static int 781xputc(int c) 782{ 783 if (ioctrl & IO_KEYBOARD) 784 putc(c); 785 if (ioctrl & IO_SERIAL) 786 sio_putc(c); 787 return c; 788} 789 790static int 791getc(int fn) 792{ 793 v86.addr = 0x18; 794 v86.eax = fn << 8; 795 v86int(); 796 if (fn) 797 return (v86.ebx >> 8) & 0x01; 798 else 799 return v86.eax & 0xff; 800} 801 802static int 803xgetc(int fn) 804{ 805 if (OPT_CHECK(RBX_NOINTR)) 806 return 0; 807 for (;;) { 808 if (ioctrl & IO_KEYBOARD && getc(1)) 809 return fn ? 1 : getc(0); 810 if (ioctrl & IO_SERIAL && sio_ischar()) 811 return fn ? 1 : sio_getc(); 812 if (fn) 813 return 0; 814 } 815} 816