gptboot.c revision 151367
1106266Sjulian/*-
2106266Sjulian * Copyright (c) 1998 Robert Nordier
3139823Simp * All rights reserved.
4139823Simp *
5139823Simp * Redistribution and use in source and binary forms are freely
6144674Sglebius * permitted provided that the above copyright notice and this
7106266Sjulian * paragraph and the following disclaimer are duplicated in all
8106266Sjulian * such forms.
9106266Sjulian *
10106266Sjulian * This software is provided "AS IS" and without any express or
11106266Sjulian * implied warranties, including, without limitation, the implied
12106319Sjulian * warranties of merchantability and fitness for a particular
13106266Sjulian * purpose.
14106319Sjulian */
15106319Sjulian
16106266Sjulian#include <sys/cdefs.h>
17106319Sjulian__FBSDID("$FreeBSD: head/sys/boot/i386/gptboot/gptboot.c 151367 2005-10-16 01:55:35Z sobomax $");
18106319Sjulian
19106266Sjulian#include <sys/param.h>
20106266Sjulian#include <sys/disklabel.h>
21106266Sjulian#include <sys/diskmbr.h>
22106319Sjulian#include <sys/dirent.h>
23106319Sjulian#include <sys/reboot.h>
24106319Sjulian
25106266Sjulian#include <machine/bootinfo.h>
26106266Sjulian#include <machine/elf.h>
27106266Sjulian
28106266Sjulian#include <stdarg.h>
29106266Sjulian
30106319Sjulian#include <a.out.h>
31106266Sjulian
32106266Sjulian#include <btxv86.h>
33106266Sjulian
34106266Sjulian#include "boot2.h"
35106266Sjulian#include "lib.h"
36106266Sjulian
37106266Sjulian#define IO_KEYBOARD	1
38106266Sjulian#define IO_SERIAL	2
39106266Sjulian
40106266Sjulian#define SECOND		18	/* Circa that many ticks in a second. */
41125077Sharti
42125077Sharti#define RBX_ASKNAME	0x0	/* -a */
43125077Sharti#define RBX_SINGLE	0x1	/* -s */
44106266Sjulian/* 0x2 is reserved for log2(RB_NOSYNC). */
45106266Sjulian/* 0x3 is reserved for log2(RB_HALT). */
46143387Sbmilekic/* 0x4 is reserved for log2(RB_INITNAME). */
47143387Sbmilekic#define RBX_DFLTROOT	0x5	/* -r */
48143387Sbmilekic#define RBX_KDB 	0x6	/* -d */
49143387Sbmilekic/* 0x7 is reserved for log2(RB_RDONLY). */
50106266Sjulian/* 0x8 is reserved for log2(RB_DUMP). */
51106266Sjulian/* 0x9 is reserved for log2(RB_MINIROOT). */
52106266Sjulian#define RBX_CONFIG	0xa	/* -c */
53106266Sjulian#define RBX_VERBOSE	0xb	/* -v */
54106266Sjulian#define RBX_SERIAL	0xc	/* -h */
55106266Sjulian#define RBX_CDROM	0xd	/* -C */
56143387Sbmilekic/* 0xe is reserved for log2(RB_POWEROFF). */
57106266Sjulian#define RBX_GDB 	0xf	/* -g */
58106266Sjulian#define RBX_MUTE	0x10	/* -m */
59106266Sjulian/* 0x11 is reserved for log2(RB_SELFTEST). */
60106266Sjulian/* 0x12 is reserved for boot programs. */
61106266Sjulian/* 0x13 is reserved for boot programs. */
62106266Sjulian#define RBX_PAUSE	0x14	/* -p */
63106266Sjulian/* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */
64106266Sjulian#define RBX_DUAL	0x1d	/* -D */
65106266Sjulian/* 0x1f is reserved for log2(RB_BOOTINFO). */
66106266Sjulian/* group of internal options below */
67106266Sjulian#define RBX_NOINTR	0x20	/* -n */
68144674Sglebius#define RBX_QUIET	0x21	/* -q */
69106266Sjulian
70106266Sjulian/* pass: -a, -s, -r, -d, -c, -v, -h, -C, -g, -m, -p, -D */
71106266Sjulian#define RBX_MASK	0xffffffff
72106266Sjulian
73106266Sjulian#define PATH_CONFIG	"/boot.config"
74106266Sjulian#define PATH_BOOT3	"/boot/loader"
75106266Sjulian#define PATH_KERNEL	"/boot/kernel/kernel"
76106266Sjulian
77106266Sjulian#define ARGS		0x900
78106266Sjulian#define NOPT		12
79106266Sjulian#define NDEV		3
80106266Sjulian#define MEM_BASE	0x12
81106266Sjulian#define MEM_EXT 	0x15
82106266Sjulian#define V86_CY(x)	((x) & 1)
83144674Sglebius#define V86_ZR(x)	((x) & 0x40)
84144674Sglebius
85106266Sjulian#define DRV_HARD	0x80
86106319Sjulian#define DRV_MASK	0x7f
87106266Sjulian
88137138Sglebius#define TYPE_AD		0
89144674Sglebius#define TYPE_DA		1
90144674Sglebius#define TYPE_MAXHARD	TYPE_DA
91106266Sjulian#define TYPE_FD		2
92106266Sjulian
93106266Sjulian#define OPT_CHECK(opt)	((opts >> (opt)) & 0x1)
94106266Sjulian
95106266Sjulianextern uint32_t _end;
96106266Sjulian
97106266Sjulianstatic const char optstr[NOPT] = "DhaCgmnpqrsv"; /* Also 'P', 'S' */
98106266Sjulianstatic const unsigned char flags[NOPT] = {
99106266Sjulian    RBX_DUAL,
100106266Sjulian    RBX_SERIAL,
101106266Sjulian    RBX_ASKNAME,
102144674Sglebius    RBX_CDROM,
103106266Sjulian    RBX_GDB,
104106266Sjulian    RBX_MUTE,
105106266Sjulian    RBX_NOINTR,
106106266Sjulian    RBX_PAUSE,
107125243Sharti    RBX_QUIET,
108106266Sjulian    RBX_DFLTROOT,
109144674Sglebius    RBX_SINGLE,
110106266Sjulian    RBX_VERBOSE
111106266Sjulian};
112144674Sglebius
113106266Sjulianstatic const char *const dev_nm[NDEV] = {"ad", "da", "fd"};
114106266Sjulianstatic const unsigned char dev_maj[NDEV] = {30, 4, 2};
115125077Sharti
116106266Sjulianstatic struct dsk {
117106266Sjulian    unsigned drive;
118106266Sjulian    unsigned type;
119106266Sjulian    unsigned unit;
120106266Sjulian    unsigned slice;
121106266Sjulian    unsigned part;
122106266Sjulian    unsigned start;
123106266Sjulian    int init;
124106266Sjulian} dsk;
125106266Sjulianstatic char cmd[512];
126106266Sjulianstatic char kname[1024];
127106266Sjulianstatic uint64_t opts;
128106266Sjulianstatic int comspeed = SIOSPD;
129106266Sjulianstatic struct bootinfo bootinfo;
130106266Sjulianstatic uint8_t ioctrl = IO_KEYBOARD;
131106266Sjulian
132106266Sjulianvoid exit(int);
133106266Sjulianstatic void load(void);
134106266Sjulianstatic int parse(void);
135106266Sjulianstatic int xfsread(ino_t, void *, size_t);
136106266Sjulianstatic int dskread(void *, unsigned, unsigned);
137106266Sjulianstatic void printf(const char *,...);
138106266Sjulianstatic void putchar(int);
139106266Sjulianstatic uint32_t memsize(void);
140106266Sjulianstatic int drvread(void *, unsigned, unsigned);
141106266Sjulianstatic int keyhit(unsigned);
142106266Sjulianstatic int xputc(int);
143106266Sjulianstatic int xgetc(int);
144106266Sjulianstatic int getc(int);
145106266Sjulian
146106266Sjulianstatic void memcpy(void *, const void *, int);
147106266Sjulianstatic void
148106266Sjulianmemcpy(void *dst, const void *src, int len)
149106266Sjulian{
150106266Sjulian    const char *s = src;
151106266Sjulian    char *d = dst;
152106266Sjulian
153106266Sjulian    while (len--)
154106266Sjulian        *d++ = *s++;
155106266Sjulian}
156106266Sjulian
157106266Sjulianstatic inline int
158106266Sjulianstrcmp(const char *s1, const char *s2)
159106266Sjulian{
160106266Sjulian    for (; *s1 == *s2 && *s1; s1++, s2++);
161106266Sjulian    return (unsigned char)*s1 - (unsigned char)*s2;
162106266Sjulian}
163106266Sjulian
164106266Sjulian#include "ufsread.c"
165106266Sjulian
166106266Sjulianstatic inline int
167106266Sjulianxfsread(ino_t inode, void *buf, size_t nbyte)
168106266Sjulian{
169106266Sjulian    if ((size_t)fsread(inode, buf, nbyte) != nbyte) {
170106266Sjulian	printf("Invalid %s\n", "format");
171106266Sjulian	return -1;
172106266Sjulian    }
173106266Sjulian    return 0;
174106266Sjulian}
175106266Sjulian
176106266Sjulianstatic inline uint32_t
177125033Shartimemsize(void)
178125033Sharti{
179144674Sglebius    v86.addr = MEM_EXT;
180144674Sglebius    v86.eax = 0x8800;
181144674Sglebius    v86int();
182125033Sharti    return v86.eax;
183125033Sharti}
184153690Sglebius
185153690Sglebiusstatic inline void
186153690Sglebiusgetstr(void)
187153690Sglebius{
188153690Sglebius    char *s;
189153690Sglebius    int c;
190153690Sglebius
191106266Sjulian    s = cmd;
192106266Sjulian    for (;;) {
193106266Sjulian	switch (c = xgetc(0)) {
194106266Sjulian	case 0:
195106266Sjulian	    break;
196129823Sjulian	case '\177':
197129823Sjulian	case '\b':
198129823Sjulian	    if (s > cmd) {
199129823Sjulian		s--;
200129823Sjulian		printf("\b \b");
201129823Sjulian	    }
202144674Sglebius	    break;
203129823Sjulian	case '\n':
204129823Sjulian	case '\r':
205129823Sjulian	    *s = 0;
206106266Sjulian	    return;
207106266Sjulian	default:
208106266Sjulian	    if (s - cmd < sizeof(cmd) - 1)
209144674Sglebius		*s++ = c;
210125032Sharti	    putchar(c);
211106266Sjulian	}
212106266Sjulian    }
213106266Sjulian}
214106266Sjulian
215106321Sjulianstatic inline void
216106266Sjulianputc(int c)
217106266Sjulian{
218106266Sjulian    v86.addr = 0x10;
219125030Sharti    v86.eax = 0xe00 | (c & 0xff);
220106266Sjulian    v86.ebx = 0x7;
221106266Sjulian    v86int();
222106266Sjulian}
223106321Sjulian
224106321Sjulianint
225106266Sjulianmain(void)
226137138Sglebius{
227137138Sglebius    int autoboot;
228106266Sjulian    ino_t ino;
229106266Sjulian
230106266Sjulian    dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base);
231106266Sjulian    v86.ctl = V86_FLAGS;
232106266Sjulian    dsk.drive = *(uint8_t *)PTOV(ARGS);
233106266Sjulian    dsk.type = dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD;
234106266Sjulian    dsk.unit = dsk.drive & DRV_MASK;
235106266Sjulian    dsk.slice = *(uint8_t *)PTOV(ARGS + 1) + 1;
236106266Sjulian    bootinfo.bi_version = BOOTINFO_VERSION;
237144674Sglebius    bootinfo.bi_size = sizeof(bootinfo);
238106266Sjulian    bootinfo.bi_basemem = 0;	/* XXX will be filled by loader or kernel */
239106266Sjulian    bootinfo.bi_extmem = memsize();
240144674Sglebius    bootinfo.bi_memsizes_valid++;
241106266Sjulian
242144674Sglebius    /* Process configuration file */
243106266Sjulian
244106266Sjulian    autoboot = 1;
245106266Sjulian
246106266Sjulian    if ((ino = lookup(PATH_CONFIG)))
247144674Sglebius	fsread(ino, cmd, sizeof(cmd));
248106266Sjulian
249106266Sjulian    if (*cmd) {
250106266Sjulian	if (parse())
251106266Sjulian	    autoboot = 0;
252144674Sglebius	if (!OPT_CHECK(RBX_QUIET))
253144674Sglebius	    printf("%s: %s", PATH_CONFIG, cmd);
254144674Sglebius	/* Do not process this command twice */
255144674Sglebius	*cmd = 0;
256144674Sglebius    }
257144674Sglebius
258144674Sglebius    /*
259144674Sglebius     * Try to exec stage 3 boot loader. If interrupted by a keypress,
260144674Sglebius     * or in case of failure, try to load a kernel directly instead.
261144674Sglebius     */
262144674Sglebius
263144674Sglebius    if (autoboot && !*kname) {
264144674Sglebius	memcpy(kname, PATH_BOOT3, sizeof(PATH_BOOT3));
265144674Sglebius	if (!keyhit(3*SECOND)) {
266144674Sglebius	    load();
267144674Sglebius	    memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL));
268144674Sglebius	}
269144674Sglebius    }
270144674Sglebius
271144674Sglebius    /* Present the user with the boot2 prompt. */
272144674Sglebius
273144674Sglebius    for (;;) {
274144674Sglebius	if (!autoboot || !OPT_CHECK(RBX_QUIET))
275144674Sglebius	    printf("\nFreeBSD/i386 boot\n"
276144674Sglebius	           "Default: %u:%s(%u,%c)%s\n"
277144674Sglebius	           "boot: ",
278144674Sglebius	           dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit,
279144674Sglebius	           'a' + dsk.part, kname);
280144674Sglebius	if (ioctrl & IO_SERIAL)
281144674Sglebius	    sio_flush();
282144674Sglebius	if (!autoboot || keyhit(5*SECOND))
283106266Sjulian	    getstr();
284106266Sjulian	else if (!autoboot || !OPT_CHECK(RBX_QUIET))
285106266Sjulian	    putchar('\n');
286106321Sjulian	autoboot = 0;
287106266Sjulian	if (parse())
288144674Sglebius	    putchar('\a');
289144674Sglebius	else
290106266Sjulian	    load();
291106266Sjulian    }
292106321Sjulian}
293144674Sglebius
294106266Sjulian/* XXX - Needed for btxld to link the boot2 binary; do not remove. */
295106266Sjulianvoid
296106435Sjulianexit(int x)
297106435Sjulian{
298106435Sjulian}
299106435Sjulian
300106266Sjulianstatic void
301106266Sjulianload(void)
302106266Sjulian{
303106266Sjulian    static union {
304106266Sjulian	struct exec ex;
305106266Sjulian	Elf32_Ehdr eh;
306106266Sjulian    } hdr;
307106266Sjulian    static Elf32_Phdr ep[2];
308106266Sjulian    static Elf32_Shdr es[2];
309106266Sjulian    caddr_t p;
310106266Sjulian    ino_t ino;
311106266Sjulian    uint32_t addr, x;
312106266Sjulian    int fmt, i, j;
313106266Sjulian
314106266Sjulian    if (!(ino = lookup(kname))) {
315106319Sjulian	if (!ls)
316106321Sjulian	    printf("No %s\n", kname);
317106266Sjulian	return;
318106319Sjulian    }
319106266Sjulian    if (xfsread(ino, &hdr, sizeof(hdr)))
320106319Sjulian	return;
321106266Sjulian    if (N_GETMAGIC(hdr.ex) == ZMAGIC)
322106319Sjulian	fmt = 0;
323106266Sjulian    else if (IS_ELF(hdr.eh))
324106266Sjulian	fmt = 1;
325106266Sjulian    else {
326106266Sjulian	printf("Invalid %s\n", "format");
327106266Sjulian	return;
328106266Sjulian    }
329106266Sjulian    if (fmt == 0) {
330106266Sjulian	addr = hdr.ex.a_entry;
331144674Sglebius	p = PTOV(addr);
332144674Sglebius	fs_off = PAGE_SIZE;
333144674Sglebius	if (xfsread(ino, p, hdr.ex.a_text))
334106266Sjulian	    return;
335106266Sjulian	p += roundup2(hdr.ex.a_text, PAGE_SIZE);
336106266Sjulian	if (xfsread(ino, p, hdr.ex.a_data))
337125033Sharti	    return;
338144674Sglebius	p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE);
339144674Sglebius	bootinfo.bi_symtab = VTOP(p);
340144674Sglebius	memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms));
341144674Sglebius	p += sizeof(hdr.ex.a_syms);
342144674Sglebius	if (hdr.ex.a_syms) {
343125033Sharti	    if (xfsread(ino, p, hdr.ex.a_syms))
344106266Sjulian		return;
345106266Sjulian	    p += hdr.ex.a_syms;
346106266Sjulian	    if (xfsread(ino, p, sizeof(int)))
347106266Sjulian		return;
348106266Sjulian	    x = *(uint32_t *)p;
349106266Sjulian	    p += sizeof(int);
350144674Sglebius	    x -= sizeof(int);
351144674Sglebius	    if (xfsread(ino, p, x))
352144674Sglebius		return;
353144674Sglebius	    p += x;
354144674Sglebius	}
355144674Sglebius    } else {
356144674Sglebius	fs_off = hdr.eh.e_phoff;
357144674Sglebius	for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) {
358144674Sglebius	    if (xfsread(ino, ep + j, sizeof(ep[0])))
359144674Sglebius		return;
360144674Sglebius	    if (ep[j].p_type == PT_LOAD)
361144674Sglebius		j++;
362153690Sglebius	}
363153690Sglebius	for (i = 0; i < 2; i++) {
364153690Sglebius	    p = PTOV(ep[i].p_paddr);
365153690Sglebius	    fs_off = ep[i].p_offset;
366153690Sglebius	    if (xfsread(ino, p, ep[i].p_filesz))
367153690Sglebius		return;
368153690Sglebius	}
369153690Sglebius	p += roundup2(ep[1].p_memsz, PAGE_SIZE);
370153690Sglebius	bootinfo.bi_symtab = VTOP(p);
371153690Sglebius	if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) {
372153690Sglebius	    fs_off = hdr.eh.e_shoff + sizeof(es[0]) *
373153690Sglebius		(hdr.eh.e_shstrndx + 1);
374153690Sglebius	    if (xfsread(ino, &es, sizeof(es)))
375153690Sglebius		return;
376153690Sglebius	    for (i = 0; i < 2; i++) {
377106266Sjulian		memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size));
378106266Sjulian		p += sizeof(es[i].sh_size);
379106266Sjulian		fs_off = es[i].sh_offset;
380106266Sjulian		if (xfsread(ino, p, es[i].sh_size))
381106266Sjulian		    return;
382106435Sjulian		p += es[i].sh_size;
383106435Sjulian	    }
384106435Sjulian	}
385106435Sjulian	addr = hdr.eh.e_entry;
386106435Sjulian    }
387106435Sjulian    bootinfo.bi_esymtab = VTOP(p);
388144674Sglebius    bootinfo.bi_kernelname = VTOP(kname);
389144674Sglebius    bootinfo.bi_bios_dev = dsk.drive;
390144674Sglebius    __exec((caddr_t)addr, RB_BOOTINFO | (uint32_t)(opts & RBX_MASK),
391144674Sglebius	   MAKEBOOTDEV(dev_maj[dsk.type], 0, dsk.slice, dsk.unit, dsk.part),
392144674Sglebius	   0, 0, 0, VTOP(&bootinfo));
393144674Sglebius}
394144674Sglebius
395144674Sglebiusstatic int
396144674Sglebiusparse()
397144674Sglebius{
398106435Sjulian    char *arg = cmd;
399106435Sjulian    char *ep, *p, *q;
400144674Sglebius    const char *cp;
401106435Sjulian    unsigned int drv;
402106435Sjulian    int c, i, j;
403106435Sjulian
404106435Sjulian    while ((c = *arg++)) {
405106266Sjulian	if (c == ' ' || c == '\t' || c == '\n')
406106266Sjulian	    continue;
407106266Sjulian	for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++);
408106266Sjulian	ep = p;
409106266Sjulian	if (*p)
410106266Sjulian	    *p++ = 0;
411144674Sglebius	if (c == '-') {
412106321Sjulian	    while ((c = *arg++)) {
413144674Sglebius		if (c == 'P') {
414106321Sjulian		    if (*(uint8_t *)PTOV(0x496) & 0x10) {
415106266Sjulian			cp = "yes";
416106266Sjulian		    } else {
417106266Sjulian			opts |= (uint64_t)1 << RBX_DUAL | (uint64_t)1 << RBX_SERIAL;
418106266Sjulian			cp = "no";
419106266Sjulian		    }
420106266Sjulian		    printf("Keyboard: %s\n", cp);
421106266Sjulian		    continue;
422106266Sjulian		} else if (c == 'S') {
423106266Sjulian		    j = 0;
424106266Sjulian		    while ((unsigned int)(i = *arg++ - '0') <= 9)
425106321Sjulian			j = j * 10 + i;
426106266Sjulian		    if (j > 0 && i == -'0') {
427144674Sglebius			comspeed = j;
428144674Sglebius			break;
429106266Sjulian		    }
430106266Sjulian		    /* Fall through to error below ('S' not in optstr[]). */
431106321Sjulian		}
432106321Sjulian		for (i = 0; c != optstr[i]; i++)
433106266Sjulian		    if (i == NOPT - 1)
434106266Sjulian			return -1;
435144674Sglebius		opts ^= (uint64_t)1 << flags[i];
436106266Sjulian	    }
437106321Sjulian	    ioctrl = opts & (uint64_t)1 << RBX_DUAL ? (IO_SERIAL|IO_KEYBOARD) :
438106266Sjulian		     opts & (uint64_t)1 << RBX_SERIAL ? IO_SERIAL : IO_KEYBOARD;
439106266Sjulian	    if (ioctrl & IO_SERIAL)
440144674Sglebius	        sio_init(115200 / comspeed);
441106266Sjulian	} else {
442144674Sglebius	    for (q = arg--; *q && *q != '('; q++);
443106266Sjulian	    if (*q) {
444125031Sharti		drv = -1;
445106266Sjulian		if (arg[1] == ':') {
446106266Sjulian		    drv = *arg - '0';
447106266Sjulian		    if (drv > 9)
448106266Sjulian			return (-1);
449106266Sjulian		    arg += 2;
450106266Sjulian		}
451106266Sjulian		if (q - arg != 2)
452106266Sjulian		    return -1;
453106266Sjulian		for (i = 0; arg[0] != dev_nm[i][0] ||
454106266Sjulian			    arg[1] != dev_nm[i][1]; i++)
455106266Sjulian		    if (i == NDEV - 1)
456144674Sglebius			return -1;
457106266Sjulian		dsk.type = i;
458106266Sjulian		arg += 3;
459106266Sjulian		dsk.unit = *arg - '0';
460106321Sjulian		if (arg[1] != ',' || dsk.unit > 9)
461106321Sjulian		    return -1;
462125077Sharti		arg += 2;
463144674Sglebius		dsk.slice = WHOLE_DISK_SLICE;
464106266Sjulian		if (arg[1] == ',') {
465106266Sjulian		    dsk.slice = *arg - '0' + 1;
466106266Sjulian		    if (dsk.slice > NDOSPART)
467106266Sjulian			return -1;
468106266Sjulian		    arg += 2;
469106266Sjulian		}
470106266Sjulian		if (arg[1] != ')')
471106266Sjulian		    return -1;
472106266Sjulian		dsk.part = *arg - 'a';
473106319Sjulian		if (dsk.part > 7)
474106266Sjulian		    return (-1);
475106321Sjulian		arg += 2;
476125077Sharti		if (drv == -1)
477144674Sglebius		    drv = dsk.unit;
478106321Sjulian		dsk.drive = (dsk.type <= TYPE_MAXHARD
479106266Sjulian			     ? DRV_HARD : 0) + drv;
480106266Sjulian		dsk_meta = 0;
481106266Sjulian	    }
482106266Sjulian	    if ((i = ep - arg)) {
483106435Sjulian		if ((size_t)i >= sizeof(kname))
484106435Sjulian		    return -1;
485106435Sjulian		memcpy(kname, arg, i + 1);
486106435Sjulian	    }
487144674Sglebius	}
488106435Sjulian	arg = p;
489106435Sjulian    }
490106435Sjulian    return 0;
491106266Sjulian}
492144674Sglebius
493106266Sjulianstatic int
494106266Sjuliandskread(void *buf, unsigned lba, unsigned nblk)
495125077Sharti{
496106266Sjulian    struct dos_partition *dp;
497106266Sjulian    struct disklabel *d;
498106266Sjulian    char *sec;
499106266Sjulian    unsigned sl, i;
500106266Sjulian
501106266Sjulian    if (!dsk_meta) {
502106266Sjulian	sec = dmadat->secbuf;
503106266Sjulian	dsk.start = 0;
504106266Sjulian	if (drvread(sec, DOSBBSECTOR, 1))
505106266Sjulian	    return -1;
506106266Sjulian	dp = (void *)(sec + DOSPARTOFF);
507125077Sharti	sl = dsk.slice;
508106266Sjulian	if (sl < BASE_SLICE) {
509106319Sjulian	    for (i = 0; i < NDOSPART; i++)
510106266Sjulian		if (dp[i].dp_typ == DOSPTYP_386BSD &&
511106266Sjulian		    (dp[i].dp_flag & 0x80 || sl < BASE_SLICE)) {
512106266Sjulian		    sl = BASE_SLICE + i;
513106266Sjulian		    if (dp[i].dp_flag & 0x80 ||
514106266Sjulian			dsk.slice == COMPATIBILITY_SLICE)
515106266Sjulian			break;
516106266Sjulian		}
517106266Sjulian	    if (dsk.slice == WHOLE_DISK_SLICE)
518106266Sjulian		dsk.slice = sl;
519106266Sjulian	}
520106266Sjulian	if (sl != WHOLE_DISK_SLICE) {
521144674Sglebius	    if (sl != COMPATIBILITY_SLICE)
522106266Sjulian		dp += sl - BASE_SLICE;
523106266Sjulian	    if (dp->dp_typ != DOSPTYP_386BSD) {
524106266Sjulian		printf("Invalid %s\n", "slice");
525106266Sjulian		return -1;
526106266Sjulian	    }
527144674Sglebius	    dsk.start = dp->dp_start;
528106266Sjulian	}
529106266Sjulian	if (drvread(sec, dsk.start + LABELSECTOR, 1))
530106266Sjulian		return -1;
531144674Sglebius	d = (void *)(sec + LABELOFFSET);
532144674Sglebius	if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) {
533106266Sjulian	    if (dsk.part != RAW_PART) {
534106266Sjulian		printf("Invalid %s\n", "label");
535106266Sjulian		return -1;
536106266Sjulian	    }
537106266Sjulian	} else {
538106266Sjulian	    if (!dsk.init) {
539106266Sjulian		if (d->d_type == DTYPE_SCSI)
540106266Sjulian		    dsk.type = TYPE_DA;
541106266Sjulian		dsk.init++;
542106266Sjulian	    }
543106266Sjulian	    if (dsk.part >= d->d_npartitions ||
544106266Sjulian		!d->d_partitions[dsk.part].p_size) {
545125031Sharti		printf("Invalid %s\n", "partition");
546106266Sjulian		return -1;
547106266Sjulian	    }
548106266Sjulian	    dsk.start += d->d_partitions[dsk.part].p_offset;
549106266Sjulian	    dsk.start -= d->d_partitions[RAW_PART].p_offset;
550106266Sjulian	}
551106266Sjulian    }
552106266Sjulian    return drvread(buf, dsk.start + lba, nblk);
553106266Sjulian}
554106266Sjulian
555106266Sjulianstatic void
556144674Sglebiusprintf(const char *fmt,...)
557144674Sglebius{
558106266Sjulian    va_list ap;
559144674Sglebius    char buf[10];
560144674Sglebius    char *s;
561144674Sglebius    unsigned u;
562144674Sglebius    int c;
563144674Sglebius
564144674Sglebius    va_start(ap, fmt);
565144674Sglebius    while ((c = *fmt++)) {
566144674Sglebius	if (c == '%') {
567144674Sglebius	    c = *fmt++;
568144674Sglebius	    switch (c) {
569144674Sglebius	    case 'c':
570144674Sglebius		putchar(va_arg(ap, int));
571144674Sglebius		continue;
572144674Sglebius	    case 's':
573153690Sglebius		for (s = va_arg(ap, char *); *s; s++)
574144674Sglebius		    putchar(*s);
575144674Sglebius		continue;
576144674Sglebius	    case 'u':
577144674Sglebius		u = va_arg(ap, unsigned);
578106266Sjulian		s = buf;
579106266Sjulian		do
580106266Sjulian		    *s++ = '0' + u % 10U;
581106266Sjulian		while (u /= 10U);
582106266Sjulian		while (--s >= buf)
583106266Sjulian		    putchar(*s);
584144674Sglebius		continue;
585106266Sjulian	    }
586144674Sglebius	}
587144674Sglebius	putchar(c);
588144674Sglebius    }
589144674Sglebius    va_end(ap);
590144674Sglebius    return;
591106266Sjulian}
592106266Sjulian
593106266Sjulianstatic void
594106266Sjulianputchar(int c)
595106266Sjulian{
596106266Sjulian    if (c == '\n')
597106266Sjulian	xputc('\r');
598106266Sjulian    xputc(c);
599125243Sharti}
600106266Sjulian
601125243Shartistatic int
602106266Sjuliandrvread(void *buf, unsigned lba, unsigned nblk)
603106266Sjulian{
604106266Sjulian    static unsigned c = 0x2d5c7c2f;
605125077Sharti
606106266Sjulian    if (!OPT_CHECK(RBX_QUIET))
607144674Sglebius	printf("%c\b", c = c << 8 | c >> 24);
608106321Sjulian    v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS;
609106266Sjulian    v86.addr = XREADORG;		/* call to xread in boot1 */
610106266Sjulian    v86.es = VTOPSEG(buf);
611106266Sjulian    v86.eax = lba;
612106266Sjulian    v86.ebx = VTOPOFF(buf);
613125033Sharti    v86.ecx = lba >> 16;
614141745Sru    v86.edx = nblk << 8 | dsk.drive;
615125033Sharti    v86int();
616125033Sharti    v86.ctl = V86_FLAGS;
617125033Sharti    if (V86_CY(v86.efl)) {
618125033Sharti	printf("error %u lba %u\n", v86.eax >> 8 & 0xff, lba);
619153690Sglebius	return -1;
620153690Sglebius    }
621153690Sglebius    return 0;
622153690Sglebius}
623153690Sglebius
624153690Sglebiusstatic int
625153690Sglebiuskeyhit(unsigned ticks)
626153690Sglebius{
627153690Sglebius    uint32_t t0, t1;
628153690Sglebius
629153690Sglebius    if (OPT_CHECK(RBX_NOINTR))
630153690Sglebius	return 0;
631153690Sglebius    t0 = 0;
632153690Sglebius    for (;;) {
633153690Sglebius	if (xgetc(1))
634106266Sjulian	    return 1;
635125243Sharti	t1 = *(uint32_t *)PTOV(0x46c);
636106266Sjulian	if (!t0)
637125243Sharti	    t0 = t1;
638138268Sglebius	if (t1 < t0 || t1 >= t0 + ticks)
639137136Sglebius	    return 0;
640106266Sjulian    }
641106266Sjulian}
642106266Sjulian
643106266Sjulianstatic int
644106266Sjulianxputc(int c)
645106266Sjulian{
646106266Sjulian    if (ioctrl & IO_KEYBOARD)
647106266Sjulian	putc(c);
648106266Sjulian    if (ioctrl & IO_SERIAL)
649106266Sjulian	sio_putc(c);
650106266Sjulian    return c;
651106266Sjulian}
652106266Sjulian
653125077Shartistatic int
654106321Sjulianxgetc(int fn)
655125077Sharti{
656106266Sjulian    if (OPT_CHECK(RBX_NOINTR))
657144674Sglebius	return 0;
658106266Sjulian    for (;;) {
659106266Sjulian	if (ioctrl & IO_KEYBOARD && getc(1))
660106266Sjulian	    return fn ? 1 : getc(0);
661106266Sjulian	if (ioctrl & IO_SERIAL && sio_ischar())
662106266Sjulian	    return fn ? 1 : sio_getc();
663125031Sharti	if (fn)
664106266Sjulian	    return 0;
665106266Sjulian    }
666106266Sjulian}
667106266Sjulian
668111119Simpstatic int
669106266Sjuliangetc(int fn)
670125031Sharti{
671106266Sjulian    v86.addr = 0x16;
672106266Sjulian    v86.eax = fn << 8;
673106266Sjulian    v86int();
674106266Sjulian    return fn == 0 ? v86.eax & 0xff : !V86_ZR(v86.efl);
675144674Sglebius}
676125031Sharti