zfsboot.c revision 198079
1/*-
2 * Copyright (c) 1998 Robert Nordier
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are freely
6 * permitted provided that the above copyright notice and this
7 * paragraph and the following disclaimer are duplicated in all
8 * such forms.
9 *
10 * This software is provided "AS IS" and without any express or
11 * implied warranties, including, without limitation, the implied
12 * warranties of merchantability and fitness for a particular
13 * purpose.
14 */
15
16#include <sys/cdefs.h>
17__FBSDID("$FreeBSD: head/sys/boot/i386/zfsboot/zfsboot.c 198079 2009-10-14 14:13:42Z jhb $");
18
19#include <sys/param.h>
20#include <sys/errno.h>
21#include <sys/diskmbr.h>
22#ifdef GPT
23#include <sys/gpt.h>
24#endif
25#include <sys/reboot.h>
26#include <sys/queue.h>
27
28#include <machine/bootinfo.h>
29#include <machine/elf.h>
30
31#include <stdarg.h>
32#include <stddef.h>
33
34#include <a.out.h>
35
36#include <btxv86.h>
37
38#ifndef GPT
39#include "zfsboot.h"
40#endif
41#include "lib.h"
42
43#define IO_KEYBOARD	1
44#define IO_SERIAL	2
45
46#define SECOND		18	/* Circa that many ticks in a second. */
47
48#define RBX_ASKNAME	0x0	/* -a */
49#define RBX_SINGLE	0x1	/* -s */
50/* 0x2 is reserved for log2(RB_NOSYNC). */
51/* 0x3 is reserved for log2(RB_HALT). */
52/* 0x4 is reserved for log2(RB_INITNAME). */
53#define RBX_DFLTROOT	0x5	/* -r */
54#define RBX_KDB 	0x6	/* -d */
55/* 0x7 is reserved for log2(RB_RDONLY). */
56/* 0x8 is reserved for log2(RB_DUMP). */
57/* 0x9 is reserved for log2(RB_MINIROOT). */
58#define RBX_CONFIG	0xa	/* -c */
59#define RBX_VERBOSE	0xb	/* -v */
60#define RBX_SERIAL	0xc	/* -h */
61#define RBX_CDROM	0xd	/* -C */
62/* 0xe is reserved for log2(RB_POWEROFF). */
63#define RBX_GDB 	0xf	/* -g */
64#define RBX_MUTE	0x10	/* -m */
65/* 0x11 is reserved for log2(RB_SELFTEST). */
66/* 0x12 is reserved for boot programs. */
67/* 0x13 is reserved for boot programs. */
68#define RBX_PAUSE	0x14	/* -p */
69#define RBX_QUIET	0x15	/* -q */
70#define RBX_NOINTR	0x1c	/* -n */
71/* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */
72#define RBX_DUAL	0x1d	/* -D */
73/* 0x1f is reserved for log2(RB_BOOTINFO). */
74
75/* pass: -a, -s, -r, -d, -c, -v, -h, -C, -g, -m, -p, -D */
76#define RBX_MASK	(OPT_SET(RBX_ASKNAME) | OPT_SET(RBX_SINGLE) | \
77			OPT_SET(RBX_DFLTROOT) | OPT_SET(RBX_KDB ) | \
78			OPT_SET(RBX_CONFIG) | OPT_SET(RBX_VERBOSE) | \
79			OPT_SET(RBX_SERIAL) | OPT_SET(RBX_CDROM) | \
80			OPT_SET(RBX_GDB ) | OPT_SET(RBX_MUTE) | \
81			OPT_SET(RBX_PAUSE) | OPT_SET(RBX_DUAL))
82
83/* Hint to loader that we came from ZFS */
84#define	KARGS_FLAGS_ZFS		0x4
85
86#define PATH_CONFIG	"/boot.config"
87#define PATH_BOOT3	"/boot/loader"
88#define PATH_KERNEL	"/boot/kernel/kernel"
89
90#define ARGS		0x900
91#define NOPT		14
92#define NDEV		3
93#define MEM_BASE	0x12
94#define MEM_EXT 	0x15
95#define V86_CY(x)	((x) & 1)
96#define V86_ZR(x)	((x) & 0x40)
97
98#define DRV_HARD	0x80
99#define DRV_MASK	0x7f
100
101#define TYPE_AD		0
102#define TYPE_DA		1
103#define TYPE_MAXHARD	TYPE_DA
104#define TYPE_FD		2
105
106#define OPT_SET(opt)	(1 << (opt))
107#define OPT_CHECK(opt)	((opts) & OPT_SET(opt))
108
109extern uint32_t _end;
110
111#ifdef GPT
112static const uuid_t freebsd_zfs_uuid = GPT_ENT_TYPE_FREEBSD_ZFS;
113#endif
114static const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */
115static const unsigned char flags[NOPT] = {
116    RBX_DUAL,
117    RBX_SERIAL,
118    RBX_ASKNAME,
119    RBX_CDROM,
120    RBX_CONFIG,
121    RBX_KDB,
122    RBX_GDB,
123    RBX_MUTE,
124    RBX_NOINTR,
125    RBX_PAUSE,
126    RBX_QUIET,
127    RBX_DFLTROOT,
128    RBX_SINGLE,
129    RBX_VERBOSE
130};
131
132static const char *const dev_nm[NDEV] = {"ad", "da", "fd"};
133static const unsigned char dev_maj[NDEV] = {30, 4, 2};
134
135struct dsk {
136    unsigned drive;
137    unsigned type;
138    unsigned unit;
139    unsigned slice;
140    unsigned part;
141    unsigned start;
142    int init;
143};
144static char cmd[512];
145static char kname[1024];
146static uint32_t opts;
147static int comspeed = SIOSPD;
148static struct bootinfo bootinfo;
149static uint32_t bootdev;
150static uint8_t ioctrl = IO_KEYBOARD;
151
152/* Buffers that must not span a 64k boundary. */
153#define READ_BUF_SIZE	8192
154struct dmadat {
155	char rdbuf[READ_BUF_SIZE];	/* for reading large things */
156	char secbuf[READ_BUF_SIZE];	/* for MBR/disklabel */
157};
158static struct dmadat *dmadat;
159
160void exit(int);
161static void load(void);
162static int parse(void);
163static void printf(const char *,...);
164static void putchar(int);
165static uint32_t memsize(void);
166static int drvread(struct dsk *, void *, unsigned, unsigned);
167static int keyhit(unsigned);
168static int xputc(int);
169static int xgetc(int);
170static int getc(int);
171
172static void memcpy(void *, const void *, int);
173static void
174memcpy(void *dst, const void *src, int len)
175{
176    const char *s = src;
177    char *d = dst;
178
179    while (len--)
180        *d++ = *s++;
181}
182
183static void
184strcpy(char *dst, const char *src)
185{
186    while (*src)
187	*dst++ = *src++;
188    *dst++ = 0;
189}
190
191static void
192strcat(char *dst, const char *src)
193{
194    while (*dst)
195	dst++;
196    while (*src)
197	*dst++ = *src++;
198    *dst++ = 0;
199}
200
201static int
202strcmp(const char *s1, const char *s2)
203{
204    for (; *s1 == *s2 && *s1; s1++, s2++);
205    return (unsigned char)*s1 - (unsigned char)*s2;
206}
207
208static const char *
209strchr(const char *s, char ch)
210{
211    for (; *s; s++)
212	if (*s == ch)
213		return s;
214    return 0;
215}
216
217static int
218memcmp(const void *p1, const void *p2, size_t n)
219{
220    const char *s1 = (const char *) p1;
221    const char *s2 = (const char *) p2;
222    for (; n > 0 && *s1 == *s2; s1++, s2++, n--);
223    if (n)
224        return (unsigned char)*s1 - (unsigned char)*s2;
225    else
226	return 0;
227}
228
229static void
230memset(void *p, char val, size_t n)
231{
232    char *s = (char *) p;
233    while (n--)
234	*s++ = val;
235}
236
237static void *
238malloc(size_t n)
239{
240	static char *heap_next;
241	static char *heap_end;
242
243	if (!heap_next) {
244		heap_next = (char *) dmadat + sizeof(*dmadat);
245		heap_end = (char *) (640*1024);
246	}
247
248	char *p = heap_next;
249	if (p + n > heap_end) {
250		printf("malloc failure\n");
251		for (;;)
252		    ;
253		return 0;
254	}
255	heap_next += n;
256	return p;
257}
258
259static size_t
260strlen(const char *s)
261{
262	size_t len = 0;
263	while (*s++)
264		len++;
265	return len;
266}
267
268static char *
269strdup(const char *s)
270{
271	char *p = malloc(strlen(s) + 1);
272	strcpy(p, s);
273	return p;
274}
275
276#include "zfsimpl.c"
277
278/*
279 * Read from a dnode (which must be from a ZPL filesystem).
280 */
281static int
282zfs_read(spa_t *spa, const dnode_phys_t *dnode, off_t *offp, void *start, size_t size)
283{
284	const znode_phys_t *zp = (const znode_phys_t *) dnode->dn_bonus;
285	size_t n;
286	int rc;
287
288	n = size;
289	if (*offp + n > zp->zp_size)
290		n = zp->zp_size - *offp;
291
292	rc = dnode_read(spa, dnode, *offp, start, n);
293	if (rc)
294		return (-1);
295	*offp += n;
296
297	return (n);
298}
299
300/*
301 * Current ZFS pool
302 */
303spa_t *spa;
304
305/*
306 * A wrapper for dskread that doesn't have to worry about whether the
307 * buffer pointer crosses a 64k boundary.
308 */
309static int
310vdev_read(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes)
311{
312	char *p;
313	unsigned int lba, nb;
314	struct dsk *dsk = (struct dsk *) priv;
315
316	if ((off & (DEV_BSIZE - 1)) || (bytes & (DEV_BSIZE - 1)))
317		return -1;
318
319	p = buf;
320	lba = off / DEV_BSIZE;
321	while (bytes > 0) {
322		nb = bytes / DEV_BSIZE;
323		if (nb > READ_BUF_SIZE / DEV_BSIZE)
324			nb = READ_BUF_SIZE / DEV_BSIZE;
325		if (drvread(dsk, dmadat->rdbuf, lba, nb))
326			return -1;
327		memcpy(p, dmadat->rdbuf, nb * DEV_BSIZE);
328		p += nb * DEV_BSIZE;
329		lba += nb;
330		bytes -= nb * DEV_BSIZE;
331	}
332
333	return 0;
334}
335
336static int
337xfsread(const dnode_phys_t *dnode, off_t *offp, void *buf, size_t nbyte)
338{
339    if ((size_t)zfs_read(spa, dnode, offp, buf, nbyte) != nbyte) {
340	printf("Invalid %s\n", "format");
341	return -1;
342    }
343    return 0;
344}
345
346static inline uint32_t
347memsize(void)
348{
349    v86.addr = MEM_EXT;
350    v86.eax = 0x8800;
351    v86int();
352    return v86.eax;
353}
354
355static inline void
356getstr(void)
357{
358    char *s;
359    int c;
360
361    s = cmd;
362    for (;;) {
363	switch (c = xgetc(0)) {
364	case 0:
365	    break;
366	case '\177':
367	case '\b':
368	    if (s > cmd) {
369		s--;
370		printf("\b \b");
371	    }
372	    break;
373	case '\n':
374	case '\r':
375	    *s = 0;
376	    return;
377	default:
378	    if (s - cmd < sizeof(cmd) - 1)
379		*s++ = c;
380	    putchar(c);
381	}
382    }
383}
384
385static inline void
386putc(int c)
387{
388    v86.addr = 0x10;
389    v86.eax = 0xe00 | (c & 0xff);
390    v86.ebx = 0x7;
391    v86int();
392}
393
394/*
395 * Try to detect a device supported by the legacy int13 BIOS
396 */
397static int
398int13probe(int drive)
399{
400    v86.ctl = V86_FLAGS;
401    v86.addr = 0x13;
402    v86.eax = 0x800;
403    v86.edx = drive;
404    v86int();
405
406    if (!(v86.efl & 0x1) &&				/* carry clear */
407	((v86.edx & 0xff) != (drive & DRV_MASK))) {	/* unit # OK */
408	if ((v86.ecx & 0x3f) == 0) {			/* absurd sector size */
409		return(0);				/* skip device */
410	}
411	return (1);
412    }
413    return(0);
414}
415
416/*
417 * We call this when we find a ZFS vdev - ZFS consumes the dsk
418 * structure so we must make a new one.
419 */
420static struct dsk *
421copy_dsk(struct dsk *dsk)
422{
423    struct dsk *newdsk;
424
425    newdsk = malloc(sizeof(struct dsk));
426    *newdsk = *dsk;
427    return (newdsk);
428}
429
430static void
431probe_drive(struct dsk *dsk, spa_t **spap)
432{
433#ifdef GPT
434    struct gpt_hdr hdr;
435    struct gpt_ent *ent;
436    daddr_t slba, elba;
437    unsigned part, entries_per_sec;
438#endif
439    struct dos_partition *dp;
440    char *sec;
441    unsigned i;
442
443    /*
444     * If we find a vdev on the whole disk, stop here. Otherwise dig
445     * out the MBR and probe each slice in turn for a vdev.
446     */
447    if (vdev_probe(vdev_read, dsk, spap) == 0)
448	return;
449
450    sec = dmadat->secbuf;
451    dsk->start = 0;
452
453#ifdef GPT
454    /*
455     * First check for GPT.
456     */
457    if (drvread(dsk, sec, 1, 1)) {
458	return;
459    }
460    memcpy(&hdr, sec, sizeof(hdr));
461    if (memcmp(hdr.hdr_sig, GPT_HDR_SIG, sizeof(hdr.hdr_sig)) != 0 ||
462	hdr.hdr_lba_self != 1 || hdr.hdr_revision < 0x00010000 ||
463	hdr.hdr_entsz < sizeof(*ent) || DEV_BSIZE % hdr.hdr_entsz != 0) {
464	goto trymbr;
465    }
466
467    /*
468     * Probe all GPT partitions for the presense of ZFS pools. We
469     * return the spa_t for the first we find (if requested). This
470     * will have the effect of booting from the first pool on the
471     * disk.
472     */
473    entries_per_sec = DEV_BSIZE / hdr.hdr_entsz;
474    slba = hdr.hdr_lba_table;
475    elba = slba + hdr.hdr_entries / entries_per_sec;
476    while (slba < elba) {
477	if (drvread(dsk, sec, slba, 1))
478	    return;
479	for (part = 0; part < entries_per_sec; part++) {
480	    ent = (struct gpt_ent *)(sec + part * hdr.hdr_entsz);
481	    if (memcmp(&ent->ent_type, &freebsd_zfs_uuid,
482		     sizeof(uuid_t)) == 0) {
483		dsk->start = ent->ent_lba_start;
484		if (vdev_probe(vdev_read, dsk, spap) == 0) {
485		    /*
486		     * We record the first pool we find (we will try
487		     * to boot from that one).
488		     */
489		    spap = 0;
490
491		    /*
492		     * This slice had a vdev. We need a new dsk
493		     * structure now since the vdev now owns this one.
494		     */
495		    dsk = copy_dsk(dsk);
496		}
497		break;
498	    }
499	}
500	slba++;
501    }
502    return;
503trymbr:
504#endif
505
506    if (drvread(dsk, sec, DOSBBSECTOR, 1))
507	return;
508    dp = (void *)(sec + DOSPARTOFF);
509
510    for (i = 0; i < NDOSPART; i++) {
511	if (!dp[i].dp_typ)
512	    continue;
513	dsk->start = dp[i].dp_start;
514	if (vdev_probe(vdev_read, dsk, spap) == 0) {
515	    /*
516	     * We record the first pool we find (we will try to boot
517	     * from that one.
518	     */
519	    spap = 0;
520
521	    /*
522	     * This slice had a vdev. We need a new dsk structure now
523	     * since the vdev now owns this one.
524	     */
525	    dsk = copy_dsk(dsk);
526	}
527    }
528}
529
530int
531main(void)
532{
533    int autoboot, i;
534    dnode_phys_t dn;
535    off_t off;
536    struct dsk *dsk;
537
538    dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base);
539    v86.ctl = V86_FLAGS;
540
541    dsk = malloc(sizeof(struct dsk));
542    dsk->drive = *(uint8_t *)PTOV(ARGS);
543    dsk->type = dsk->drive & DRV_HARD ? TYPE_AD : TYPE_FD;
544    dsk->unit = dsk->drive & DRV_MASK;
545    dsk->slice = *(uint8_t *)PTOV(ARGS + 1) + 1;
546    dsk->part = 0;
547    dsk->start = 0;
548    dsk->init = 0;
549
550    bootinfo.bi_version = BOOTINFO_VERSION;
551    bootinfo.bi_size = sizeof(bootinfo);
552    bootinfo.bi_basemem = 0;	/* XXX will be filled by loader or kernel */
553    bootinfo.bi_extmem = memsize();
554    bootinfo.bi_memsizes_valid++;
555    bootinfo.bi_bios_dev = dsk->drive;
556
557    bootdev = MAKEBOOTDEV(dev_maj[dsk->type],
558			  dsk->slice, dsk->unit, dsk->part),
559
560    /* Process configuration file */
561
562    autoboot = 1;
563
564    zfs_init();
565
566    /*
567     * Probe the boot drive first - we will try to boot from whatever
568     * pool we find on that drive.
569     */
570    probe_drive(dsk, &spa);
571
572    /*
573     * Probe the rest of the drives that the bios knows about. This
574     * will find any other available pools and it may fill in missing
575     * vdevs for the boot pool.
576     */
577    for (i = 0; i < 128; i++) {
578	if ((i | DRV_HARD) == *(uint8_t *)PTOV(ARGS))
579	    continue;
580
581	if (!int13probe(i | DRV_HARD))
582	    break;
583
584	dsk = malloc(sizeof(struct dsk));
585	dsk->drive = i | DRV_HARD;
586	dsk->type = dsk->drive & TYPE_AD;
587	dsk->unit = i;
588	dsk->slice = 0;
589	dsk->part = 0;
590	dsk->start = 0;
591	dsk->init = 0;
592	probe_drive(dsk, 0);
593    }
594
595    /*
596     * If we didn't find a pool on the boot drive, default to the
597     * first pool we found, if any.
598     */
599    if (!spa) {
600	spa = STAILQ_FIRST(&zfs_pools);
601	if (!spa) {
602	    printf("No ZFS pools located, can't boot\n");
603	    for (;;)
604		;
605	}
606    }
607
608    zfs_mount_pool(spa);
609
610    if (zfs_lookup(spa, PATH_CONFIG, &dn) == 0) {
611	off = 0;
612	zfs_read(spa, &dn, &off, cmd, sizeof(cmd));
613    }
614
615    if (*cmd) {
616	if (parse())
617	    autoboot = 0;
618	if (!OPT_CHECK(RBX_QUIET))
619	    printf("%s: %s", PATH_CONFIG, cmd);
620	/* Do not process this command twice */
621	*cmd = 0;
622    }
623
624    /*
625     * Try to exec stage 3 boot loader. If interrupted by a keypress,
626     * or in case of failure, try to load a kernel directly instead.
627     */
628
629    if (autoboot && !*kname) {
630	memcpy(kname, PATH_BOOT3, sizeof(PATH_BOOT3));
631	if (!keyhit(3*SECOND)) {
632	    load();
633	    memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL));
634	}
635    }
636
637    /* Present the user with the boot2 prompt. */
638
639    for (;;) {
640	if (!autoboot || !OPT_CHECK(RBX_QUIET))
641	    printf("\nFreeBSD/i386 boot\n"
642		   "Default: %s:%s\n"
643		   "boot: ",
644		   spa->spa_name, kname);
645	if (ioctrl & IO_SERIAL)
646	    sio_flush();
647	if (!autoboot || keyhit(5*SECOND))
648	    getstr();
649	else if (!autoboot || !OPT_CHECK(RBX_QUIET))
650	    putchar('\n');
651	autoboot = 0;
652	if (parse())
653	    putchar('\a');
654	else
655	    load();
656    }
657}
658
659/* XXX - Needed for btxld to link the boot2 binary; do not remove. */
660void
661exit(int x)
662{
663}
664
665static void
666load(void)
667{
668    union {
669	struct exec ex;
670	Elf32_Ehdr eh;
671    } hdr;
672    static Elf32_Phdr ep[2];
673    static Elf32_Shdr es[2];
674    caddr_t p;
675    dnode_phys_t dn;
676    off_t off;
677    uint32_t addr, x;
678    int fmt, i, j;
679
680    if (zfs_lookup(spa, kname, &dn)) {
681	return;
682    }
683    off = 0;
684    if (xfsread(&dn, &off, &hdr, sizeof(hdr)))
685	return;
686    if (N_GETMAGIC(hdr.ex) == ZMAGIC)
687	fmt = 0;
688    else if (IS_ELF(hdr.eh))
689	fmt = 1;
690    else {
691	printf("Invalid %s\n", "format");
692	return;
693    }
694    if (fmt == 0) {
695	addr = hdr.ex.a_entry & 0xffffff;
696	p = PTOV(addr);
697	off = PAGE_SIZE;
698	if (xfsread(&dn, &off, p, hdr.ex.a_text))
699	    return;
700	p += roundup2(hdr.ex.a_text, PAGE_SIZE);
701	if (xfsread(&dn, &off, p, hdr.ex.a_data))
702	    return;
703	p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE);
704	bootinfo.bi_symtab = VTOP(p);
705	memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms));
706	p += sizeof(hdr.ex.a_syms);
707	if (hdr.ex.a_syms) {
708	    if (xfsread(&dn, &off, p, hdr.ex.a_syms))
709		return;
710	    p += hdr.ex.a_syms;
711	    if (xfsread(&dn, &off, p, sizeof(int)))
712		return;
713	    x = *(uint32_t *)p;
714	    p += sizeof(int);
715	    x -= sizeof(int);
716	    if (xfsread(&dn, &off, p, x))
717		return;
718	    p += x;
719	}
720    } else {
721	off = hdr.eh.e_phoff;
722	for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) {
723	    if (xfsread(&dn, &off, ep + j, sizeof(ep[0])))
724		return;
725	    if (ep[j].p_type == PT_LOAD)
726		j++;
727	}
728	for (i = 0; i < 2; i++) {
729	    p = PTOV(ep[i].p_paddr & 0xffffff);
730	    off = ep[i].p_offset;
731	    if (xfsread(&dn, &off, p, ep[i].p_filesz))
732		return;
733	}
734	p += roundup2(ep[1].p_memsz, PAGE_SIZE);
735	bootinfo.bi_symtab = VTOP(p);
736	if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) {
737	    off = hdr.eh.e_shoff + sizeof(es[0]) *
738		(hdr.eh.e_shstrndx + 1);
739	    if (xfsread(&dn, &off, &es, sizeof(es)))
740		return;
741	    for (i = 0; i < 2; i++) {
742		memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size));
743		p += sizeof(es[i].sh_size);
744		off = es[i].sh_offset;
745		if (xfsread(&dn, &off, p, es[i].sh_size))
746		    return;
747		p += es[i].sh_size;
748	    }
749	}
750	addr = hdr.eh.e_entry & 0xffffff;
751    }
752    bootinfo.bi_esymtab = VTOP(p);
753    bootinfo.bi_kernelname = VTOP(kname);
754    __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK),
755	   bootdev,
756	   KARGS_FLAGS_ZFS,
757	   (uint32_t) spa->spa_guid,
758	   (uint32_t) (spa->spa_guid >> 32),
759	   VTOP(&bootinfo));
760}
761
762static int
763parse()
764{
765    char *arg = cmd;
766    char *ep, *p, *q;
767    const char *cp;
768    //unsigned int drv;
769    int c, i, j;
770
771    while ((c = *arg++)) {
772	if (c == ' ' || c == '\t' || c == '\n')
773	    continue;
774	for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++);
775	ep = p;
776	if (*p)
777	    *p++ = 0;
778	if (c == '-') {
779	    while ((c = *arg++)) {
780		if (c == 'P') {
781		    if (*(uint8_t *)PTOV(0x496) & 0x10) {
782			cp = "yes";
783		    } else {
784			opts |= OPT_SET(RBX_DUAL) | OPT_SET(RBX_SERIAL);
785			cp = "no";
786		    }
787		    printf("Keyboard: %s\n", cp);
788		    continue;
789		} else if (c == 'S') {
790		    j = 0;
791		    while ((unsigned int)(i = *arg++ - '0') <= 9)
792			j = j * 10 + i;
793		    if (j > 0 && i == -'0') {
794			comspeed = j;
795			break;
796		    }
797		    /* Fall through to error below ('S' not in optstr[]). */
798		}
799		for (i = 0; c != optstr[i]; i++)
800		    if (i == NOPT - 1)
801			return -1;
802		opts ^= OPT_SET(flags[i]);
803	    }
804	    ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) :
805		     OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD;
806	    if (ioctrl & IO_SERIAL)
807	        sio_init(115200 / comspeed);
808	} if (c == '?') {
809	    dnode_phys_t dn;
810
811	    if (zfs_lookup(spa, arg, &dn) == 0) {
812		zap_list(spa, &dn);
813	    }
814	    return -1;
815	} else {
816	    arg--;
817
818	    /*
819	     * Report pool status if the comment is 'status'. Lets
820	     * hope no-one wants to load /status as a kernel.
821	     */
822	    if (!strcmp(arg, "status")) {
823		spa_all_status();
824		return -1;
825	    }
826
827	    /*
828	     * If there is a colon, switch pools.
829	     */
830	    q = (char *) strchr(arg, ':');
831	    if (q) {
832		spa_t *newspa;
833
834		*q++ = 0;
835		newspa = spa_find_by_name(arg);
836		if (newspa) {
837		    spa = newspa;
838		    zfs_mount_pool(spa);
839		} else {
840		    printf("\nCan't find ZFS pool %s\n", arg);
841		    return -1;
842		}
843		arg = q;
844	    }
845	    if ((i = ep - arg)) {
846		if ((size_t)i >= sizeof(kname))
847		    return -1;
848		memcpy(kname, arg, i + 1);
849	    }
850	}
851	arg = p;
852    }
853    return 0;
854}
855
856static void
857printf(const char *fmt,...)
858{
859    va_list ap;
860    char buf[10];
861    char *s;
862    unsigned u;
863    int c;
864    int minus;
865    int prec;
866    int len;
867    int pad;
868
869    va_start(ap, fmt);
870    while ((c = *fmt++)) {
871	if (c == '%') {
872	    minus = 0;
873	    prec = 0;
874	nextfmt:
875	    c = *fmt++;
876	    switch (c) {
877	    case '-':
878		minus = 1;
879		goto nextfmt;
880	    case '0':
881	    case '1':
882	    case '2':
883	    case '3':
884	    case '4':
885	    case '5':
886	    case '6':
887	    case '7':
888	    case '8':
889	    case '9':
890		prec = 10 * prec + (c - '0');
891		goto nextfmt;
892	    case 'c':
893		putchar(va_arg(ap, int));
894		continue;
895	    case 's':
896		s = va_arg(ap, char *);
897		if (prec) {
898		    len = strlen(s);
899		    if (len < prec)
900			pad = prec - len;
901		    else
902			pad = 0;
903		    if (minus)
904			while (pad--)
905			    putchar(' ');
906		    for (; *s; s++)
907			putchar(*s);
908		    if (!minus)
909			while (pad--)
910			    putchar(' ');
911		} else {
912		    for (; *s; s++)
913			putchar(*s);
914		}
915		continue;
916	    case 'u':
917		u = va_arg(ap, unsigned);
918		s = buf;
919		do
920		    *s++ = '0' + u % 10U;
921		while (u /= 10U);
922		while (--s >= buf)
923		    putchar(*s);
924		continue;
925	    }
926	}
927	putchar(c);
928    }
929    va_end(ap);
930    return;
931}
932
933static void
934putchar(int c)
935{
936    if (c == '\n')
937	xputc('\r');
938    xputc(c);
939}
940
941#ifdef GPT
942static struct {
943	uint16_t len;
944	uint16_t count;
945	uint16_t seg;
946	uint16_t off;
947	uint64_t lba;
948} packet;
949#endif
950
951static int
952drvread(struct dsk *dsk, void *buf, unsigned lba, unsigned nblk)
953{
954#ifdef GPT
955    static unsigned c = 0x2d5c7c2f;
956
957    if (!OPT_CHECK(RBX_QUIET))
958	printf("%c\b", c = c << 8 | c >> 24);
959    packet.len = 0x10;
960    packet.count = nblk;
961    packet.seg = VTOPOFF(buf);
962    packet.off = VTOPSEG(buf);
963    packet.lba = lba + dsk->start;
964    v86.ctl = V86_FLAGS;
965    v86.addr = 0x13;
966    v86.eax = 0x4200;
967    v86.edx = dsk->drive;
968    v86.ds = VTOPSEG(&packet);
969    v86.esi = VTOPOFF(&packet);
970    v86int();
971    if (V86_CY(v86.efl)) {
972	printf("error %u lba %u\n", v86.eax >> 8 & 0xff, lba);
973	return -1;
974    }
975    return 0;
976#else
977    static unsigned c = 0x2d5c7c2f;
978
979    lba += dsk->start;
980    if (!OPT_CHECK(RBX_QUIET))
981	printf("%c\b", c = c << 8 | c >> 24);
982    v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS;
983    v86.addr = XREADORG;		/* call to xread in boot1 */
984    v86.es = VTOPSEG(buf);
985    v86.eax = lba;
986    v86.ebx = VTOPOFF(buf);
987    v86.ecx = lba >> 16;
988    v86.edx = nblk << 8 | dsk->drive;
989    v86int();
990    v86.ctl = V86_FLAGS;
991    if (V86_CY(v86.efl)) {
992	printf("error %u lba %u\n", v86.eax >> 8 & 0xff, lba);
993	return -1;
994    }
995    return 0;
996#endif
997}
998
999static int
1000keyhit(unsigned ticks)
1001{
1002    uint32_t t0, t1;
1003
1004    if (OPT_CHECK(RBX_NOINTR))
1005	return 0;
1006    t0 = 0;
1007    for (;;) {
1008	if (xgetc(1))
1009	    return 1;
1010	t1 = *(uint32_t *)PTOV(0x46c);
1011	if (!t0)
1012	    t0 = t1;
1013	if (t1 < t0 || t1 >= t0 + ticks)
1014	    return 0;
1015    }
1016}
1017
1018static int
1019xputc(int c)
1020{
1021    if (ioctrl & IO_KEYBOARD)
1022	putc(c);
1023    if (ioctrl & IO_SERIAL)
1024	sio_putc(c);
1025    return c;
1026}
1027
1028static int
1029xgetc(int fn)
1030{
1031    if (OPT_CHECK(RBX_NOINTR))
1032	return 0;
1033    for (;;) {
1034	if (ioctrl & IO_KEYBOARD && getc(1))
1035	    return fn ? 1 : getc(0);
1036	if (ioctrl & IO_SERIAL && sio_ischar())
1037	    return fn ? 1 : sio_getc();
1038	if (fn)
1039	    return 0;
1040    }
1041}
1042
1043static int
1044getc(int fn)
1045{
1046    /*
1047     * The extra comparison against zero is an attempt to work around
1048     * what appears to be a bug in QEMU and Bochs. Both emulators
1049     * sometimes report a key-press with scancode one and ascii zero
1050     * when no such key is pressed in reality. As far as I can tell,
1051     * this only happens shortly after a reboot.
1052     */
1053    v86.addr = 0x16;
1054    v86.eax = fn << 8;
1055    v86int();
1056    return fn == 0 ? v86.eax & 0xff : (!V86_ZR(v86.efl) && (v86.eax & 0xff));
1057}
1058