zfsboot.c revision 344295
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: stable/11/stand/i386/zfsboot/zfsboot.c 344295 2019-02-19 19:16:28Z kevans $"); 18185029Spjd 19329175Skevans#include "stand.h" 20329175Skevans 21185029Spjd#include <sys/param.h> 22185029Spjd#include <sys/errno.h> 23185029Spjd#include <sys/diskmbr.h> 24185096Sdfr#ifdef GPT 25185096Sdfr#include <sys/gpt.h> 26185096Sdfr#endif 27185029Spjd#include <sys/reboot.h> 28185029Spjd#include <sys/queue.h> 29185029Spjd 30185029Spjd#include <machine/bootinfo.h> 31185029Spjd#include <machine/elf.h> 32200309Sjhb#include <machine/pc/bios.h> 33185029Spjd 34185029Spjd#include <stdarg.h> 35185029Spjd#include <stddef.h> 36185029Spjd 37185029Spjd#include <a.out.h> 38185029Spjd 39185029Spjd#include <btxv86.h> 40185029Spjd 41185029Spjd#include "lib.h" 42213136Spjd#include "rbx.h" 43213136Spjd#include "drv.h" 44329100Skevans#include "edd.h" 45213136Spjd#include "cons.h" 46235154Savg#include "bootargs.h" 47294765Simp#include "paths.h" 48185029Spjd 49235329Savg#include "libzfs.h" 50235329Savg 51297629Sallanjude#define ARGS 0x900 52297629Sallanjude#define NOPT 14 53297629Sallanjude#define NDEV 3 54185029Spjd 55297629Sallanjude#define BIOS_NUMDRIVES 0x475 56297629Sallanjude#define DRV_HARD 0x80 57297629Sallanjude#define DRV_MASK 0x7f 58185029Spjd 59297629Sallanjude#define TYPE_AD 0 60297629Sallanjude#define TYPE_DA 1 61297629Sallanjude#define TYPE_MAXHARD TYPE_DA 62297629Sallanjude#define TYPE_FD 2 63185029Spjd 64297629Sallanjude#define DEV_GELIBOOT_BSIZE 4096 65297629Sallanjude 66185029Spjdextern uint32_t _end; 67185029Spjd 68185096Sdfr#ifdef GPT 69185096Sdfrstatic const uuid_t freebsd_zfs_uuid = GPT_ENT_TYPE_FREEBSD_ZFS; 70185096Sdfr#endif 71185029Spjdstatic const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */ 72185029Spjdstatic const unsigned char flags[NOPT] = { 73185029Spjd RBX_DUAL, 74185029Spjd RBX_SERIAL, 75185029Spjd RBX_ASKNAME, 76185029Spjd RBX_CDROM, 77185029Spjd RBX_CONFIG, 78185029Spjd RBX_KDB, 79185029Spjd RBX_GDB, 80185029Spjd RBX_MUTE, 81185029Spjd RBX_NOINTR, 82185029Spjd RBX_PAUSE, 83185029Spjd RBX_QUIET, 84185029Spjd RBX_DFLTROOT, 85185029Spjd RBX_SINGLE, 86185029Spjd RBX_VERBOSE 87185029Spjd}; 88213136Spjduint32_t opts; 89185029Spjd 90185029Spjdstatic const unsigned char dev_maj[NDEV] = {30, 4, 2}; 91185029Spjd 92185029Spjdstatic char cmd[512]; 93234339Savgstatic char cmddup[512]; 94185029Spjdstatic char kname[1024]; 95235329Savgstatic char rootname[256]; 96185029Spjdstatic int comspeed = SIOSPD; 97185029Spjdstatic struct bootinfo bootinfo; 98185029Spjdstatic uint32_t bootdev; 99235329Savgstatic struct zfs_boot_args zfsargs; 100185029Spjd 101200309Sjhbvm_offset_t high_heap_base; 102200309Sjhbuint32_t bios_basemem, bios_extmem, high_heap_size; 103200309Sjhb 104200309Sjhbstatic struct bios_smap smap; 105200309Sjhb 106200309Sjhb/* 107200309Sjhb * The minimum amount of memory to reserve in bios_extmem for the heap. 108200309Sjhb */ 109328866Skevans#define HEAP_MIN (64 * 1024 * 1024) 110200309Sjhb 111200309Sjhbstatic char *heap_next; 112200309Sjhbstatic char *heap_end; 113200309Sjhb 114185029Spjd/* Buffers that must not span a 64k boundary. */ 115297629Sallanjude#define READ_BUF_SIZE 8192 116185029Spjdstruct dmadat { 117185029Spjd char rdbuf[READ_BUF_SIZE]; /* for reading large things */ 118185029Spjd char secbuf[READ_BUF_SIZE]; /* for MBR/disklabel */ 119185029Spjd}; 120185029Spjdstatic struct dmadat *dmadat; 121185029Spjd 122185029Spjdvoid exit(int); 123308914Savgvoid reboot(void); 124185029Spjdstatic void load(void); 125329099Skevansstatic int parse_cmd(void); 126200309Sjhbstatic void bios_getmem(void); 127329100Skevansint main(void); 128185029Spjd 129296963Sallanjude#ifdef LOADER_GELI_SUPPORT 130296963Sallanjude#include "geliboot.c" 131296963Sallanjudestatic char gelipw[GELI_PW_MAXLEN]; 132329099Skevansstatic struct keybuf *gelibuf; 133296963Sallanjude#endif 134296963Sallanjude 135185029Spjd#include "zfsimpl.c" 136185029Spjd 137185029Spjd/* 138185029Spjd * Read from a dnode (which must be from a ZPL filesystem). 139185029Spjd */ 140185029Spjdstatic int 141185029Spjdzfs_read(spa_t *spa, const dnode_phys_t *dnode, off_t *offp, void *start, size_t size) 142185029Spjd{ 143185029Spjd const znode_phys_t *zp = (const znode_phys_t *) dnode->dn_bonus; 144185029Spjd size_t n; 145185029Spjd int rc; 146185029Spjd 147185029Spjd n = size; 148185029Spjd if (*offp + n > zp->zp_size) 149185029Spjd n = zp->zp_size - *offp; 150308914Savg 151185029Spjd rc = dnode_read(spa, dnode, *offp, start, n); 152185029Spjd if (rc) 153185029Spjd return (-1); 154185029Spjd *offp += n; 155185029Spjd 156185029Spjd return (n); 157185029Spjd} 158185029Spjd 159185029Spjd/* 160185029Spjd * Current ZFS pool 161185029Spjd */ 162235329Savgstatic spa_t *spa; 163241293Savgstatic spa_t *primary_spa; 164241293Savgstatic vdev_t *primary_vdev; 165185029Spjd 166185029Spjd/* 167185029Spjd * A wrapper for dskread that doesn't have to worry about whether the 168185029Spjd * buffer pointer crosses a 64k boundary. 169185029Spjd */ 170185029Spjdstatic int 171329175Skevansvdev_read(void *xvdev, void *priv, off_t off, void *buf, size_t bytes) 172185029Spjd{ 173185029Spjd char *p; 174297629Sallanjude daddr_t lba, alignlba; 175300257Sallanjude off_t diff; 176297629Sallanjude unsigned int nb, alignnb; 177185029Spjd struct dsk *dsk = (struct dsk *) priv; 178185029Spjd 179185029Spjd if ((off & (DEV_BSIZE - 1)) || (bytes & (DEV_BSIZE - 1))) 180185029Spjd return -1; 181185029Spjd 182185029Spjd p = buf; 183185029Spjd lba = off / DEV_BSIZE; 184213136Spjd lba += dsk->start; 185297629Sallanjude /* 186300257Sallanjude * Align reads to 4k else 4k sector GELIs will not decrypt. 187300257Sallanjude * Round LBA down to nearest multiple of DEV_GELIBOOT_BSIZE bytes. 188300257Sallanjude */ 189300257Sallanjude alignlba = rounddown2(off, DEV_GELIBOOT_BSIZE) / DEV_BSIZE; 190300257Sallanjude /* 191297629Sallanjude * The read must be aligned to DEV_GELIBOOT_BSIZE bytes relative to the 192297629Sallanjude * start of the GELI partition, not the start of the actual disk. 193297629Sallanjude */ 194297629Sallanjude alignlba += dsk->start; 195297629Sallanjude diff = (lba - alignlba) * DEV_BSIZE; 196297629Sallanjude 197185029Spjd while (bytes > 0) { 198185029Spjd nb = bytes / DEV_BSIZE; 199297629Sallanjude /* 200297629Sallanjude * Ensure that the read size plus the leading offset does not 201297629Sallanjude * exceed the size of the read buffer. 202297629Sallanjude */ 203298949Speter if (nb > (READ_BUF_SIZE - diff) / DEV_BSIZE) 204298949Speter nb = (READ_BUF_SIZE - diff) / DEV_BSIZE; 205297629Sallanjude /* 206297629Sallanjude * Round the number of blocks to read up to the nearest multiple 207297629Sallanjude * of DEV_GELIBOOT_BSIZE. 208297629Sallanjude */ 209298949Speter alignnb = roundup2(nb * DEV_BSIZE + diff, DEV_GELIBOOT_BSIZE) 210298949Speter / DEV_BSIZE; 211297629Sallanjude 212344295Skevans if (dsk->size > 0 && alignlba + alignnb > dsk->size + dsk->start) { 213344295Skevans printf("Shortening read at %lld from %d to %lld\n", alignlba, 214344295Skevans alignnb, (dsk->size + dsk->start) - alignlba); 215344295Skevans alignnb = (dsk->size + dsk->start) - alignlba; 216344295Skevans } 217344295Skevans 218297629Sallanjude if (drvread(dsk, dmadat->rdbuf, alignlba, alignnb)) 219185029Spjd return -1; 220296963Sallanjude#ifdef LOADER_GELI_SUPPORT 221296963Sallanjude /* decrypt */ 222296963Sallanjude if (is_geli(dsk) == 0) { 223297629Sallanjude if (geli_read(dsk, ((alignlba - dsk->start) * 224297629Sallanjude DEV_BSIZE), dmadat->rdbuf, alignnb * DEV_BSIZE)) 225297629Sallanjude return (-1); 226296963Sallanjude } 227296963Sallanjude#endif 228297629Sallanjude memcpy(p, dmadat->rdbuf + diff, nb * DEV_BSIZE); 229185029Spjd p += nb * DEV_BSIZE; 230185029Spjd lba += nb; 231297629Sallanjude alignlba += alignnb; 232185029Spjd bytes -= nb * DEV_BSIZE; 233297629Sallanjude /* Don't need the leading offset after the first block. */ 234297629Sallanjude diff = 0; 235185029Spjd } 236185029Spjd 237185029Spjd return 0; 238185029Spjd} 239329175Skevans/* Match the signature exactly due to signature madness */ 240329175Skevansstatic int 241329175Skevansvdev_read2(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes) 242329175Skevans{ 243329175Skevans return vdev_read(vdev, priv, off, buf, bytes); 244329175Skevans} 245185029Spjd 246329175Skevans 247185029Spjdstatic int 248308914Savgvdev_write(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes) 249308914Savg{ 250308914Savg char *p; 251308914Savg daddr_t lba; 252308914Savg unsigned int nb; 253308914Savg struct dsk *dsk = (struct dsk *) priv; 254308914Savg 255308914Savg if ((off & (DEV_BSIZE - 1)) || (bytes & (DEV_BSIZE - 1))) 256308914Savg return -1; 257308914Savg 258308914Savg p = buf; 259308914Savg lba = off / DEV_BSIZE; 260308914Savg lba += dsk->start; 261308914Savg while (bytes > 0) { 262308914Savg nb = bytes / DEV_BSIZE; 263308914Savg if (nb > READ_BUF_SIZE / DEV_BSIZE) 264308914Savg nb = READ_BUF_SIZE / DEV_BSIZE; 265308914Savg memcpy(dmadat->rdbuf, p, nb * DEV_BSIZE); 266308914Savg if (drvwrite(dsk, dmadat->rdbuf, lba, nb)) 267308914Savg return -1; 268308914Savg p += nb * DEV_BSIZE; 269308914Savg lba += nb; 270308914Savg bytes -= nb * DEV_BSIZE; 271308914Savg } 272308914Savg 273308914Savg return 0; 274308914Savg} 275308914Savg 276308914Savgstatic int 277185029Spjdxfsread(const dnode_phys_t *dnode, off_t *offp, void *buf, size_t nbyte) 278185029Spjd{ 279185029Spjd if ((size_t)zfs_read(spa, dnode, offp, buf, nbyte) != nbyte) { 280235329Savg printf("Invalid format\n"); 281185029Spjd return -1; 282185029Spjd } 283185029Spjd return 0; 284185029Spjd} 285185029Spjd 286308914Savg/* 287308914Savg * Read Pad2 (formerly "Boot Block Header") area of the first 288308914Savg * vdev label of the given vdev. 289308914Savg */ 290308914Savgstatic int 291308914Savgvdev_read_pad2(vdev_t *vdev, char *buf, size_t size) 292308914Savg{ 293308914Savg blkptr_t bp; 294308914Savg char *tmp = zap_scratch; 295308914Savg off_t off = offsetof(vdev_label_t, vl_pad2); 296308914Savg 297308914Savg if (size > VDEV_PAD_SIZE) 298308914Savg size = VDEV_PAD_SIZE; 299308914Savg 300308914Savg BP_ZERO(&bp); 301308914Savg BP_SET_LSIZE(&bp, VDEV_PAD_SIZE); 302308914Savg BP_SET_PSIZE(&bp, VDEV_PAD_SIZE); 303308914Savg BP_SET_CHECKSUM(&bp, ZIO_CHECKSUM_LABEL); 304308914Savg BP_SET_COMPRESS(&bp, ZIO_COMPRESS_OFF); 305308914Savg DVA_SET_OFFSET(BP_IDENTITY(&bp), off); 306308914Savg if (vdev_read_phys(vdev, &bp, tmp, off, 0)) 307308914Savg return (EIO); 308308914Savg memcpy(buf, tmp, size); 309308914Savg return (0); 310308914Savg} 311308914Savg 312308914Savgstatic int 313308914Savgvdev_clear_pad2(vdev_t *vdev) 314308914Savg{ 315308914Savg char *zeroes = zap_scratch; 316308914Savg uint64_t *end; 317308914Savg off_t off = offsetof(vdev_label_t, vl_pad2); 318308914Savg 319308914Savg memset(zeroes, 0, VDEV_PAD_SIZE); 320308914Savg end = (uint64_t *)(zeroes + VDEV_PAD_SIZE); 321308914Savg /* ZIO_CHECKSUM_LABEL magic and pre-calcualted checksum for all zeros */ 322308914Savg end[-5] = 0x0210da7ab10c7a11; 323308914Savg end[-4] = 0x97f48f807f6e2a3f; 324308914Savg end[-3] = 0xaf909f1658aacefc; 325308914Savg end[-2] = 0xcbd1ea57ff6db48b; 326308914Savg end[-1] = 0x6ec692db0d465fab; 327308914Savg if (vdev_write(vdev, vdev->v_read_priv, off, zeroes, VDEV_PAD_SIZE)) 328308914Savg return (EIO); 329308914Savg return (0); 330308914Savg} 331308914Savg 332200309Sjhbstatic void 333200309Sjhbbios_getmem(void) 334185029Spjd{ 335200309Sjhb uint64_t size; 336185029Spjd 337200309Sjhb /* Parse system memory map */ 338200309Sjhb v86.ebx = 0; 339200309Sjhb do { 340200309Sjhb v86.ctl = V86_FLAGS; 341200309Sjhb v86.addr = 0x15; /* int 0x15 function 0xe820*/ 342200309Sjhb v86.eax = 0xe820; 343200309Sjhb v86.ecx = sizeof(struct bios_smap); 344200309Sjhb v86.edx = SMAP_SIG; 345200309Sjhb v86.es = VTOPSEG(&smap); 346200309Sjhb v86.edi = VTOPOFF(&smap); 347200309Sjhb v86int(); 348292682Sjhb if (V86_CY(v86.efl) || (v86.eax != SMAP_SIG)) 349200309Sjhb break; 350200309Sjhb /* look for a low-memory segment that's large enough */ 351200309Sjhb if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0) && 352200309Sjhb (smap.length >= (512 * 1024))) 353200309Sjhb bios_basemem = smap.length; 354200309Sjhb /* look for the first segment in 'extended' memory */ 355200309Sjhb if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0x100000)) { 356200309Sjhb bios_extmem = smap.length; 357200309Sjhb } 358200309Sjhb 359200309Sjhb /* 360200309Sjhb * Look for the largest segment in 'extended' memory beyond 361200309Sjhb * 1MB but below 4GB. 362200309Sjhb */ 363200309Sjhb if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base > 0x100000) && 364200309Sjhb (smap.base < 0x100000000ull)) { 365200309Sjhb size = smap.length; 366200309Sjhb 367200309Sjhb /* 368200309Sjhb * If this segment crosses the 4GB boundary, truncate it. 369200309Sjhb */ 370200309Sjhb if (smap.base + size > 0x100000000ull) 371200309Sjhb size = 0x100000000ull - smap.base; 372200309Sjhb 373200309Sjhb if (size > high_heap_size) { 374200309Sjhb high_heap_size = size; 375200309Sjhb high_heap_base = smap.base; 376200309Sjhb } 377200309Sjhb } 378200309Sjhb } while (v86.ebx != 0); 379200309Sjhb 380200309Sjhb /* Fall back to the old compatibility function for base memory */ 381200309Sjhb if (bios_basemem == 0) { 382200309Sjhb v86.ctl = 0; 383200309Sjhb v86.addr = 0x12; /* int 0x12 */ 384200309Sjhb v86int(); 385200309Sjhb 386200309Sjhb bios_basemem = (v86.eax & 0xffff) * 1024; 387200309Sjhb } 388200309Sjhb 389200309Sjhb /* Fall back through several compatibility functions for extended memory */ 390200309Sjhb if (bios_extmem == 0) { 391200309Sjhb v86.ctl = V86_FLAGS; 392200309Sjhb v86.addr = 0x15; /* int 0x15 function 0xe801*/ 393200309Sjhb v86.eax = 0xe801; 394200309Sjhb v86int(); 395292682Sjhb if (!V86_CY(v86.efl)) { 396200309Sjhb bios_extmem = ((v86.ecx & 0xffff) + ((v86.edx & 0xffff) * 64)) * 1024; 397200309Sjhb } 398200309Sjhb } 399200309Sjhb if (bios_extmem == 0) { 400200309Sjhb v86.ctl = 0; 401200309Sjhb v86.addr = 0x15; /* int 0x15 function 0x88*/ 402200309Sjhb v86.eax = 0x8800; 403200309Sjhb v86int(); 404200309Sjhb bios_extmem = (v86.eax & 0xffff) * 1024; 405200309Sjhb } 406200309Sjhb 407200309Sjhb /* 408200309Sjhb * If we have extended memory and did not find a suitable heap 409200309Sjhb * region in the SMAP, use the last 3MB of 'extended' memory as a 410200309Sjhb * high heap candidate. 411200309Sjhb */ 412200309Sjhb if (bios_extmem >= HEAP_MIN && high_heap_size < HEAP_MIN) { 413200309Sjhb high_heap_size = HEAP_MIN; 414200309Sjhb high_heap_base = bios_extmem + 0x100000 - HEAP_MIN; 415200309Sjhb } 416296963Sallanjude} 417200309Sjhb 418185029Spjd/* 419185029Spjd * Try to detect a device supported by the legacy int13 BIOS 420185029Spjd */ 421185029Spjdstatic int 422185029Spjdint13probe(int drive) 423185029Spjd{ 424185029Spjd v86.ctl = V86_FLAGS; 425185029Spjd v86.addr = 0x13; 426185029Spjd v86.eax = 0x800; 427185029Spjd v86.edx = drive; 428185029Spjd v86int(); 429185029Spjd 430292682Sjhb if (!V86_CY(v86.efl) && /* carry clear */ 431185029Spjd ((v86.edx & 0xff) != (drive & DRV_MASK))) { /* unit # OK */ 432185029Spjd if ((v86.ecx & 0x3f) == 0) { /* absurd sector size */ 433185029Spjd return(0); /* skip device */ 434185029Spjd } 435185029Spjd return (1); 436185029Spjd } 437185029Spjd return(0); 438185029Spjd} 439185029Spjd 440192194Sdfr/* 441192194Sdfr * We call this when we find a ZFS vdev - ZFS consumes the dsk 442192194Sdfr * structure so we must make a new one. 443192194Sdfr */ 444192194Sdfrstatic struct dsk * 445192194Sdfrcopy_dsk(struct dsk *dsk) 446192194Sdfr{ 447192194Sdfr struct dsk *newdsk; 448192194Sdfr 449192194Sdfr newdsk = malloc(sizeof(struct dsk)); 450192194Sdfr *newdsk = *dsk; 451192194Sdfr return (newdsk); 452192194Sdfr} 453192194Sdfr 454329100Skevans/* 455329100Skevans * Get disk size from eax=0x800 and 0x4800. We need to probe both 456329100Skevans * because 0x4800 may not be available and we would like to get more 457329100Skevans * or less correct disk size - if it is possible at all. 458329100Skevans * Note we do not really want to touch drv.c because that code is shared 459329100Skevans * with boot2 and we can not afford to grow that code. 460329100Skevans */ 461329100Skevansstatic uint64_t 462329100Skevansdrvsize_ext(struct dsk *dskp) 463329100Skevans{ 464329100Skevans uint64_t size, tmp; 465329100Skevans int cyl, hds, sec; 466329100Skevans 467329100Skevans v86.ctl = V86_FLAGS; 468329100Skevans v86.addr = 0x13; 469329100Skevans v86.eax = 0x800; 470329100Skevans v86.edx = dskp->drive; 471329100Skevans v86int(); 472329100Skevans 473329100Skevans /* Don't error out if we get bad sector number, try EDD as well */ 474329100Skevans if (V86_CY(v86.efl) || /* carry set */ 475329100Skevans (v86.edx & 0xff) <= (unsigned)(dskp->drive & 0x7f)) /* unit # bad */ 476329100Skevans return (0); 477329100Skevans cyl = ((v86.ecx & 0xc0) << 2) + ((v86.ecx & 0xff00) >> 8) + 1; 478329100Skevans /* Convert max head # -> # of heads */ 479329100Skevans hds = ((v86.edx & 0xff00) >> 8) + 1; 480329100Skevans sec = v86.ecx & 0x3f; 481329100Skevans 482329100Skevans size = (uint64_t)cyl * hds * sec; 483329100Skevans 484329100Skevans /* Determine if we can use EDD with this device. */ 485329100Skevans v86.ctl = V86_FLAGS; 486329100Skevans v86.addr = 0x13; 487329100Skevans v86.eax = 0x4100; 488329100Skevans v86.edx = dskp->drive; 489329100Skevans v86.ebx = 0x55aa; 490329100Skevans v86int(); 491329100Skevans if (V86_CY(v86.efl) || /* carry set */ 492329100Skevans (v86.ebx & 0xffff) != 0xaa55 || /* signature */ 493329100Skevans (v86.ecx & EDD_INTERFACE_FIXED_DISK) == 0) 494329100Skevans return (size); 495329100Skevans 496329100Skevans tmp = drvsize(dskp); 497329100Skevans if (tmp > size) 498329100Skevans size = tmp; 499329100Skevans 500329100Skevans return (size); 501329100Skevans} 502329100Skevans 503329100Skevans/* 504329100Skevans * The "layered" ioctl to read disk/partition size. Unfortunately 505329100Skevans * the zfsboot case is hardest, because we do not have full software 506329100Skevans * stack available, so we need to do some manual work here. 507329100Skevans */ 508329100Skevansuint64_t 509329100Skevansldi_get_size(void *priv) 510329100Skevans{ 511329100Skevans struct dsk *dskp = priv; 512329100Skevans uint64_t size = dskp->size; 513329100Skevans 514329100Skevans if (dskp->start == 0) 515329100Skevans size = drvsize_ext(dskp); 516329100Skevans 517329100Skevans return (size * DEV_BSIZE); 518329100Skevans} 519329100Skevans 520185029Spjdstatic void 521241294Savgprobe_drive(struct dsk *dsk) 522185029Spjd{ 523185096Sdfr#ifdef GPT 524185096Sdfr struct gpt_hdr hdr; 525185096Sdfr struct gpt_ent *ent; 526185096Sdfr unsigned part, entries_per_sec; 527299997Speter daddr_t slba; 528185096Sdfr#endif 529299997Speter#if defined(GPT) || defined(LOADER_GELI_SUPPORT) 530299997Speter daddr_t elba; 531299660Sngie#endif 532299997Speter 533185029Spjd struct dos_partition *dp; 534185029Spjd char *sec; 535185029Spjd unsigned i; 536185029Spjd 537185029Spjd /* 538296963Sallanjude * If we find a vdev on the whole disk, stop here. 539185029Spjd */ 540329175Skevans if (vdev_probe(vdev_read2, dsk, NULL) == 0) 541185029Spjd return; 542185029Spjd 543296963Sallanjude#ifdef LOADER_GELI_SUPPORT 544296963Sallanjude /* 545296963Sallanjude * Taste the disk, if it is GELI encrypted, decrypt it and check to see if 546296963Sallanjude * it is a usable vdev then. Otherwise dig 547296963Sallanjude * out the partition table and probe each slice/partition 548296963Sallanjude * in turn for a vdev or GELI encrypted vdev. 549296963Sallanjude */ 550329100Skevans elba = drvsize_ext(dsk); 551296963Sallanjude if (elba > 0) { 552296963Sallanjude elba--; 553296963Sallanjude } 554296963Sallanjude if (geli_taste(vdev_read, dsk, elba) == 0) { 555329175Skevans if (geli_havekey(dsk) == 0 || geli_passphrase(gelipw, dsk->unit, 556329099Skevans ':', 0, dsk) == 0) { 557329175Skevans if (vdev_probe(vdev_read2, dsk, NULL) == 0) { 558296963Sallanjude return; 559296963Sallanjude } 560296963Sallanjude } 561296963Sallanjude } 562296963Sallanjude#endif /* LOADER_GELI_SUPPORT */ 563296963Sallanjude 564185029Spjd sec = dmadat->secbuf; 565185029Spjd dsk->start = 0; 566185096Sdfr 567185096Sdfr#ifdef GPT 568185096Sdfr /* 569185096Sdfr * First check for GPT. 570185096Sdfr */ 571185096Sdfr if (drvread(dsk, sec, 1, 1)) { 572185096Sdfr return; 573185096Sdfr } 574185096Sdfr memcpy(&hdr, sec, sizeof(hdr)); 575185096Sdfr if (memcmp(hdr.hdr_sig, GPT_HDR_SIG, sizeof(hdr.hdr_sig)) != 0 || 576185096Sdfr hdr.hdr_lba_self != 1 || hdr.hdr_revision < 0x00010000 || 577185096Sdfr hdr.hdr_entsz < sizeof(*ent) || DEV_BSIZE % hdr.hdr_entsz != 0) { 578185096Sdfr goto trymbr; 579185096Sdfr } 580185096Sdfr 581185096Sdfr /* 582298826Spfg * Probe all GPT partitions for the presence of ZFS pools. We 583185096Sdfr * return the spa_t for the first we find (if requested). This 584185096Sdfr * will have the effect of booting from the first pool on the 585185096Sdfr * disk. 586296963Sallanjude * 587296963Sallanjude * If no vdev is found, GELI decrypting the device and try again 588185096Sdfr */ 589185096Sdfr entries_per_sec = DEV_BSIZE / hdr.hdr_entsz; 590185096Sdfr slba = hdr.hdr_lba_table; 591185096Sdfr elba = slba + hdr.hdr_entries / entries_per_sec; 592185096Sdfr while (slba < elba) { 593198420Srnoland dsk->start = 0; 594185096Sdfr if (drvread(dsk, sec, slba, 1)) 595185096Sdfr return; 596185096Sdfr for (part = 0; part < entries_per_sec; part++) { 597185096Sdfr ent = (struct gpt_ent *)(sec + part * hdr.hdr_entsz); 598185096Sdfr if (memcmp(&ent->ent_type, &freebsd_zfs_uuid, 599185096Sdfr sizeof(uuid_t)) == 0) { 600185096Sdfr dsk->start = ent->ent_lba_start; 601329100Skevans dsk->size = ent->ent_lba_end - ent->ent_lba_start + 1; 602296963Sallanjude dsk->slice = part + 1; 603296963Sallanjude dsk->part = 255; 604329175Skevans if (vdev_probe(vdev_read2, dsk, NULL) == 0) { 605185096Sdfr /* 606185096Sdfr * This slice had a vdev. We need a new dsk 607185096Sdfr * structure now since the vdev now owns this one. 608185096Sdfr */ 609192194Sdfr dsk = copy_dsk(dsk); 610185096Sdfr } 611296963Sallanjude#ifdef LOADER_GELI_SUPPORT 612296963Sallanjude else if (geli_taste(vdev_read, dsk, ent->ent_lba_end - 613296963Sallanjude ent->ent_lba_start) == 0) { 614329175Skevans if (geli_havekey(dsk) == 0 || geli_passphrase(gelipw, 615329099Skevans dsk->unit, 'p', dsk->slice, dsk) == 0) { 616296963Sallanjude /* 617296963Sallanjude * This slice has GELI, check it for ZFS. 618296963Sallanjude */ 619329175Skevans if (vdev_probe(vdev_read2, dsk, NULL) == 0) { 620296963Sallanjude /* 621296963Sallanjude * This slice had a vdev. We need a new dsk 622296963Sallanjude * structure now since the vdev now owns this one. 623296963Sallanjude */ 624296963Sallanjude dsk = copy_dsk(dsk); 625296963Sallanjude } 626296963Sallanjude break; 627296963Sallanjude } 628296963Sallanjude } 629296963Sallanjude#endif /* LOADER_GELI_SUPPORT */ 630185096Sdfr } 631185096Sdfr } 632185096Sdfr slba++; 633185096Sdfr } 634185096Sdfr return; 635185096Sdfrtrymbr: 636296963Sallanjude#endif /* GPT */ 637185096Sdfr 638185029Spjd if (drvread(dsk, sec, DOSBBSECTOR, 1)) 639185029Spjd return; 640185029Spjd dp = (void *)(sec + DOSPARTOFF); 641185029Spjd 642185029Spjd for (i = 0; i < NDOSPART; i++) { 643185029Spjd if (!dp[i].dp_typ) 644185029Spjd continue; 645185029Spjd dsk->start = dp[i].dp_start; 646329100Skevans dsk->size = dp[i].dp_size; 647296963Sallanjude dsk->slice = i + 1; 648329175Skevans if (vdev_probe(vdev_read2, dsk, NULL) == 0) { 649192194Sdfr dsk = copy_dsk(dsk); 650185029Spjd } 651296963Sallanjude#ifdef LOADER_GELI_SUPPORT 652296963Sallanjude else if (geli_taste(vdev_read, dsk, dp[i].dp_size - 653296963Sallanjude dp[i].dp_start) == 0) { 654329175Skevans if (geli_havekey(dsk) == 0 || geli_passphrase(gelipw, dsk->unit, 655329099Skevans 's', i, dsk) == 0) { 656296963Sallanjude /* 657296963Sallanjude * This slice has GELI, check it for ZFS. 658296963Sallanjude */ 659329175Skevans if (vdev_probe(vdev_read2, dsk, NULL) == 0) { 660296963Sallanjude /* 661296963Sallanjude * This slice had a vdev. We need a new dsk 662296963Sallanjude * structure now since the vdev now owns this one. 663296963Sallanjude */ 664296963Sallanjude dsk = copy_dsk(dsk); 665296963Sallanjude } 666296963Sallanjude break; 667296963Sallanjude } 668296963Sallanjude } 669296963Sallanjude#endif /* LOADER_GELI_SUPPORT */ 670185029Spjd } 671185029Spjd} 672185029Spjd 673185029Spjdint 674185029Spjdmain(void) 675185029Spjd{ 676185029Spjd dnode_phys_t dn; 677185029Spjd off_t off; 678185029Spjd struct dsk *dsk; 679308914Savg int autoboot, i; 680308914Savg int nextboot; 681308914Savg int rc; 682185029Spjd 683208388Sjhb dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base); 684208388Sjhb 685200309Sjhb bios_getmem(); 686200309Sjhb 687200309Sjhb if (high_heap_size > 0) { 688200309Sjhb heap_end = PTOV(high_heap_base + high_heap_size); 689200309Sjhb heap_next = PTOV(high_heap_base); 690200309Sjhb } else { 691296963Sallanjude heap_next = (char *)dmadat + sizeof(*dmadat); 692296963Sallanjude heap_end = (char *)PTOV(bios_basemem); 693200309Sjhb } 694329175Skevans setheap(heap_next, heap_end); 695200309Sjhb 696185029Spjd dsk = malloc(sizeof(struct dsk)); 697185029Spjd dsk->drive = *(uint8_t *)PTOV(ARGS); 698185029Spjd dsk->type = dsk->drive & DRV_HARD ? TYPE_AD : TYPE_FD; 699185029Spjd dsk->unit = dsk->drive & DRV_MASK; 700185029Spjd dsk->slice = *(uint8_t *)PTOV(ARGS + 1) + 1; 701185029Spjd dsk->part = 0; 702185029Spjd dsk->start = 0; 703344295Skevans dsk->size = drvsize_ext(dsk); 704185029Spjd 705185029Spjd bootinfo.bi_version = BOOTINFO_VERSION; 706185029Spjd bootinfo.bi_size = sizeof(bootinfo); 707200309Sjhb bootinfo.bi_basemem = bios_basemem / 1024; 708200309Sjhb bootinfo.bi_extmem = bios_extmem / 1024; 709185029Spjd bootinfo.bi_memsizes_valid++; 710185029Spjd bootinfo.bi_bios_dev = dsk->drive; 711185029Spjd 712185029Spjd bootdev = MAKEBOOTDEV(dev_maj[dsk->type], 713305614Spfg dsk->slice, dsk->unit, dsk->part); 714185029Spjd 715185029Spjd /* Process configuration file */ 716185029Spjd 717185029Spjd autoboot = 1; 718185029Spjd 719296963Sallanjude#ifdef LOADER_GELI_SUPPORT 720296963Sallanjude geli_init(); 721296963Sallanjude#endif 722185029Spjd zfs_init(); 723185029Spjd 724185029Spjd /* 725185029Spjd * Probe the boot drive first - we will try to boot from whatever 726185029Spjd * pool we find on that drive. 727185029Spjd */ 728241294Savg probe_drive(dsk); 729185029Spjd 730185029Spjd /* 731185029Spjd * Probe the rest of the drives that the bios knows about. This 732185029Spjd * will find any other available pools and it may fill in missing 733185029Spjd * vdevs for the boot pool. 734185029Spjd */ 735212805Spjd#ifndef VIRTUALBOX 736212805Spjd for (i = 0; i < *(unsigned char *)PTOV(BIOS_NUMDRIVES); i++) 737212805Spjd#else 738212805Spjd for (i = 0; i < MAXBDDEV; i++) 739212805Spjd#endif 740212805Spjd { 741185029Spjd if ((i | DRV_HARD) == *(uint8_t *)PTOV(ARGS)) 742185029Spjd continue; 743185029Spjd 744192194Sdfr if (!int13probe(i | DRV_HARD)) 745192194Sdfr break; 746192194Sdfr 747185029Spjd dsk = malloc(sizeof(struct dsk)); 748185029Spjd dsk->drive = i | DRV_HARD; 749185029Spjd dsk->type = dsk->drive & TYPE_AD; 750185029Spjd dsk->unit = i; 751185029Spjd dsk->slice = 0; 752185029Spjd dsk->part = 0; 753185029Spjd dsk->start = 0; 754344295Skevans dsk->size = drvsize_ext(dsk); 755241294Savg probe_drive(dsk); 756185029Spjd } 757185029Spjd 758185029Spjd /* 759241294Savg * The first discovered pool, if any, is the pool. 760185029Spjd */ 761241294Savg spa = spa_get_primary(); 762185029Spjd if (!spa) { 763241294Savg printf("%s: No ZFS pools located, can't boot\n", BOOTPROG); 764241294Savg for (;;) 765241294Savg ; 766185029Spjd } 767185029Spjd 768241293Savg primary_spa = spa; 769241293Savg primary_vdev = spa_get_primary_vdev(spa); 770241293Savg 771308914Savg nextboot = 0; 772308914Savg rc = vdev_read_pad2(primary_vdev, cmd, sizeof(cmd)); 773308914Savg if (vdev_clear_pad2(primary_vdev)) 774308914Savg printf("failed to clear pad2 area of primary vdev\n"); 775308914Savg if (rc == 0) { 776308914Savg if (*cmd) { 777308914Savg /* 778308914Savg * We could find an old-style ZFS Boot Block header here. 779308914Savg * Simply ignore it. 780308914Savg */ 781308914Savg if (*(uint64_t *)cmd != 0x2f5b007b10c) { 782308914Savg /* 783308914Savg * Note that parse() is destructive to cmd[] and we also want 784308914Savg * to honor RBX_QUIET option that could be present in cmd[]. 785308914Savg */ 786308914Savg nextboot = 1; 787308914Savg memcpy(cmddup, cmd, sizeof(cmd)); 788329099Skevans if (parse_cmd()) { 789308914Savg printf("failed to parse pad2 area of primary vdev\n"); 790308914Savg reboot(); 791308914Savg } 792308914Savg if (!OPT_CHECK(RBX_QUIET)) 793308914Savg printf("zfs nextboot: %s\n", cmddup); 794308914Savg } 795308914Savg /* Do not process this command twice */ 796308914Savg *cmd = 0; 797308914Savg } 798308914Savg } else 799308914Savg printf("failed to read pad2 area of primary vdev\n"); 800308914Savg 801308914Savg /* Mount ZFS only if it's not already mounted via nextboot parsing. */ 802308914Savg if (zfsmount.spa == NULL && 803308914Savg (zfs_spa_init(spa) != 0 || zfs_mount(spa, 0, &zfsmount) != 0)) { 804235329Savg printf("%s: failed to mount default pool %s\n", 805235329Savg BOOTPROG, spa->spa_name); 806235329Savg autoboot = 0; 807235329Savg } else if (zfs_lookup(&zfsmount, PATH_CONFIG, &dn) == 0 || 808235329Savg zfs_lookup(&zfsmount, PATH_DOTCONFIG, &dn) == 0) { 809185029Spjd off = 0; 810198079Sjhb zfs_read(spa, &dn, &off, cmd, sizeof(cmd)); 811185029Spjd } 812185029Spjd 813185029Spjd if (*cmd) { 814234339Savg /* 815329099Skevans * Note that parse_cmd() is destructive to cmd[] and we also want 816234339Savg * to honor RBX_QUIET option that could be present in cmd[]. 817234339Savg */ 818234339Savg memcpy(cmddup, cmd, sizeof(cmd)); 819329099Skevans if (parse_cmd()) 820185029Spjd autoboot = 0; 821234339Savg if (!OPT_CHECK(RBX_QUIET)) 822241288Savg printf("%s: %s\n", PATH_CONFIG, cmddup); 823185029Spjd /* Do not process this command twice */ 824185029Spjd *cmd = 0; 825185029Spjd } 826185029Spjd 827308914Savg /* Do not risk waiting at the prompt forever. */ 828308914Savg if (nextboot && !autoboot) 829308914Savg reboot(); 830308914Savg 831185029Spjd /* 832294925Simp * Try to exec /boot/loader. If interrupted by a keypress, 833185029Spjd * or in case of failure, try to load a kernel directly instead. 834185029Spjd */ 835185029Spjd 836185029Spjd if (autoboot && !*kname) { 837294925Simp memcpy(kname, PATH_LOADER_ZFS, sizeof(PATH_LOADER_ZFS)); 838213136Spjd if (!keyhit(3)) { 839185029Spjd load(); 840185029Spjd memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL)); 841185029Spjd } 842185029Spjd } 843185029Spjd 844185029Spjd /* Present the user with the boot2 prompt. */ 845185029Spjd 846185029Spjd for (;;) { 847235329Savg if (!autoboot || !OPT_CHECK(RBX_QUIET)) { 848235329Savg printf("\nFreeBSD/x86 boot\n"); 849235329Savg if (zfs_rlookup(spa, zfsmount.rootobj, rootname) != 0) 850241288Savg printf("Default: %s/<0x%llx>:%s\n" 851235329Savg "boot: ", 852235329Savg spa->spa_name, zfsmount.rootobj, kname); 853241288Savg else if (rootname[0] != '\0') 854241288Savg printf("Default: %s/%s:%s\n" 855241288Savg "boot: ", 856241288Savg spa->spa_name, rootname, kname); 857235329Savg else 858241288Savg printf("Default: %s:%s\n" 859235329Savg "boot: ", 860241288Savg spa->spa_name, kname); 861235329Savg } 862185029Spjd if (ioctrl & IO_SERIAL) 863185029Spjd sio_flush(); 864213136Spjd if (!autoboot || keyhit(5)) 865213136Spjd getstr(cmd, sizeof(cmd)); 866185029Spjd else if (!autoboot || !OPT_CHECK(RBX_QUIET)) 867185029Spjd putchar('\n'); 868185029Spjd autoboot = 0; 869329099Skevans if (parse_cmd()) 870185029Spjd putchar('\a'); 871185029Spjd else 872185029Spjd load(); 873185029Spjd } 874185029Spjd} 875185029Spjd 876185029Spjd/* XXX - Needed for btxld to link the boot2 binary; do not remove. */ 877185029Spjdvoid 878185029Spjdexit(int x) 879185029Spjd{ 880308914Savg __exit(x); 881185029Spjd} 882185029Spjd 883308914Savgvoid 884308914Savgreboot(void) 885308914Savg{ 886308914Savg __exit(0); 887308914Savg} 888308914Savg 889185029Spjdstatic void 890185029Spjdload(void) 891185029Spjd{ 892185029Spjd union { 893185029Spjd struct exec ex; 894185029Spjd Elf32_Ehdr eh; 895185029Spjd } hdr; 896185029Spjd static Elf32_Phdr ep[2]; 897185029Spjd static Elf32_Shdr es[2]; 898185029Spjd caddr_t p; 899185029Spjd dnode_phys_t dn; 900185029Spjd off_t off; 901185029Spjd uint32_t addr, x; 902185029Spjd int fmt, i, j; 903185029Spjd 904235329Savg if (zfs_lookup(&zfsmount, kname, &dn)) { 905235329Savg printf("\nCan't find %s\n", kname); 906185029Spjd return; 907185029Spjd } 908185029Spjd off = 0; 909185029Spjd if (xfsread(&dn, &off, &hdr, sizeof(hdr))) 910185029Spjd return; 911185029Spjd if (N_GETMAGIC(hdr.ex) == ZMAGIC) 912185029Spjd fmt = 0; 913185029Spjd else if (IS_ELF(hdr.eh)) 914185029Spjd fmt = 1; 915185029Spjd else { 916185029Spjd printf("Invalid %s\n", "format"); 917185029Spjd return; 918185029Spjd } 919185029Spjd if (fmt == 0) { 920185029Spjd addr = hdr.ex.a_entry & 0xffffff; 921185029Spjd p = PTOV(addr); 922185029Spjd off = PAGE_SIZE; 923185029Spjd if (xfsread(&dn, &off, p, hdr.ex.a_text)) 924185029Spjd return; 925185029Spjd p += roundup2(hdr.ex.a_text, PAGE_SIZE); 926185029Spjd if (xfsread(&dn, &off, p, hdr.ex.a_data)) 927185029Spjd return; 928185029Spjd p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE); 929185029Spjd bootinfo.bi_symtab = VTOP(p); 930185029Spjd memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms)); 931185029Spjd p += sizeof(hdr.ex.a_syms); 932185029Spjd if (hdr.ex.a_syms) { 933185029Spjd if (xfsread(&dn, &off, p, hdr.ex.a_syms)) 934185029Spjd return; 935185029Spjd p += hdr.ex.a_syms; 936185029Spjd if (xfsread(&dn, &off, p, sizeof(int))) 937185029Spjd return; 938185029Spjd x = *(uint32_t *)p; 939185029Spjd p += sizeof(int); 940185029Spjd x -= sizeof(int); 941185029Spjd if (xfsread(&dn, &off, p, x)) 942185029Spjd return; 943185029Spjd p += x; 944185029Spjd } 945185029Spjd } else { 946185029Spjd off = hdr.eh.e_phoff; 947185029Spjd for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) { 948185029Spjd if (xfsread(&dn, &off, ep + j, sizeof(ep[0]))) 949185029Spjd return; 950185029Spjd if (ep[j].p_type == PT_LOAD) 951185029Spjd j++; 952185029Spjd } 953185029Spjd for (i = 0; i < 2; i++) { 954185029Spjd p = PTOV(ep[i].p_paddr & 0xffffff); 955185029Spjd off = ep[i].p_offset; 956185029Spjd if (xfsread(&dn, &off, p, ep[i].p_filesz)) 957185029Spjd return; 958185029Spjd } 959185029Spjd p += roundup2(ep[1].p_memsz, PAGE_SIZE); 960185029Spjd bootinfo.bi_symtab = VTOP(p); 961185029Spjd if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { 962185029Spjd off = hdr.eh.e_shoff + sizeof(es[0]) * 963185029Spjd (hdr.eh.e_shstrndx + 1); 964185029Spjd if (xfsread(&dn, &off, &es, sizeof(es))) 965185029Spjd return; 966185029Spjd for (i = 0; i < 2; i++) { 967185029Spjd memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size)); 968185029Spjd p += sizeof(es[i].sh_size); 969185029Spjd off = es[i].sh_offset; 970185029Spjd if (xfsread(&dn, &off, p, es[i].sh_size)) 971185029Spjd return; 972185029Spjd p += es[i].sh_size; 973185029Spjd } 974185029Spjd } 975185029Spjd addr = hdr.eh.e_entry & 0xffffff; 976185029Spjd } 977185029Spjd bootinfo.bi_esymtab = VTOP(p); 978185029Spjd bootinfo.bi_kernelname = VTOP(kname); 979235329Savg zfsargs.size = sizeof(zfsargs); 980235329Savg zfsargs.pool = zfsmount.spa->spa_guid; 981235329Savg zfsargs.root = zfsmount.rootobj; 982241293Savg zfsargs.primary_pool = primary_spa->spa_guid; 983296963Sallanjude#ifdef LOADER_GELI_SUPPORT 984329099Skevans explicit_bzero(gelipw, sizeof(gelipw)); 985329099Skevans gelibuf = malloc(sizeof(struct keybuf) + (GELI_MAX_KEYS * sizeof(struct keybuf_ent))); 986329099Skevans geli_fill_keybuf(gelibuf); 987329099Skevans zfsargs.notapw = '\0'; 988329099Skevans zfsargs.keybuf_sentinel = KEYBUF_SENTINEL; 989329099Skevans zfsargs.keybuf = gelibuf; 990296963Sallanjude#else 991296963Sallanjude zfsargs.gelipw[0] = '\0'; 992296963Sallanjude#endif 993241293Savg if (primary_vdev != NULL) 994241293Savg zfsargs.primary_vdev = primary_vdev->v_guid; 995241293Savg else 996241293Savg printf("failed to detect primary vdev\n"); 997185029Spjd __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), 998185029Spjd bootdev, 999235329Savg KARGS_FLAGS_ZFS | KARGS_FLAGS_EXTARG, 1000185029Spjd (uint32_t) spa->spa_guid, 1001185029Spjd (uint32_t) (spa->spa_guid >> 32), 1002235329Savg VTOP(&bootinfo), 1003235329Savg zfsargs); 1004185029Spjd} 1005185029Spjd 1006185029Spjdstatic int 1007241288Savgzfs_mount_ds(char *dsname) 1008241288Savg{ 1009241288Savg uint64_t newroot; 1010241288Savg spa_t *newspa; 1011241288Savg char *q; 1012241288Savg 1013241288Savg q = strchr(dsname, '/'); 1014241288Savg if (q) 1015241288Savg *q++ = '\0'; 1016241288Savg newspa = spa_find_by_name(dsname); 1017241288Savg if (newspa == NULL) { 1018241288Savg printf("\nCan't find ZFS pool %s\n", dsname); 1019241288Savg return -1; 1020241288Savg } 1021241288Savg 1022241288Savg if (zfs_spa_init(newspa)) 1023241288Savg return -1; 1024241288Savg 1025241288Savg newroot = 0; 1026241288Savg if (q) { 1027241288Savg if (zfs_lookup_dataset(newspa, q, &newroot)) { 1028241288Savg printf("\nCan't find dataset %s in ZFS pool %s\n", 1029241288Savg q, newspa->spa_name); 1030241288Savg return -1; 1031241288Savg } 1032241288Savg } 1033241288Savg if (zfs_mount(newspa, newroot, &zfsmount)) { 1034241288Savg printf("\nCan't mount ZFS dataset\n"); 1035241288Savg return -1; 1036241288Savg } 1037241288Savg spa = newspa; 1038241288Savg return (0); 1039241288Savg} 1040241288Savg 1041241288Savgstatic int 1042329099Skevansparse_cmd(void) 1043185029Spjd{ 1044185029Spjd char *arg = cmd; 1045185029Spjd char *ep, *p, *q; 1046185029Spjd const char *cp; 1047185029Spjd int c, i, j; 1048185029Spjd 1049185029Spjd while ((c = *arg++)) { 1050185029Spjd if (c == ' ' || c == '\t' || c == '\n') 1051185029Spjd continue; 1052185029Spjd for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++); 1053185029Spjd ep = p; 1054185029Spjd if (*p) 1055185029Spjd *p++ = 0; 1056185029Spjd if (c == '-') { 1057185029Spjd while ((c = *arg++)) { 1058185029Spjd if (c == 'P') { 1059185029Spjd if (*(uint8_t *)PTOV(0x496) & 0x10) { 1060185029Spjd cp = "yes"; 1061185029Spjd } else { 1062185029Spjd opts |= OPT_SET(RBX_DUAL) | OPT_SET(RBX_SERIAL); 1063185029Spjd cp = "no"; 1064185029Spjd } 1065185029Spjd printf("Keyboard: %s\n", cp); 1066185029Spjd continue; 1067185029Spjd } else if (c == 'S') { 1068185029Spjd j = 0; 1069185029Spjd while ((unsigned int)(i = *arg++ - '0') <= 9) 1070185029Spjd j = j * 10 + i; 1071185029Spjd if (j > 0 && i == -'0') { 1072185029Spjd comspeed = j; 1073185029Spjd break; 1074185029Spjd } 1075185029Spjd /* Fall through to error below ('S' not in optstr[]). */ 1076185029Spjd } 1077185029Spjd for (i = 0; c != optstr[i]; i++) 1078185029Spjd if (i == NOPT - 1) 1079185029Spjd return -1; 1080185029Spjd opts ^= OPT_SET(flags[i]); 1081185029Spjd } 1082185029Spjd ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) : 1083185029Spjd OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD; 1084241301Savg if (ioctrl & IO_SERIAL) { 1085241301Savg if (sio_init(115200 / comspeed) != 0) 1086241301Savg ioctrl &= ~IO_SERIAL; 1087241301Savg } 1088185029Spjd } if (c == '?') { 1089185029Spjd dnode_phys_t dn; 1090185029Spjd 1091235329Savg if (zfs_lookup(&zfsmount, arg, &dn) == 0) { 1092185029Spjd zap_list(spa, &dn); 1093185029Spjd } 1094185029Spjd return -1; 1095185029Spjd } else { 1096185029Spjd arg--; 1097185029Spjd 1098185029Spjd /* 1099185029Spjd * Report pool status if the comment is 'status'. Lets 1100185029Spjd * hope no-one wants to load /status as a kernel. 1101185029Spjd */ 1102185029Spjd if (!strcmp(arg, "status")) { 1103185029Spjd spa_all_status(); 1104185029Spjd return -1; 1105185029Spjd } 1106185029Spjd 1107185029Spjd /* 1108241288Savg * If there is "zfs:" prefix simply ignore it. 1109241288Savg */ 1110241288Savg if (strncmp(arg, "zfs:", 4) == 0) 1111241288Savg arg += 4; 1112241288Savg 1113241288Savg /* 1114185029Spjd * If there is a colon, switch pools. 1115185029Spjd */ 1116241288Savg q = strchr(arg, ':'); 1117185029Spjd if (q) { 1118241288Savg *q++ = '\0'; 1119241288Savg if (zfs_mount_ds(arg) != 0) 1120185029Spjd return -1; 1121241288Savg arg = q; 1122185029Spjd } 1123185029Spjd if ((i = ep - arg)) { 1124185029Spjd if ((size_t)i >= sizeof(kname)) 1125185029Spjd return -1; 1126185029Spjd memcpy(kname, arg, i + 1); 1127185029Spjd } 1128185029Spjd } 1129185029Spjd arg = p; 1130185029Spjd } 1131185029Spjd return 0; 1132185029Spjd} 1133