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