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