gptboot.c revision 89368
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/* 17 * $FreeBSD: head/sys/boot/i386/gptboot/gptboot.c 89368 2002-01-14 19:39:19Z iedowse $ 18 */ 19 20#include <sys/param.h> 21#include <sys/reboot.h> 22#include <sys/diskslice.h> 23#include <sys/disklabel.h> 24#include <sys/dirent.h> 25#include <machine/bootinfo.h> 26#include <machine/elf.h> 27 28#include <ufs/ffs/fs.h> 29#include <ufs/ufs/dinode.h> 30 31#include <stdarg.h> 32 33#include <a.out.h> 34 35#include <btxv86.h> 36 37#include "boot2.h" 38#include "lib.h" 39 40#define RBX_ASKNAME 0x0 /* -a */ 41#define RBX_SINGLE 0x1 /* -s */ 42#define RBX_DFLTROOT 0x5 /* -r */ 43#define RBX_KDB 0x6 /* -d */ 44#define RBX_CONFIG 0xa /* -c */ 45#define RBX_VERBOSE 0xb /* -v */ 46#define RBX_SERIAL 0xc /* -h */ 47#define RBX_CDROM 0xd /* -C */ 48#define RBX_GDB 0xf /* -g */ 49#define RBX_DUAL 0x1d /* -D */ 50#define RBX_PROBEKBD 0x1e /* -P */ 51 52#define RBX_MASK 0x2000ffff 53 54#define PATH_CONFIG "/boot.config" 55#define PATH_BOOT3 "/boot/loader" 56#define PATH_KERNEL "/kernel" 57 58#define ARGS 0x900 59#define NOPT 11 60#define NDEV 5 61#define MEM_BASE 0x12 62#define MEM_EXT 0x15 63#define V86_CY(x) ((x) & 1) 64#define V86_ZR(x) ((x) & 0x40) 65 66/* 67 * We use 4k `virtual' blocks for filesystem data, whatever the actual 68 * filesystem block size. FFS blocks are always a multiple of 4k. 69 */ 70#define VBLKSIZE 4096 71#define VBLKMASK (VBLKSIZE - 1) 72#define DBPERVBLK (VBLKSIZE / DEV_BSIZE) 73#define IPERVBLK (VBLKSIZE / sizeof(struct dinode)) 74#define INDIRPERVBLK (VBLKSIZE / sizeof(ufs_daddr_t)) 75#define INO_TO_VBA(fs, x) (fsbtodb(fs, ino_to_fsba(fs, x)) + \ 76 (ino_to_fsbo(fs, x) / IPERVBLK) * DBPERVBLK) 77#define INO_TO_VBO(fs, x) (ino_to_fsbo(fs, x) % IPERVBLK) 78#define FS_TO_VBA(fs, fsb, off) (fsbtodb(fs, fsb) + \ 79 ((off) / VBLKSIZE) * DBPERVBLK) 80#define FS_TO_VBO(fs, fsb, off) ((off) & VBLKMASK) 81 82#define DRV_HARD 0x80 83#define DRV_MASK 0x7f 84 85#define TYPE_AD 0 86#define TYPE_WD 1 87#define TYPE_WFD 2 88#define TYPE_FD 3 89#define TYPE_DA 4 90 91extern uint32_t _end; 92 93static const char optstr[NOPT] = "DhaCcdgPrsv"; 94static const unsigned char flags[NOPT] = { 95 RBX_DUAL, 96 RBX_SERIAL, 97 RBX_ASKNAME, 98 RBX_CDROM, 99 RBX_CONFIG, 100 RBX_KDB, 101 RBX_GDB, 102 RBX_PROBEKBD, 103 RBX_DFLTROOT, 104 RBX_SINGLE, 105 RBX_VERBOSE 106}; 107 108static const char *const dev_nm[] = {"ad", "wd", " ", "fd", "da"}; 109static const unsigned dev_maj[] = {30, 0, 1, 2, 4}; 110 111static struct dsk { 112 unsigned drive; 113 unsigned type; 114 unsigned unit; 115 unsigned slice; 116 unsigned part; 117 unsigned start; 118 int init; 119 int meta; 120} dsk; 121static char cmd[512]; 122static char kname[1024]; 123static uint32_t opts; 124static struct bootinfo bootinfo; 125static int ls; 126static uint32_t fs_off; 127static uint8_t ioctrl = 0x1; 128 129void exit(int); 130static void load(const char *); 131static int parse(char *); 132static ino_t lookup(const char *); 133static int xfsread(ino_t, void *, size_t); 134static ssize_t fsread(ino_t, void *, size_t); 135static int dskread(void *, unsigned, unsigned); 136static int printf(const char *,...); 137static int putchar(int); 138static void *memcpy(void *, const void *, size_t); 139static uint32_t memsize(int); 140static int drvread(void *, unsigned, unsigned); 141static int keyhit(unsigned); 142static int xputc(int); 143static int xgetc(int); 144static int getc(int); 145 146static inline void 147readfile(const char *fname, void *buf, size_t size) 148{ 149 ino_t ino; 150 151 if ((ino = lookup(fname))) 152 fsread(ino, buf, size); 153} 154 155static inline int 156strcmp(const char *s1, const char *s2) 157{ 158 for (; *s1 == *s2 && *s1; s1++, s2++); 159 return (u_char)*s1 - (u_char)*s2; 160} 161 162static inline int 163fsfind(const char *name, ino_t * ino) 164{ 165 char buf[DEV_BSIZE]; 166 struct dirent *d; 167 char *s; 168 ssize_t n; 169 170 fs_off = 0; 171 while ((n = fsread(*ino, buf, DEV_BSIZE)) > 0) 172 for (s = buf; s < buf + DEV_BSIZE;) { 173 d = (void *)s; 174 if (ls) 175 printf("%s ", d->d_name); 176 else if (!strcmp(name, d->d_name)) { 177 *ino = d->d_fileno; 178 return d->d_type; 179 } 180 s += d->d_reclen; 181 } 182 if (n != -1 && ls) 183 putchar('\n'); 184 return 0; 185} 186 187static inline int 188getchar(void) 189{ 190 int c; 191 192 c = xgetc(0); 193 if (c == '\r') 194 c = '\n'; 195 return c; 196} 197 198static inline void 199getstr(char *str, int size) 200{ 201 char *s; 202 int c; 203 204 s = str; 205 do { 206 switch (c = getchar()) { 207 case 0: 208 break; 209 case '\b': 210 case '\177': 211 if (s > str) { 212 s--; 213 putchar('\b'); 214 putchar(' '); 215 } else 216 c = 0; 217 break; 218 case '\n': 219 *s = 0; 220 break; 221 default: 222 if (s - str < size - 1) 223 *s++ = c; 224 } 225 if (c) 226 putchar(c); 227 } while (c != '\n'); 228} 229 230static inline uint32_t 231drvinfo(int drive) 232{ 233 v86.addr = 0x13; 234 v86.eax = 0x800; 235 v86.edx = DRV_HARD + drive; 236 v86int(); 237 if (V86_CY(v86.efl)) 238 return 0x4f010f; 239 return ((v86.ecx & 0xc0) << 18) | ((v86.ecx & 0xff00) << 8) | 240 (v86.edx & 0xff00) | (v86.ecx & 0x3f); 241} 242 243static inline void 244putc(int c) 245{ 246 v86.addr = 0x10; 247 v86.eax = 0xe00 | (c & 0xff); 248 v86.ebx = 0x7; 249 v86int(); 250} 251 252int 253main(void) 254{ 255 int autoboot, i; 256 257 v86.ctl = V86_FLAGS; 258 dsk.drive = *(uint8_t *)PTOV(ARGS); 259 dsk.type = dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD; 260 dsk.unit = dsk.drive & DRV_MASK; 261 dsk.slice = *(uint8_t *)PTOV(ARGS + 1) + 1; 262 bootinfo.bi_version = BOOTINFO_VERSION; 263 bootinfo.bi_size = sizeof(bootinfo); 264 bootinfo.bi_basemem = memsize(MEM_BASE); 265 bootinfo.bi_extmem = memsize(MEM_EXT); 266 bootinfo.bi_memsizes_valid++; 267 for (i = 0; i < N_BIOS_GEOM; i++) 268 bootinfo.bi_bios_geom[i] = drvinfo(i); 269 autoboot = 2; 270 readfile(PATH_CONFIG, cmd, sizeof(cmd)); 271 if (*cmd) { 272 printf("%s: %s", PATH_CONFIG, cmd); 273 if (parse(cmd)) 274 autoboot = 0; 275 *cmd = 0; 276 } 277 if (autoboot && !*kname) { 278 if (autoboot == 2) { 279 memcpy(kname, PATH_BOOT3, sizeof(PATH_BOOT3)); 280 if (!keyhit(0x37)) { 281 load(kname); 282 autoboot = 1; 283 } 284 } 285 if (autoboot == 1) 286 memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL)); 287 } 288 for (;;) { 289 printf(" \n>> FreeBSD/i386 BOOT\n" 290 "Default: %u:%s(%u,%c)%s\n" 291 "boot: ", 292 dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit, 293 'a' + dsk.part, kname); 294 if (ioctrl & 0x2) 295 sio_flush(); 296 if (!autoboot || keyhit(0x5a)) 297 getstr(cmd, sizeof(cmd)); 298 else 299 putchar('\n'); 300 autoboot = 0; 301 if (parse(cmd)) 302 putchar('\a'); 303 else 304 load(kname); 305 } 306} 307 308/* XXX - Needed for btxld to link the boot2 binary; do not remove. */ 309void 310exit(int x) 311{ 312} 313 314static void 315load(const char *fname) 316{ 317 union { 318 struct exec ex; 319 Elf32_Ehdr eh; 320 } hdr; 321 Elf32_Phdr ep[2]; 322 Elf32_Shdr es[2]; 323 caddr_t p; 324 ino_t ino; 325 uint32_t addr, x; 326 int fmt, i, j; 327 328 if (!(ino = lookup(fname))) { 329 if (!ls) 330 printf("No %s\n", fname); 331 return; 332 } 333 if (xfsread(ino, &hdr, sizeof(hdr))) 334 return; 335 if (N_GETMAGIC(hdr.ex) == ZMAGIC) 336 fmt = 0; 337 else if (IS_ELF(hdr.eh)) 338 fmt = 1; 339 else { 340 printf("Invalid %s\n", "format"); 341 return; 342 } 343 if (fmt == 0) { 344 addr = hdr.ex.a_entry & 0xffffff; 345 p = PTOV(addr); 346 fs_off = PAGE_SIZE; 347 if (xfsread(ino, p, hdr.ex.a_text)) 348 return; 349 p += roundup2(hdr.ex.a_text, PAGE_SIZE); 350 if (xfsread(ino, p, hdr.ex.a_data)) 351 return; 352 p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE); 353 bootinfo.bi_symtab = VTOP(p); 354 memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms)); 355 p += sizeof(hdr.ex.a_syms); 356 if (hdr.ex.a_syms) { 357 if (xfsread(ino, p, hdr.ex.a_syms)) 358 return; 359 p += hdr.ex.a_syms; 360 if (xfsread(ino, p, sizeof(int))) 361 return; 362 x = *(uint32_t *)p; 363 p += sizeof(int); 364 x -= sizeof(int); 365 if (xfsread(ino, p, x)) 366 return; 367 p += x; 368 } 369 } else { 370 fs_off = hdr.eh.e_phoff; 371 for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) { 372 if (xfsread(ino, ep + j, sizeof(ep[0]))) 373 return; 374 if (ep[j].p_type == PT_LOAD) 375 j++; 376 } 377 for (i = 0; i < 2; i++) { 378 p = PTOV(ep[i].p_paddr & 0xffffff); 379 fs_off = ep[i].p_offset; 380 if (xfsread(ino, p, ep[i].p_filesz)) 381 return; 382 } 383 p += roundup2(ep[1].p_memsz, PAGE_SIZE); 384 bootinfo.bi_symtab = VTOP(p); 385 if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { 386 fs_off = hdr.eh.e_shoff + sizeof(es[0]) * 387 (hdr.eh.e_shstrndx + 1); 388 if (xfsread(ino, &es, sizeof(es))) 389 return; 390 for (i = 0; i < 2; i++) { 391 memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size)); 392 p += sizeof(es[i].sh_size); 393 fs_off = es[i].sh_offset; 394 if (xfsread(ino, p, es[i].sh_size)) 395 return; 396 p += es[i].sh_size; 397 } 398 } 399 addr = hdr.eh.e_entry & 0xffffff; 400 } 401 bootinfo.bi_esymtab = VTOP(p); 402 bootinfo.bi_kernelname = VTOP(fname); 403 bootinfo.bi_bios_dev = dsk.drive; 404 __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), 405 MAKEBOOTDEV(dev_maj[dsk.type], 0, dsk.slice, dsk.unit, dsk.part), 406 0, 0, 0, VTOP(&bootinfo)); 407} 408 409static int 410parse(char *arg) 411{ 412 char *p, *q; 413 int drv, c, i; 414 415 while ((c = *arg++)) { 416 if (c == ' ' || c == '\t' || c == '\n') 417 continue; 418 for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++); 419 if (*p) 420 *p++ = 0; 421 if (c == '-') { 422 while ((c = *arg++)) { 423 for (i = 0; c != optstr[i]; i++) 424 if (i == NOPT - 1) 425 return -1; 426 opts ^= 1 << flags[i]; 427 } 428 if (opts & 1 << RBX_PROBEKBD) { 429 i = *(uint8_t *)PTOV(0x496) & 0x10; 430 printf("Keyboard: %s\n", i ? "yes" : "no"); 431 if (!i) 432 opts |= 1 << RBX_DUAL | 1 << RBX_SERIAL; 433 opts &= ~(1 << RBX_PROBEKBD); 434 } 435 ioctrl = opts & 1 << RBX_DUAL ? 0x3 : 436 opts & 1 << RBX_SERIAL ? 0x2 : 0x1; 437 if (ioctrl & 0x2) 438 sio_init(); 439 } else { 440 for (q = arg--; *q && *q != '('; q++); 441 if (*q) { 442 drv = -1; 443 if (arg[1] == ':') { 444 if (*arg < '0' || *arg > '9') 445 return -1; 446 drv = *arg - '0'; 447 arg += 2; 448 } 449 if (q - arg != 2) 450 return -1; 451 for (i = 0; arg[0] != dev_nm[i][0] || 452 arg[1] != dev_nm[i][1]; i++) 453 if (i == NDEV - 1) 454 return -1; 455 dsk.type = i; 456 arg += 3; 457 if (arg[1] != ',' || *arg < '0' || *arg > '9') 458 return -1; 459 dsk.unit = *arg - '0'; 460 arg += 2; 461 dsk.slice = WHOLE_DISK_SLICE; 462 if (arg[1] == ',') { 463 if (*arg < '0' || *arg > '0' + NDOSPART) 464 return -1; 465 if ((dsk.slice = *arg - '0')) 466 dsk.slice++; 467 arg += 2; 468 } 469 if (arg[1] != ')' || *arg < 'a' || *arg > 'p') 470 return -1; 471 dsk.part = *arg - 'a'; 472 arg += 2; 473 if (drv == -1) 474 drv = dsk.unit; 475 dsk.drive = (dsk.type == TYPE_WD || 476 dsk.type == TYPE_AD || 477 dsk.type == TYPE_DA ? DRV_HARD : 0) + drv; 478 dsk.meta = 0; 479 fsread(0, NULL, 0); 480 } 481 if ((i = p - arg - !*(p - 1))) { 482 if (i >= sizeof(kname)) 483 return -1; 484 memcpy(kname, arg, i + 1); 485 } 486 } 487 arg = p; 488 } 489 return 0; 490} 491 492static ino_t 493lookup(const char *path) 494{ 495 char name[MAXNAMLEN + 1]; 496 const char *s; 497 ino_t ino; 498 ssize_t n; 499 int dt; 500 501 ino = ROOTINO; 502 dt = DT_DIR; 503 for (;;) { 504 if (*path == '/') 505 path++; 506 if (!*path) 507 break; 508 for (s = path; *s && *s != '/'; s++); 509 if ((n = s - path) > MAXNAMLEN) 510 return 0; 511 ls = *path == '?' && n == 1 && !*s; 512 memcpy(name, path, n); 513 name[n] = 0; 514 if ((dt = fsfind(name, &ino)) <= 0) 515 break; 516 path = s; 517 } 518 return dt == DT_REG ? ino : 0; 519} 520static int 521xfsread(ino_t inode, void *buf, size_t nbyte) 522{ 523 if (fsread(inode, buf, nbyte) != nbyte) { 524 printf("Invalid %s\n", "format"); 525 return -1; 526 } 527 return 0; 528} 529 530static ssize_t 531fsread(ino_t inode, void *buf, size_t nbyte) 532{ 533 static char blkbuf[VBLKSIZE]; 534 static ufs_daddr_t indbuf[VBLKSIZE / sizeof(ufs_daddr_t)]; 535 static char sbbuf[SBSIZE]; 536 static struct dinode din; 537 static struct fs *fs = (struct fs *)sbbuf; 538 static ino_t inomap; 539 static daddr_t blkmap, indmap; 540 char *s; 541 ufs_daddr_t lbn, addr; 542 daddr_t vbaddr; 543 size_t n, nb, off, vboff; 544 545 if (!dsk.meta) { 546 inomap = 0; 547 if (dskread(sbbuf, SBOFF / DEV_BSIZE, SBSIZE / DEV_BSIZE)) 548 return -1; 549 if (fs->fs_magic != FS_MAGIC) { 550 printf("Not ufs\n"); 551 return -1; 552 } 553 dsk.meta++; 554 } 555 if (!inode) 556 return 0; 557 if (inomap != inode) { 558 if (dskread(blkbuf, INO_TO_VBA(fs, inode), DBPERVBLK)) 559 return -1; 560 din = ((struct dinode *)blkbuf)[INO_TO_VBO(fs, inode)]; 561 inomap = inode; 562 fs_off = 0; 563 blkmap = indmap = 0; 564 } 565 s = buf; 566 if (nbyte > (n = din.di_size - fs_off)) 567 nbyte = n; 568 nb = nbyte; 569 while (nb) { 570 lbn = lblkno(fs, fs_off); 571 off = blkoff(fs, fs_off); 572 if (lbn < NDADDR) 573 addr = din.di_db[lbn]; 574 else { 575 vbaddr = FS_TO_VBA(fs, din.di_ib[0], sizeof(indbuf[0]) * 576 ((lbn - NDADDR) % NINDIR(fs))); 577 if (indmap != vbaddr) { 578 if (dskread(indbuf, vbaddr, DBPERVBLK)) 579 return -1; 580 indmap = vbaddr; 581 } 582 addr = indbuf[(lbn - NDADDR) % INDIRPERVBLK]; 583 } 584 vbaddr = FS_TO_VBA(fs, addr, off); 585 vboff = FS_TO_VBO(fs, addr, off); 586 n = dblksize(fs, &din, lbn) - (off & ~VBLKMASK); 587 if (n > VBLKSIZE) 588 n = VBLKSIZE; 589 if (blkmap != vbaddr) { 590 if (dskread(blkbuf, vbaddr, n >> DEV_BSHIFT)) 591 return -1; 592 blkmap = vbaddr; 593 } 594 n -= vboff; 595 if (n > nb) 596 n = nb; 597 memcpy(s, blkbuf + vboff, n); 598 s += n; 599 fs_off += n; 600 nb -= n; 601 } 602 return nbyte; 603} 604 605static int 606dskread(void *buf, unsigned lba, unsigned nblk) 607{ 608 static char sec[DEV_BSIZE]; 609 struct dos_partition *dp; 610 struct disklabel *d; 611 unsigned sl, i; 612 613 if (!dsk.meta) { 614 dsk.start = 0; 615 if (drvread(sec, DOSBBSECTOR, 1)) 616 return -1; 617 dp = (void *)(sec + DOSPARTOFF); 618 sl = dsk.slice; 619 if (sl < BASE_SLICE) { 620 for (i = 0; i < NDOSPART; i++) 621 if (dp[i].dp_typ == DOSPTYP_386BSD && 622 (dp[i].dp_flag & 0x80 || sl < BASE_SLICE)) { 623 sl = BASE_SLICE + i; 624 if (dp[i].dp_flag & 0x80 || 625 dsk.slice == COMPATIBILITY_SLICE) 626 break; 627 } 628 if (dsk.slice == WHOLE_DISK_SLICE) 629 dsk.slice = sl; 630 } 631 if (sl != WHOLE_DISK_SLICE) { 632 if (sl != COMPATIBILITY_SLICE) 633 dp += sl - BASE_SLICE; 634 if (dp->dp_typ != DOSPTYP_386BSD) { 635 printf("Invalid %s\n", "slice"); 636 return -1; 637 } 638 dsk.start = dp->dp_start; 639 } 640 if (drvread(sec, dsk.start + LABELSECTOR, 1)) 641 return -1; 642 d = (void *)(sec + LABELOFFSET); 643 if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) { 644 if (dsk.part != RAW_PART) { 645 printf("Invalid %s\n", "label"); 646 return -1; 647 } 648 } else { 649 if (!dsk.init) { 650 if (d->d_type == DTYPE_SCSI) 651 dsk.type = TYPE_DA; 652 dsk.init++; 653 } 654 if (dsk.part >= d->d_npartitions || 655 !d->d_partitions[dsk.part].p_size) { 656 printf("Invalid %s\n", "partition"); 657 return -1; 658 } 659 dsk.start = d->d_partitions[dsk.part].p_offset; 660 } 661 } 662 return drvread(buf, dsk.start + lba, nblk); 663} 664 665static int 666printf(const char *fmt,...) 667{ 668 static const char digits[16] = "0123456789abcdef"; 669 va_list ap; 670 char buf[10]; 671 char *s; 672 unsigned r, u; 673 int c; 674 675 va_start(ap, fmt); 676 while ((c = *fmt++)) { 677 if (c == '%') { 678 c = *fmt++; 679 switch (c) { 680 case 'c': 681 putchar(va_arg(ap, int)); 682 continue; 683 case 's': 684 for (s = va_arg(ap, char *); *s; s++) 685 putchar(*s); 686 continue; 687 case 'u': 688 case 'x': 689 r = c == 'u' ? 10U : 16U; 690 u = va_arg(ap, unsigned); 691 s = buf; 692 do 693 *s++ = digits[u % r]; 694 while (u /= r); 695 while (--s >= buf) 696 putchar(*s); 697 continue; 698 } 699 } 700 putchar(c); 701 } 702 va_end(ap); 703 return 0; 704} 705 706static int 707putchar(int c) 708{ 709 if (c == '\n') 710 xputc('\r'); 711 return xputc(c); 712} 713 714static void * 715memcpy(void *dst, const void *src, size_t size) 716{ 717 const char *s; 718 char *d; 719 720 for (d = dst, s = src; size; size--) 721 *d++ = *s++; 722 return dst; 723} 724 725static uint32_t 726memsize(int type) 727{ 728 v86.addr = type; 729 v86.eax = 0x8800; 730 v86int(); 731 return v86.eax; 732} 733 734static int 735drvread(void *buf, unsigned lba, unsigned nblk) 736{ 737 static unsigned c = 0x2d5c7c2f; 738 739 printf("%c\b", c = c << 8 | c >> 24); 740 v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; 741 v86.addr = XREADORG; /* call to xread in boot1 */ 742 v86.es = VTOPSEG(buf); 743 v86.eax = lba; 744 v86.ebx = VTOPOFF(buf); 745 v86.ecx = lba >> 16; 746 v86.edx = nblk << 8 | dsk.drive; 747 v86int(); 748 v86.ctl = V86_FLAGS; 749 if (V86_CY(v86.efl)) { 750 printf("Disk error 0x%x (lba=0x%x)\n", v86.eax >> 8 & 0xff, 751 lba); 752 return -1; 753 } 754 return 0; 755} 756 757static int 758keyhit(unsigned ticks) 759{ 760 uint32_t t0, t1; 761 762 t0 = 0; 763 for (;;) { 764 if (xgetc(1)) 765 return 1; 766 t1 = *(uint32_t *)PTOV(0x46c); 767 if (!t0) 768 t0 = t1; 769 if (t1 < t0 || t1 >= t0 + ticks) 770 return 0; 771 } 772} 773 774static int 775xputc(int c) 776{ 777 if (ioctrl & 0x1) 778 putc(c); 779 if (ioctrl & 0x2) 780 sio_putc(c); 781 return c; 782} 783 784static int 785xgetc(int fn) 786{ 787 for (;;) { 788 if (ioctrl & 0x1 && getc(1)) 789 return fn ? 1 : getc(0); 790 if (ioctrl & 0x2 && sio_ischar()) 791 return fn ? 1 : sio_getc(); 792 if (fn) 793 return 0; 794 } 795} 796 797static int 798getc(int fn) 799{ 800 v86.addr = 0x16; 801 v86.eax = fn << 8; 802 v86int(); 803 return fn == 0 ? v86.eax & 0xff : !V86_ZR(v86.efl); 804} 805