gptboot.c revision 135410
155714Skris/*- 255714Skris * Copyright (c) 1998 Robert Nordier 355714Skris * All rights reserved. 455714Skris * 555714Skris * Redistribution and use in source and binary forms are freely 655714Skris * permitted provided that the above copyright notice and this 755714Skris * paragraph and the following disclaimer are duplicated in all 8280297Sjkim * such forms. 955714Skris * 1055714Skris * This software is provided "AS IS" and without any express or 1155714Skris * implied warranties, including, without limitation, the implied 1255714Skris * warranties of merchantability and fitness for a particular 1355714Skris * purpose. 1455714Skris */ 15280297Sjkim 1655714Skris#include <sys/cdefs.h> 1755714Skris__FBSDID("$FreeBSD: head/sys/boot/i386/gptboot/gptboot.c 135410 2004-09-18 02:07:00Z jhb $"); 1855714Skris 1955714Skris#include <sys/param.h> 2055714Skris#include <sys/disklabel.h> 2155714Skris#include <sys/diskmbr.h> 22280297Sjkim#include <sys/dirent.h> 2355714Skris#include <sys/reboot.h> 2455714Skris 2555714Skris#include <machine/bootinfo.h> 2655714Skris#include <machine/elf.h> 2755714Skris 2855714Skris#include <stdarg.h> 2955714Skris 3055714Skris#include <a.out.h> 3155714Skris 3255714Skris#include <btxv86.h> 3355714Skris 3455714Skris#include "boot2.h" 3555714Skris#include "lib.h" 3655714Skris 37280297Sjkim#define IO_KEYBOARD 1 3855714Skris#define IO_SERIAL 2 3955714Skris 40280297Sjkim#define SECOND 18 /* Circa that many ticks in a second. */ 4155714Skris 4255714Skris#define RBX_ASKNAME 0x0 /* -a */ 4355714Skris#define RBX_SINGLE 0x1 /* -s */ 4455714Skris/* 0x2 is reserved for log2(RB_NOSYNC). */ 4555714Skris/* 0x3 is reserved for log2(RB_HALT). */ 4655714Skris/* 0x4 is reserved for log2(RB_INITNAME). */ 4755714Skris#define RBX_DFLTROOT 0x5 /* -r */ 4855714Skris#define RBX_KDB 0x6 /* -d */ 4955714Skris/* 0x7 is reserved for log2(RB_RDONLY). */ 5055714Skris/* 0x8 is reserved for log2(RB_DUMP). */ 5155714Skris/* 0x9 is reserved for log2(RB_MINIROOT). */ 52280297Sjkim#define RBX_CONFIG 0xa /* -c */ 5355714Skris#define RBX_VERBOSE 0xb /* -v */ 5455714Skris#define RBX_SERIAL 0xc /* -h */ 5555714Skris#define RBX_CDROM 0xd /* -C */ 5655714Skris/* 0xe is reserved for log2(RB_POWEROFF). */ 5755714Skris#define RBX_GDB 0xf /* -g */ 5855714Skris#define RBX_MUTE 0x10 /* -m */ 5955714Skris/* 0x11 is reserved for log2(RB_SELFTEST). */ 6055714Skris/* 0x12 is reserved for boot programs. */ 6155714Skris/* 0x13 is reserved for boot programs. */ 6255714Skris#define RBX_PAUSE 0x14 /* -p */ 6355714Skris#define RBX_NOINTR 0x1c /* -n */ 6468651Skris/* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */ 6568651Skris#define RBX_DUAL 0x1d /* -D */ 6668651Skris#define RBX_PROBEKBD 0x1e /* -P */ 6768651Skris/* 0x1f is reserved for log2(RB_BOOTINFO). */ 6868651Skris 6955714Skris/* pass: -a, -s, -r, -d, -c, -v, -h, -C, -g, -m, -p, -D */ 7055714Skris#define RBX_MASK 0x2005ffff 71280297Sjkim 72280297Sjkim#define PATH_CONFIG "/boot.config" 73280297Sjkim#define PATH_BOOT3 "/boot/loader" 74280297Sjkim#define PATH_KERNEL "/kernel" 75280297Sjkim 76280297Sjkim#define ARGS 0x900 77280297Sjkim#define NOPT 12 78280297Sjkim#define NDEV 3 79280297Sjkim#define MEM_BASE 0x12 80280297Sjkim#define MEM_EXT 0x15 81280297Sjkim#define V86_CY(x) ((x) & 1) 82280297Sjkim#define V86_ZR(x) ((x) & 0x40) 8355714Skris 84280297Sjkim#define DRV_HARD 0x80 85280297Sjkim#define DRV_MASK 0x7f 86280297Sjkim 87280297Sjkim#define TYPE_AD 0 8855714Skris#define TYPE_DA 1 8955714Skris#define TYPE_MAXHARD TYPE_DA 90280297Sjkim#define TYPE_FD 2 91280297Sjkim 92280297Sjkimextern uint32_t _end; 9355714Skris 94296279Sjkimstatic const char optstr[NOPT] = "DhaCgmnPprsv"; 95296279Sjkimstatic const unsigned char flags[NOPT] = { 9659191Skris RBX_DUAL, 97280297Sjkim RBX_SERIAL, 98280297Sjkim RBX_ASKNAME, 99280297Sjkim RBX_CDROM, 100238405Sjkim RBX_GDB, 101280297Sjkim RBX_MUTE, 102280297Sjkim RBX_NOINTR, 103280297Sjkim RBX_PROBEKBD, 104280297Sjkim RBX_PAUSE, 105280297Sjkim RBX_DFLTROOT, 106280297Sjkim RBX_SINGLE, 107280297Sjkim RBX_VERBOSE 108280297Sjkim}; 109296279Sjkim 110296279Sjkimstatic const char *const dev_nm[NDEV] = {"ad", "da", "fd"}; 111280297Sjkimstatic const unsigned char dev_maj[NDEV] = {30, 4, 2}; 112280297Sjkim 113280297Sjkimstatic struct dsk { 114280297Sjkim unsigned drive; 115280297Sjkim unsigned type; 116280297Sjkim unsigned unit; 11759191Skris unsigned slice; 11859191Skris unsigned part; 11955714Skris unsigned start; 120280297Sjkim int init; 121280297Sjkim} dsk; 12255714Skrisstatic char cmd[512]; 123280297Sjkimstatic char kname[1024]; 124280297Sjkimstatic uint32_t opts; 125280297Sjkimstatic struct bootinfo bootinfo; 126280297Sjkimstatic uint8_t ioctrl = IO_KEYBOARD; 127280297Sjkim 128280297Sjkimvoid exit(int); 129280297Sjkimstatic void load(void); 130280297Sjkimstatic int parse(void); 13155714Skrisstatic int xfsread(ino_t, void *, size_t); 13255714Skrisstatic int dskread(void *, unsigned, unsigned); 133280297Sjkimstatic void printf(const char *,...); 134280297Sjkimstatic void putchar(int); 135280297Sjkimstatic uint32_t memsize(void); 136280297Sjkimstatic int drvread(void *, unsigned, unsigned); 137280297Sjkimstatic int keyhit(unsigned); 138280297Sjkimstatic int xputc(int); 139280297Sjkimstatic int xgetc(int); 140280297Sjkimstatic int getc(int); 141280297Sjkim 142280297Sjkimstatic void memcpy(void *, const void *, int); 143280297Sjkimstatic void 144280297Sjkimmemcpy(void *dst, const void *src, int len) 145280297Sjkim{ 146280297Sjkim const char *s = src; 147280297Sjkim char *d = dst; 148280297Sjkim 14955714Skris while (len--) 150280297Sjkim *d++ = *s++; 151280297Sjkim} 152280297Sjkim 15355714Skrisstatic inline int 154280297Sjkimstrcmp(const char *s1, const char *s2) 155280297Sjkim{ 156280297Sjkim for (; *s1 == *s2 && *s1; s1++, s2++); 157280297Sjkim return (unsigned char)*s1 - (unsigned char)*s2; 158280297Sjkim} 159280297Sjkim 160280297Sjkim#include "ufsread.c" 161280297Sjkim 162280297Sjkimstatic int 163280297Sjkimxfsread(ino_t inode, void *buf, size_t nbyte) 164280297Sjkim{ 165280297Sjkim if ((size_t)fsread(inode, buf, nbyte) != nbyte) { 166280297Sjkim printf("Invalid %s\n", "format"); 167280297Sjkim return -1; 168280297Sjkim } 169280297Sjkim return 0; 170280297Sjkim} 171280297Sjkim 17255714Skrisstatic inline uint32_t 17368651Skrismemsize(void) 174280297Sjkim{ 175280297Sjkim v86.addr = MEM_EXT; 176280297Sjkim v86.eax = 0x8800; 177280297Sjkim v86int(); 17855714Skris return v86.eax; 179280297Sjkim} 180280297Sjkim 181280297Sjkimstatic inline void 182280297Sjkimgetstr(void) 183280297Sjkim{ 18455714Skris char *s; 185280297Sjkim int c; 186280297Sjkim 187280297Sjkim s = cmd; 188280297Sjkim for (;;) { 18959191Skris switch (c = xgetc(0)) { 190280297Sjkim case 0: 191280297Sjkim break; 192280297Sjkim case '\177': 193280297Sjkim case '\b': 194280297Sjkim if (s > cmd) { 195280297Sjkim s--; 196280297Sjkim printf("\b \b"); 197280297Sjkim } 198280297Sjkim break; 19955714Skris case '\n': 20068651Skris case '\r': 201280297Sjkim *s = 0; 202280297Sjkim return; 203280297Sjkim default: 20455714Skris if (s - cmd < sizeof(cmd) - 1) 205280297Sjkim *s++ = c; 20655714Skris putchar(c); 207280297Sjkim } 208280297Sjkim } 209280297Sjkim} 210280297Sjkim 211280297Sjkimstatic inline void 212280297Sjkimputc(int c) 213280297Sjkim{ 214280297Sjkim v86.addr = 0x10; 215280297Sjkim v86.eax = 0xe00 | (c & 0xff); 216280297Sjkim v86.ebx = 0x7; 217280297Sjkim v86int(); 218280297Sjkim} 219280297Sjkim 220280297Sjkimint 221280297Sjkimmain(void) 222280297Sjkim{ 223280297Sjkim int autoboot; 224280297Sjkim ino_t ino; 225280297Sjkim 226280297Sjkim dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base); 227280297Sjkim v86.ctl = V86_FLAGS; 228280297Sjkim dsk.drive = *(uint8_t *)PTOV(ARGS); 229280297Sjkim dsk.type = dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD; 230280297Sjkim dsk.unit = dsk.drive & DRV_MASK; 231280297Sjkim dsk.slice = *(uint8_t *)PTOV(ARGS + 1) + 1; 232280297Sjkim bootinfo.bi_version = BOOTINFO_VERSION; 233280297Sjkim bootinfo.bi_size = sizeof(bootinfo); 234280297Sjkim bootinfo.bi_basemem = 0; /* XXX will be filled by loader or kernel */ 235280297Sjkim bootinfo.bi_extmem = memsize(); 236280297Sjkim bootinfo.bi_memsizes_valid++; 237280297Sjkim 238280297Sjkim /* Process configuration file */ 239280297Sjkim 240280297Sjkim autoboot = 1; 241280297Sjkim 242280297Sjkim if ((ino = lookup(PATH_CONFIG))) 243280297Sjkim fsread(ino, cmd, sizeof(cmd)); 244280297Sjkim 245280297Sjkim if (*cmd) { 246280297Sjkim printf("%s: %s", PATH_CONFIG, cmd); 247280297Sjkim if (parse()) 248280297Sjkim autoboot = 0; 249280297Sjkim /* Do not process this command twice */ 25055714Skris *cmd = 0; 251280297Sjkim } 252280297Sjkim 253280297Sjkim /* 254280297Sjkim * Try to exec stage 3 boot loader. If interrupted by a keypress, 255280297Sjkim * or in case of failure, try to load a kernel directly instead. 256280297Sjkim */ 257280297Sjkim 258280297Sjkim if (autoboot && !*kname) { 259280297Sjkim memcpy(kname, PATH_BOOT3, sizeof(PATH_BOOT3)); 260280297Sjkim if (!keyhit(3*SECOND)) { 261280297Sjkim load(); 262280297Sjkim memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL)); 263280297Sjkim } 264280297Sjkim } 265280297Sjkim 266280297Sjkim /* Present the user with the boot2 prompt. */ 267280297Sjkim 268280297Sjkim for (;;) { 26955714Skris printf("\nFreeBSD/i386 boot\n" 27055714Skris "Default: %u:%s(%u,%c)%s\n" 271280297Sjkim "boot: ", 272280297Sjkim dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit, 273280297Sjkim 'a' + dsk.part, kname); 274280297Sjkim if (ioctrl & IO_SERIAL) 275280297Sjkim sio_flush(); 27655714Skris if (!autoboot || keyhit(5*SECOND)) 277280297Sjkim getstr(); 278280297Sjkim else 279280297Sjkim putchar('\n'); 280280297Sjkim autoboot = 0; 281280297Sjkim if (parse()) 282280297Sjkim putchar('\a'); 283280297Sjkim else 284280297Sjkim load(); 285280297Sjkim } 286280297Sjkim} 287280297Sjkim 288280297Sjkim/* XXX - Needed for btxld to link the boot2 binary; do not remove. */ 289280297Sjkimvoid 290280297Sjkimexit(int x) 291280297Sjkim{ 292194206Ssimon} 293280297Sjkim 294280297Sjkimstatic void 295280297Sjkimload(void) 296280297Sjkim{ 297194206Ssimon union { 298280297Sjkim struct exec ex; 299280297Sjkim Elf32_Ehdr eh; 300280297Sjkim } hdr; 301280297Sjkim Elf32_Phdr ep[2]; 302280297Sjkim Elf32_Shdr es[2]; 303280297Sjkim caddr_t p; 30455714Skris ino_t ino; 30568651Skris uint32_t addr, x; 306280297Sjkim int fmt, i, j; 307280297Sjkim 30855714Skris if (!(ino = lookup(kname))) { 309280297Sjkim if (!ls) 310280297Sjkim printf("No %s\n", kname); 311280297Sjkim return; 312280297Sjkim } 313280297Sjkim if (xfsread(ino, &hdr, sizeof(hdr))) 314 return; 315 if (N_GETMAGIC(hdr.ex) == ZMAGIC) 316 fmt = 0; 317 else if (IS_ELF(hdr.eh)) 318 fmt = 1; 319 else { 320 printf("Invalid %s\n", "format"); 321 return; 322 } 323 if (fmt == 0) { 324 addr = hdr.ex.a_entry; 325 p = PTOV(addr); 326 fs_off = PAGE_SIZE; 327 if (xfsread(ino, p, hdr.ex.a_text)) 328 return; 329 p += roundup2(hdr.ex.a_text, PAGE_SIZE); 330 if (xfsread(ino, p, hdr.ex.a_data)) 331 return; 332 p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE); 333 bootinfo.bi_symtab = VTOP(p); 334 memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms)); 335 p += sizeof(hdr.ex.a_syms); 336 if (hdr.ex.a_syms) { 337 if (xfsread(ino, p, hdr.ex.a_syms)) 338 return; 339 p += hdr.ex.a_syms; 340 if (xfsread(ino, p, sizeof(int))) 341 return; 342 x = *(uint32_t *)p; 343 p += sizeof(int); 344 x -= sizeof(int); 345 if (xfsread(ino, p, x)) 346 return; 347 p += x; 348 } 349 } else { 350 fs_off = hdr.eh.e_phoff; 351 for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) { 352 if (xfsread(ino, ep + j, sizeof(ep[0]))) 353 return; 354 if (ep[j].p_type == PT_LOAD) 355 j++; 356 } 357 for (i = 0; i < 2; i++) { 358 p = PTOV(ep[i].p_paddr); 359 fs_off = ep[i].p_offset; 360 if (xfsread(ino, p, ep[i].p_filesz)) 361 return; 362 } 363 p += roundup2(ep[1].p_memsz, PAGE_SIZE); 364 bootinfo.bi_symtab = VTOP(p); 365 if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { 366 fs_off = hdr.eh.e_shoff + sizeof(es[0]) * 367 (hdr.eh.e_shstrndx + 1); 368 if (xfsread(ino, &es, sizeof(es))) 369 return; 370 for (i = 0; i < 2; i++) { 371 memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size)); 372 p += sizeof(es[i].sh_size); 373 fs_off = es[i].sh_offset; 374 if (xfsread(ino, p, es[i].sh_size)) 375 return; 376 p += es[i].sh_size; 377 } 378 } 379 addr = hdr.eh.e_entry; 380 } 381 bootinfo.bi_esymtab = VTOP(p); 382 bootinfo.bi_kernelname = VTOP(kname); 383 bootinfo.bi_bios_dev = dsk.drive; 384 __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), 385 MAKEBOOTDEV(dev_maj[dsk.type], 0, dsk.slice, dsk.unit, dsk.part), 386 0, 0, 0, VTOP(&bootinfo)); 387} 388 389static int 390parse() 391{ 392 char *arg = cmd; 393 char *p, *q; 394 unsigned int drv; 395 int c, i; 396 397 while ((c = *arg++)) { 398 if (c == ' ' || c == '\t' || c == '\n') 399 continue; 400 for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++); 401 if (*p) 402 *p++ = 0; 403 if (c == '-') { 404 while ((c = *arg++)) { 405 for (i = 0; c != optstr[i]; i++) 406 if (i == NOPT - 1) 407 return -1; 408 opts ^= 1 << flags[i]; 409 } 410 if (opts & 1 << RBX_PROBEKBD) { 411 i = *(uint8_t *)PTOV(0x496) & 0x10; 412 printf("Keyboard: %s\n", i ? "yes" : "no"); 413 if (!i) 414 opts |= 1 << RBX_DUAL | 1 << RBX_SERIAL; 415 opts &= ~(1 << RBX_PROBEKBD); 416 } 417 ioctrl = opts & 1 << RBX_DUAL ? (IO_SERIAL|IO_KEYBOARD) : 418 opts & 1 << RBX_SERIAL ? IO_SERIAL : IO_KEYBOARD; 419 if (ioctrl & IO_SERIAL) 420 sio_init(); 421 } else { 422 for (q = arg--; *q && *q != '('; q++); 423 if (*q) { 424 drv = -1; 425 if (arg[1] == ':') { 426 drv = *arg - '0'; 427 if (drv > 9) 428 return (-1); 429 arg += 2; 430 } 431 if (q - arg != 2) 432 return -1; 433 for (i = 0; arg[0] != dev_nm[i][0] || 434 arg[1] != dev_nm[i][1]; i++) 435 if (i == NDEV - 1) 436 return -1; 437 dsk.type = i; 438 arg += 3; 439 dsk.unit = *arg - '0'; 440 if (arg[1] != ',' || dsk.unit > 9) 441 return -1; 442 arg += 2; 443 dsk.slice = WHOLE_DISK_SLICE; 444 if (arg[1] == ',') { 445 dsk.slice = *arg - '0' + 1; 446 if (dsk.slice > NDOSPART) 447 return -1; 448 arg += 2; 449 } 450 if (arg[1] != ')') 451 return -1; 452 dsk.part = *arg - 'a'; 453 if (dsk.part > 7) 454 return (-1); 455 arg += 2; 456 if (drv == -1) 457 drv = dsk.unit; 458 dsk.drive = (dsk.type <= TYPE_MAXHARD 459 ? DRV_HARD : 0) + drv; 460 dsk_meta = 0; 461 } 462 if ((i = p - arg - !*(p - 1))) { 463 if ((size_t)i >= sizeof(kname)) 464 return -1; 465 memcpy(kname, arg, i + 1); 466 } 467 } 468 arg = p; 469 } 470 return 0; 471} 472 473static int 474dskread(void *buf, unsigned lba, unsigned nblk) 475{ 476 struct dos_partition *dp; 477 struct disklabel *d; 478 char *sec; 479 unsigned sl, i; 480 481 if (!dsk_meta) { 482 sec = dmadat->secbuf; 483 dsk.start = 0; 484 if (drvread(sec, DOSBBSECTOR, 1)) 485 return -1; 486 dp = (void *)(sec + DOSPARTOFF); 487 sl = dsk.slice; 488 if (sl < BASE_SLICE) { 489 for (i = 0; i < NDOSPART; i++) 490 if (dp[i].dp_typ == DOSPTYP_386BSD && 491 (dp[i].dp_flag & 0x80 || sl < BASE_SLICE)) { 492 sl = BASE_SLICE + i; 493 if (dp[i].dp_flag & 0x80 || 494 dsk.slice == COMPATIBILITY_SLICE) 495 break; 496 } 497 if (dsk.slice == WHOLE_DISK_SLICE) 498 dsk.slice = sl; 499 } 500 if (sl != WHOLE_DISK_SLICE) { 501 if (sl != COMPATIBILITY_SLICE) 502 dp += sl - BASE_SLICE; 503 if (dp->dp_typ != DOSPTYP_386BSD) { 504 printf("Invalid %s\n", "slice"); 505 return -1; 506 } 507 dsk.start = dp->dp_start; 508 } 509 if (drvread(sec, dsk.start + LABELSECTOR, 1)) 510 return -1; 511 d = (void *)(sec + LABELOFFSET); 512 if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) { 513 if (dsk.part != RAW_PART) { 514 printf("Invalid %s\n", "label"); 515 return -1; 516 } 517 } else { 518 if (!dsk.init) { 519 if (d->d_type == DTYPE_SCSI) 520 dsk.type = TYPE_DA; 521 dsk.init++; 522 } 523 if (dsk.part >= d->d_npartitions || 524 !d->d_partitions[dsk.part].p_size) { 525 printf("Invalid %s\n", "partition"); 526 return -1; 527 } 528 dsk.start += d->d_partitions[dsk.part].p_offset; 529 dsk.start -= d->d_partitions[RAW_PART].p_offset; 530 } 531 } 532 return drvread(buf, dsk.start + lba, nblk); 533} 534 535static void 536printf(const char *fmt,...) 537{ 538 va_list ap; 539 char buf[10]; 540 char *s; 541 unsigned u; 542 int c; 543 544 va_start(ap, fmt); 545 while ((c = *fmt++)) { 546 if (c == '%') { 547 c = *fmt++; 548 switch (c) { 549 case 'c': 550 putchar(va_arg(ap, int)); 551 continue; 552 case 's': 553 for (s = va_arg(ap, char *); *s; s++) 554 putchar(*s); 555 continue; 556 case 'u': 557 u = va_arg(ap, unsigned); 558 s = buf; 559 do 560 *s++ = '0' + u % 10U; 561 while (u /= 10U); 562 while (--s >= buf) 563 putchar(*s); 564 continue; 565 } 566 } 567 putchar(c); 568 } 569 va_end(ap); 570 return; 571} 572 573static void 574putchar(int c) 575{ 576 if (c == '\n') 577 xputc('\r'); 578 xputc(c); 579} 580 581static int 582drvread(void *buf, unsigned lba, unsigned nblk) 583{ 584 static unsigned c = 0x2d5c7c2f; 585 586 printf("%c\b", c = c << 8 | c >> 24); 587 v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; 588 v86.addr = XREADORG; /* call to xread in boot1 */ 589 v86.es = VTOPSEG(buf); 590 v86.eax = lba; 591 v86.ebx = VTOPOFF(buf); 592 v86.ecx = lba >> 16; 593 v86.edx = nblk << 8 | dsk.drive; 594 v86int(); 595 v86.ctl = V86_FLAGS; 596 if (V86_CY(v86.efl)) { 597 printf("error %u lba %u\n", v86.eax >> 8 & 0xff, lba); 598 return -1; 599 } 600 return 0; 601} 602 603static int 604keyhit(unsigned ticks) 605{ 606 uint32_t t0, t1; 607 608 if (opts & 1 << RBX_NOINTR) 609 return 0; 610 t0 = 0; 611 for (;;) { 612 if (xgetc(1)) 613 return 1; 614 t1 = *(uint32_t *)PTOV(0x46c); 615 if (!t0) 616 t0 = t1; 617 if (t1 < t0 || t1 >= t0 + ticks) 618 return 0; 619 } 620} 621 622static int 623xputc(int c) 624{ 625 if (ioctrl & IO_KEYBOARD) 626 putc(c); 627 if (ioctrl & IO_SERIAL) 628 sio_putc(c); 629 return c; 630} 631 632static int 633xgetc(int fn) 634{ 635 if (opts & 1 << RBX_NOINTR) 636 return 0; 637 for (;;) { 638 if (ioctrl & IO_KEYBOARD && getc(1)) 639 return fn ? 1 : getc(0); 640 if (ioctrl & IO_SERIAL && sio_ischar()) 641 return fn ? 1 : sio_getc(); 642 if (fn) 643 return 0; 644 } 645} 646 647static int 648getc(int fn) 649{ 650 v86.addr = 0x16; 651 v86.eax = fn << 8; 652 v86int(); 653 return fn == 0 ? v86.eax & 0xff : !V86_ZR(v86.efl); 654} 655