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