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