gptboot.c revision 41013
1260067Skargl/* 2260067Skargl * Copyright (c) 1998 Robert Nordier 3260067Skargl * All rights reserved. 4260067Skargl * 5260067Skargl * Redistribution and use in source and binary forms are freely 6260067Skargl * permitted provided that the above copyright notice and this 7260067Skargl * paragraph and the following disclaimer are duplicated in all 8260067Skargl * such forms. 9260067Skargl * 10260067Skargl * This software is provided "AS IS" and without any express or 11260067Skargl * implied warranties, including, without limitation, the implied 12260067Skargl * warranties of merchantability and fitness for a particular 13260067Skargl * purpose. 14260067Skargl */ 15260067Skargl 16260067Skargl/* 17260067Skargl * $Id: boot2.c,v 1.15 1998/11/08 18:29:29 rnordier Exp $ 18260067Skargl */ 19260067Skargl 20260067Skargl#include <sys/param.h> 21260067Skargl#include <sys/reboot.h> 22260067Skargl#include <sys/diskslice.h> 23260067Skargl#include <sys/disklabel.h> 24260067Skargl#include <sys/dirent.h> 25260067Skargl#include <machine/bootinfo.h> 26260067Skargl 27260067Skargl#include <ufs/ffs/fs.h> 28260067Skargl#include <ufs/ufs/dinode.h> 29260067Skargl 30260067Skargl#include <stdarg.h> 31260067Skargl 32260067Skargl#include <a.out.h> 33260067Skargl#include <elf.h> 34260067Skargl 35260067Skargl#include <btxv86.h> 36260067Skargl 37260067Skargl#include "lib.h" 38260067Skargl 39260067Skargl#define RBX_ASKNAME 0x0 /* -a */ 40260067Skargl#define RBX_SINGLE 0x1 /* -s */ 41260067Skargl#define RBX_DFLTROOT 0x5 /* -r */ 42260067Skargl#define RBX_KDB 0x6 /* -d */ 43260067Skargl#define RBX_CONFIG 0xa /* -c */ 44260067Skargl#define RBX_VERBOSE 0xb /* -v */ 45260067Skargl#define RBX_SERIAL 0xc /* -h */ 46260067Skargl#define RBX_CDROM 0xd /* -C */ 47260067Skargl#define RBX_GDB 0xf /* -g */ 48260067Skargl#define RBX_DUAL 0x1d /* -D */ 49260067Skargl#define RBX_PROBEKBD 0x1e /* -P */ 50260067Skargl 51260067Skargl#define RBX_MASK 0xffff 52260067Skargl 53260067Skargl#define PATH_CONFIG "/boot.config" 54260067Skargl#define PATH_BOOT3 "/boot/loader" 55260067Skargl#define PATH_KERNEL "/kernel" 56260067Skargl#define PATH_HELP "boot.help" 57260067Skargl 58260067Skargl#define ARGS 0x800 59260067Skargl#define NOPT 11 60260067Skargl#define BSIZEMAX 8192 61260067Skargl#define NDEV 5 62260067Skargl#define MEM_BASE 0x12 63260067Skargl#define MEM_EXT 0x15 64260067Skargl#define V86_CY(x) ((x) & 1) 65260067Skargl#define V86_ZR(x) ((x) & 0x40) 66260067Skargl 67260067Skargl#define DRV_HARD 0x80 68260067Skargl#define DRV_MASK 0x7f 69260067Skargl 70260067Skargl#define MAJ_WD 0 71260067Skargl#define MAJ_WFD 1 72260067Skargl#define MAJ_FD 2 73260067Skargl#define MAJ_DA 4 74260067Skargl 75260067Skarglextern uint32_t _end; 76260067Skargl 77260067Skarglstatic const char optstr[NOPT] = "DhaCcdgPrsv"; 78260067Skarglstatic const unsigned char flags[NOPT] = { 79260067Skargl RBX_DUAL, 80260145Skargl RBX_SERIAL, 81260067Skargl RBX_ASKNAME, 82260067Skargl RBX_CDROM, 83260067Skargl RBX_CONFIG, 84260067Skargl RBX_KDB, 85260067Skargl RBX_GDB, 86260067Skargl RBX_PROBEKBD, 87260067Skargl RBX_DFLTROOT, 88260067Skargl RBX_SINGLE, 89260067Skargl RBX_VERBOSE 90260067Skargl}; 91260067Skargl 92260067Skarglstatic const char *const dev_nm[] = {"wd", " ", "fd", " ", "da"}; 93260067Skargl 94260067Skarglstatic struct dsk { 95260067Skargl unsigned drive; 96260067Skargl unsigned type; 97260067Skargl unsigned unit; 98260067Skargl unsigned slice; 99260067Skargl unsigned part; 100260067Skargl unsigned start; 101260067Skargl int init; 102260067Skargl int meta; 103260067Skargl} dsk; 104260067Skarglstatic char cmd[512]; 105260067Skarglstatic char kname[1024]; 106260067Skarglstatic char help[2048]; 107260067Skarglstatic uint32_t opts; 108260067Skarglstatic struct bootinfo bootinfo; 109260067Skarglstatic int ls; 110260067Skarglstatic uint32_t fs_off; 111260067Skarglstatic uint8_t ioctrl = 0x1; 112260067Skargl 113260067Skarglvoid exit(int); 114260067Skarglstatic void load(const char *); 115260067Skarglstatic int parse(char *); 116260067Skarglstatic void readfile(const char *, void *, size_t); 117260067Skarglstatic ino_t lookup(const char *); 118260067Skarglstatic int fsfind(const char *, ino_t *); 119260067Skarglstatic int xfsread(ino_t, void *, size_t); 120260067Skarglstatic ssize_t fsread(ino_t, void *, size_t); 121260067Skarglstatic int dskread(void *, unsigned, unsigned); 122260067Skarglstatic int printf(const char *,...); 123260067Skarglstatic void getstr(char *, int); 124260067Skarglstatic int putchar(int); 125260067Skarglstatic int getchar(void); 126260067Skarglstatic void *memcpy(void *, const void *, size_t); 127260067Skarglstatic int strcmp(const char *, const char *); 128260067Skarglstatic void *malloc(size_t); 129260067Skarglstatic uint32_t memsize(int); 130260067Skarglstatic uint32_t drvinfo(int); 131260067Skarglstatic 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, helpon, i; 142 143 v86.ctl = V86_FLAGS; 144 dsk.drive = *(uint8_t *)PTOV(ARGS); 145 dsk.type = dsk.drive & DRV_HARD ? MAJ_WD : MAJ_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 helpon = 1; 157 readfile(PATH_HELP, help, sizeof(help)); 158 readfile(PATH_CONFIG, cmd, sizeof(cmd)); 159 if (*cmd) { 160 printf("%s: %s", PATH_CONFIG, cmd); 161 if (parse(cmd)) 162 autoboot = 0; 163 *cmd = 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 else 188 putchar('\n'); 189 autoboot = helpon = 0; 190 if (parse(cmd)) 191 helpon = 1; 192 else 193 load(kname); 194 } 195} 196 197void 198exit(int x) 199{ 200} 201 202static void 203load(const char *fname) 204{ 205 union { 206 struct exec ex; 207 Elf32_Ehdr eh; 208 } hdr; 209 Elf32_Phdr ep[2]; 210 Elf32_Shdr es[2]; 211 caddr_t p; 212 ino_t ino; 213 uint32_t addr, x; 214 int fmt, i, j; 215 216 if (!(ino = lookup(fname))) { 217 if (!ls) 218 printf("No %s\n", fname); 219 return; 220 } 221 if (xfsread(ino, &hdr, sizeof(hdr))) 222 return; 223 if (N_GETMAGIC(hdr.ex) == ZMAGIC) 224 fmt = 0; 225 else if (IS_ELF(hdr.eh)) 226 fmt = 1; 227 else { 228 printf("Invalid %s\n", "format"); 229 return; 230 } 231 if (fmt == 0) { 232 addr = hdr.ex.a_entry & 0xffffff; 233 p = PTOV(addr); 234 fs_off = PAGE_SIZE; 235 if (xfsread(ino, p, hdr.ex.a_text)) 236 return; 237 p += roundup2(hdr.ex.a_text, PAGE_SIZE); 238 if (xfsread(ino, p, hdr.ex.a_data)) 239 return; 240 p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE); 241 bootinfo.bi_symtab = VTOP(p); 242 memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms)); 243 p += sizeof(hdr.ex.a_syms); 244 if (hdr.ex.a_syms) { 245 if (xfsread(ino, p, hdr.ex.a_syms)) 246 return; 247 p += hdr.ex.a_syms; 248 if (xfsread(ino, p, sizeof(int))) 249 return; 250 x = *(uint32_t *)p; 251 p += sizeof(int); 252 x -= sizeof(int); 253 if (xfsread(ino, p, x)) 254 return; 255 p += x; 256 } 257 } else { 258 fs_off = hdr.eh.e_phoff; 259 for (j = i = 0; i < hdr.eh.e_phoff && j < 2; i++) { 260 if (xfsread(ino, ep + j, sizeof(ep[0]))) 261 return; 262 if (ep[j].p_type == PT_LOAD) 263 j++; 264 } 265 for (i = 0; i < 2; i++) { 266 p = PTOV(ep[i].p_paddr & 0xffffff); 267 fs_off = ep[i].p_offset; 268 if (xfsread(ino, p, ep[i].p_filesz)) 269 return; 270 } 271 p += roundup2(ep[1].p_memsz, PAGE_SIZE); 272 bootinfo.bi_symtab = VTOP(p); 273 if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { 274 fs_off = hdr.eh.e_shoff + sizeof(es[0]) * 275 (hdr.eh.e_shstrndx + 1); 276 if (xfsread(ino, &es, sizeof(es))) 277 return; 278 for (i = 0; i < 2; i++) { 279 memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size)); 280 p += sizeof(es[i].sh_size); 281 fs_off = es[i].sh_offset; 282 if (xfsread(ino, p, es[i].sh_size)) 283 return; 284 p += es[i].sh_size; 285 } 286 } 287 addr = hdr.eh.e_entry & 0xffffff; 288 } 289 bootinfo.bi_esymtab = VTOP(p); 290 bootinfo.bi_kernelname = VTOP(fname); 291 __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), 292 MAKEBOOTDEV(dsk.type, 0, dsk.slice, dsk.unit, dsk.part), 293 0, 0, 0, VTOP(&bootinfo)); 294} 295 296static int 297parse(char *arg) 298{ 299 char *p, *q; 300 int drv, c, i; 301 302 while ((c = *arg++)) { 303 if (c == ' ') 304 continue; 305 for (p = arg; *p && *p != '\n' && *p != ' '; p++); 306 if (*p) 307 *p++ = 0; 308 if (c == '-') { 309 while ((c = *arg++)) { 310 for (i = 0; c != optstr[i]; i++) 311 if (i == NOPT - 1) 312 return -1; 313 opts ^= 1 << flags[i]; 314 } 315 if (opts & 1 << RBX_PROBEKBD) { 316 i = *(uint8_t *)PTOV(0x496) & 0x10; 317 printf("Keyboard: %s\n", i ? "yes" : "no"); 318 if (!i) 319 opts |= 1 << RBX_DUAL | 1 << RBX_SERIAL; 320 opts &= ~(1 << RBX_PROBEKBD); 321 } 322 ioctrl = opts & 1 << RBX_DUAL ? 0x3 : 323 opts & 1 << RBX_SERIAL ? 0x2 : 0x1; 324 if (ioctrl & 0x2) 325 sio_init(); 326 } else { 327 for (q = arg--; *q && *q != '('; q++); 328 if (*q) { 329 drv = -1; 330 if (arg[1] == ':') { 331 if (*arg < '0' || *arg > '9') 332 return -1; 333 drv = *arg - '0'; 334 arg += 2; 335 } 336 if (q - arg != 2) 337 return -1; 338 for (i = 0; arg[0] != dev_nm[i][0] || 339 arg[1] != dev_nm[i][1]; i++) 340 if (i == NDEV - 1) 341 return -1; 342 dsk.type = i; 343 arg += 3; 344 if (arg[1] != ',' || *arg < '0' || *arg > '9') 345 return -1; 346 dsk.unit = *arg - '0'; 347 arg += 2; 348 dsk.slice = WHOLE_DISK_SLICE; 349 if (arg[1] == ',') { 350 if (*arg < '0' || *arg > '0' + NDOSPART) 351 return -1; 352 if ((dsk.slice = *arg - '0')) 353 dsk.slice++; 354 arg += 2; 355 } 356 if (arg[1] != ')' || *arg < 'a' || *arg > 'p') 357 return -1; 358 dsk.part = *arg - 'a'; 359 arg += 2; 360 if (drv == -1) 361 drv = dsk.unit; 362 dsk.drive = (dsk.type == MAJ_WD || 363 dsk.type == MAJ_DA ? DRV_HARD : 0) + drv; 364 dsk.meta = 0; 365 fsread(0, NULL, 0); 366 } 367 if ((i = p - arg - !*(p - 1))) { 368 if (i >= sizeof(kname)) 369 return -1; 370 memcpy(kname, arg, i + 1); 371 } 372 } 373 arg = p; 374 } 375 return 0; 376} 377 378static void 379readfile(const char *fname, void *buf, size_t size) 380{ 381 ino_t ino; 382 383 if ((ino = lookup(fname))) 384 fsread(ino, buf, size); 385} 386 387static ino_t 388lookup(const char *path) 389{ 390 char name[MAXNAMLEN + 1]; 391 const char *s; 392 ino_t ino; 393 ssize_t n; 394 int dt; 395 396 ino = ROOTINO; 397 dt = DT_DIR; 398 for (;;) { 399 if (*path == '/') 400 path++; 401 if (!*path) 402 break; 403 for (s = path; *s && *s != '/'; s++); 404 if ((n = s - path) > MAXNAMLEN) 405 return 0; 406 ls = *path == '?' && n == 1 && !*s; 407 memcpy(name, path, n); 408 name[n] = 0; 409 if ((dt = fsfind(name, &ino)) <= 0) 410 break; 411 path = s; 412 } 413 return dt == DT_REG ? ino : 0; 414} 415 416static int 417fsfind(const char *name, ino_t * ino) 418{ 419 char buf[DEV_BSIZE]; 420 struct dirent *d; 421 char *s; 422 ssize_t n; 423 424 fs_off = 0; 425 while ((n = fsread(*ino, buf, DEV_BSIZE)) > 0) 426 for (s = buf; s < buf + DEV_BSIZE;) { 427 d = (void *)s; 428 if (ls) 429 printf("%s ", d->d_name); 430 else if (!strcmp(name, d->d_name)) { 431 *ino = d->d_fileno; 432 return d->d_type; 433 } 434 s += d->d_reclen; 435 } 436 if (n != -1 && ls) 437 putchar('\n'); 438 return 0; 439} 440 441static int 442xfsread(ino_t inode, void *buf, size_t nbyte) 443{ 444 if (fsread(inode, buf, nbyte) != nbyte) { 445 printf("Invalid %s\n", "format"); 446 return -1; 447 } 448 return 0; 449} 450 451static ssize_t 452fsread(ino_t inode, void *buf, size_t nbyte) 453{ 454 static struct fs fs; 455 static struct dinode din; 456 static char *blkbuf; 457 static ufs_daddr_t *indbuf; 458 static ino_t inomap; 459 static ufs_daddr_t blkmap, indmap; 460 static unsigned fsblks; 461 char *s; 462 ufs_daddr_t lbn, addr; 463 size_t n, nb, off; 464 465 if (!dsk.meta) { 466 if (!blkbuf) 467 blkbuf = malloc(BSIZEMAX); 468 inomap = 0; 469 if (dskread(blkbuf, SBOFF / DEV_BSIZE, SBSIZE / DEV_BSIZE)) 470 return -1; 471 memcpy(&fs, blkbuf, sizeof(fs)); 472 if (fs.fs_magic != FS_MAGIC) { 473 printf("Not ufs\n"); 474 return -1; 475 } 476 fsblks = fs.fs_bsize >> DEV_BSHIFT; 477 dsk.meta++; 478 } 479 if (!inode) 480 return 0; 481 if (inomap != inode) { 482 if (dskread(blkbuf, fsbtodb(&fs, ino_to_fsba(&fs, inode)), 483 fsblks)) 484 return -1; 485 din = ((struct dinode *)blkbuf)[inode % INOPB(&fs)]; 486 inomap = inode; 487 fs_off = 0; 488 blkmap = indmap = 0; 489 } 490 s = buf; 491 if (nbyte > (n = din.di_size - fs_off)) 492 nbyte = n; 493 nb = nbyte; 494 while (nb) { 495 lbn = lblkno(&fs, fs_off); 496 if (lbn < NDADDR) 497 addr = din.di_db[lbn]; 498 else { 499 if (indmap != din.di_ib[0]) { 500 if (!indbuf) 501 indbuf = malloc(BSIZEMAX); 502 if (dskread(indbuf, fsbtodb(&fs, din.di_ib[0]), 503 fsblks)) 504 return -1; 505 indmap = din.di_ib[0]; 506 } 507 addr = indbuf[(lbn - NDADDR) % NINDIR(&fs)]; 508 } 509 n = dblksize(&fs, &din, lbn); 510 if (blkmap != addr) { 511 if (dskread(blkbuf, fsbtodb(&fs, addr), n >> DEV_BSHIFT)) 512 return -1; 513 blkmap = addr; 514 } 515 off = blkoff(&fs, fs_off); 516 n -= off; 517 if (n > nb) 518 n = nb; 519 memcpy(s, blkbuf + off, n); 520 s += n; 521 fs_off += n; 522 nb -= n; 523 } 524 return nbyte; 525} 526 527static int 528dskread(void *buf, unsigned lba, unsigned nblk) 529{ 530 static char *sec; 531 struct dos_partition *dp; 532 struct disklabel *d; 533 unsigned sl, i; 534 535 if (!dsk.meta) { 536 if (!sec) 537 sec = malloc(DEV_BSIZE); 538 dsk.start = 0; 539 if (drvread(sec, DOSBBSECTOR, 1)) 540 return -1; 541 dp = (void *)(sec + DOSPARTOFF); 542 sl = dsk.slice; 543 if (sl < BASE_SLICE) { 544 for (i = 0; i < NDOSPART; i++) 545 if (dp[i].dp_typ == DOSPTYP_386BSD && 546 (dp[i].dp_flag & 0x80 || sl < BASE_SLICE)) { 547 sl = BASE_SLICE + i; 548 if (dp[i].dp_flag & 0x80 || 549 dsk.slice == COMPATIBILITY_SLICE) 550 break; 551 } 552 if (dsk.slice == WHOLE_DISK_SLICE) 553 dsk.slice = sl; 554 } 555 if (sl != WHOLE_DISK_SLICE) { 556 if (sl != COMPATIBILITY_SLICE) 557 dp += sl - BASE_SLICE; 558 if (dp->dp_typ != DOSPTYP_386BSD) { 559 printf("Invalid %s\n", "slice"); 560 return -1; 561 } 562 dsk.start = dp->dp_start; 563 } 564 if (drvread(sec, dsk.start + LABELSECTOR, 1)) 565 return -1; 566 d = (void *)(sec + LABELOFFSET); 567 if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) { 568 if (dsk.part != RAW_PART) { 569 printf("Invalid %s\n", "label"); 570 return -1; 571 } 572 } else { 573 if (!dsk.init) { 574 if (d->d_type == DTYPE_SCSI) 575 dsk.type = MAJ_DA; 576 dsk.init++; 577 } 578 if (dsk.part >= d->d_npartitions) { 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 if (s > str) { 642 s--; 643 putchar(c); 644 putchar(' '); 645 } else 646 c = 0; 647 break; 648 case '\n': 649 *s = 0; 650 break; 651 default: 652 if (s - str < size - 1) 653 *s++ = c; 654 } 655 if (c) 656 putchar(c); 657 } while (c != '\n'); 658} 659 660static int 661putchar(int c) 662{ 663 if (c == '\n') 664 xputc('\r'); 665 return xputc(c); 666} 667 668static int 669getchar(void) 670{ 671 int c; 672 673 c = xgetc(0); 674 if (c == '\r') 675 c = '\n'; 676 return c; 677} 678 679static void * 680memcpy(void *dst, const void *src, size_t size) 681{ 682 const char *s; 683 char *d; 684 685 for (d = dst, s = src; size; size--) 686 *d++ = *s++; 687 return dst; 688} 689 690static int 691strcmp(const char *s1, const char *s2) 692{ 693 for (; *s1 == *s2 && *s1; s1++, s2++); 694 return (u_char)*s1 - (u_char)*s2; 695} 696 697static void * 698malloc(size_t size) 699{ 700 static uint32_t next; 701 void *p; 702 703 if (!next) 704 next = roundup2(__base + _end, 0x10000) - __base; 705 p = (void *)next; 706 next += size; 707 return p; 708} 709 710static uint32_t 711memsize(int type) 712{ 713 v86.addr = type; 714 v86.eax = 0x8800; 715 v86int(); 716 return v86.eax; 717} 718 719static uint32_t 720drvinfo(int drive) 721{ 722 v86.addr = 0x13; 723 v86.eax = 0x800; 724 v86.edx = DRV_HARD + drive; 725 v86int(); 726 if (V86_CY(v86.efl)) 727 return 0x4f010f; 728 return ((v86.ecx & 0xc0) << 18) | ((v86.ecx & 0xff00) << 8) | 729 (v86.edx & 0xff00) | (v86.ecx & 0x3f); 730} 731 732static int 733drvread(void *buf, unsigned lba, unsigned nblk) 734{ 735 static unsigned c = 0x2d5c7c2f; 736 737 printf("%c\b", c = c << 8 | c >> 24); 738 v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; 739 v86.addr = 0x604; 740 v86.es = VTOPSEG(buf); 741 v86.eax = lba; 742 v86.ebx = VTOPOFF(buf); 743 v86.ecx = lba >> 16; 744 v86.edx = nblk << 8 | dsk.drive; 745 v86int(); 746 v86.ctl = V86_FLAGS; 747 if (V86_CY(v86.efl)) { 748 printf("Disk error 0x%x (lba=0x%x)\n", v86.eax >> 8 & 0xff, 749 lba); 750 return -1; 751 } 752 return 0; 753} 754 755static int 756keyhit(unsigned ticks) 757{ 758 uint32_t t0, t1; 759 760 t0 = 0; 761 for (;;) { 762 if (xgetc(1)) 763 return 1; 764 t1 = *(uint32_t *)PTOV(0x46c); 765 if (!t0) 766 t0 = t1; 767 if (t1 < t0 || t1 >= t0 + ticks) 768 return 0; 769 } 770} 771 772static int 773xputc(int c) 774{ 775 if (ioctrl & 0x1) 776 putc(c); 777 if (ioctrl & 0x2) 778 sio_putc(c); 779 return c; 780} 781 782static int 783xgetc(int fn) 784{ 785 for (;;) { 786 if (ioctrl & 0x1 && getc(1)) 787 return fn ? 1 : getc(0); 788 if (ioctrl & 0x2 && sio_ischar()) 789 return fn ? 1 : sio_getc(); 790 if (fn) 791 return 0; 792 } 793} 794 795static void 796putc(int c) 797{ 798 v86.addr = 0x10; 799 v86.eax = 0xe00 | (c & 0xff); 800 v86.ebx = 0x7; 801 v86int(); 802} 803 804static int 805getc(int fn) 806{ 807 v86.addr = 0x16; 808 v86.eax = fn << 8; 809 v86int(); 810 return fn == 0 ? v86.eax & 0xff : !V86_ZR(v86.efl); 811} 812