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