gptboot.c revision 122749
11590Srgrimes/*- 21590Srgrimes * Copyright (c) 1998 Robert Nordier 31590Srgrimes * All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms are freely 61590Srgrimes * permitted provided that the above copyright notice and this 71590Srgrimes * paragraph and the following disclaimer are duplicated in all 81590Srgrimes * such forms. 91590Srgrimes * 101590Srgrimes * This software is provided "AS IS" and without any express or 111590Srgrimes * implied warranties, including, without limitation, the implied 121590Srgrimes * warranties of merchantability and fitness for a particular 131590Srgrimes * purpose. 141590Srgrimes */ 151590Srgrimes 161590Srgrimes#include <sys/cdefs.h> 171590Srgrimes__FBSDID("$FreeBSD: head/sys/boot/i386/gptboot/gptboot.c 122749 2003-11-15 10:04:06Z bde $"); 181590Srgrimes 191590Srgrimes#include <sys/param.h> 201590Srgrimes#include <sys/disklabel.h> 211590Srgrimes#include <sys/diskmbr.h> 221590Srgrimes#include <sys/dirent.h> 231590Srgrimes#include <sys/reboot.h> 241590Srgrimes 251590Srgrimes#include <machine/bootinfo.h> 261590Srgrimes#include <machine/elf.h> 271590Srgrimes 281590Srgrimes#include <stdarg.h> 291590Srgrimes 301590Srgrimes#include <a.out.h> 311590Srgrimes 321590Srgrimes#include <btxv86.h> 331590Srgrimes 341590Srgrimes#include "boot2.h" 351590Srgrimes#include "lib.h" 361590Srgrimes 371590Srgrimes#define IO_KEYBOARD 1 381590Srgrimes#define IO_SERIAL 2 391590Srgrimes 401590Srgrimes#define SECOND 18 /* Circa that many ticks in a second. */ 411590Srgrimes 421590Srgrimes#define RBX_ASKNAME 0x0 /* -a */ 431590Srgrimes#define RBX_SINGLE 0x1 /* -s */ 441590Srgrimes/* 0x2 is reserved for log2(RB_NOSYNC). */ 451590Srgrimes/* 0x3 is reserved for log2(RB_HALT). */ 461590Srgrimes/* 0x4 is reserved for log2(RB_INITNAME). */ 471590Srgrimes#define RBX_DFLTROOT 0x5 /* -r */ 481590Srgrimes#define RBX_KDB 0x6 /* -d */ 491590Srgrimes/* 0x7 is reserved for log2(RB_RDONLY). */ 501590Srgrimes/* 0x8 is reserved for log2(RB_DUMP). */ 511590Srgrimes/* 0x9 is reserved for log2(RB_MINIROOT). */ 521590Srgrimes#define RBX_CONFIG 0xa /* -c */ 531590Srgrimes#define RBX_VERBOSE 0xb /* -v */ 541590Srgrimes#define RBX_SERIAL 0xc /* -h */ 551590Srgrimes#define RBX_CDROM 0xd /* -C */ 561590Srgrimes/* 0xe is reserved for log2(RB_POWEROFF). */ 571590Srgrimes#define RBX_GDB 0xf /* -g */ 581590Srgrimes#define RBX_MUTE 0x10 /* -m */ 591590Srgrimes/* 0x11 is reserved for log2(RB_SELFTEST). */ 601590Srgrimes/* 0x12 is reserved for boot programs. */ 611590Srgrimes/* 0x13 is reserved for boot programs. */ 621590Srgrimes#define RBX_PAUSE 0x14 /* -p */ 631590Srgrimes#define RBX_NOINTR 0x1c /* -n */ 641590Srgrimes/* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */ 651590Srgrimes#define RBX_DUAL 0x1d /* -D */ 661590Srgrimes#define RBX_PROBEKBD 0x1e /* -P */ 671590Srgrimes/* 0x1f is reserved for log2(RB_BOOTINFO). */ 681590Srgrimes 691590Srgrimes/* pass: -a, -s, -r, -d, -c, -v, -h, -C, -g, -m, -p, -D */ 701590Srgrimes#define RBX_MASK 0x2005ffff 711590Srgrimes 721590Srgrimes#define PATH_CONFIG "/boot.config" 731590Srgrimes#define PATH_BOOT3 "/boot/loader" 741590Srgrimes#define PATH_KERNEL "/kernel" 751590Srgrimes 761590Srgrimes#define ARGS 0x900 771590Srgrimes#define NOPT 12 781590Srgrimes#define NDEV 3 791590Srgrimes#define MEM_BASE 0x12 801590Srgrimes#define MEM_EXT 0x15 811590Srgrimes#define V86_CY(x) ((x) & 1) 821590Srgrimes#define V86_ZR(x) ((x) & 0x40) 831590Srgrimes 841590Srgrimes#define DRV_HARD 0x80 851590Srgrimes#define DRV_MASK 0x7f 861590Srgrimes 871590Srgrimes#define TYPE_AD 0 881590Srgrimes#define TYPE_DA 1 891590Srgrimes#define TYPE_MAXHARD TYPE_DA 901590Srgrimes#define TYPE_FD 2 911590Srgrimes 921590Srgrimesextern uint32_t _end; 931590Srgrimes 941590Srgrimesstatic const char optstr[NOPT] = "DhaCgmnPprsv"; 951590Srgrimesstatic const unsigned char flags[NOPT] = { 961590Srgrimes RBX_DUAL, 971590Srgrimes RBX_SERIAL, 981590Srgrimes RBX_ASKNAME, 991590Srgrimes RBX_CDROM, 1001590Srgrimes RBX_GDB, 1011590Srgrimes RBX_MUTE, 1021590Srgrimes RBX_NOINTR, 1031590Srgrimes RBX_PROBEKBD, 1041590Srgrimes RBX_PAUSE, 1051590Srgrimes RBX_DFLTROOT, 1061590Srgrimes RBX_SINGLE, 1071590Srgrimes RBX_VERBOSE 1081590Srgrimes}; 1091590Srgrimes 1101590Srgrimesstatic const char *const dev_nm[NDEV] = {"ad", "da", "fd"}; 1111590Srgrimesstatic const unsigned char dev_maj[NDEV] = {30, 4, 2}; 1121590Srgrimes 1131590Srgrimesstatic struct dsk { 1141590Srgrimes unsigned drive; 1151590Srgrimes unsigned type; 1161590Srgrimes unsigned unit; 1171590Srgrimes unsigned slice; 1181590Srgrimes unsigned part; 1191590Srgrimes unsigned start; 1201590Srgrimes int init; 1211590Srgrimes} dsk; 1221590Srgrimesstatic char cmd[512]; 1231590Srgrimesstatic char kname[1024]; 1241590Srgrimesstatic uint32_t opts; 1251590Srgrimesstatic struct bootinfo bootinfo; 1261590Srgrimesstatic uint8_t ioctrl = IO_KEYBOARD; 1271590Srgrimes 1281590Srgrimesvoid exit(int); 1291590Srgrimesstatic void load(void); 1301590Srgrimesstatic int parse(void); 1311590Srgrimesstatic int xfsread(ino_t, void *, size_t); 1321590Srgrimesstatic int dskread(void *, unsigned, unsigned); 1331590Srgrimesstatic void printf(const char *,...); 1341590Srgrimesstatic void putchar(int); 1351590Srgrimesstatic uint32_t memsize(void); 1361590Srgrimesstatic int drvread(void *, unsigned, unsigned); 1371590Srgrimesstatic int keyhit(unsigned); 1381590Srgrimesstatic int xputc(int); 1391590Srgrimesstatic int xgetc(int); 1401590Srgrimesstatic int getc(int); 1411590Srgrimes 1421590Srgrimes#define memcpy __builtin_memcpy 1431590Srgrimes 1441590Srgrimesstatic inline int 1451590Srgrimesstrcmp(const char *s1, const char *s2) 1461590Srgrimes{ 1471590Srgrimes for (; *s1 == *s2 && *s1; s1++, s2++); 1481590Srgrimes return (unsigned char)*s1 - (unsigned char)*s2; 1491590Srgrimes} 1501590Srgrimes 1511590Srgrimes#include "ufsread.c" 1521590Srgrimes 1531590Srgrimesstatic int 1541590Srgrimesxfsread(ino_t inode, void *buf, size_t nbyte) 1551590Srgrimes{ 1561590Srgrimes if ((size_t)fsread(inode, buf, nbyte) != nbyte) { 1571590Srgrimes printf("Invalid %s\n", "format"); 1581590Srgrimes return -1; 1591590Srgrimes } 1601590Srgrimes return 0; 1611590Srgrimes} 1621590Srgrimes 1631590Srgrimesstatic inline uint32_t 1641590Srgrimesmemsize(void) 1651590Srgrimes{ 1661590Srgrimes v86.addr = MEM_EXT; 1671590Srgrimes v86.eax = 0x8800; 1681590Srgrimes v86int(); 1691590Srgrimes return v86.eax; 1701590Srgrimes} 1711590Srgrimes 1721590Srgrimesstatic inline void 1731590Srgrimesgetstr(void) 1741590Srgrimes{ 1751590Srgrimes char *s; 1761590Srgrimes int c; 1771590Srgrimes 1781590Srgrimes s = cmd; 1791590Srgrimes for (;;) { 1801590Srgrimes switch (c = xgetc(0)) { 1811590Srgrimes case 0: 1821590Srgrimes break; 1831590Srgrimes case '\177': 1841590Srgrimes case '\b': 1851590Srgrimes if (s > cmd) { 1861590Srgrimes s--; 1871590Srgrimes printf("\b \b"); 1881590Srgrimes } 1891590Srgrimes break; 1901590Srgrimes case '\n': 1911590Srgrimes case '\r': 1921590Srgrimes *s = 0; 1931590Srgrimes return; 1941590Srgrimes default: 1951590Srgrimes if (s - cmd < sizeof(cmd) - 1) 1961590Srgrimes *s++ = c; 1971590Srgrimes putchar(c); 1981590Srgrimes } 1991590Srgrimes } 2001590Srgrimes} 2011590Srgrimes 2021590Srgrimesstatic inline void 2031590Srgrimesputc(int c) 2041590Srgrimes{ 2051590Srgrimes v86.addr = 0x10; 2061590Srgrimes v86.eax = 0xe00 | (c & 0xff); 2071590Srgrimes v86.ebx = 0x7; 2081590Srgrimes v86int(); 2091590Srgrimes} 2101590Srgrimes 2111590Srgrimesint 2121590Srgrimesmain(void) 2131590Srgrimes{ 2141590Srgrimes int autoboot; 2151590Srgrimes ino_t ino; 2161590Srgrimes 2171590Srgrimes dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base); 2181590Srgrimes v86.ctl = V86_FLAGS; 2191590Srgrimes dsk.drive = *(uint8_t *)PTOV(ARGS); 2201590Srgrimes dsk.type = dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD; 2211590Srgrimes dsk.unit = dsk.drive & DRV_MASK; 2221590Srgrimes dsk.slice = *(uint8_t *)PTOV(ARGS + 1) + 1; 2231590Srgrimes bootinfo.bi_version = BOOTINFO_VERSION; 2241590Srgrimes bootinfo.bi_size = sizeof(bootinfo); 2251590Srgrimes bootinfo.bi_basemem = 0; /* XXX will be filled by loader or kernel */ 2261590Srgrimes bootinfo.bi_extmem = memsize(); 2271590Srgrimes bootinfo.bi_memsizes_valid++; 2281590Srgrimes 2291590Srgrimes /* Process configuration file */ 2301590Srgrimes 2311590Srgrimes autoboot = 1; 2321590Srgrimes 2331590Srgrimes if ((ino = lookup(PATH_CONFIG))) 2341590Srgrimes fsread(ino, cmd, sizeof(cmd)); 2351590Srgrimes 2361590Srgrimes if (*cmd) { 2371590Srgrimes printf("%s: %s", PATH_CONFIG, cmd); 2381590Srgrimes if (parse()) 2391590Srgrimes autoboot = 0; 2401590Srgrimes /* Do not process this command twice */ 2411590Srgrimes *cmd = 0; 2421590Srgrimes } 2431590Srgrimes 2441590Srgrimes /* 2451590Srgrimes * Try to exec stage 3 boot loader. If interrupted by a keypress, 2461590Srgrimes * or in case of failure, try to load a kernel directly instead. 2471590Srgrimes */ 2481590Srgrimes 2491590Srgrimes if (autoboot && !*kname) { 2501590Srgrimes memcpy(kname, PATH_BOOT3, sizeof(PATH_BOOT3)); 2511590Srgrimes if (!keyhit(3*SECOND)) { 2521590Srgrimes load(); 2531590Srgrimes memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL)); 2541590Srgrimes } 2551590Srgrimes } 2561590Srgrimes 2571590Srgrimes /* Present the user with the boot2 prompt. */ 2581590Srgrimes 2591590Srgrimes for (;;) { 2601590Srgrimes printf("\nFreeBSD/i386 boot\n" 2611590Srgrimes "Default: %u:%s(%u,%c)%s\n" 2621590Srgrimes "boot: ", 2631590Srgrimes dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit, 2641590Srgrimes 'a' + dsk.part, kname); 2651590Srgrimes if (ioctrl & IO_SERIAL) 2661590Srgrimes sio_flush(); 2671590Srgrimes if (!autoboot || keyhit(5*SECOND)) 2681590Srgrimes getstr(); 2691590Srgrimes else 2701590Srgrimes putchar('\n'); 2711590Srgrimes autoboot = 0; 2721590Srgrimes if (parse()) 2731590Srgrimes putchar('\a'); 2741590Srgrimes else 2751590Srgrimes load(); 2761590Srgrimes } 2771590Srgrimes} 2781590Srgrimes 2791590Srgrimes/* XXX - Needed for btxld to link the boot2 binary; do not remove. */ 2801590Srgrimesvoid 2811590Srgrimesexit(int x) 2821590Srgrimes{ 2831590Srgrimes} 2841590Srgrimes 2851590Srgrimesstatic void 2861590Srgrimesload(void) 2871590Srgrimes{ 2881590Srgrimes union { 2891590Srgrimes struct exec ex; 2901590Srgrimes Elf32_Ehdr eh; 2911590Srgrimes } hdr; 2921590Srgrimes Elf32_Phdr ep[2]; 2931590Srgrimes Elf32_Shdr es[2]; 2941590Srgrimes caddr_t p; 2951590Srgrimes ino_t ino; 2961590Srgrimes uint32_t addr, x; 2971590Srgrimes int fmt, i, j; 2981590Srgrimes 2991590Srgrimes if (!(ino = lookup(kname))) { 3001590Srgrimes if (!ls) 3011590Srgrimes printf("No %s\n", kname); 3021590Srgrimes return; 3031590Srgrimes } 3041590Srgrimes if (xfsread(ino, &hdr, sizeof(hdr))) 3051590Srgrimes return; 3061590Srgrimes if (N_GETMAGIC(hdr.ex) == ZMAGIC) 3071590Srgrimes fmt = 0; 3081590Srgrimes else if (IS_ELF(hdr.eh)) 3091590Srgrimes fmt = 1; 3101590Srgrimes else { 3111590Srgrimes printf("Invalid %s\n", "format"); 3121590Srgrimes return; 3131590Srgrimes } 3141590Srgrimes if (fmt == 0) { 3151590Srgrimes addr = hdr.ex.a_entry & 0xffffff; 3161590Srgrimes p = PTOV(addr); 3171590Srgrimes fs_off = PAGE_SIZE; 3181590Srgrimes if (xfsread(ino, p, hdr.ex.a_text)) 3191590Srgrimes return; 3201590Srgrimes p += roundup2(hdr.ex.a_text, PAGE_SIZE); 3211590Srgrimes if (xfsread(ino, p, hdr.ex.a_data)) 3221590Srgrimes return; 3231590Srgrimes p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE); 3241590Srgrimes bootinfo.bi_symtab = VTOP(p); 3251590Srgrimes memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms)); 3261590Srgrimes p += sizeof(hdr.ex.a_syms); 3271590Srgrimes if (hdr.ex.a_syms) { 3281590Srgrimes if (xfsread(ino, p, hdr.ex.a_syms)) 3291590Srgrimes return; 3301590Srgrimes p += hdr.ex.a_syms; 3311590Srgrimes if (xfsread(ino, p, sizeof(int))) 3321590Srgrimes return; 3331590Srgrimes x = *(uint32_t *)p; 3341590Srgrimes p += sizeof(int); 3351590Srgrimes x -= sizeof(int); 3361590Srgrimes if (xfsread(ino, p, x)) 3371590Srgrimes return; 3381590Srgrimes p += x; 3391590Srgrimes } 3401590Srgrimes } else { 3411590Srgrimes fs_off = hdr.eh.e_phoff; 3421590Srgrimes for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) { 3431590Srgrimes if (xfsread(ino, ep + j, sizeof(ep[0]))) 3441590Srgrimes return; 3451590Srgrimes if (ep[j].p_type == PT_LOAD) 3461590Srgrimes j++; 3471590Srgrimes } 348 for (i = 0; i < 2; i++) { 349 p = PTOV(ep[i].p_paddr & 0xffffff); 350 fs_off = ep[i].p_offset; 351 if (xfsread(ino, p, ep[i].p_filesz)) 352 return; 353 } 354 p += roundup2(ep[1].p_memsz, PAGE_SIZE); 355 bootinfo.bi_symtab = VTOP(p); 356 if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { 357 fs_off = hdr.eh.e_shoff + sizeof(es[0]) * 358 (hdr.eh.e_shstrndx + 1); 359 if (xfsread(ino, &es, sizeof(es))) 360 return; 361 for (i = 0; i < 2; i++) { 362 memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size)); 363 p += sizeof(es[i].sh_size); 364 fs_off = es[i].sh_offset; 365 if (xfsread(ino, p, es[i].sh_size)) 366 return; 367 p += es[i].sh_size; 368 } 369 } 370 addr = hdr.eh.e_entry & 0xffffff; 371 } 372 bootinfo.bi_esymtab = VTOP(p); 373 bootinfo.bi_kernelname = VTOP(kname); 374 bootinfo.bi_bios_dev = dsk.drive; 375 __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), 376 MAKEBOOTDEV(dev_maj[dsk.type], 0, dsk.slice, dsk.unit, dsk.part), 377 0, 0, 0, VTOP(&bootinfo)); 378} 379 380static int 381parse() 382{ 383 char *arg = cmd; 384 char *p, *q; 385 unsigned int drv; 386 int c, i; 387 388 while ((c = *arg++)) { 389 if (c == ' ' || c == '\t' || c == '\n') 390 continue; 391 for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++); 392 if (*p) 393 *p++ = 0; 394 if (c == '-') { 395 while ((c = *arg++)) { 396 for (i = 0; c != optstr[i]; i++) 397 if (i == NOPT - 1) 398 return -1; 399 opts ^= 1 << flags[i]; 400 } 401 if (opts & 1 << RBX_PROBEKBD) { 402 i = *(uint8_t *)PTOV(0x496) & 0x10; 403 printf("Keyboard: %s\n", i ? "yes" : "no"); 404 if (!i) 405 opts |= 1 << RBX_DUAL | 1 << RBX_SERIAL; 406 opts &= ~(1 << RBX_PROBEKBD); 407 } 408 ioctrl = opts & 1 << RBX_DUAL ? (IO_SERIAL|IO_KEYBOARD) : 409 opts & 1 << RBX_SERIAL ? IO_SERIAL : IO_KEYBOARD; 410 if (ioctrl & IO_SERIAL) 411 sio_init(); 412 } else { 413 for (q = arg--; *q && *q != '('; q++); 414 if (*q) { 415 drv = -1; 416 if (arg[1] == ':') { 417 drv = *arg - '0'; 418 if (drv > 9) 419 return (-1); 420 arg += 2; 421 } 422 if (q - arg != 2) 423 return -1; 424 for (i = 0; arg[0] != dev_nm[i][0] || 425 arg[1] != dev_nm[i][1]; i++) 426 if (i == NDEV - 1) 427 return -1; 428 dsk.type = i; 429 arg += 3; 430 dsk.unit = *arg - '0'; 431 if (arg[1] != ',' || dsk.unit > 9) 432 return -1; 433 arg += 2; 434 dsk.slice = WHOLE_DISK_SLICE; 435 if (arg[1] == ',') { 436 dsk.slice = *arg - '0' + 1; 437 if (dsk.slice > NDOSPART) 438 return -1; 439 arg += 2; 440 } 441 if (arg[1] != ')') 442 return -1; 443 dsk.part = *arg - 'a'; 444 if (dsk.part > 7) 445 return (-1); 446 arg += 2; 447 if (drv == -1) 448 drv = dsk.unit; 449 dsk.drive = (dsk.type <= TYPE_MAXHARD 450 ? DRV_HARD : 0) + drv; 451 dsk_meta = 0; 452 } 453 if ((i = p - arg - !*(p - 1))) { 454 if ((size_t)i >= sizeof(kname)) 455 return -1; 456 memcpy(kname, arg, i + 1); 457 } 458 } 459 arg = p; 460 } 461 return 0; 462} 463 464static int 465dskread(void *buf, unsigned lba, unsigned nblk) 466{ 467 struct dos_partition *dp; 468 struct disklabel *d; 469 char *sec; 470 unsigned sl, i; 471 472 if (!dsk_meta) { 473 sec = dmadat->secbuf; 474 dsk.start = 0; 475 if (drvread(sec, DOSBBSECTOR, 1)) 476 return -1; 477 dp = (void *)(sec + DOSPARTOFF); 478 sl = dsk.slice; 479 if (sl < BASE_SLICE) { 480 for (i = 0; i < NDOSPART; i++) 481 if (dp[i].dp_typ == DOSPTYP_386BSD && 482 (dp[i].dp_flag & 0x80 || sl < BASE_SLICE)) { 483 sl = BASE_SLICE + i; 484 if (dp[i].dp_flag & 0x80 || 485 dsk.slice == COMPATIBILITY_SLICE) 486 break; 487 } 488 if (dsk.slice == WHOLE_DISK_SLICE) 489 dsk.slice = sl; 490 } 491 if (sl != WHOLE_DISK_SLICE) { 492 if (sl != COMPATIBILITY_SLICE) 493 dp += sl - BASE_SLICE; 494 if (dp->dp_typ != DOSPTYP_386BSD) { 495 printf("Invalid %s\n", "slice"); 496 return -1; 497 } 498 dsk.start = dp->dp_start; 499 } 500 if (drvread(sec, dsk.start + LABELSECTOR, 1)) 501 return -1; 502 d = (void *)(sec + LABELOFFSET); 503 if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) { 504 if (dsk.part != RAW_PART) { 505 printf("Invalid %s\n", "label"); 506 return -1; 507 } 508 } else { 509 if (!dsk.init) { 510 if (d->d_type == DTYPE_SCSI) 511 dsk.type = TYPE_DA; 512 dsk.init++; 513 } 514 if (dsk.part >= d->d_npartitions || 515 !d->d_partitions[dsk.part].p_size) { 516 printf("Invalid %s\n", "partition"); 517 return -1; 518 } 519 dsk.start += d->d_partitions[dsk.part].p_offset; 520 dsk.start -= d->d_partitions[RAW_PART].p_offset; 521 } 522 } 523 return drvread(buf, dsk.start + lba, nblk); 524} 525 526static void 527printf(const char *fmt,...) 528{ 529 va_list ap; 530 char buf[10]; 531 char *s; 532 unsigned u; 533 int c; 534 535 va_start(ap, fmt); 536 while ((c = *fmt++)) { 537 if (c == '%') { 538 c = *fmt++; 539 switch (c) { 540 case 'c': 541 putchar(va_arg(ap, int)); 542 continue; 543 case 's': 544 for (s = va_arg(ap, char *); *s; s++) 545 putchar(*s); 546 continue; 547 case 'u': 548 u = va_arg(ap, unsigned); 549 s = buf; 550 do 551 *s++ = '0' + u % 10U; 552 while (u /= 10U); 553 while (--s >= buf) 554 putchar(*s); 555 continue; 556 } 557 } 558 putchar(c); 559 } 560 va_end(ap); 561 return; 562} 563 564static void 565putchar(int c) 566{ 567 if (c == '\n') 568 xputc('\r'); 569 xputc(c); 570} 571 572static int 573drvread(void *buf, unsigned lba, unsigned nblk) 574{ 575 static unsigned c = 0x2d5c7c2f; 576 577 printf("%c\b", c = c << 8 | c >> 24); 578 v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; 579 v86.addr = XREADORG; /* call to xread in boot1 */ 580 v86.es = VTOPSEG(buf); 581 v86.eax = lba; 582 v86.ebx = VTOPOFF(buf); 583 v86.ecx = lba >> 16; 584 v86.edx = nblk << 8 | dsk.drive; 585 v86int(); 586 v86.ctl = V86_FLAGS; 587 if (V86_CY(v86.efl)) { 588 printf("error %u lba %u\n", v86.eax >> 8 & 0xff, lba); 589 return -1; 590 } 591 return 0; 592} 593 594static int 595keyhit(unsigned ticks) 596{ 597 uint32_t t0, t1; 598 599 if (opts & 1 << RBX_NOINTR) 600 return 0; 601 t0 = 0; 602 for (;;) { 603 if (xgetc(1)) 604 return 1; 605 t1 = *(uint32_t *)PTOV(0x46c); 606 if (!t0) 607 t0 = t1; 608 if (t1 < t0 || t1 >= t0 + ticks) 609 return 0; 610 } 611} 612 613static int 614xputc(int c) 615{ 616 if (ioctrl & IO_KEYBOARD) 617 putc(c); 618 if (ioctrl & IO_SERIAL) 619 sio_putc(c); 620 return c; 621} 622 623static int 624xgetc(int fn) 625{ 626 if (opts & 1 << RBX_NOINTR) 627 return 0; 628 for (;;) { 629 if (ioctrl & IO_KEYBOARD && getc(1)) 630 return fn ? 1 : getc(0); 631 if (ioctrl & IO_SERIAL && sio_ischar()) 632 return fn ? 1 : sio_getc(); 633 if (fn) 634 return 0; 635 } 636} 637 638static int 639getc(int fn) 640{ 641 v86.addr = 0x16; 642 v86.eax = fn << 8; 643 v86int(); 644 return fn == 0 ? v86.eax & 0xff : !V86_ZR(v86.efl); 645} 646