zfsboot.c revision 212805
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 212805 2010-09-17 22:59:15Z pjd $"); 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 97212805Spjd#define BIOS_NUMDRIVES 0x475 98185029Spjd#define DRV_HARD 0x80 99185029Spjd#define DRV_MASK 0x7f 100185029Spjd 101185029Spjd#define TYPE_AD 0 102185029Spjd#define TYPE_DA 1 103185029Spjd#define TYPE_MAXHARD TYPE_DA 104185029Spjd#define TYPE_FD 2 105185029Spjd 106185029Spjd#define OPT_SET(opt) (1 << (opt)) 107185029Spjd#define OPT_CHECK(opt) ((opts) & OPT_SET(opt)) 108185029Spjd 109185029Spjdextern uint32_t _end; 110185029Spjd 111185096Sdfr#ifdef GPT 112185096Sdfrstatic const uuid_t freebsd_zfs_uuid = GPT_ENT_TYPE_FREEBSD_ZFS; 113185096Sdfr#endif 114185029Spjdstatic const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */ 115185029Spjdstatic const unsigned char flags[NOPT] = { 116185029Spjd RBX_DUAL, 117185029Spjd RBX_SERIAL, 118185029Spjd RBX_ASKNAME, 119185029Spjd RBX_CDROM, 120185029Spjd RBX_CONFIG, 121185029Spjd RBX_KDB, 122185029Spjd RBX_GDB, 123185029Spjd RBX_MUTE, 124185029Spjd RBX_NOINTR, 125185029Spjd RBX_PAUSE, 126185029Spjd RBX_QUIET, 127185029Spjd RBX_DFLTROOT, 128185029Spjd RBX_SINGLE, 129185029Spjd RBX_VERBOSE 130185029Spjd}; 131185029Spjd 132185029Spjdstatic const char *const dev_nm[NDEV] = {"ad", "da", "fd"}; 133185029Spjdstatic const unsigned char dev_maj[NDEV] = {30, 4, 2}; 134185029Spjd 135185029Spjdstruct dsk { 136185029Spjd unsigned drive; 137185029Spjd unsigned type; 138185029Spjd unsigned unit; 139185029Spjd unsigned slice; 140185029Spjd unsigned part; 141185029Spjd int init; 142199579Sjhb daddr_t start; 143185029Spjd}; 144185029Spjdstatic char cmd[512]; 145185029Spjdstatic char kname[1024]; 146185029Spjdstatic uint32_t opts; 147185029Spjdstatic int comspeed = SIOSPD; 148185029Spjdstatic struct bootinfo bootinfo; 149185029Spjdstatic uint32_t bootdev; 150185029Spjdstatic uint8_t ioctrl = IO_KEYBOARD; 151185029Spjd 152200309Sjhbvm_offset_t high_heap_base; 153200309Sjhbuint32_t bios_basemem, bios_extmem, high_heap_size; 154200309Sjhb 155200309Sjhbstatic struct bios_smap smap; 156200309Sjhb 157200309Sjhb/* 158200309Sjhb * The minimum amount of memory to reserve in bios_extmem for the heap. 159200309Sjhb */ 160200309Sjhb#define HEAP_MIN (3 * 1024 * 1024) 161200309Sjhb 162200309Sjhbstatic char *heap_next; 163200309Sjhbstatic char *heap_end; 164200309Sjhb 165185029Spjd/* Buffers that must not span a 64k boundary. */ 166185029Spjd#define READ_BUF_SIZE 8192 167185029Spjdstruct dmadat { 168185029Spjd char rdbuf[READ_BUF_SIZE]; /* for reading large things */ 169185029Spjd char secbuf[READ_BUF_SIZE]; /* for MBR/disklabel */ 170185029Spjd}; 171185029Spjdstatic struct dmadat *dmadat; 172185029Spjd 173185029Spjdvoid exit(int); 174185029Spjdstatic void load(void); 175185029Spjdstatic int parse(void); 176185029Spjdstatic void printf(const char *,...); 177185029Spjdstatic void putchar(int); 178200309Sjhbstatic void bios_getmem(void); 179199579Sjhbstatic int drvread(struct dsk *, void *, daddr_t, unsigned); 180185029Spjdstatic int keyhit(unsigned); 181185029Spjdstatic int xputc(int); 182185029Spjdstatic int xgetc(int); 183185029Spjdstatic int getc(int); 184185029Spjd 185185029Spjdstatic void memcpy(void *, const void *, int); 186185029Spjdstatic void 187185029Spjdmemcpy(void *dst, const void *src, int len) 188185029Spjd{ 189185029Spjd const char *s = src; 190185029Spjd char *d = dst; 191185029Spjd 192185029Spjd while (len--) 193185029Spjd *d++ = *s++; 194185029Spjd} 195185029Spjd 196185029Spjdstatic void 197185029Spjdstrcpy(char *dst, const char *src) 198185029Spjd{ 199185029Spjd while (*src) 200185029Spjd *dst++ = *src++; 201185029Spjd *dst++ = 0; 202185029Spjd} 203185029Spjd 204185029Spjdstatic void 205185029Spjdstrcat(char *dst, const char *src) 206185029Spjd{ 207185029Spjd while (*dst) 208185029Spjd dst++; 209185029Spjd while (*src) 210185029Spjd *dst++ = *src++; 211185029Spjd *dst++ = 0; 212185029Spjd} 213185029Spjd 214185029Spjdstatic int 215185029Spjdstrcmp(const char *s1, const char *s2) 216185029Spjd{ 217185029Spjd for (; *s1 == *s2 && *s1; s1++, s2++); 218185029Spjd return (unsigned char)*s1 - (unsigned char)*s2; 219185029Spjd} 220185029Spjd 221185029Spjdstatic const char * 222185029Spjdstrchr(const char *s, char ch) 223185029Spjd{ 224185029Spjd for (; *s; s++) 225185029Spjd if (*s == ch) 226185029Spjd return s; 227185029Spjd return 0; 228185029Spjd} 229185029Spjd 230185029Spjdstatic int 231185029Spjdmemcmp(const void *p1, const void *p2, size_t n) 232185029Spjd{ 233185029Spjd const char *s1 = (const char *) p1; 234185029Spjd const char *s2 = (const char *) p2; 235185029Spjd for (; n > 0 && *s1 == *s2; s1++, s2++, n--); 236185029Spjd if (n) 237185029Spjd return (unsigned char)*s1 - (unsigned char)*s2; 238185029Spjd else 239185029Spjd return 0; 240185029Spjd} 241185029Spjd 242185029Spjdstatic void 243185029Spjdmemset(void *p, char val, size_t n) 244185029Spjd{ 245185029Spjd char *s = (char *) p; 246185029Spjd while (n--) 247185029Spjd *s++ = val; 248185029Spjd} 249185029Spjd 250185029Spjdstatic void * 251185029Spjdmalloc(size_t n) 252185029Spjd{ 253185029Spjd char *p = heap_next; 254185029Spjd if (p + n > heap_end) { 255185029Spjd printf("malloc failure\n"); 256185029Spjd for (;;) 257185029Spjd ; 258185029Spjd return 0; 259185029Spjd } 260185029Spjd heap_next += n; 261185029Spjd return p; 262185029Spjd} 263185029Spjd 264185029Spjdstatic size_t 265185029Spjdstrlen(const char *s) 266185029Spjd{ 267185029Spjd size_t len = 0; 268185029Spjd while (*s++) 269185029Spjd len++; 270185029Spjd return len; 271185029Spjd} 272185029Spjd 273185029Spjdstatic char * 274185029Spjdstrdup(const char *s) 275185029Spjd{ 276185029Spjd char *p = malloc(strlen(s) + 1); 277185029Spjd strcpy(p, s); 278185029Spjd return p; 279185029Spjd} 280185029Spjd 281185029Spjd#include "zfsimpl.c" 282185029Spjd 283185029Spjd/* 284185029Spjd * Read from a dnode (which must be from a ZPL filesystem). 285185029Spjd */ 286185029Spjdstatic int 287185029Spjdzfs_read(spa_t *spa, const dnode_phys_t *dnode, off_t *offp, void *start, size_t size) 288185029Spjd{ 289185029Spjd const znode_phys_t *zp = (const znode_phys_t *) dnode->dn_bonus; 290185029Spjd size_t n; 291185029Spjd int rc; 292185029Spjd 293185029Spjd n = size; 294185029Spjd if (*offp + n > zp->zp_size) 295185029Spjd n = zp->zp_size - *offp; 296185029Spjd 297185029Spjd rc = dnode_read(spa, dnode, *offp, start, n); 298185029Spjd if (rc) 299185029Spjd return (-1); 300185029Spjd *offp += n; 301185029Spjd 302185029Spjd return (n); 303185029Spjd} 304185029Spjd 305185029Spjd/* 306185029Spjd * Current ZFS pool 307185029Spjd */ 308185029Spjdspa_t *spa; 309185029Spjd 310185029Spjd/* 311185029Spjd * A wrapper for dskread that doesn't have to worry about whether the 312185029Spjd * buffer pointer crosses a 64k boundary. 313185029Spjd */ 314185029Spjdstatic int 315185029Spjdvdev_read(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes) 316185029Spjd{ 317185029Spjd char *p; 318199579Sjhb daddr_t lba; 319199579Sjhb unsigned int nb; 320185029Spjd struct dsk *dsk = (struct dsk *) priv; 321185029Spjd 322185029Spjd if ((off & (DEV_BSIZE - 1)) || (bytes & (DEV_BSIZE - 1))) 323185029Spjd return -1; 324185029Spjd 325185029Spjd p = buf; 326185029Spjd lba = off / DEV_BSIZE; 327185029Spjd while (bytes > 0) { 328185029Spjd nb = bytes / DEV_BSIZE; 329185029Spjd if (nb > READ_BUF_SIZE / DEV_BSIZE) 330185029Spjd nb = READ_BUF_SIZE / DEV_BSIZE; 331185029Spjd if (drvread(dsk, dmadat->rdbuf, lba, nb)) 332185029Spjd return -1; 333185029Spjd memcpy(p, dmadat->rdbuf, nb * DEV_BSIZE); 334185029Spjd p += nb * DEV_BSIZE; 335185029Spjd lba += nb; 336185029Spjd bytes -= nb * DEV_BSIZE; 337185029Spjd } 338185029Spjd 339185029Spjd return 0; 340185029Spjd} 341185029Spjd 342185029Spjdstatic int 343185029Spjdxfsread(const dnode_phys_t *dnode, off_t *offp, void *buf, size_t nbyte) 344185029Spjd{ 345185029Spjd if ((size_t)zfs_read(spa, dnode, offp, buf, nbyte) != nbyte) { 346185029Spjd printf("Invalid %s\n", "format"); 347185029Spjd return -1; 348185029Spjd } 349185029Spjd return 0; 350185029Spjd} 351185029Spjd 352200309Sjhbstatic void 353200309Sjhbbios_getmem(void) 354185029Spjd{ 355200309Sjhb uint64_t size; 356185029Spjd 357200309Sjhb /* Parse system memory map */ 358200309Sjhb v86.ebx = 0; 359200309Sjhb do { 360200309Sjhb v86.ctl = V86_FLAGS; 361200309Sjhb v86.addr = 0x15; /* int 0x15 function 0xe820*/ 362200309Sjhb v86.eax = 0xe820; 363200309Sjhb v86.ecx = sizeof(struct bios_smap); 364200309Sjhb v86.edx = SMAP_SIG; 365200309Sjhb v86.es = VTOPSEG(&smap); 366200309Sjhb v86.edi = VTOPOFF(&smap); 367200309Sjhb v86int(); 368200309Sjhb if ((v86.efl & 1) || (v86.eax != SMAP_SIG)) 369200309Sjhb break; 370200309Sjhb /* look for a low-memory segment that's large enough */ 371200309Sjhb if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0) && 372200309Sjhb (smap.length >= (512 * 1024))) 373200309Sjhb bios_basemem = smap.length; 374200309Sjhb /* look for the first segment in 'extended' memory */ 375200309Sjhb if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0x100000)) { 376200309Sjhb bios_extmem = smap.length; 377200309Sjhb } 378200309Sjhb 379200309Sjhb /* 380200309Sjhb * Look for the largest segment in 'extended' memory beyond 381200309Sjhb * 1MB but below 4GB. 382200309Sjhb */ 383200309Sjhb if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base > 0x100000) && 384200309Sjhb (smap.base < 0x100000000ull)) { 385200309Sjhb size = smap.length; 386200309Sjhb 387200309Sjhb /* 388200309Sjhb * If this segment crosses the 4GB boundary, truncate it. 389200309Sjhb */ 390200309Sjhb if (smap.base + size > 0x100000000ull) 391200309Sjhb size = 0x100000000ull - smap.base; 392200309Sjhb 393200309Sjhb if (size > high_heap_size) { 394200309Sjhb high_heap_size = size; 395200309Sjhb high_heap_base = smap.base; 396200309Sjhb } 397200309Sjhb } 398200309Sjhb } while (v86.ebx != 0); 399200309Sjhb 400200309Sjhb /* Fall back to the old compatibility function for base memory */ 401200309Sjhb if (bios_basemem == 0) { 402200309Sjhb v86.ctl = 0; 403200309Sjhb v86.addr = 0x12; /* int 0x12 */ 404200309Sjhb v86int(); 405200309Sjhb 406200309Sjhb bios_basemem = (v86.eax & 0xffff) * 1024; 407200309Sjhb } 408200309Sjhb 409200309Sjhb /* Fall back through several compatibility functions for extended memory */ 410200309Sjhb if (bios_extmem == 0) { 411200309Sjhb v86.ctl = V86_FLAGS; 412200309Sjhb v86.addr = 0x15; /* int 0x15 function 0xe801*/ 413200309Sjhb v86.eax = 0xe801; 414200309Sjhb v86int(); 415200309Sjhb if (!(v86.efl & 1)) { 416200309Sjhb bios_extmem = ((v86.ecx & 0xffff) + ((v86.edx & 0xffff) * 64)) * 1024; 417200309Sjhb } 418200309Sjhb } 419200309Sjhb if (bios_extmem == 0) { 420200309Sjhb v86.ctl = 0; 421200309Sjhb v86.addr = 0x15; /* int 0x15 function 0x88*/ 422200309Sjhb v86.eax = 0x8800; 423200309Sjhb v86int(); 424200309Sjhb bios_extmem = (v86.eax & 0xffff) * 1024; 425200309Sjhb } 426200309Sjhb 427200309Sjhb /* 428200309Sjhb * If we have extended memory and did not find a suitable heap 429200309Sjhb * region in the SMAP, use the last 3MB of 'extended' memory as a 430200309Sjhb * high heap candidate. 431200309Sjhb */ 432200309Sjhb if (bios_extmem >= HEAP_MIN && high_heap_size < HEAP_MIN) { 433200309Sjhb high_heap_size = HEAP_MIN; 434200309Sjhb high_heap_base = bios_extmem + 0x100000 - HEAP_MIN; 435200309Sjhb } 436200309Sjhb} 437200309Sjhb 438185029Spjdstatic inline void 439185029Spjdgetstr(void) 440185029Spjd{ 441185029Spjd char *s; 442185029Spjd int c; 443185029Spjd 444185029Spjd s = cmd; 445185029Spjd for (;;) { 446185029Spjd switch (c = xgetc(0)) { 447185029Spjd case 0: 448185029Spjd break; 449185029Spjd case '\177': 450185029Spjd case '\b': 451185029Spjd if (s > cmd) { 452185029Spjd s--; 453185029Spjd printf("\b \b"); 454185029Spjd } 455185029Spjd break; 456185029Spjd case '\n': 457185029Spjd case '\r': 458185029Spjd *s = 0; 459185029Spjd return; 460185029Spjd default: 461185029Spjd if (s - cmd < sizeof(cmd) - 1) 462185029Spjd *s++ = c; 463185029Spjd putchar(c); 464185029Spjd } 465185029Spjd } 466185029Spjd} 467185029Spjd 468185029Spjdstatic inline void 469185029Spjdputc(int c) 470185029Spjd{ 471208388Sjhb v86.ctl = 0; 472185029Spjd v86.addr = 0x10; 473185029Spjd v86.eax = 0xe00 | (c & 0xff); 474185029Spjd v86.ebx = 0x7; 475185029Spjd v86int(); 476185029Spjd} 477185029Spjd 478185029Spjd/* 479185029Spjd * Try to detect a device supported by the legacy int13 BIOS 480185029Spjd */ 481185029Spjdstatic int 482185029Spjdint13probe(int drive) 483185029Spjd{ 484185029Spjd v86.ctl = V86_FLAGS; 485185029Spjd v86.addr = 0x13; 486185029Spjd v86.eax = 0x800; 487185029Spjd v86.edx = drive; 488185029Spjd v86int(); 489185029Spjd 490185029Spjd if (!(v86.efl & 0x1) && /* carry clear */ 491185029Spjd ((v86.edx & 0xff) != (drive & DRV_MASK))) { /* unit # OK */ 492185029Spjd if ((v86.ecx & 0x3f) == 0) { /* absurd sector size */ 493185029Spjd return(0); /* skip device */ 494185029Spjd } 495185029Spjd return (1); 496185029Spjd } 497185029Spjd return(0); 498185029Spjd} 499185029Spjd 500192194Sdfr/* 501192194Sdfr * We call this when we find a ZFS vdev - ZFS consumes the dsk 502192194Sdfr * structure so we must make a new one. 503192194Sdfr */ 504192194Sdfrstatic struct dsk * 505192194Sdfrcopy_dsk(struct dsk *dsk) 506192194Sdfr{ 507192194Sdfr struct dsk *newdsk; 508192194Sdfr 509192194Sdfr newdsk = malloc(sizeof(struct dsk)); 510192194Sdfr *newdsk = *dsk; 511192194Sdfr return (newdsk); 512192194Sdfr} 513192194Sdfr 514185029Spjdstatic void 515185029Spjdprobe_drive(struct dsk *dsk, spa_t **spap) 516185029Spjd{ 517185096Sdfr#ifdef GPT 518185096Sdfr struct gpt_hdr hdr; 519185096Sdfr struct gpt_ent *ent; 520185096Sdfr daddr_t slba, elba; 521185096Sdfr unsigned part, entries_per_sec; 522185096Sdfr#endif 523185029Spjd struct dos_partition *dp; 524185029Spjd char *sec; 525185029Spjd unsigned i; 526185029Spjd 527185029Spjd /* 528185029Spjd * If we find a vdev on the whole disk, stop here. Otherwise dig 529185029Spjd * out the MBR and probe each slice in turn for a vdev. 530185029Spjd */ 531185029Spjd if (vdev_probe(vdev_read, dsk, spap) == 0) 532185029Spjd return; 533185029Spjd 534185029Spjd sec = dmadat->secbuf; 535185029Spjd dsk->start = 0; 536185096Sdfr 537185096Sdfr#ifdef GPT 538185096Sdfr /* 539185096Sdfr * First check for GPT. 540185096Sdfr */ 541185096Sdfr if (drvread(dsk, sec, 1, 1)) { 542185096Sdfr return; 543185096Sdfr } 544185096Sdfr memcpy(&hdr, sec, sizeof(hdr)); 545185096Sdfr if (memcmp(hdr.hdr_sig, GPT_HDR_SIG, sizeof(hdr.hdr_sig)) != 0 || 546185096Sdfr hdr.hdr_lba_self != 1 || hdr.hdr_revision < 0x00010000 || 547185096Sdfr hdr.hdr_entsz < sizeof(*ent) || DEV_BSIZE % hdr.hdr_entsz != 0) { 548185096Sdfr goto trymbr; 549185096Sdfr } 550185096Sdfr 551185096Sdfr /* 552185096Sdfr * Probe all GPT partitions for the presense of ZFS pools. We 553185096Sdfr * return the spa_t for the first we find (if requested). This 554185096Sdfr * will have the effect of booting from the first pool on the 555185096Sdfr * disk. 556185096Sdfr */ 557185096Sdfr entries_per_sec = DEV_BSIZE / hdr.hdr_entsz; 558185096Sdfr slba = hdr.hdr_lba_table; 559185096Sdfr elba = slba + hdr.hdr_entries / entries_per_sec; 560185096Sdfr while (slba < elba) { 561198420Srnoland dsk->start = 0; 562185096Sdfr if (drvread(dsk, sec, slba, 1)) 563185096Sdfr return; 564185096Sdfr for (part = 0; part < entries_per_sec; part++) { 565185096Sdfr ent = (struct gpt_ent *)(sec + part * hdr.hdr_entsz); 566185096Sdfr if (memcmp(&ent->ent_type, &freebsd_zfs_uuid, 567185096Sdfr sizeof(uuid_t)) == 0) { 568185096Sdfr dsk->start = ent->ent_lba_start; 569185096Sdfr if (vdev_probe(vdev_read, dsk, spap) == 0) { 570185096Sdfr /* 571185096Sdfr * We record the first pool we find (we will try 572192194Sdfr * to boot from that one). 573185096Sdfr */ 574185096Sdfr spap = 0; 575185096Sdfr 576185096Sdfr /* 577185096Sdfr * This slice had a vdev. We need a new dsk 578185096Sdfr * structure now since the vdev now owns this one. 579185096Sdfr */ 580192194Sdfr dsk = copy_dsk(dsk); 581185096Sdfr } 582185096Sdfr } 583185096Sdfr } 584185096Sdfr slba++; 585185096Sdfr } 586185096Sdfr return; 587185096Sdfrtrymbr: 588185096Sdfr#endif 589185096Sdfr 590185029Spjd if (drvread(dsk, sec, DOSBBSECTOR, 1)) 591185029Spjd return; 592185029Spjd dp = (void *)(sec + DOSPARTOFF); 593185029Spjd 594185029Spjd for (i = 0; i < NDOSPART; i++) { 595185029Spjd if (!dp[i].dp_typ) 596185029Spjd continue; 597185029Spjd dsk->start = dp[i].dp_start; 598185029Spjd if (vdev_probe(vdev_read, dsk, spap) == 0) { 599185029Spjd /* 600185029Spjd * We record the first pool we find (we will try to boot 601185029Spjd * from that one. 602185029Spjd */ 603185029Spjd spap = 0; 604185029Spjd 605185029Spjd /* 606185029Spjd * This slice had a vdev. We need a new dsk structure now 607185096Sdfr * since the vdev now owns this one. 608185029Spjd */ 609192194Sdfr dsk = copy_dsk(dsk); 610185029Spjd } 611185029Spjd } 612185029Spjd} 613185029Spjd 614185029Spjdint 615185029Spjdmain(void) 616185029Spjd{ 617185029Spjd int autoboot, i; 618185029Spjd dnode_phys_t dn; 619185029Spjd off_t off; 620185029Spjd struct dsk *dsk; 621185029Spjd 622208388Sjhb dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base); 623208388Sjhb 624200309Sjhb bios_getmem(); 625200309Sjhb 626200309Sjhb if (high_heap_size > 0) { 627200309Sjhb heap_end = PTOV(high_heap_base + high_heap_size); 628200309Sjhb heap_next = PTOV(high_heap_base); 629200309Sjhb } else { 630200309Sjhb heap_next = (char *) dmadat + sizeof(*dmadat); 631200309Sjhb heap_end = (char *) PTOV(bios_basemem); 632200309Sjhb } 633200309Sjhb 634185029Spjd dsk = malloc(sizeof(struct dsk)); 635185029Spjd dsk->drive = *(uint8_t *)PTOV(ARGS); 636185029Spjd dsk->type = dsk->drive & DRV_HARD ? TYPE_AD : TYPE_FD; 637185029Spjd dsk->unit = dsk->drive & DRV_MASK; 638185029Spjd dsk->slice = *(uint8_t *)PTOV(ARGS + 1) + 1; 639185029Spjd dsk->part = 0; 640185029Spjd dsk->start = 0; 641185029Spjd dsk->init = 0; 642185029Spjd 643185029Spjd bootinfo.bi_version = BOOTINFO_VERSION; 644185029Spjd bootinfo.bi_size = sizeof(bootinfo); 645200309Sjhb bootinfo.bi_basemem = bios_basemem / 1024; 646200309Sjhb bootinfo.bi_extmem = bios_extmem / 1024; 647185029Spjd bootinfo.bi_memsizes_valid++; 648185029Spjd bootinfo.bi_bios_dev = dsk->drive; 649185029Spjd 650185029Spjd bootdev = MAKEBOOTDEV(dev_maj[dsk->type], 651185029Spjd dsk->slice, dsk->unit, dsk->part), 652185029Spjd 653185029Spjd /* Process configuration file */ 654185029Spjd 655185029Spjd autoboot = 1; 656185029Spjd 657185029Spjd zfs_init(); 658185029Spjd 659185029Spjd /* 660185029Spjd * Probe the boot drive first - we will try to boot from whatever 661185029Spjd * pool we find on that drive. 662185029Spjd */ 663185029Spjd probe_drive(dsk, &spa); 664185029Spjd 665185029Spjd /* 666185029Spjd * Probe the rest of the drives that the bios knows about. This 667185029Spjd * will find any other available pools and it may fill in missing 668185029Spjd * vdevs for the boot pool. 669185029Spjd */ 670212805Spjd#ifndef VIRTUALBOX 671212805Spjd for (i = 0; i < *(unsigned char *)PTOV(BIOS_NUMDRIVES); i++) 672212805Spjd#else 673212805Spjd for (i = 0; i < MAXBDDEV; i++) 674212805Spjd#endif 675212805Spjd { 676185029Spjd if ((i | DRV_HARD) == *(uint8_t *)PTOV(ARGS)) 677185029Spjd continue; 678185029Spjd 679192194Sdfr if (!int13probe(i | DRV_HARD)) 680192194Sdfr break; 681192194Sdfr 682185029Spjd dsk = malloc(sizeof(struct dsk)); 683185029Spjd dsk->drive = i | DRV_HARD; 684185029Spjd dsk->type = dsk->drive & TYPE_AD; 685185029Spjd dsk->unit = i; 686185029Spjd dsk->slice = 0; 687185029Spjd dsk->part = 0; 688185029Spjd dsk->start = 0; 689185029Spjd dsk->init = 0; 690185029Spjd probe_drive(dsk, 0); 691185029Spjd } 692185029Spjd 693185029Spjd /* 694185029Spjd * If we didn't find a pool on the boot drive, default to the 695185029Spjd * first pool we found, if any. 696185029Spjd */ 697185029Spjd if (!spa) { 698185029Spjd spa = STAILQ_FIRST(&zfs_pools); 699185029Spjd if (!spa) { 700185029Spjd printf("No ZFS pools located, can't boot\n"); 701185029Spjd for (;;) 702185029Spjd ; 703185029Spjd } 704185029Spjd } 705185029Spjd 706185029Spjd zfs_mount_pool(spa); 707185029Spjd 708185029Spjd if (zfs_lookup(spa, PATH_CONFIG, &dn) == 0) { 709185029Spjd off = 0; 710198079Sjhb zfs_read(spa, &dn, &off, cmd, sizeof(cmd)); 711185029Spjd } 712185029Spjd 713185029Spjd if (*cmd) { 714185029Spjd if (parse()) 715185029Spjd autoboot = 0; 716185029Spjd if (!OPT_CHECK(RBX_QUIET)) 717185029Spjd printf("%s: %s", PATH_CONFIG, cmd); 718185029Spjd /* Do not process this command twice */ 719185029Spjd *cmd = 0; 720185029Spjd } 721185029Spjd 722185029Spjd /* 723185029Spjd * Try to exec stage 3 boot loader. If interrupted by a keypress, 724185029Spjd * or in case of failure, try to load a kernel directly instead. 725185029Spjd */ 726185029Spjd 727185029Spjd if (autoboot && !*kname) { 728185029Spjd memcpy(kname, PATH_BOOT3, sizeof(PATH_BOOT3)); 729185029Spjd if (!keyhit(3*SECOND)) { 730185029Spjd load(); 731185029Spjd memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL)); 732185029Spjd } 733185029Spjd } 734185029Spjd 735185029Spjd /* Present the user with the boot2 prompt. */ 736185029Spjd 737185029Spjd for (;;) { 738185029Spjd if (!autoboot || !OPT_CHECK(RBX_QUIET)) 739205662Sdelphij printf("\nFreeBSD/x86 boot\n" 740185029Spjd "Default: %s:%s\n" 741185029Spjd "boot: ", 742185029Spjd spa->spa_name, kname); 743185029Spjd if (ioctrl & IO_SERIAL) 744185029Spjd sio_flush(); 745185029Spjd if (!autoboot || keyhit(5*SECOND)) 746185029Spjd getstr(); 747185029Spjd else if (!autoboot || !OPT_CHECK(RBX_QUIET)) 748185029Spjd putchar('\n'); 749185029Spjd autoboot = 0; 750185029Spjd if (parse()) 751185029Spjd putchar('\a'); 752185029Spjd else 753185029Spjd load(); 754185029Spjd } 755185029Spjd} 756185029Spjd 757185029Spjd/* XXX - Needed for btxld to link the boot2 binary; do not remove. */ 758185029Spjdvoid 759185029Spjdexit(int x) 760185029Spjd{ 761185029Spjd} 762185029Spjd 763185029Spjdstatic void 764185029Spjdload(void) 765185029Spjd{ 766185029Spjd union { 767185029Spjd struct exec ex; 768185029Spjd Elf32_Ehdr eh; 769185029Spjd } hdr; 770185029Spjd static Elf32_Phdr ep[2]; 771185029Spjd static Elf32_Shdr es[2]; 772185029Spjd caddr_t p; 773185029Spjd dnode_phys_t dn; 774185029Spjd off_t off; 775185029Spjd uint32_t addr, x; 776185029Spjd int fmt, i, j; 777185029Spjd 778185029Spjd if (zfs_lookup(spa, kname, &dn)) { 779185029Spjd return; 780185029Spjd } 781185029Spjd off = 0; 782185029Spjd if (xfsread(&dn, &off, &hdr, sizeof(hdr))) 783185029Spjd return; 784185029Spjd if (N_GETMAGIC(hdr.ex) == ZMAGIC) 785185029Spjd fmt = 0; 786185029Spjd else if (IS_ELF(hdr.eh)) 787185029Spjd fmt = 1; 788185029Spjd else { 789185029Spjd printf("Invalid %s\n", "format"); 790185029Spjd return; 791185029Spjd } 792185029Spjd if (fmt == 0) { 793185029Spjd addr = hdr.ex.a_entry & 0xffffff; 794185029Spjd p = PTOV(addr); 795185029Spjd off = PAGE_SIZE; 796185029Spjd if (xfsread(&dn, &off, p, hdr.ex.a_text)) 797185029Spjd return; 798185029Spjd p += roundup2(hdr.ex.a_text, PAGE_SIZE); 799185029Spjd if (xfsread(&dn, &off, p, hdr.ex.a_data)) 800185029Spjd return; 801185029Spjd p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE); 802185029Spjd bootinfo.bi_symtab = VTOP(p); 803185029Spjd memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms)); 804185029Spjd p += sizeof(hdr.ex.a_syms); 805185029Spjd if (hdr.ex.a_syms) { 806185029Spjd if (xfsread(&dn, &off, p, hdr.ex.a_syms)) 807185029Spjd return; 808185029Spjd p += hdr.ex.a_syms; 809185029Spjd if (xfsread(&dn, &off, p, sizeof(int))) 810185029Spjd return; 811185029Spjd x = *(uint32_t *)p; 812185029Spjd p += sizeof(int); 813185029Spjd x -= sizeof(int); 814185029Spjd if (xfsread(&dn, &off, p, x)) 815185029Spjd return; 816185029Spjd p += x; 817185029Spjd } 818185029Spjd } else { 819185029Spjd off = hdr.eh.e_phoff; 820185029Spjd for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) { 821185029Spjd if (xfsread(&dn, &off, ep + j, sizeof(ep[0]))) 822185029Spjd return; 823185029Spjd if (ep[j].p_type == PT_LOAD) 824185029Spjd j++; 825185029Spjd } 826185029Spjd for (i = 0; i < 2; i++) { 827185029Spjd p = PTOV(ep[i].p_paddr & 0xffffff); 828185029Spjd off = ep[i].p_offset; 829185029Spjd if (xfsread(&dn, &off, p, ep[i].p_filesz)) 830185029Spjd return; 831185029Spjd } 832185029Spjd p += roundup2(ep[1].p_memsz, PAGE_SIZE); 833185029Spjd bootinfo.bi_symtab = VTOP(p); 834185029Spjd if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { 835185029Spjd off = hdr.eh.e_shoff + sizeof(es[0]) * 836185029Spjd (hdr.eh.e_shstrndx + 1); 837185029Spjd if (xfsread(&dn, &off, &es, sizeof(es))) 838185029Spjd return; 839185029Spjd for (i = 0; i < 2; i++) { 840185029Spjd memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size)); 841185029Spjd p += sizeof(es[i].sh_size); 842185029Spjd off = es[i].sh_offset; 843185029Spjd if (xfsread(&dn, &off, p, es[i].sh_size)) 844185029Spjd return; 845185029Spjd p += es[i].sh_size; 846185029Spjd } 847185029Spjd } 848185029Spjd addr = hdr.eh.e_entry & 0xffffff; 849185029Spjd } 850185029Spjd bootinfo.bi_esymtab = VTOP(p); 851185029Spjd bootinfo.bi_kernelname = VTOP(kname); 852185029Spjd __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), 853185029Spjd bootdev, 854185029Spjd KARGS_FLAGS_ZFS, 855185029Spjd (uint32_t) spa->spa_guid, 856185029Spjd (uint32_t) (spa->spa_guid >> 32), 857185029Spjd VTOP(&bootinfo)); 858185029Spjd} 859185029Spjd 860185029Spjdstatic int 861185029Spjdparse() 862185029Spjd{ 863185029Spjd char *arg = cmd; 864185029Spjd char *ep, *p, *q; 865185029Spjd const char *cp; 866185029Spjd //unsigned int drv; 867185029Spjd int c, i, j; 868185029Spjd 869185029Spjd while ((c = *arg++)) { 870185029Spjd if (c == ' ' || c == '\t' || c == '\n') 871185029Spjd continue; 872185029Spjd for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++); 873185029Spjd ep = p; 874185029Spjd if (*p) 875185029Spjd *p++ = 0; 876185029Spjd if (c == '-') { 877185029Spjd while ((c = *arg++)) { 878185029Spjd if (c == 'P') { 879185029Spjd if (*(uint8_t *)PTOV(0x496) & 0x10) { 880185029Spjd cp = "yes"; 881185029Spjd } else { 882185029Spjd opts |= OPT_SET(RBX_DUAL) | OPT_SET(RBX_SERIAL); 883185029Spjd cp = "no"; 884185029Spjd } 885185029Spjd printf("Keyboard: %s\n", cp); 886185029Spjd continue; 887185029Spjd } else if (c == 'S') { 888185029Spjd j = 0; 889185029Spjd while ((unsigned int)(i = *arg++ - '0') <= 9) 890185029Spjd j = j * 10 + i; 891185029Spjd if (j > 0 && i == -'0') { 892185029Spjd comspeed = j; 893185029Spjd break; 894185029Spjd } 895185029Spjd /* Fall through to error below ('S' not in optstr[]). */ 896185029Spjd } 897185029Spjd for (i = 0; c != optstr[i]; i++) 898185029Spjd if (i == NOPT - 1) 899185029Spjd return -1; 900185029Spjd opts ^= OPT_SET(flags[i]); 901185029Spjd } 902185029Spjd ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) : 903185029Spjd OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD; 904185029Spjd if (ioctrl & IO_SERIAL) 905185029Spjd sio_init(115200 / comspeed); 906185029Spjd } if (c == '?') { 907185029Spjd dnode_phys_t dn; 908185029Spjd 909185029Spjd if (zfs_lookup(spa, arg, &dn) == 0) { 910185029Spjd zap_list(spa, &dn); 911185029Spjd } 912185029Spjd return -1; 913185029Spjd } else { 914185029Spjd arg--; 915185029Spjd 916185029Spjd /* 917185029Spjd * Report pool status if the comment is 'status'. Lets 918185029Spjd * hope no-one wants to load /status as a kernel. 919185029Spjd */ 920185029Spjd if (!strcmp(arg, "status")) { 921185029Spjd spa_all_status(); 922185029Spjd return -1; 923185029Spjd } 924185029Spjd 925185029Spjd /* 926185029Spjd * If there is a colon, switch pools. 927185029Spjd */ 928185029Spjd q = (char *) strchr(arg, ':'); 929185029Spjd if (q) { 930185029Spjd spa_t *newspa; 931185029Spjd 932185029Spjd *q++ = 0; 933185029Spjd newspa = spa_find_by_name(arg); 934185029Spjd if (newspa) { 935185029Spjd spa = newspa; 936185029Spjd zfs_mount_pool(spa); 937185029Spjd } else { 938185029Spjd printf("\nCan't find ZFS pool %s\n", arg); 939185029Spjd return -1; 940185029Spjd } 941185029Spjd arg = q; 942185029Spjd } 943185029Spjd if ((i = ep - arg)) { 944185029Spjd if ((size_t)i >= sizeof(kname)) 945185029Spjd return -1; 946185029Spjd memcpy(kname, arg, i + 1); 947185029Spjd } 948185029Spjd } 949185029Spjd arg = p; 950185029Spjd } 951185029Spjd return 0; 952185029Spjd} 953185029Spjd 954185029Spjdstatic void 955185029Spjdprintf(const char *fmt,...) 956185029Spjd{ 957185029Spjd va_list ap; 958198420Srnoland char buf[20]; 959185029Spjd char *s; 960198420Srnoland unsigned long long u; 961185029Spjd int c; 962185029Spjd int minus; 963185029Spjd int prec; 964198420Srnoland int l; 965185029Spjd int len; 966185029Spjd int pad; 967185029Spjd 968185029Spjd va_start(ap, fmt); 969185029Spjd while ((c = *fmt++)) { 970185029Spjd if (c == '%') { 971185029Spjd minus = 0; 972185029Spjd prec = 0; 973198420Srnoland l = 0; 974185029Spjd nextfmt: 975185029Spjd c = *fmt++; 976185029Spjd switch (c) { 977185029Spjd case '-': 978185029Spjd minus = 1; 979185029Spjd goto nextfmt; 980185029Spjd case '0': 981185029Spjd case '1': 982185029Spjd case '2': 983185029Spjd case '3': 984185029Spjd case '4': 985185029Spjd case '5': 986185029Spjd case '6': 987185029Spjd case '7': 988185029Spjd case '8': 989185029Spjd case '9': 990185029Spjd prec = 10 * prec + (c - '0'); 991185029Spjd goto nextfmt; 992185029Spjd case 'c': 993185029Spjd putchar(va_arg(ap, int)); 994185029Spjd continue; 995198420Srnoland case 'l': 996198420Srnoland l++; 997198420Srnoland goto nextfmt; 998185029Spjd case 's': 999185029Spjd s = va_arg(ap, char *); 1000185029Spjd if (prec) { 1001185029Spjd len = strlen(s); 1002185029Spjd if (len < prec) 1003185029Spjd pad = prec - len; 1004185029Spjd else 1005185029Spjd pad = 0; 1006185029Spjd if (minus) 1007185029Spjd while (pad--) 1008185029Spjd putchar(' '); 1009185029Spjd for (; *s; s++) 1010185029Spjd putchar(*s); 1011185029Spjd if (!minus) 1012185029Spjd while (pad--) 1013185029Spjd putchar(' '); 1014185029Spjd } else { 1015185029Spjd for (; *s; s++) 1016185029Spjd putchar(*s); 1017185029Spjd } 1018185029Spjd continue; 1019185029Spjd case 'u': 1020198420Srnoland switch (l) { 1021198420Srnoland case 2: 1022198420Srnoland u = va_arg(ap, unsigned long long); 1023198420Srnoland break; 1024198420Srnoland case 1: 1025198420Srnoland u = va_arg(ap, unsigned long); 1026198420Srnoland break; 1027198420Srnoland default: 1028198420Srnoland u = va_arg(ap, unsigned); 1029198420Srnoland break; 1030198420Srnoland } 1031185029Spjd s = buf; 1032185029Spjd do 1033185029Spjd *s++ = '0' + u % 10U; 1034185029Spjd while (u /= 10U); 1035185029Spjd while (--s >= buf) 1036185029Spjd putchar(*s); 1037185029Spjd continue; 1038185029Spjd } 1039185029Spjd } 1040185029Spjd putchar(c); 1041185029Spjd } 1042185029Spjd va_end(ap); 1043185029Spjd return; 1044185029Spjd} 1045185029Spjd 1046185029Spjdstatic void 1047185029Spjdputchar(int c) 1048185029Spjd{ 1049185029Spjd if (c == '\n') 1050185029Spjd xputc('\r'); 1051185029Spjd xputc(c); 1052185029Spjd} 1053185029Spjd 1054185096Sdfr#ifdef GPT 1055185096Sdfrstatic struct { 1056185096Sdfr uint16_t len; 1057185096Sdfr uint16_t count; 1058200310Sjhb uint16_t off; 1059185096Sdfr uint16_t seg; 1060185096Sdfr uint64_t lba; 1061185096Sdfr} packet; 1062185096Sdfr#endif 1063185096Sdfr 1064185029Spjdstatic int 1065199579Sjhbdrvread(struct dsk *dsk, void *buf, daddr_t lba, unsigned nblk) 1066185029Spjd{ 1067185096Sdfr#ifdef GPT 1068192194Sdfr static unsigned c = 0x2d5c7c2f; 1069185096Sdfr 1070185096Sdfr if (!OPT_CHECK(RBX_QUIET)) 1071185096Sdfr printf("%c\b", c = c << 8 | c >> 24); 1072185096Sdfr packet.len = 0x10; 1073185096Sdfr packet.count = nblk; 1074200310Sjhb packet.off = VTOPOFF(buf); 1075200310Sjhb packet.seg = VTOPSEG(buf); 1076185096Sdfr packet.lba = lba + dsk->start; 1077185096Sdfr v86.ctl = V86_FLAGS; 1078185096Sdfr v86.addr = 0x13; 1079185096Sdfr v86.eax = 0x4200; 1080185096Sdfr v86.edx = dsk->drive; 1081185096Sdfr v86.ds = VTOPSEG(&packet); 1082185096Sdfr v86.esi = VTOPOFF(&packet); 1083185096Sdfr v86int(); 1084185096Sdfr if (V86_CY(v86.efl)) { 1085185096Sdfr printf("error %u lba %u\n", v86.eax >> 8 & 0xff, lba); 1086185096Sdfr return -1; 1087185096Sdfr } 1088185096Sdfr return 0; 1089185096Sdfr#else 1090185029Spjd static unsigned c = 0x2d5c7c2f; 1091185029Spjd 1092185029Spjd lba += dsk->start; 1093185029Spjd if (!OPT_CHECK(RBX_QUIET)) 1094185029Spjd printf("%c\b", c = c << 8 | c >> 24); 1095185029Spjd v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; 1096185029Spjd v86.addr = XREADORG; /* call to xread in boot1 */ 1097185029Spjd v86.es = VTOPSEG(buf); 1098185029Spjd v86.eax = lba; 1099185029Spjd v86.ebx = VTOPOFF(buf); 1100199579Sjhb v86.ecx = lba >> 32; 1101185029Spjd v86.edx = nblk << 8 | dsk->drive; 1102185029Spjd v86int(); 1103185029Spjd v86.ctl = V86_FLAGS; 1104185029Spjd if (V86_CY(v86.efl)) { 1105185029Spjd printf("error %u lba %u\n", v86.eax >> 8 & 0xff, lba); 1106185029Spjd return -1; 1107185029Spjd } 1108185029Spjd return 0; 1109185096Sdfr#endif 1110185029Spjd} 1111185029Spjd 1112185029Spjdstatic int 1113185029Spjdkeyhit(unsigned ticks) 1114185029Spjd{ 1115185029Spjd uint32_t t0, t1; 1116185029Spjd 1117185029Spjd if (OPT_CHECK(RBX_NOINTR)) 1118185029Spjd return 0; 1119185029Spjd t0 = 0; 1120185029Spjd for (;;) { 1121185029Spjd if (xgetc(1)) 1122185029Spjd return 1; 1123185029Spjd t1 = *(uint32_t *)PTOV(0x46c); 1124185029Spjd if (!t0) 1125185029Spjd t0 = t1; 1126185029Spjd if (t1 < t0 || t1 >= t0 + ticks) 1127185029Spjd return 0; 1128185029Spjd } 1129185029Spjd} 1130185029Spjd 1131185029Spjdstatic int 1132185029Spjdxputc(int c) 1133185029Spjd{ 1134185029Spjd if (ioctrl & IO_KEYBOARD) 1135185029Spjd putc(c); 1136185029Spjd if (ioctrl & IO_SERIAL) 1137185029Spjd sio_putc(c); 1138185029Spjd return c; 1139185029Spjd} 1140185029Spjd 1141185029Spjdstatic int 1142185029Spjdxgetc(int fn) 1143185029Spjd{ 1144185029Spjd if (OPT_CHECK(RBX_NOINTR)) 1145185029Spjd return 0; 1146185029Spjd for (;;) { 1147185029Spjd if (ioctrl & IO_KEYBOARD && getc(1)) 1148185029Spjd return fn ? 1 : getc(0); 1149185029Spjd if (ioctrl & IO_SERIAL && sio_ischar()) 1150185029Spjd return fn ? 1 : sio_getc(); 1151185029Spjd if (fn) 1152185029Spjd return 0; 1153185029Spjd } 1154185029Spjd} 1155185029Spjd 1156185029Spjdstatic int 1157185029Spjdgetc(int fn) 1158185029Spjd{ 1159185029Spjd /* 1160185029Spjd * The extra comparison against zero is an attempt to work around 1161185029Spjd * what appears to be a bug in QEMU and Bochs. Both emulators 1162185029Spjd * sometimes report a key-press with scancode one and ascii zero 1163185029Spjd * when no such key is pressed in reality. As far as I can tell, 1164185029Spjd * this only happens shortly after a reboot. 1165185029Spjd */ 1166208388Sjhb v86.ctl = V86_FLAGS; 1167185029Spjd v86.addr = 0x16; 1168185029Spjd v86.eax = fn << 8; 1169185029Spjd v86int(); 1170185029Spjd return fn == 0 ? v86.eax & 0xff : (!V86_ZR(v86.efl) && (v86.eax & 0xff)); 1171185029Spjd} 1172