zfsboot.c revision 200309
1185029Spjd/*- 2185029Spjd * Copyright (c) 1998 Robert Nordier 3185029Spjd * All rights reserved. 4185029Spjd * 5185029Spjd * Redistribution and use in source and binary forms are freely 6185029Spjd * permitted provided that the above copyright notice and this 7185029Spjd * paragraph and the following disclaimer are duplicated in all 8185029Spjd * such forms. 9185029Spjd * 10185029Spjd * This software is provided "AS IS" and without any express or 11185029Spjd * implied warranties, including, without limitation, the implied 12185029Spjd * warranties of merchantability and fitness for a particular 13185029Spjd * purpose. 14185029Spjd */ 15185029Spjd 16185029Spjd#include <sys/cdefs.h> 17185029Spjd__FBSDID("$FreeBSD: head/sys/boot/i386/zfsboot/zfsboot.c 200309 2009-12-09 20:36:56Z jhb $"); 18185029Spjd 19185029Spjd#include <sys/param.h> 20185029Spjd#include <sys/errno.h> 21185029Spjd#include <sys/diskmbr.h> 22185096Sdfr#ifdef GPT 23185096Sdfr#include <sys/gpt.h> 24185096Sdfr#endif 25185029Spjd#include <sys/reboot.h> 26185029Spjd#include <sys/queue.h> 27185029Spjd 28185029Spjd#include <machine/bootinfo.h> 29185029Spjd#include <machine/elf.h> 30200309Sjhb#include <machine/pc/bios.h> 31185029Spjd 32185029Spjd#include <stdarg.h> 33185029Spjd#include <stddef.h> 34185029Spjd 35185029Spjd#include <a.out.h> 36185029Spjd 37185029Spjd#include <btxv86.h> 38185029Spjd 39185096Sdfr#ifndef GPT 40185029Spjd#include "zfsboot.h" 41185096Sdfr#endif 42185029Spjd#include "lib.h" 43185029Spjd 44185029Spjd#define IO_KEYBOARD 1 45185029Spjd#define IO_SERIAL 2 46185029Spjd 47185029Spjd#define SECOND 18 /* Circa that many ticks in a second. */ 48185029Spjd 49185029Spjd#define RBX_ASKNAME 0x0 /* -a */ 50185029Spjd#define RBX_SINGLE 0x1 /* -s */ 51185029Spjd/* 0x2 is reserved for log2(RB_NOSYNC). */ 52185029Spjd/* 0x3 is reserved for log2(RB_HALT). */ 53185029Spjd/* 0x4 is reserved for log2(RB_INITNAME). */ 54185029Spjd#define RBX_DFLTROOT 0x5 /* -r */ 55185029Spjd#define RBX_KDB 0x6 /* -d */ 56185029Spjd/* 0x7 is reserved for log2(RB_RDONLY). */ 57185029Spjd/* 0x8 is reserved for log2(RB_DUMP). */ 58185029Spjd/* 0x9 is reserved for log2(RB_MINIROOT). */ 59185029Spjd#define RBX_CONFIG 0xa /* -c */ 60185029Spjd#define RBX_VERBOSE 0xb /* -v */ 61185029Spjd#define RBX_SERIAL 0xc /* -h */ 62185029Spjd#define RBX_CDROM 0xd /* -C */ 63185029Spjd/* 0xe is reserved for log2(RB_POWEROFF). */ 64185029Spjd#define RBX_GDB 0xf /* -g */ 65185029Spjd#define RBX_MUTE 0x10 /* -m */ 66185029Spjd/* 0x11 is reserved for log2(RB_SELFTEST). */ 67185029Spjd/* 0x12 is reserved for boot programs. */ 68185029Spjd/* 0x13 is reserved for boot programs. */ 69185029Spjd#define RBX_PAUSE 0x14 /* -p */ 70185029Spjd#define RBX_QUIET 0x15 /* -q */ 71185029Spjd#define RBX_NOINTR 0x1c /* -n */ 72185029Spjd/* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */ 73185029Spjd#define RBX_DUAL 0x1d /* -D */ 74185029Spjd/* 0x1f is reserved for log2(RB_BOOTINFO). */ 75185029Spjd 76185029Spjd/* pass: -a, -s, -r, -d, -c, -v, -h, -C, -g, -m, -p, -D */ 77185029Spjd#define RBX_MASK (OPT_SET(RBX_ASKNAME) | OPT_SET(RBX_SINGLE) | \ 78185029Spjd OPT_SET(RBX_DFLTROOT) | OPT_SET(RBX_KDB ) | \ 79185029Spjd OPT_SET(RBX_CONFIG) | OPT_SET(RBX_VERBOSE) | \ 80185029Spjd OPT_SET(RBX_SERIAL) | OPT_SET(RBX_CDROM) | \ 81185029Spjd OPT_SET(RBX_GDB ) | OPT_SET(RBX_MUTE) | \ 82185029Spjd OPT_SET(RBX_PAUSE) | OPT_SET(RBX_DUAL)) 83185029Spjd 84185029Spjd/* Hint to loader that we came from ZFS */ 85185029Spjd#define KARGS_FLAGS_ZFS 0x4 86185029Spjd 87185029Spjd#define PATH_CONFIG "/boot.config" 88199714Srnoland#define PATH_BOOT3 "/boot/zfsloader" 89185029Spjd#define PATH_KERNEL "/boot/kernel/kernel" 90185029Spjd 91185029Spjd#define ARGS 0x900 92185029Spjd#define NOPT 14 93185029Spjd#define NDEV 3 94185029Spjd#define V86_CY(x) ((x) & 1) 95185029Spjd#define V86_ZR(x) ((x) & 0x40) 96185029Spjd 97185029Spjd#define DRV_HARD 0x80 98185029Spjd#define DRV_MASK 0x7f 99185029Spjd 100185029Spjd#define TYPE_AD 0 101185029Spjd#define TYPE_DA 1 102185029Spjd#define TYPE_MAXHARD TYPE_DA 103185029Spjd#define TYPE_FD 2 104185029Spjd 105185029Spjd#define OPT_SET(opt) (1 << (opt)) 106185029Spjd#define OPT_CHECK(opt) ((opts) & OPT_SET(opt)) 107185029Spjd 108185029Spjdextern uint32_t _end; 109185029Spjd 110185096Sdfr#ifdef GPT 111185096Sdfrstatic const uuid_t freebsd_zfs_uuid = GPT_ENT_TYPE_FREEBSD_ZFS; 112185096Sdfr#endif 113185029Spjdstatic const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */ 114185029Spjdstatic const unsigned char flags[NOPT] = { 115185029Spjd RBX_DUAL, 116185029Spjd RBX_SERIAL, 117185029Spjd RBX_ASKNAME, 118185029Spjd RBX_CDROM, 119185029Spjd RBX_CONFIG, 120185029Spjd RBX_KDB, 121185029Spjd RBX_GDB, 122185029Spjd RBX_MUTE, 123185029Spjd RBX_NOINTR, 124185029Spjd RBX_PAUSE, 125185029Spjd RBX_QUIET, 126185029Spjd RBX_DFLTROOT, 127185029Spjd RBX_SINGLE, 128185029Spjd RBX_VERBOSE 129185029Spjd}; 130185029Spjd 131185029Spjdstatic const char *const dev_nm[NDEV] = {"ad", "da", "fd"}; 132185029Spjdstatic const unsigned char dev_maj[NDEV] = {30, 4, 2}; 133185029Spjd 134185029Spjdstruct dsk { 135185029Spjd unsigned drive; 136185029Spjd unsigned type; 137185029Spjd unsigned unit; 138185029Spjd unsigned slice; 139185029Spjd unsigned part; 140185029Spjd int init; 141199579Sjhb daddr_t start; 142185029Spjd}; 143185029Spjdstatic char cmd[512]; 144185029Spjdstatic char kname[1024]; 145185029Spjdstatic uint32_t opts; 146185029Spjdstatic int comspeed = SIOSPD; 147185029Spjdstatic struct bootinfo bootinfo; 148185029Spjdstatic uint32_t bootdev; 149185029Spjdstatic uint8_t ioctrl = IO_KEYBOARD; 150185029Spjd 151200309Sjhbvm_offset_t high_heap_base; 152200309Sjhbuint32_t bios_basemem, bios_extmem, high_heap_size; 153200309Sjhb 154200309Sjhbstatic struct bios_smap smap; 155200309Sjhb 156200309Sjhb/* 157200309Sjhb * The minimum amount of memory to reserve in bios_extmem for the heap. 158200309Sjhb */ 159200309Sjhb#define HEAP_MIN (3 * 1024 * 1024) 160200309Sjhb 161200309Sjhbstatic char *heap_next; 162200309Sjhbstatic char *heap_end; 163200309Sjhb 164185029Spjd/* Buffers that must not span a 64k boundary. */ 165185029Spjd#define READ_BUF_SIZE 8192 166185029Spjdstruct dmadat { 167185029Spjd char rdbuf[READ_BUF_SIZE]; /* for reading large things */ 168185029Spjd char secbuf[READ_BUF_SIZE]; /* for MBR/disklabel */ 169185029Spjd}; 170185029Spjdstatic struct dmadat *dmadat; 171185029Spjd 172185029Spjdvoid exit(int); 173185029Spjdstatic void load(void); 174185029Spjdstatic int parse(void); 175185029Spjdstatic void printf(const char *,...); 176185029Spjdstatic void putchar(int); 177200309Sjhbstatic void bios_getmem(void); 178199579Sjhbstatic int drvread(struct dsk *, void *, daddr_t, unsigned); 179185029Spjdstatic int keyhit(unsigned); 180185029Spjdstatic int xputc(int); 181185029Spjdstatic int xgetc(int); 182185029Spjdstatic int getc(int); 183185029Spjd 184185029Spjdstatic void memcpy(void *, const void *, int); 185185029Spjdstatic void 186185029Spjdmemcpy(void *dst, const void *src, int len) 187185029Spjd{ 188185029Spjd const char *s = src; 189185029Spjd char *d = dst; 190185029Spjd 191185029Spjd while (len--) 192185029Spjd *d++ = *s++; 193185029Spjd} 194185029Spjd 195185029Spjdstatic void 196185029Spjdstrcpy(char *dst, const char *src) 197185029Spjd{ 198185029Spjd while (*src) 199185029Spjd *dst++ = *src++; 200185029Spjd *dst++ = 0; 201185029Spjd} 202185029Spjd 203185029Spjdstatic void 204185029Spjdstrcat(char *dst, const char *src) 205185029Spjd{ 206185029Spjd while (*dst) 207185029Spjd dst++; 208185029Spjd while (*src) 209185029Spjd *dst++ = *src++; 210185029Spjd *dst++ = 0; 211185029Spjd} 212185029Spjd 213185029Spjdstatic int 214185029Spjdstrcmp(const char *s1, const char *s2) 215185029Spjd{ 216185029Spjd for (; *s1 == *s2 && *s1; s1++, s2++); 217185029Spjd return (unsigned char)*s1 - (unsigned char)*s2; 218185029Spjd} 219185029Spjd 220185029Spjdstatic const char * 221185029Spjdstrchr(const char *s, char ch) 222185029Spjd{ 223185029Spjd for (; *s; s++) 224185029Spjd if (*s == ch) 225185029Spjd return s; 226185029Spjd return 0; 227185029Spjd} 228185029Spjd 229185029Spjdstatic int 230185029Spjdmemcmp(const void *p1, const void *p2, size_t n) 231185029Spjd{ 232185029Spjd const char *s1 = (const char *) p1; 233185029Spjd const char *s2 = (const char *) p2; 234185029Spjd for (; n > 0 && *s1 == *s2; s1++, s2++, n--); 235185029Spjd if (n) 236185029Spjd return (unsigned char)*s1 - (unsigned char)*s2; 237185029Spjd else 238185029Spjd return 0; 239185029Spjd} 240185029Spjd 241185029Spjdstatic void 242185029Spjdmemset(void *p, char val, size_t n) 243185029Spjd{ 244185029Spjd char *s = (char *) p; 245185029Spjd while (n--) 246185029Spjd *s++ = val; 247185029Spjd} 248185029Spjd 249185029Spjdstatic void * 250185029Spjdmalloc(size_t n) 251185029Spjd{ 252185029Spjd char *p = heap_next; 253185029Spjd if (p + n > heap_end) { 254185029Spjd printf("malloc failure\n"); 255185029Spjd for (;;) 256185029Spjd ; 257185029Spjd return 0; 258185029Spjd } 259185029Spjd heap_next += n; 260185029Spjd return p; 261185029Spjd} 262185029Spjd 263185029Spjdstatic size_t 264185029Spjdstrlen(const char *s) 265185029Spjd{ 266185029Spjd size_t len = 0; 267185029Spjd while (*s++) 268185029Spjd len++; 269185029Spjd return len; 270185029Spjd} 271185029Spjd 272185029Spjdstatic char * 273185029Spjdstrdup(const char *s) 274185029Spjd{ 275185029Spjd char *p = malloc(strlen(s) + 1); 276185029Spjd strcpy(p, s); 277185029Spjd return p; 278185029Spjd} 279185029Spjd 280185029Spjd#include "zfsimpl.c" 281185029Spjd 282185029Spjd/* 283185029Spjd * Read from a dnode (which must be from a ZPL filesystem). 284185029Spjd */ 285185029Spjdstatic int 286185029Spjdzfs_read(spa_t *spa, const dnode_phys_t *dnode, off_t *offp, void *start, size_t size) 287185029Spjd{ 288185029Spjd const znode_phys_t *zp = (const znode_phys_t *) dnode->dn_bonus; 289185029Spjd size_t n; 290185029Spjd int rc; 291185029Spjd 292185029Spjd n = size; 293185029Spjd if (*offp + n > zp->zp_size) 294185029Spjd n = zp->zp_size - *offp; 295185029Spjd 296185029Spjd rc = dnode_read(spa, dnode, *offp, start, n); 297185029Spjd if (rc) 298185029Spjd return (-1); 299185029Spjd *offp += n; 300185029Spjd 301185029Spjd return (n); 302185029Spjd} 303185029Spjd 304185029Spjd/* 305185029Spjd * Current ZFS pool 306185029Spjd */ 307185029Spjdspa_t *spa; 308185029Spjd 309185029Spjd/* 310185029Spjd * A wrapper for dskread that doesn't have to worry about whether the 311185029Spjd * buffer pointer crosses a 64k boundary. 312185029Spjd */ 313185029Spjdstatic int 314185029Spjdvdev_read(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes) 315185029Spjd{ 316185029Spjd char *p; 317199579Sjhb daddr_t lba; 318199579Sjhb unsigned int nb; 319185029Spjd struct dsk *dsk = (struct dsk *) priv; 320185029Spjd 321185029Spjd if ((off & (DEV_BSIZE - 1)) || (bytes & (DEV_BSIZE - 1))) 322185029Spjd return -1; 323185029Spjd 324185029Spjd p = buf; 325185029Spjd lba = off / DEV_BSIZE; 326185029Spjd while (bytes > 0) { 327185029Spjd nb = bytes / DEV_BSIZE; 328185029Spjd if (nb > READ_BUF_SIZE / DEV_BSIZE) 329185029Spjd nb = READ_BUF_SIZE / DEV_BSIZE; 330185029Spjd if (drvread(dsk, dmadat->rdbuf, lba, nb)) 331185029Spjd return -1; 332185029Spjd memcpy(p, dmadat->rdbuf, nb * DEV_BSIZE); 333185029Spjd p += nb * DEV_BSIZE; 334185029Spjd lba += nb; 335185029Spjd bytes -= nb * DEV_BSIZE; 336185029Spjd } 337185029Spjd 338185029Spjd return 0; 339185029Spjd} 340185029Spjd 341185029Spjdstatic int 342185029Spjdxfsread(const dnode_phys_t *dnode, off_t *offp, void *buf, size_t nbyte) 343185029Spjd{ 344185029Spjd if ((size_t)zfs_read(spa, dnode, offp, buf, nbyte) != nbyte) { 345185029Spjd printf("Invalid %s\n", "format"); 346185029Spjd return -1; 347185029Spjd } 348185029Spjd return 0; 349185029Spjd} 350185029Spjd 351200309Sjhbstatic void 352200309Sjhbbios_getmem(void) 353185029Spjd{ 354200309Sjhb uint64_t size; 355185029Spjd 356200309Sjhb /* Parse system memory map */ 357200309Sjhb v86.ebx = 0; 358200309Sjhb do { 359200309Sjhb v86.ctl = V86_FLAGS; 360200309Sjhb v86.addr = 0x15; /* int 0x15 function 0xe820*/ 361200309Sjhb v86.eax = 0xe820; 362200309Sjhb v86.ecx = sizeof(struct bios_smap); 363200309Sjhb v86.edx = SMAP_SIG; 364200309Sjhb v86.es = VTOPSEG(&smap); 365200309Sjhb v86.edi = VTOPOFF(&smap); 366200309Sjhb v86int(); 367200309Sjhb if ((v86.efl & 1) || (v86.eax != SMAP_SIG)) 368200309Sjhb break; 369200309Sjhb /* look for a low-memory segment that's large enough */ 370200309Sjhb if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0) && 371200309Sjhb (smap.length >= (512 * 1024))) 372200309Sjhb bios_basemem = smap.length; 373200309Sjhb /* look for the first segment in 'extended' memory */ 374200309Sjhb if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0x100000)) { 375200309Sjhb bios_extmem = smap.length; 376200309Sjhb } 377200309Sjhb 378200309Sjhb /* 379200309Sjhb * Look for the largest segment in 'extended' memory beyond 380200309Sjhb * 1MB but below 4GB. 381200309Sjhb */ 382200309Sjhb if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base > 0x100000) && 383200309Sjhb (smap.base < 0x100000000ull)) { 384200309Sjhb size = smap.length; 385200309Sjhb 386200309Sjhb /* 387200309Sjhb * If this segment crosses the 4GB boundary, truncate it. 388200309Sjhb */ 389200309Sjhb if (smap.base + size > 0x100000000ull) 390200309Sjhb size = 0x100000000ull - smap.base; 391200309Sjhb 392200309Sjhb if (size > high_heap_size) { 393200309Sjhb high_heap_size = size; 394200309Sjhb high_heap_base = smap.base; 395200309Sjhb } 396200309Sjhb } 397200309Sjhb } while (v86.ebx != 0); 398200309Sjhb 399200309Sjhb /* Fall back to the old compatibility function for base memory */ 400200309Sjhb if (bios_basemem == 0) { 401200309Sjhb v86.ctl = 0; 402200309Sjhb v86.addr = 0x12; /* int 0x12 */ 403200309Sjhb v86int(); 404200309Sjhb 405200309Sjhb bios_basemem = (v86.eax & 0xffff) * 1024; 406200309Sjhb } 407200309Sjhb 408200309Sjhb /* Fall back through several compatibility functions for extended memory */ 409200309Sjhb if (bios_extmem == 0) { 410200309Sjhb v86.ctl = V86_FLAGS; 411200309Sjhb v86.addr = 0x15; /* int 0x15 function 0xe801*/ 412200309Sjhb v86.eax = 0xe801; 413200309Sjhb v86int(); 414200309Sjhb if (!(v86.efl & 1)) { 415200309Sjhb bios_extmem = ((v86.ecx & 0xffff) + ((v86.edx & 0xffff) * 64)) * 1024; 416200309Sjhb } 417200309Sjhb } 418200309Sjhb if (bios_extmem == 0) { 419200309Sjhb v86.ctl = 0; 420200309Sjhb v86.addr = 0x15; /* int 0x15 function 0x88*/ 421200309Sjhb v86.eax = 0x8800; 422200309Sjhb v86int(); 423200309Sjhb bios_extmem = (v86.eax & 0xffff) * 1024; 424200309Sjhb } 425200309Sjhb 426200309Sjhb /* 427200309Sjhb * If we have extended memory and did not find a suitable heap 428200309Sjhb * region in the SMAP, use the last 3MB of 'extended' memory as a 429200309Sjhb * high heap candidate. 430200309Sjhb */ 431200309Sjhb if (bios_extmem >= HEAP_MIN && high_heap_size < HEAP_MIN) { 432200309Sjhb high_heap_size = HEAP_MIN; 433200309Sjhb high_heap_base = bios_extmem + 0x100000 - HEAP_MIN; 434200309Sjhb } 435200309Sjhb} 436200309Sjhb 437185029Spjdstatic inline void 438185029Spjdgetstr(void) 439185029Spjd{ 440185029Spjd char *s; 441185029Spjd int c; 442185029Spjd 443185029Spjd s = cmd; 444185029Spjd for (;;) { 445185029Spjd switch (c = xgetc(0)) { 446185029Spjd case 0: 447185029Spjd break; 448185029Spjd case '\177': 449185029Spjd case '\b': 450185029Spjd if (s > cmd) { 451185029Spjd s--; 452185029Spjd printf("\b \b"); 453185029Spjd } 454185029Spjd break; 455185029Spjd case '\n': 456185029Spjd case '\r': 457185029Spjd *s = 0; 458185029Spjd return; 459185029Spjd default: 460185029Spjd if (s - cmd < sizeof(cmd) - 1) 461185029Spjd *s++ = c; 462185029Spjd putchar(c); 463185029Spjd } 464185029Spjd } 465185029Spjd} 466185029Spjd 467185029Spjdstatic inline void 468185029Spjdputc(int c) 469185029Spjd{ 470185029Spjd v86.addr = 0x10; 471185029Spjd v86.eax = 0xe00 | (c & 0xff); 472185029Spjd v86.ebx = 0x7; 473185029Spjd v86int(); 474185029Spjd} 475185029Spjd 476185029Spjd/* 477185029Spjd * Try to detect a device supported by the legacy int13 BIOS 478185029Spjd */ 479185029Spjdstatic int 480185029Spjdint13probe(int drive) 481185029Spjd{ 482185029Spjd v86.ctl = V86_FLAGS; 483185029Spjd v86.addr = 0x13; 484185029Spjd v86.eax = 0x800; 485185029Spjd v86.edx = drive; 486185029Spjd v86int(); 487185029Spjd 488185029Spjd if (!(v86.efl & 0x1) && /* carry clear */ 489185029Spjd ((v86.edx & 0xff) != (drive & DRV_MASK))) { /* unit # OK */ 490185029Spjd if ((v86.ecx & 0x3f) == 0) { /* absurd sector size */ 491185029Spjd return(0); /* skip device */ 492185029Spjd } 493185029Spjd return (1); 494185029Spjd } 495185029Spjd return(0); 496185029Spjd} 497185029Spjd 498192194Sdfr/* 499192194Sdfr * We call this when we find a ZFS vdev - ZFS consumes the dsk 500192194Sdfr * structure so we must make a new one. 501192194Sdfr */ 502192194Sdfrstatic struct dsk * 503192194Sdfrcopy_dsk(struct dsk *dsk) 504192194Sdfr{ 505192194Sdfr struct dsk *newdsk; 506192194Sdfr 507192194Sdfr newdsk = malloc(sizeof(struct dsk)); 508192194Sdfr *newdsk = *dsk; 509192194Sdfr return (newdsk); 510192194Sdfr} 511192194Sdfr 512185029Spjdstatic void 513185029Spjdprobe_drive(struct dsk *dsk, spa_t **spap) 514185029Spjd{ 515185096Sdfr#ifdef GPT 516185096Sdfr struct gpt_hdr hdr; 517185096Sdfr struct gpt_ent *ent; 518185096Sdfr daddr_t slba, elba; 519185096Sdfr unsigned part, entries_per_sec; 520185096Sdfr#endif 521185029Spjd struct dos_partition *dp; 522185029Spjd char *sec; 523185029Spjd unsigned i; 524185029Spjd 525185029Spjd /* 526185029Spjd * If we find a vdev on the whole disk, stop here. Otherwise dig 527185029Spjd * out the MBR and probe each slice in turn for a vdev. 528185029Spjd */ 529185029Spjd if (vdev_probe(vdev_read, dsk, spap) == 0) 530185029Spjd return; 531185029Spjd 532185029Spjd sec = dmadat->secbuf; 533185029Spjd dsk->start = 0; 534185096Sdfr 535185096Sdfr#ifdef GPT 536185096Sdfr /* 537185096Sdfr * First check for GPT. 538185096Sdfr */ 539185096Sdfr if (drvread(dsk, sec, 1, 1)) { 540185096Sdfr return; 541185096Sdfr } 542185096Sdfr memcpy(&hdr, sec, sizeof(hdr)); 543185096Sdfr if (memcmp(hdr.hdr_sig, GPT_HDR_SIG, sizeof(hdr.hdr_sig)) != 0 || 544185096Sdfr hdr.hdr_lba_self != 1 || hdr.hdr_revision < 0x00010000 || 545185096Sdfr hdr.hdr_entsz < sizeof(*ent) || DEV_BSIZE % hdr.hdr_entsz != 0) { 546185096Sdfr goto trymbr; 547185096Sdfr } 548185096Sdfr 549185096Sdfr /* 550185096Sdfr * Probe all GPT partitions for the presense of ZFS pools. We 551185096Sdfr * return the spa_t for the first we find (if requested). This 552185096Sdfr * will have the effect of booting from the first pool on the 553185096Sdfr * disk. 554185096Sdfr */ 555185096Sdfr entries_per_sec = DEV_BSIZE / hdr.hdr_entsz; 556185096Sdfr slba = hdr.hdr_lba_table; 557185096Sdfr elba = slba + hdr.hdr_entries / entries_per_sec; 558185096Sdfr while (slba < elba) { 559198420Srnoland dsk->start = 0; 560185096Sdfr if (drvread(dsk, sec, slba, 1)) 561185096Sdfr return; 562185096Sdfr for (part = 0; part < entries_per_sec; part++) { 563185096Sdfr ent = (struct gpt_ent *)(sec + part * hdr.hdr_entsz); 564185096Sdfr if (memcmp(&ent->ent_type, &freebsd_zfs_uuid, 565185096Sdfr sizeof(uuid_t)) == 0) { 566185096Sdfr dsk->start = ent->ent_lba_start; 567185096Sdfr if (vdev_probe(vdev_read, dsk, spap) == 0) { 568185096Sdfr /* 569185096Sdfr * We record the first pool we find (we will try 570192194Sdfr * to boot from that one). 571185096Sdfr */ 572185096Sdfr spap = 0; 573185096Sdfr 574185096Sdfr /* 575185096Sdfr * This slice had a vdev. We need a new dsk 576185096Sdfr * structure now since the vdev now owns this one. 577185096Sdfr */ 578192194Sdfr dsk = copy_dsk(dsk); 579185096Sdfr } 580185096Sdfr } 581185096Sdfr } 582185096Sdfr slba++; 583185096Sdfr } 584185096Sdfr return; 585185096Sdfrtrymbr: 586185096Sdfr#endif 587185096Sdfr 588185029Spjd if (drvread(dsk, sec, DOSBBSECTOR, 1)) 589185029Spjd return; 590185029Spjd dp = (void *)(sec + DOSPARTOFF); 591185029Spjd 592185029Spjd for (i = 0; i < NDOSPART; i++) { 593185029Spjd if (!dp[i].dp_typ) 594185029Spjd continue; 595185029Spjd dsk->start = dp[i].dp_start; 596185029Spjd if (vdev_probe(vdev_read, dsk, spap) == 0) { 597185029Spjd /* 598185029Spjd * We record the first pool we find (we will try to boot 599185029Spjd * from that one. 600185029Spjd */ 601185029Spjd spap = 0; 602185029Spjd 603185029Spjd /* 604185029Spjd * This slice had a vdev. We need a new dsk structure now 605185096Sdfr * since the vdev now owns this one. 606185029Spjd */ 607192194Sdfr dsk = copy_dsk(dsk); 608185029Spjd } 609185029Spjd } 610185029Spjd} 611185029Spjd 612185029Spjdint 613185029Spjdmain(void) 614185029Spjd{ 615185029Spjd int autoboot, i; 616185029Spjd dnode_phys_t dn; 617185029Spjd off_t off; 618185029Spjd struct dsk *dsk; 619185029Spjd 620200309Sjhb bios_getmem(); 621200309Sjhb 622200309Sjhb if (high_heap_size > 0) { 623200309Sjhb heap_end = PTOV(high_heap_base + high_heap_size); 624200309Sjhb heap_next = PTOV(high_heap_base); 625200309Sjhb } else { 626200309Sjhb heap_next = (char *) dmadat + sizeof(*dmadat); 627200309Sjhb heap_end = (char *) PTOV(bios_basemem); 628200309Sjhb } 629200309Sjhb 630185029Spjd dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base); 631185029Spjd v86.ctl = V86_FLAGS; 632185029Spjd 633185029Spjd dsk = malloc(sizeof(struct dsk)); 634185029Spjd dsk->drive = *(uint8_t *)PTOV(ARGS); 635185029Spjd dsk->type = dsk->drive & DRV_HARD ? TYPE_AD : TYPE_FD; 636185029Spjd dsk->unit = dsk->drive & DRV_MASK; 637185029Spjd dsk->slice = *(uint8_t *)PTOV(ARGS + 1) + 1; 638185029Spjd dsk->part = 0; 639185029Spjd dsk->start = 0; 640185029Spjd dsk->init = 0; 641185029Spjd 642185029Spjd bootinfo.bi_version = BOOTINFO_VERSION; 643185029Spjd bootinfo.bi_size = sizeof(bootinfo); 644200309Sjhb bootinfo.bi_basemem = bios_basemem / 1024; 645200309Sjhb bootinfo.bi_extmem = bios_extmem / 1024; 646185029Spjd bootinfo.bi_memsizes_valid++; 647185029Spjd bootinfo.bi_bios_dev = dsk->drive; 648185029Spjd 649185029Spjd bootdev = MAKEBOOTDEV(dev_maj[dsk->type], 650185029Spjd dsk->slice, dsk->unit, dsk->part), 651185029Spjd 652185029Spjd /* Process configuration file */ 653185029Spjd 654185029Spjd autoboot = 1; 655185029Spjd 656185029Spjd zfs_init(); 657185029Spjd 658185029Spjd /* 659185029Spjd * Probe the boot drive first - we will try to boot from whatever 660185029Spjd * pool we find on that drive. 661185029Spjd */ 662185029Spjd probe_drive(dsk, &spa); 663185029Spjd 664185029Spjd /* 665185029Spjd * Probe the rest of the drives that the bios knows about. This 666185029Spjd * will find any other available pools and it may fill in missing 667185029Spjd * vdevs for the boot pool. 668185029Spjd */ 669192194Sdfr for (i = 0; i < 128; i++) { 670185029Spjd if ((i | DRV_HARD) == *(uint8_t *)PTOV(ARGS)) 671185029Spjd continue; 672185029Spjd 673192194Sdfr if (!int13probe(i | DRV_HARD)) 674192194Sdfr break; 675192194Sdfr 676185029Spjd dsk = malloc(sizeof(struct dsk)); 677185029Spjd dsk->drive = i | DRV_HARD; 678185029Spjd dsk->type = dsk->drive & TYPE_AD; 679185029Spjd dsk->unit = i; 680185029Spjd dsk->slice = 0; 681185029Spjd dsk->part = 0; 682185029Spjd dsk->start = 0; 683185029Spjd dsk->init = 0; 684185029Spjd probe_drive(dsk, 0); 685185029Spjd } 686185029Spjd 687185029Spjd /* 688185029Spjd * If we didn't find a pool on the boot drive, default to the 689185029Spjd * first pool we found, if any. 690185029Spjd */ 691185029Spjd if (!spa) { 692185029Spjd spa = STAILQ_FIRST(&zfs_pools); 693185029Spjd if (!spa) { 694185029Spjd printf("No ZFS pools located, can't boot\n"); 695185029Spjd for (;;) 696185029Spjd ; 697185029Spjd } 698185029Spjd } 699185029Spjd 700185029Spjd zfs_mount_pool(spa); 701185029Spjd 702185029Spjd if (zfs_lookup(spa, PATH_CONFIG, &dn) == 0) { 703185029Spjd off = 0; 704198079Sjhb zfs_read(spa, &dn, &off, cmd, sizeof(cmd)); 705185029Spjd } 706185029Spjd 707185029Spjd if (*cmd) { 708185029Spjd if (parse()) 709185029Spjd autoboot = 0; 710185029Spjd if (!OPT_CHECK(RBX_QUIET)) 711185029Spjd printf("%s: %s", PATH_CONFIG, cmd); 712185029Spjd /* Do not process this command twice */ 713185029Spjd *cmd = 0; 714185029Spjd } 715185029Spjd 716185029Spjd /* 717185029Spjd * Try to exec stage 3 boot loader. If interrupted by a keypress, 718185029Spjd * or in case of failure, try to load a kernel directly instead. 719185029Spjd */ 720185029Spjd 721185029Spjd if (autoboot && !*kname) { 722185029Spjd memcpy(kname, PATH_BOOT3, sizeof(PATH_BOOT3)); 723185029Spjd if (!keyhit(3*SECOND)) { 724185029Spjd load(); 725185029Spjd memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL)); 726185029Spjd } 727185029Spjd } 728185029Spjd 729185029Spjd /* Present the user with the boot2 prompt. */ 730185029Spjd 731185029Spjd for (;;) { 732185029Spjd if (!autoboot || !OPT_CHECK(RBX_QUIET)) 733185029Spjd printf("\nFreeBSD/i386 boot\n" 734185029Spjd "Default: %s:%s\n" 735185029Spjd "boot: ", 736185029Spjd spa->spa_name, kname); 737185029Spjd if (ioctrl & IO_SERIAL) 738185029Spjd sio_flush(); 739185029Spjd if (!autoboot || keyhit(5*SECOND)) 740185029Spjd getstr(); 741185029Spjd else if (!autoboot || !OPT_CHECK(RBX_QUIET)) 742185029Spjd putchar('\n'); 743185029Spjd autoboot = 0; 744185029Spjd if (parse()) 745185029Spjd putchar('\a'); 746185029Spjd else 747185029Spjd load(); 748185029Spjd } 749185029Spjd} 750185029Spjd 751185029Spjd/* XXX - Needed for btxld to link the boot2 binary; do not remove. */ 752185029Spjdvoid 753185029Spjdexit(int x) 754185029Spjd{ 755185029Spjd} 756185029Spjd 757185029Spjdstatic void 758185029Spjdload(void) 759185029Spjd{ 760185029Spjd union { 761185029Spjd struct exec ex; 762185029Spjd Elf32_Ehdr eh; 763185029Spjd } hdr; 764185029Spjd static Elf32_Phdr ep[2]; 765185029Spjd static Elf32_Shdr es[2]; 766185029Spjd caddr_t p; 767185029Spjd dnode_phys_t dn; 768185029Spjd off_t off; 769185029Spjd uint32_t addr, x; 770185029Spjd int fmt, i, j; 771185029Spjd 772185029Spjd if (zfs_lookup(spa, kname, &dn)) { 773185029Spjd return; 774185029Spjd } 775185029Spjd off = 0; 776185029Spjd if (xfsread(&dn, &off, &hdr, sizeof(hdr))) 777185029Spjd return; 778185029Spjd if (N_GETMAGIC(hdr.ex) == ZMAGIC) 779185029Spjd fmt = 0; 780185029Spjd else if (IS_ELF(hdr.eh)) 781185029Spjd fmt = 1; 782185029Spjd else { 783185029Spjd printf("Invalid %s\n", "format"); 784185029Spjd return; 785185029Spjd } 786185029Spjd if (fmt == 0) { 787185029Spjd addr = hdr.ex.a_entry & 0xffffff; 788185029Spjd p = PTOV(addr); 789185029Spjd off = PAGE_SIZE; 790185029Spjd if (xfsread(&dn, &off, p, hdr.ex.a_text)) 791185029Spjd return; 792185029Spjd p += roundup2(hdr.ex.a_text, PAGE_SIZE); 793185029Spjd if (xfsread(&dn, &off, p, hdr.ex.a_data)) 794185029Spjd return; 795185029Spjd p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE); 796185029Spjd bootinfo.bi_symtab = VTOP(p); 797185029Spjd memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms)); 798185029Spjd p += sizeof(hdr.ex.a_syms); 799185029Spjd if (hdr.ex.a_syms) { 800185029Spjd if (xfsread(&dn, &off, p, hdr.ex.a_syms)) 801185029Spjd return; 802185029Spjd p += hdr.ex.a_syms; 803185029Spjd if (xfsread(&dn, &off, p, sizeof(int))) 804185029Spjd return; 805185029Spjd x = *(uint32_t *)p; 806185029Spjd p += sizeof(int); 807185029Spjd x -= sizeof(int); 808185029Spjd if (xfsread(&dn, &off, p, x)) 809185029Spjd return; 810185029Spjd p += x; 811185029Spjd } 812185029Spjd } else { 813185029Spjd off = hdr.eh.e_phoff; 814185029Spjd for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) { 815185029Spjd if (xfsread(&dn, &off, ep + j, sizeof(ep[0]))) 816185029Spjd return; 817185029Spjd if (ep[j].p_type == PT_LOAD) 818185029Spjd j++; 819185029Spjd } 820185029Spjd for (i = 0; i < 2; i++) { 821185029Spjd p = PTOV(ep[i].p_paddr & 0xffffff); 822185029Spjd off = ep[i].p_offset; 823185029Spjd if (xfsread(&dn, &off, p, ep[i].p_filesz)) 824185029Spjd return; 825185029Spjd } 826185029Spjd p += roundup2(ep[1].p_memsz, PAGE_SIZE); 827185029Spjd bootinfo.bi_symtab = VTOP(p); 828185029Spjd if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { 829185029Spjd off = hdr.eh.e_shoff + sizeof(es[0]) * 830185029Spjd (hdr.eh.e_shstrndx + 1); 831185029Spjd if (xfsread(&dn, &off, &es, sizeof(es))) 832185029Spjd return; 833185029Spjd for (i = 0; i < 2; i++) { 834185029Spjd memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size)); 835185029Spjd p += sizeof(es[i].sh_size); 836185029Spjd off = es[i].sh_offset; 837185029Spjd if (xfsread(&dn, &off, p, es[i].sh_size)) 838185029Spjd return; 839185029Spjd p += es[i].sh_size; 840185029Spjd } 841185029Spjd } 842185029Spjd addr = hdr.eh.e_entry & 0xffffff; 843185029Spjd } 844185029Spjd bootinfo.bi_esymtab = VTOP(p); 845185029Spjd bootinfo.bi_kernelname = VTOP(kname); 846185029Spjd __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), 847185029Spjd bootdev, 848185029Spjd KARGS_FLAGS_ZFS, 849185029Spjd (uint32_t) spa->spa_guid, 850185029Spjd (uint32_t) (spa->spa_guid >> 32), 851185029Spjd VTOP(&bootinfo)); 852185029Spjd} 853185029Spjd 854185029Spjdstatic int 855185029Spjdparse() 856185029Spjd{ 857185029Spjd char *arg = cmd; 858185029Spjd char *ep, *p, *q; 859185029Spjd const char *cp; 860185029Spjd //unsigned int drv; 861185029Spjd int c, i, j; 862185029Spjd 863185029Spjd while ((c = *arg++)) { 864185029Spjd if (c == ' ' || c == '\t' || c == '\n') 865185029Spjd continue; 866185029Spjd for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++); 867185029Spjd ep = p; 868185029Spjd if (*p) 869185029Spjd *p++ = 0; 870185029Spjd if (c == '-') { 871185029Spjd while ((c = *arg++)) { 872185029Spjd if (c == 'P') { 873185029Spjd if (*(uint8_t *)PTOV(0x496) & 0x10) { 874185029Spjd cp = "yes"; 875185029Spjd } else { 876185029Spjd opts |= OPT_SET(RBX_DUAL) | OPT_SET(RBX_SERIAL); 877185029Spjd cp = "no"; 878185029Spjd } 879185029Spjd printf("Keyboard: %s\n", cp); 880185029Spjd continue; 881185029Spjd } else if (c == 'S') { 882185029Spjd j = 0; 883185029Spjd while ((unsigned int)(i = *arg++ - '0') <= 9) 884185029Spjd j = j * 10 + i; 885185029Spjd if (j > 0 && i == -'0') { 886185029Spjd comspeed = j; 887185029Spjd break; 888185029Spjd } 889185029Spjd /* Fall through to error below ('S' not in optstr[]). */ 890185029Spjd } 891185029Spjd for (i = 0; c != optstr[i]; i++) 892185029Spjd if (i == NOPT - 1) 893185029Spjd return -1; 894185029Spjd opts ^= OPT_SET(flags[i]); 895185029Spjd } 896185029Spjd ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) : 897185029Spjd OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD; 898185029Spjd if (ioctrl & IO_SERIAL) 899185029Spjd sio_init(115200 / comspeed); 900185029Spjd } if (c == '?') { 901185029Spjd dnode_phys_t dn; 902185029Spjd 903185029Spjd if (zfs_lookup(spa, arg, &dn) == 0) { 904185029Spjd zap_list(spa, &dn); 905185029Spjd } 906185029Spjd return -1; 907185029Spjd } else { 908185029Spjd arg--; 909185029Spjd 910185029Spjd /* 911185029Spjd * Report pool status if the comment is 'status'. Lets 912185029Spjd * hope no-one wants to load /status as a kernel. 913185029Spjd */ 914185029Spjd if (!strcmp(arg, "status")) { 915185029Spjd spa_all_status(); 916185029Spjd return -1; 917185029Spjd } 918185029Spjd 919185029Spjd /* 920185029Spjd * If there is a colon, switch pools. 921185029Spjd */ 922185029Spjd q = (char *) strchr(arg, ':'); 923185029Spjd if (q) { 924185029Spjd spa_t *newspa; 925185029Spjd 926185029Spjd *q++ = 0; 927185029Spjd newspa = spa_find_by_name(arg); 928185029Spjd if (newspa) { 929185029Spjd spa = newspa; 930185029Spjd zfs_mount_pool(spa); 931185029Spjd } else { 932185029Spjd printf("\nCan't find ZFS pool %s\n", arg); 933185029Spjd return -1; 934185029Spjd } 935185029Spjd arg = q; 936185029Spjd } 937185029Spjd if ((i = ep - arg)) { 938185029Spjd if ((size_t)i >= sizeof(kname)) 939185029Spjd return -1; 940185029Spjd memcpy(kname, arg, i + 1); 941185029Spjd } 942185029Spjd } 943185029Spjd arg = p; 944185029Spjd } 945185029Spjd return 0; 946185029Spjd} 947185029Spjd 948185029Spjdstatic void 949185029Spjdprintf(const char *fmt,...) 950185029Spjd{ 951185029Spjd va_list ap; 952198420Srnoland char buf[20]; 953185029Spjd char *s; 954198420Srnoland unsigned long long u; 955185029Spjd int c; 956185029Spjd int minus; 957185029Spjd int prec; 958198420Srnoland int l; 959185029Spjd int len; 960185029Spjd int pad; 961185029Spjd 962185029Spjd va_start(ap, fmt); 963185029Spjd while ((c = *fmt++)) { 964185029Spjd if (c == '%') { 965185029Spjd minus = 0; 966185029Spjd prec = 0; 967198420Srnoland l = 0; 968185029Spjd nextfmt: 969185029Spjd c = *fmt++; 970185029Spjd switch (c) { 971185029Spjd case '-': 972185029Spjd minus = 1; 973185029Spjd goto nextfmt; 974185029Spjd case '0': 975185029Spjd case '1': 976185029Spjd case '2': 977185029Spjd case '3': 978185029Spjd case '4': 979185029Spjd case '5': 980185029Spjd case '6': 981185029Spjd case '7': 982185029Spjd case '8': 983185029Spjd case '9': 984185029Spjd prec = 10 * prec + (c - '0'); 985185029Spjd goto nextfmt; 986185029Spjd case 'c': 987185029Spjd putchar(va_arg(ap, int)); 988185029Spjd continue; 989198420Srnoland case 'l': 990198420Srnoland l++; 991198420Srnoland goto nextfmt; 992185029Spjd case 's': 993185029Spjd s = va_arg(ap, char *); 994185029Spjd if (prec) { 995185029Spjd len = strlen(s); 996185029Spjd if (len < prec) 997185029Spjd pad = prec - len; 998185029Spjd else 999185029Spjd pad = 0; 1000185029Spjd if (minus) 1001185029Spjd while (pad--) 1002185029Spjd putchar(' '); 1003185029Spjd for (; *s; s++) 1004185029Spjd putchar(*s); 1005185029Spjd if (!minus) 1006185029Spjd while (pad--) 1007185029Spjd putchar(' '); 1008185029Spjd } else { 1009185029Spjd for (; *s; s++) 1010185029Spjd putchar(*s); 1011185029Spjd } 1012185029Spjd continue; 1013185029Spjd case 'u': 1014198420Srnoland switch (l) { 1015198420Srnoland case 2: 1016198420Srnoland u = va_arg(ap, unsigned long long); 1017198420Srnoland break; 1018198420Srnoland case 1: 1019198420Srnoland u = va_arg(ap, unsigned long); 1020198420Srnoland break; 1021198420Srnoland default: 1022198420Srnoland u = va_arg(ap, unsigned); 1023198420Srnoland break; 1024198420Srnoland } 1025185029Spjd s = buf; 1026185029Spjd do 1027185029Spjd *s++ = '0' + u % 10U; 1028185029Spjd while (u /= 10U); 1029185029Spjd while (--s >= buf) 1030185029Spjd putchar(*s); 1031185029Spjd continue; 1032185029Spjd } 1033185029Spjd } 1034185029Spjd putchar(c); 1035185029Spjd } 1036185029Spjd va_end(ap); 1037185029Spjd return; 1038185029Spjd} 1039185029Spjd 1040185029Spjdstatic void 1041185029Spjdputchar(int c) 1042185029Spjd{ 1043185029Spjd if (c == '\n') 1044185029Spjd xputc('\r'); 1045185029Spjd xputc(c); 1046185029Spjd} 1047185029Spjd 1048185096Sdfr#ifdef GPT 1049185096Sdfrstatic struct { 1050185096Sdfr uint16_t len; 1051185096Sdfr uint16_t count; 1052185096Sdfr uint16_t seg; 1053185096Sdfr uint16_t off; 1054185096Sdfr uint64_t lba; 1055185096Sdfr} packet; 1056185096Sdfr#endif 1057185096Sdfr 1058185029Spjdstatic int 1059199579Sjhbdrvread(struct dsk *dsk, void *buf, daddr_t lba, unsigned nblk) 1060185029Spjd{ 1061185096Sdfr#ifdef GPT 1062192194Sdfr static unsigned c = 0x2d5c7c2f; 1063185096Sdfr 1064185096Sdfr if (!OPT_CHECK(RBX_QUIET)) 1065185096Sdfr printf("%c\b", c = c << 8 | c >> 24); 1066185096Sdfr packet.len = 0x10; 1067185096Sdfr packet.count = nblk; 1068185096Sdfr packet.seg = VTOPOFF(buf); 1069185096Sdfr packet.off = VTOPSEG(buf); 1070185096Sdfr packet.lba = lba + dsk->start; 1071185096Sdfr v86.ctl = V86_FLAGS; 1072185096Sdfr v86.addr = 0x13; 1073185096Sdfr v86.eax = 0x4200; 1074185096Sdfr v86.edx = dsk->drive; 1075185096Sdfr v86.ds = VTOPSEG(&packet); 1076185096Sdfr v86.esi = VTOPOFF(&packet); 1077185096Sdfr v86int(); 1078185096Sdfr if (V86_CY(v86.efl)) { 1079185096Sdfr printf("error %u lba %u\n", v86.eax >> 8 & 0xff, lba); 1080185096Sdfr return -1; 1081185096Sdfr } 1082185096Sdfr return 0; 1083185096Sdfr#else 1084185029Spjd static unsigned c = 0x2d5c7c2f; 1085185029Spjd 1086185029Spjd lba += dsk->start; 1087185029Spjd if (!OPT_CHECK(RBX_QUIET)) 1088185029Spjd printf("%c\b", c = c << 8 | c >> 24); 1089185029Spjd v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; 1090185029Spjd v86.addr = XREADORG; /* call to xread in boot1 */ 1091185029Spjd v86.es = VTOPSEG(buf); 1092185029Spjd v86.eax = lba; 1093185029Spjd v86.ebx = VTOPOFF(buf); 1094199579Sjhb v86.ecx = lba >> 32; 1095185029Spjd v86.edx = nblk << 8 | dsk->drive; 1096185029Spjd v86int(); 1097185029Spjd v86.ctl = V86_FLAGS; 1098185029Spjd if (V86_CY(v86.efl)) { 1099185029Spjd printf("error %u lba %u\n", v86.eax >> 8 & 0xff, lba); 1100185029Spjd return -1; 1101185029Spjd } 1102185029Spjd return 0; 1103185096Sdfr#endif 1104185029Spjd} 1105185029Spjd 1106185029Spjdstatic int 1107185029Spjdkeyhit(unsigned ticks) 1108185029Spjd{ 1109185029Spjd uint32_t t0, t1; 1110185029Spjd 1111185029Spjd if (OPT_CHECK(RBX_NOINTR)) 1112185029Spjd return 0; 1113185029Spjd t0 = 0; 1114185029Spjd for (;;) { 1115185029Spjd if (xgetc(1)) 1116185029Spjd return 1; 1117185029Spjd t1 = *(uint32_t *)PTOV(0x46c); 1118185029Spjd if (!t0) 1119185029Spjd t0 = t1; 1120185029Spjd if (t1 < t0 || t1 >= t0 + ticks) 1121185029Spjd return 0; 1122185029Spjd } 1123185029Spjd} 1124185029Spjd 1125185029Spjdstatic int 1126185029Spjdxputc(int c) 1127185029Spjd{ 1128185029Spjd if (ioctrl & IO_KEYBOARD) 1129185029Spjd putc(c); 1130185029Spjd if (ioctrl & IO_SERIAL) 1131185029Spjd sio_putc(c); 1132185029Spjd return c; 1133185029Spjd} 1134185029Spjd 1135185029Spjdstatic int 1136185029Spjdxgetc(int fn) 1137185029Spjd{ 1138185029Spjd if (OPT_CHECK(RBX_NOINTR)) 1139185029Spjd return 0; 1140185029Spjd for (;;) { 1141185029Spjd if (ioctrl & IO_KEYBOARD && getc(1)) 1142185029Spjd return fn ? 1 : getc(0); 1143185029Spjd if (ioctrl & IO_SERIAL && sio_ischar()) 1144185029Spjd return fn ? 1 : sio_getc(); 1145185029Spjd if (fn) 1146185029Spjd return 0; 1147185029Spjd } 1148185029Spjd} 1149185029Spjd 1150185029Spjdstatic int 1151185029Spjdgetc(int fn) 1152185029Spjd{ 1153185029Spjd /* 1154185029Spjd * The extra comparison against zero is an attempt to work around 1155185029Spjd * what appears to be a bug in QEMU and Bochs. Both emulators 1156185029Spjd * sometimes report a key-press with scancode one and ascii zero 1157185029Spjd * when no such key is pressed in reality. As far as I can tell, 1158185029Spjd * this only happens shortly after a reboot. 1159185029Spjd */ 1160185029Spjd v86.addr = 0x16; 1161185029Spjd v86.eax = fn << 8; 1162185029Spjd v86int(); 1163185029Spjd return fn == 0 ? v86.eax & 0xff : (!V86_ZR(v86.efl) && (v86.eax & 0xff)); 1164185029Spjd} 1165