1201342Snyan/*-
2201342Snyan * Copyright (c) 2008-2009 TAKAHASHI Yoshihiro
3201342Snyan * Copyright (c) 1998 Robert Nordier
4201342Snyan * All rights reserved.
5201342Snyan *
6201342Snyan * Redistribution and use in source and binary forms are freely
7201342Snyan * permitted provided that the above copyright notice and this
8201342Snyan * paragraph and the following disclaimer are duplicated in all
9201342Snyan * such forms.
10201342Snyan *
11201342Snyan * This software is provided "AS IS" and without any express or
12201342Snyan * implied warranties, including, without limitation, the implied
13201342Snyan * warranties of merchantability and fitness for a particular
14201342Snyan * purpose.
15201342Snyan */
16201342Snyan
17201342Snyan#include <sys/cdefs.h>
18201342Snyan__FBSDID("$FreeBSD: stable/11/stand/pc98/boot2/boot2.c 333049 2018-04-27 02:39:36Z nyan $");
19201342Snyan
20201342Snyan#include <sys/param.h>
21201342Snyan#include <sys/disklabel.h>
22201342Snyan#include <sys/diskpc98.h>
23201342Snyan#include <sys/dirent.h>
24201342Snyan#include <sys/reboot.h>
25201342Snyan
26201342Snyan#include <machine/bootinfo.h>
27201342Snyan#include <machine/cpufunc.h>
28201342Snyan#include <machine/elf.h>
29201342Snyan
30201342Snyan#include <stdarg.h>
31201342Snyan
32201342Snyan#include <a.out.h>
33201342Snyan
34201342Snyan#include <btxv86.h>
35201342Snyan
36201342Snyan#include "boot2.h"
37201342Snyan#include "lib.h"
38294765Simp#include "paths.h"
39294766Simp#include "rbx.h"
40201342Snyan
41268475Simp/* Define to 0 to omit serial support */
42268475Simp#ifndef SERIAL
43268475Simp#define SERIAL 0
44268475Simp#endif
45268475Simp
46201342Snyan#define IO_KEYBOARD	1
47201342Snyan#define IO_SERIAL	2
48201342Snyan
49268475Simp#if SERIAL
50268475Simp#define DO_KBD (ioctrl & IO_KEYBOARD)
51268475Simp#define DO_SIO (ioctrl & IO_SERIAL)
52268475Simp#else
53268475Simp#define DO_KBD (1)
54268475Simp#define DO_SIO (0)
55268475Simp#endif
56268475Simp
57201342Snyan#define SECOND		1	/* Circa that many ticks in a second. */
58201342Snyan
59201342Snyan#define ARGS		0x900
60201342Snyan#define NOPT		14
61201342Snyan#define NDEV		3
62201342Snyan
63201342Snyan#define DRV_DISK	0xf0
64201342Snyan#define DRV_UNIT	0x0f
65201342Snyan
66201342Snyan#define TYPE_AD		0
67201342Snyan#define TYPE_DA		1
68201342Snyan#define TYPE_FD		2
69201342Snyan
70201342Snyanextern uint32_t _end;
71201342Snyan
72201342Snyanstatic const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */
73201342Snyanstatic const unsigned char flags[NOPT] = {
74333049Snyan	RBX_DUAL,
75333049Snyan	RBX_SERIAL,
76333049Snyan	RBX_ASKNAME,
77333049Snyan	RBX_CDROM,
78333049Snyan	RBX_CONFIG,
79333049Snyan	RBX_KDB,
80333049Snyan	RBX_GDB,
81333049Snyan	RBX_MUTE,
82333049Snyan	RBX_NOINTR,
83333049Snyan	RBX_PAUSE,
84333049Snyan	RBX_QUIET,
85333049Snyan	RBX_DFLTROOT,
86333049Snyan	RBX_SINGLE,
87333049Snyan	RBX_VERBOSE
88201342Snyan};
89201342Snyan
90201342Snyanstatic const char *const dev_nm[NDEV] = {"ad", "da", "fd"};
91201342Snyanstatic const unsigned char dev_maj[NDEV] = {30, 4, 2};
92201342Snyanstatic const unsigned char dev_daua[NDEV] = {0x80, 0xa0, 0x90};
93201342Snyan
94201342Snyanstatic struct dsk {
95333049Snyan	unsigned daua;
96333049Snyan	unsigned type;
97333049Snyan	unsigned disk;
98333049Snyan	unsigned unit;
99333049Snyan	unsigned head;
100333049Snyan	unsigned sec;
101333049Snyan	uint8_t slice;
102333049Snyan	uint8_t part;
103333049Snyan	unsigned start;
104201342Snyan} dsk;
105232784Snyanstatic char cmd[512], cmddup[512], knamebuf[1024];
106239063Snyanstatic const char *kname;
107294847Simpuint32_t opts;
108268475Simpstatic struct bootinfo bootinfo;
109268475Simp#if SERIAL
110201342Snyanstatic int comspeed = SIOSPD;
111219960Snyanstatic uint8_t ioctrl = IO_KEYBOARD;
112268475Simp#endif
113201342Snyan
114284885Snyanint main(void);
115201342Snyanvoid exit(int);
116201342Snyanstatic void load(void);
117201342Snyanstatic int parse(void);
118201342Snyanstatic int dskread(void *, unsigned, unsigned);
119201342Snyanstatic void printf(const char *,...);
120201342Snyanstatic void putchar(int);
121201342Snyanstatic int drvread(void *, unsigned);
122201342Snyanstatic int keyhit(unsigned);
123201342Snyanstatic int xputc(int);
124201342Snyanstatic int xgetc(int);
125220685Snyanstatic inline int getc(int);
126201342Snyan
127201342Snyanstatic void memcpy(void *, const void *, int);
128201342Snyanstatic void
129201342Snyanmemcpy(void *dst, const void *src, int len)
130201342Snyan{
131333049Snyan	const char *s = src;
132333049Snyan	char *d = dst;
133201342Snyan
134333049Snyan	while (len--)
135333049Snyan		*d++ = *s++;
136201342Snyan}
137201342Snyan
138201342Snyanstatic inline int
139201342Snyanstrcmp(const char *s1, const char *s2)
140201342Snyan{
141333049Snyan
142333049Snyan	for (; *s1 == *s2 && *s1; s1++, s2++);
143333049Snyan	return ((unsigned char)*s1 - (unsigned char)*s2);
144201342Snyan}
145201342Snyan
146201342Snyan#define	UFS_SMALL_CGBASE
147201342Snyan#include "ufsread.c"
148201342Snyan
149201342Snyanstatic inline int
150235988Sglebxfsread(ufs_ino_t inode, void *buf, size_t nbyte)
151201342Snyan{
152333049Snyan
153333049Snyan	if ((size_t)fsread(inode, buf, nbyte) != nbyte) {
154333049Snyan		printf("Invalid %s\n", "format");
155333049Snyan		return (-1);
156333049Snyan	}
157333049Snyan	return (0);
158201342Snyan}
159201342Snyan
160201342Snyanstatic inline void
161201342Snyangetstr(void)
162201342Snyan{
163333049Snyan	char *s;
164333049Snyan	int c;
165201342Snyan
166333049Snyan	s = cmd;
167333049Snyan	for (;;) {
168333049Snyan		switch (c = xgetc(0)) {
169333049Snyan		case 0:
170333049Snyan			break;
171333049Snyan		case '\177':
172333049Snyan		case '\b':
173333049Snyan			if (s > cmd) {
174333049Snyan				s--;
175333049Snyan				printf("\b \b");
176333049Snyan			}
177333049Snyan			break;
178333049Snyan		case '\n':
179333049Snyan		case '\r':
180333049Snyan			*s = 0;
181333049Snyan			return;
182333049Snyan		default:
183333049Snyan			if (s - cmd < sizeof(cmd) - 1)
184333049Snyan				*s++ = c;
185333049Snyan			putchar(c);
186333049Snyan		}
187201342Snyan	}
188201342Snyan}
189201342Snyan
190201342Snyanstatic inline void
191201342Snyanputc(int c)
192201342Snyan{
193201342Snyan
194333049Snyan	v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS;
195333049Snyan	v86.addr = PUTCORG;		/* call to putc in boot1 */
196333049Snyan	v86.eax = c;
197333049Snyan	v86int();
198333049Snyan	v86.ctl = V86_FLAGS;
199201342Snyan}
200201342Snyan
201201342Snyanstatic inline int
202201342Snyanis_scsi_hd(void)
203201342Snyan{
204201342Snyan
205201342Snyan    if ((*(u_char *)PTOV(0x482) >> dsk.unit) & 0x01)
206201342Snyan	return 1;
207201342Snyan
208201342Snyan    return 0;
209201342Snyan}
210201342Snyan
211201342Snyanstatic inline void
212201342Snyanfix_sector_size(void)
213201342Snyan{
214201342Snyan    u_char *p;
215201342Snyan
216201342Snyan    p = (u_char *)PTOV(0x460 + dsk.unit * 4);	/* SCSI equipment parameter */
217201342Snyan
218201342Snyan    if ((p[0] & 0x1f) == 7) {		/* SCSI MO */
219201342Snyan	if (!(p[3] & 0x30)) {		/* 256B / sector */
220201342Snyan	    p[3] |= 0x10;		/* forced set 512B / sector */
221201342Snyan	    p[3 + 0xa1000] |= 0x10;
222201342Snyan	}
223201342Snyan    }
224201342Snyan}
225201342Snyan
226201342Snyanstatic inline uint32_t
227201342Snyanget_diskinfo(void)
228201342Snyan{
229201342Snyan
230201342Snyan    if (dsk.disk == 0x30) {				/* 1440KB FD */
231201342Snyan	/* 80 cylinders, 2 heads, 18 sectors */
232201342Snyan	return (80 << 16) | (2 << 8) | 18;
233201342Snyan    } else if (dsk.disk == 0x90) {			/* 1200KB FD */
234201342Snyan	/* 80 cylinders, 2 heads, 15 sectors */
235201342Snyan	return (80 << 16) | (2 << 8) | 15;
236201342Snyan    } else if (dsk.disk == 0x80 || is_scsi_hd()) {	/* IDE or SCSI HDD */
237201342Snyan	v86.addr = 0x1b;
238201342Snyan	v86.eax = 0x8400 | dsk.daua;
239201342Snyan	v86int();
240201342Snyan	return (v86.ecx << 16) | v86.edx;
241201342Snyan    }
242201342Snyan
243201342Snyan    /* SCSI MO or CD */
244201342Snyan    fix_sector_size();	/* SCSI MO */
245201342Snyan
246201342Snyan    /* other SCSI devices */
247201342Snyan    return (65535 << 16) | (8 << 8) | 32;
248201342Snyan}
249201342Snyan
250201342Snyanstatic void
251201342Snyanset_dsk(void)
252201342Snyan{
253201342Snyan    uint32_t di;
254201342Snyan
255201342Snyan    di = get_diskinfo();
256201342Snyan
257201342Snyan    dsk.head = (di >> 8) & 0xff;
258201342Snyan    dsk.sec = di & 0xff;
259201342Snyan    dsk.start = 0;
260201342Snyan}
261201342Snyan
262201342Snyan#ifdef GET_BIOSGEOM
263201342Snyanstatic uint32_t
264201342Snyanbd_getbigeom(int bunit)
265201342Snyan{
266201342Snyan    int hds = 0;
267201342Snyan    int unit = 0x80;		/* IDE HDD */
268201342Snyan    u_int addr = 0x55d;
269201342Snyan
270201342Snyan    while (unit < 0xa7) {
271201342Snyan	if (*(u_char *)PTOV(addr) & (1 << (unit & 0x0f)))
272201342Snyan	    if (hds++ == bunit)
273201342Snyan		break;
274201342Snyan
275201342Snyan	if (unit >= 0xA0) {
276201342Snyan	    int media = ((unsigned *)PTOV(0x460))[unit & 0x0F] & 0x1F;
277201342Snyan
278201342Snyan	    if (media == 7 && hds++ == bunit)	/* SCSI MO */
279201342Snyan		return(0xFFFE0820); /* C:65535 H:8 S:32 */
280201342Snyan	}
281201342Snyan	if (++unit == 0x84) {
282201342Snyan	    unit = 0xA0;	/* SCSI HDD */
283201342Snyan	    addr = 0x482;
284201342Snyan	}
285201342Snyan    }
286201342Snyan    if (unit == 0xa7)
287201342Snyan	return 0x4F020F;	/* 1200KB FD C:80 H:2 S:15 */
288201342Snyan    v86.addr = 0x1b;
289201342Snyan    v86.eax = 0x8400 | unit;
290201342Snyan    v86int();
291292682Sjhb    if (V86_CY(v86.efl))
292201342Snyan	return 0x4F020F;	/* 1200KB FD C:80 H:2 S:15 */
293201342Snyan    return ((v86.ecx & 0xffff) << 16) | (v86.edx & 0xffff);
294201342Snyan}
295201342Snyan#endif
296201342Snyan
297201342Snyanstatic int
298201342Snyancheck_slice(void)
299201342Snyan{
300201342Snyan    struct pc98_partition *dp;
301201342Snyan    char *sec;
302201342Snyan    unsigned i, cyl;
303201342Snyan
304201342Snyan    sec = dmadat->secbuf;
305201342Snyan    cyl = *(uint16_t *)PTOV(ARGS);
306201342Snyan    set_dsk();
307201342Snyan
308201342Snyan    if (dsk.type == TYPE_FD)
309201342Snyan	return (WHOLE_DISK_SLICE);
310254015Smarcel    if (drvread(sec, PC98_BBSECTOR))
311201342Snyan	return (WHOLE_DISK_SLICE);	/* Read error */
312254015Smarcel    dp = (void *)(sec + PC98_PARTOFF);
313254015Smarcel    for (i = 0; i < PC98_NPARTS; i++) {
314201342Snyan	if (dp[i].dp_mid == DOSMID_386BSD) {
315201342Snyan	    if (dp[i].dp_scyl <= cyl && cyl <= dp[i].dp_ecyl)
316201342Snyan		return (BASE_SLICE + i);
317201342Snyan	}
318201342Snyan    }
319201342Snyan
320201342Snyan    return (WHOLE_DISK_SLICE);
321201342Snyan}
322201342Snyan
323201342Snyanint
324201342Snyanmain(void)
325201342Snyan{
326201342Snyan#ifdef GET_BIOSGEOM
327333049Snyan	int i;
328201342Snyan#endif
329333049Snyan	uint8_t autoboot;
330333049Snyan	ufs_ino_t ino;
331333049Snyan	size_t nbyte;
332201342Snyan
333333049Snyan	dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base);
334333049Snyan	v86.ctl = V86_FLAGS;
335333049Snyan	v86.efl = PSL_RESERVED_DEFAULT | PSL_I;
336333049Snyan	dsk.daua = *(uint8_t *)PTOV(0x584);
337333049Snyan	dsk.disk = dsk.daua & DRV_DISK;
338333049Snyan	dsk.unit = dsk.daua & DRV_UNIT;
339333049Snyan	if (dsk.disk == 0x80)
340333049Snyan		dsk.type = TYPE_AD;
341333049Snyan	else if (dsk.disk == 0xa0)
342333049Snyan		dsk.type = TYPE_DA;
343333049Snyan	else /* if (dsk.disk == 0x30 || dsk.disk == 0x90) */
344333049Snyan		dsk.type = TYPE_FD;
345333049Snyan	dsk.slice = check_slice();
346201342Snyan#ifdef GET_BIOSGEOM
347333049Snyan	for (i = 0; i < N_BIOS_GEOM; i++)
348333049Snyan		bootinfo.bi_bios_geom[i] = bd_getbigeom(i);
349201342Snyan#endif
350333049Snyan	bootinfo.bi_version = BOOTINFO_VERSION;
351333049Snyan	bootinfo.bi_size = sizeof(bootinfo);
352201342Snyan
353333049Snyan	/* Process configuration file */
354201342Snyan
355333049Snyan	autoboot = 1;
356201342Snyan
357333049Snyan	if ((ino = lookup(PATH_CONFIG)) ||
358333049Snyan	    (ino = lookup(PATH_DOTCONFIG))) {
359333049Snyan		nbyte = fsread(ino, cmd, sizeof(cmd) - 1);
360333049Snyan		cmd[nbyte] = '\0';
361333049Snyan	}
362201342Snyan
363333049Snyan	if (*cmd) {
364333049Snyan		memcpy(cmddup, cmd, sizeof(cmd));
365333049Snyan		if (parse())
366333049Snyan			autoboot = 0;
367333049Snyan		if (!OPT_CHECK(RBX_QUIET))
368333049Snyan			printf("%s: %s", PATH_CONFIG, cmddup);
369333049Snyan		/* Do not process this command twice */
370333049Snyan		*cmd = 0;
371333049Snyan	}
372201342Snyan
373333049Snyan	/*
374333049Snyan	 * Try to exec stage 3 boot loader. If interrupted by a keypress,
375333049Snyan	 * or in case of failure, try to load a kernel directly instead.
376333049Snyan	 */
377201342Snyan
378333049Snyan	if (!kname) {
379333049Snyan		kname = PATH_LOADER;
380333049Snyan		if (autoboot && !keyhit(3*SECOND)) {
381333049Snyan			load();
382333049Snyan			kname = PATH_KERNEL;
383333049Snyan		}
384201342Snyan	}
385201342Snyan
386333049Snyan	/* Present the user with the boot2 prompt. */
387201342Snyan
388333049Snyan	for (;;) {
389333049Snyan		if (!autoboot || !OPT_CHECK(RBX_QUIET))
390333049Snyan			printf("\nFreeBSD/pc98 boot\n"
391333049Snyan				 "Default: %u:%s(%u,%c)%s\n"
392333049Snyan				 "boot: ",
393333049Snyan			    dsk.unit, dev_nm[dsk.type], dsk.unit,
394333049Snyan			    'a' + dsk.part, kname);
395333049Snyan		if (DO_SIO)
396333049Snyan			sio_flush();
397333049Snyan		if (!autoboot || keyhit(3*SECOND))
398333049Snyan			getstr();
399333049Snyan		else if (!autoboot || !OPT_CHECK(RBX_QUIET))
400333049Snyan			putchar('\n');
401333049Snyan		autoboot = 0;
402333049Snyan		if (parse())
403333049Snyan			putchar('\a');
404333049Snyan		else
405333049Snyan			load();
406333049Snyan	}
407201342Snyan}
408201342Snyan
409201342Snyan/* XXX - Needed for btxld to link the boot2 binary; do not remove. */
410201342Snyanvoid
411201342Snyanexit(int x)
412201342Snyan{
413333049Snyan
414201342Snyan}
415201342Snyan
416201342Snyanstatic void
417201342Snyanload(void)
418201342Snyan{
419333049Snyan	union {
420333049Snyan		struct exec ex;
421333049Snyan		Elf32_Ehdr eh;
422333049Snyan	} hdr;
423333049Snyan	static Elf32_Phdr ep[2];
424333049Snyan	static Elf32_Shdr es[2];
425333049Snyan	caddr_t p;
426333049Snyan	ufs_ino_t ino;
427333049Snyan	uint32_t addr;
428333049Snyan	int k;
429333049Snyan	uint8_t i, j;
430201342Snyan
431333049Snyan	if (!(ino = lookup(kname))) {
432333049Snyan		if (!ls)
433333049Snyan			printf("No %s\n", kname);
434201342Snyan		return;
435201342Snyan	}
436333049Snyan	if (xfsread(ino, &hdr, sizeof(hdr)))
437201342Snyan		return;
438333049Snyan
439333049Snyan	if (N_GETMAGIC(hdr.ex) == ZMAGIC) {
440333049Snyan		addr = hdr.ex.a_entry & 0xffffff;
441333049Snyan		p = PTOV(addr);
442333049Snyan		fs_off = PAGE_SIZE;
443333049Snyan		if (xfsread(ino, p, hdr.ex.a_text))
444333049Snyan			return;
445333049Snyan		p += roundup2(hdr.ex.a_text, PAGE_SIZE);
446333049Snyan		if (xfsread(ino, p, hdr.ex.a_data))
447333049Snyan			return;
448333049Snyan	} else if (IS_ELF(hdr.eh)) {
449333049Snyan		fs_off = hdr.eh.e_phoff;
450333049Snyan		for (j = k = 0; k < hdr.eh.e_phnum && j < 2; k++) {
451333049Snyan			if (xfsread(ino, ep + j, sizeof(ep[0])))
452333049Snyan				return;
453333049Snyan			if (ep[j].p_type == PT_LOAD)
454333049Snyan				j++;
455333049Snyan		}
456333049Snyan		for (i = 0; i < 2; i++) {
457333049Snyan			p = PTOV(ep[i].p_paddr & 0xffffff);
458333049Snyan			fs_off = ep[i].p_offset;
459333049Snyan			if (xfsread(ino, p, ep[i].p_filesz))
460333049Snyan				return;
461333049Snyan		}
462333049Snyan		p += roundup2(ep[1].p_memsz, PAGE_SIZE);
463333049Snyan		bootinfo.bi_symtab = VTOP(p);
464333049Snyan		if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) {
465333049Snyan			fs_off = hdr.eh.e_shoff + sizeof(es[0]) *
466333049Snyan			    (hdr.eh.e_shstrndx + 1);
467333049Snyan			if (xfsread(ino, &es, sizeof(es)))
468333049Snyan				return;
469333049Snyan			for (i = 0; i < 2; i++) {
470333049Snyan				*(Elf32_Word *)p = es[i].sh_size;
471333049Snyan				p += sizeof(es[i].sh_size);
472333049Snyan				fs_off = es[i].sh_offset;
473333049Snyan				if (xfsread(ino, p, es[i].sh_size))
474333049Snyan					return;
475333049Snyan				p += es[i].sh_size;
476333049Snyan			}
477333049Snyan		}
478333049Snyan		addr = hdr.eh.e_entry & 0xffffff;
479333049Snyan		bootinfo.bi_esymtab = VTOP(p);
480333049Snyan	} else {
481333049Snyan		printf("Invalid %s\n", "format");
482201342Snyan		return;
483201342Snyan	}
484219960Snyan
485333049Snyan	bootinfo.bi_kernelname = VTOP(kname);
486333049Snyan	bootinfo.bi_bios_dev = dsk.daua;
487333049Snyan	__exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK),
488333049Snyan	    MAKEBOOTDEV(dev_maj[dsk.type], dsk.slice, dsk.unit, dsk.part),
489333049Snyan	    0, 0, 0, VTOP(&bootinfo));
490201342Snyan}
491201342Snyan
492201342Snyanstatic int
493201342Snyanparse()
494201342Snyan{
495333049Snyan	char *arg = cmd;
496333049Snyan	char *ep, *p, *q;
497333049Snyan	const char *cp;
498333049Snyan	unsigned int drv;
499333049Snyan	int c, i, j;
500333049Snyan	size_t k;
501201342Snyan
502333049Snyan	while ((c = *arg++)) {
503333049Snyan		if (c == ' ' || c == '\t' || c == '\n')
504333049Snyan			continue;
505333049Snyan		for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++);
506333049Snyan		ep = p;
507333049Snyan		if (*p)
508333049Snyan			*p++ = 0;
509333049Snyan		if (c == '-') {
510333049Snyan			while ((c = *arg++)) {
511333049Snyan				if (c == 'P') {
512333049Snyan					if (*(uint8_t *)PTOV(0x481) & 0x48) {
513333049Snyan						cp = "yes";
514333049Snyan					} else {
515333049Snyan						opts |= OPT_SET(RBX_DUAL) |
516333049Snyan						    OPT_SET(RBX_SERIAL);
517333049Snyan						cp = "no";
518333049Snyan					}
519333049Snyan					printf("Keyboard: %s\n", cp);
520333049Snyan					continue;
521268475Simp#if SERIAL
522333049Snyan				} else if (c == 'S') {
523333049Snyan					j = 0;
524333049Snyan					while ((unsigned int)(i = *arg++ - '0') <= 9)
525333049Snyan						j = j * 10 + i;
526333049Snyan					if (j > 0 && i == -'0') {
527333049Snyan						comspeed = j;
528333049Snyan						break;
529333049Snyan					}
530333049Snyan					/*
531333049Snyan					 * Fall through to error below
532333049Snyan					 * ('S' not in optstr[]).
533333049Snyan					 */
534268475Simp#endif
535333049Snyan				}
536333049Snyan				for (i = 0; c != optstr[i]; i++)
537333049Snyan					if (i == NOPT - 1)
538333049Snyan						return (-1);
539333049Snyan				opts ^= OPT_SET(flags[i]);
540333049Snyan			}
541268475Simp#if SERIAL
542333049Snyan			ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) :
543333049Snyan			    OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD;
544333049Snyan			if (DO_SIO) {
545333049Snyan				if (sio_init(115200 / comspeed) != 0)
546333049Snyan					ioctrl &= ~IO_SERIAL;
547333049Snyan			}
548268475Simp#endif
549333049Snyan		} else {
550333049Snyan			for (q = arg--; *q && *q != '('; q++);
551333049Snyan			if (*q) {
552333049Snyan				drv = -1;
553333049Snyan				if (arg[1] == ':') {
554333049Snyan					drv = *arg - '0';
555333049Snyan					if (drv > 9)
556333049Snyan						return (-1);
557333049Snyan					arg += 2;
558333049Snyan				}
559333049Snyan				if (q - arg != 2)
560333049Snyan					return (-1);
561333049Snyan				for (i = 0; arg[0] != dev_nm[i][0] ||
562333049Snyan				    arg[1] != dev_nm[i][1]; i++)
563333049Snyan					if (i == NDEV - 1)
564333049Snyan						return (-1);
565333049Snyan				dsk.type = i;
566333049Snyan				arg += 3;
567333049Snyan				dsk.unit = *arg - '0';
568333049Snyan				if (arg[1] != ',' || dsk.unit > 9)
569333049Snyan					return (-1);
570333049Snyan				arg += 2;
571333049Snyan				dsk.slice = WHOLE_DISK_SLICE;
572333049Snyan				if (arg[1] == ',') {
573333049Snyan					dsk.slice = *arg - '0' + 1;
574333049Snyan					if (dsk.slice > PC98_NPARTS + 1)
575333049Snyan						return (-1);
576333049Snyan					arg += 2;
577333049Snyan				}
578333049Snyan				if (arg[1] != ')')
579333049Snyan					return (-1);
580333049Snyan				dsk.part = *arg - 'a';
581333049Snyan				if (dsk.part > 7)
582333049Snyan					return (-1);
583333049Snyan				arg += 2;
584333049Snyan				if (drv == -1)
585333049Snyan					drv = dsk.unit;
586333049Snyan				dsk.disk = dev_daua[dsk.type];
587333049Snyan				dsk.daua = dsk.disk | dsk.unit;
588333049Snyan				dsk_meta = 0;
589333049Snyan			}
590333049Snyan			k = ep - arg;
591333049Snyan			if (k > 0) {
592333049Snyan				if (k >= sizeof(knamebuf))
593333049Snyan					return (-1);
594333049Snyan				memcpy(knamebuf, arg, k + 1);
595333049Snyan				kname = knamebuf;
596333049Snyan			}
597201342Snyan		}
598333049Snyan		arg = p;
599201342Snyan	}
600333049Snyan	return (0);
601201342Snyan}
602201342Snyan
603201342Snyanstatic int
604201342Snyandskread(void *buf, unsigned lba, unsigned nblk)
605201342Snyan{
606333049Snyan	struct pc98_partition *dp;
607333049Snyan	struct disklabel *d;
608333049Snyan	char *sec;
609333049Snyan	unsigned i;
610333049Snyan	uint8_t sl;
611333049Snyan	u_char *p;
612333049Snyan	const char *reason;
613201342Snyan
614333049Snyan	if (!dsk_meta) {
615333049Snyan		sec = dmadat->secbuf;
616333049Snyan		set_dsk();
617333049Snyan		if (dsk.type == TYPE_FD)
618333049Snyan			goto unsliced;
619333049Snyan		if (drvread(sec, PC98_BBSECTOR))
620333049Snyan			return -1;
621333049Snyan		dp = (void *)(sec + PC98_PARTOFF);
622333049Snyan		sl = dsk.slice;
623333049Snyan		if (sl < BASE_SLICE) {
624333049Snyan			for (i = 0; i < PC98_NPARTS; i++)
625333049Snyan				if (dp[i].dp_mid == DOSMID_386BSD) {
626333049Snyan					sl = BASE_SLICE + i;
627333049Snyan					break;
628333049Snyan				}
629333049Snyan			dsk.slice = sl;
630201342Snyan		}
631333049Snyan		if (sl != WHOLE_DISK_SLICE) {
632333049Snyan			dp += sl - BASE_SLICE;
633333049Snyan			if (dp->dp_mid != DOSMID_386BSD) {
634333049Snyan				reason = "slice";
635333049Snyan				goto error;
636333049Snyan			}
637333049Snyan			dsk.start = dp->dp_scyl * dsk.head * dsk.sec +
638333049Snyan				dp->dp_shd * dsk.sec + dp->dp_ssect;
639333049Snyan		}
640333049Snyan		if (drvread(sec, dsk.start + LABELSECTOR))
641333049Snyan			return -1;
642333049Snyan		d = (void *)(sec + LABELOFFSET);
643333049Snyan		if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) {
644333049Snyan			if (dsk.part != RAW_PART) {
645333049Snyan				reason = "label";
646333049Snyan				goto error;
647333049Snyan			}
648333049Snyan		} else {
649333049Snyan			if (dsk.part >= d->d_npartitions ||
650333049Snyan			    !d->d_partitions[dsk.part].p_size) {
651333049Snyan				reason = "partition";
652333049Snyan				goto error;
653333049Snyan			}
654333049Snyan			dsk.start += d->d_partitions[dsk.part].p_offset;
655333049Snyan			dsk.start -= d->d_partitions[RAW_PART].p_offset;
656333049Snyan		}
657333049Snyan	unsliced: ;
658201342Snyan	}
659333049Snyan	for (p = buf; nblk; p += 512, lba++, nblk--) {
660333049Snyan		if ((i = drvread(p, dsk.start + lba)))
661333049Snyan			return (i);
662201342Snyan	}
663333049Snyan	return (0);
664275239Snyanerror:
665333049Snyan	printf("Invalid %s\n", reason);
666333049Snyan	return (-1);
667201342Snyan}
668201342Snyan
669201342Snyanstatic void
670201342Snyanprintf(const char *fmt,...)
671201342Snyan{
672333049Snyan	va_list ap;
673333049Snyan	static char buf[10];
674333049Snyan	char *s;
675333049Snyan	unsigned u;
676333049Snyan	int c;
677201342Snyan
678333049Snyan	va_start(ap, fmt);
679333049Snyan	while ((c = *fmt++)) {
680333049Snyan		if (c == '%') {
681333049Snyan			c = *fmt++;
682333049Snyan			switch (c) {
683333049Snyan			case 'c':
684333049Snyan				putchar(va_arg(ap, int));
685333049Snyan				continue;
686333049Snyan			case 's':
687333049Snyan				for (s = va_arg(ap, char *); *s; s++)
688333049Snyan					putchar(*s);
689333049Snyan				continue;
690333049Snyan			case 'u':
691333049Snyan				u = va_arg(ap, unsigned);
692333049Snyan				s = buf;
693333049Snyan				do
694333049Snyan					*s++ = '0' + u % 10U;
695333049Snyan				while (u /= 10U);
696333049Snyan				while (--s >= buf)
697333049Snyan					putchar(*s);
698333049Snyan				continue;
699333049Snyan			}
700333049Snyan		}
701333049Snyan		putchar(c);
702201342Snyan	}
703333049Snyan	va_end(ap);
704333049Snyan	return;
705201342Snyan}
706201342Snyan
707201342Snyanstatic void
708201342Snyanputchar(int c)
709201342Snyan{
710333049Snyan
711333049Snyan	if (c == '\n')
712333049Snyan		xputc('\r');
713333049Snyan	xputc(c);
714201342Snyan}
715201342Snyan
716201342Snyanstatic int
717201342Snyandrvread(void *buf, unsigned lba)
718201342Snyan{
719333049Snyan	static unsigned c = 0x2d5c7c2f;
720333049Snyan	unsigned bpc, x, cyl, head, sec;
721201342Snyan
722333049Snyan	bpc = dsk.sec * dsk.head;
723333049Snyan	cyl = lba / bpc;
724333049Snyan	x = lba % bpc;
725333049Snyan	head = x / dsk.sec;
726333049Snyan	sec = x % dsk.sec;
727333049Snyan
728333049Snyan	if (!OPT_CHECK(RBX_QUIET)) {
729333049Snyan		xputc(c = c << 8 | c >> 24);
730333049Snyan		xputc('\b');
731333049Snyan	}
732333049Snyan	v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS;
733333049Snyan	v86.addr = READORG;		/* call to read in boot1 */
734333049Snyan	v86.ecx = cyl;
735333049Snyan	v86.edx = (head << 8) | sec;
736333049Snyan	v86.edi = lba;
737333049Snyan	v86.ebx = 512;
738333049Snyan	v86.es = VTOPSEG(buf);
739333049Snyan	v86.ebp = VTOPOFF(buf);
740333049Snyan	v86int();
741333049Snyan	v86.ctl = V86_FLAGS;
742333049Snyan	if (V86_CY(v86.efl)) {
743333049Snyan		printf("error %u c/h/s %u/%u/%u lba %u\n", v86.eax >> 8 & 0xff,
744333049Snyan		    cyl, head, sec, lba);
745333049Snyan		return (-1);
746333049Snyan	}
747333049Snyan	return (0);
748201342Snyan}
749201342Snyan
750201342Snyanstatic inline void
751201342Snyandelay(void)
752201342Snyan{
753333049Snyan	int i;
754201342Snyan
755333049Snyan	i = 800;
756333049Snyan	do {
757333049Snyan		outb(0x5f, 0);	/* about 600ns */
758333049Snyan	} while (--i >= 0);
759201342Snyan}
760201342Snyan
761201342Snyanstatic int
762201342Snyankeyhit(unsigned sec)
763201342Snyan{
764333049Snyan	unsigned i;
765201342Snyan
766333049Snyan	if (OPT_CHECK(RBX_NOINTR))
767333049Snyan		return (0);
768333049Snyan	for (i = 0; i < sec * 1000; i++) {
769333049Snyan		if (xgetc(1))
770333049Snyan			return (1);
771333049Snyan		delay();
772333049Snyan	}
773333049Snyan	return (0);
774201342Snyan}
775201342Snyan
776201342Snyanstatic int
777201342Snyanxputc(int c)
778201342Snyan{
779333049Snyan
780333049Snyan	if (DO_KBD)
781333049Snyan		putc(c);
782333049Snyan	if (DO_SIO)
783333049Snyan		sio_putc(c);
784333049Snyan	return (c);
785201342Snyan}
786201342Snyan
787201342Snyanstatic int
788220685Snyangetc(int fn)
789220685Snyan{
790333049Snyan
791333049Snyan	v86.addr = 0x18;
792333049Snyan	v86.eax = fn << 8;
793333049Snyan	v86int();
794333049Snyan	if (fn)
795333049Snyan		return ((v86.ebx >> 8) & 0x01);
796333049Snyan	else
797333049Snyan		return (v86.eax & 0xff);
798220685Snyan}
799220685Snyan
800220685Snyanstatic int
801201342Snyanxgetc(int fn)
802201342Snyan{
803333049Snyan
804333049Snyan	if (OPT_CHECK(RBX_NOINTR))
805333049Snyan		return (0);
806333049Snyan	for (;;) {
807333049Snyan		if (DO_KBD && getc(1))
808333049Snyan			return (fn ? 1 : getc(0));
809333049Snyan		if (DO_SIO && sio_ischar())
810333049Snyan			return (fn ? 1 : sio_getc());
811333049Snyan		if (fn)
812333049Snyan			return (0);
813333049Snyan	}
814201342Snyan}
815