gptboot.c revision 107889
122514Sdarrenr/*
222514Sdarrenr * Copyright (c) 1998 Robert Nordier
322514Sdarrenr * All rights reserved.
422514Sdarrenr *
522514Sdarrenr * Redistribution and use in source and binary forms are freely
622514Sdarrenr * permitted provided that the above copyright notice and this
722514Sdarrenr * paragraph and the following disclaimer are duplicated in all
822514Sdarrenr * such forms.
922514Sdarrenr *
1022514Sdarrenr * This software is provided "AS IS" and without any express or
1122514Sdarrenr * implied warranties, including, without limitation, the implied
1222514Sdarrenr * warranties of merchantability and fitness for a particular
1322514Sdarrenr * purpose.
1422514Sdarrenr */
1522514Sdarrenr
1622514Sdarrenr/*
1722514Sdarrenr * $FreeBSD: head/sys/boot/i386/gptboot/gptboot.c 107889 2002-12-15 02:15:19Z obrien $
1822514Sdarrenr */
1922514Sdarrenr
2022514Sdarrenr#include <sys/param.h>
2122514Sdarrenr#include <sys/reboot.h>
2222514Sdarrenr#include <sys/diskslice.h>
2322514Sdarrenr#include <sys/disklabel.h>
2422514Sdarrenr#include <sys/diskmbr.h>
2522514Sdarrenr#include <sys/dirent.h>
2622514Sdarrenr#include <machine/bootinfo.h>
2722514Sdarrenr#include <machine/elf.h>
2822514Sdarrenr
2922514Sdarrenr#include <stdarg.h>
3022514Sdarrenr
3122514Sdarrenr#include <a.out.h>
3222514Sdarrenr
3322514Sdarrenr#include <btxv86.h>
3422514Sdarrenr
3522514Sdarrenr#include "boot2.h"
3622514Sdarrenr#include "lib.h"
3722514Sdarrenr
3822514Sdarrenr#define IO_KEYBOARD	1
3922514Sdarrenr#define IO_SERIAL	2
4022514Sdarrenr
4122514Sdarrenr#define SECOND		18	/* Circa that many ticks in a second. */
4222514Sdarrenr
4322514Sdarrenr#define RBX_ASKNAME	0x0	/* -a */
4422514Sdarrenr#define RBX_SINGLE	0x1	/* -s */
4522514Sdarrenr#define RBX_DFLTROOT	0x5	/* -r */
4622514Sdarrenr#define RBX_KDB 	0x6	/* -d */
4722514Sdarrenr#define RBX_CONFIG	0xa	/* -c */
4822514Sdarrenr#define RBX_VERBOSE	0xb	/* -v */
4922514Sdarrenr#define RBX_SERIAL	0xc	/* -h */
5022514Sdarrenr#define RBX_CDROM	0xd	/* -C */
5122514Sdarrenr#define RBX_GDB 	0xf	/* -g */
5222514Sdarrenr#define RBX_MUTE	0x10	/* -m */
5322514Sdarrenr#define RBX_PAUSE	0x12	/* -p */
5422514Sdarrenr#define RBX_DUAL	0x1d	/* -D */
5522514Sdarrenr#define RBX_PROBEKBD	0x1e	/* -P */
5622514Sdarrenr#define RBX_NOINTR	0x1f	/* -n */
5722514Sdarrenr
5822514Sdarrenr#define RBX_MASK	0x2005ffff
5922514Sdarrenr
6022514Sdarrenr#define PATH_CONFIG	"/boot.config"
6122514Sdarrenr#define PATH_BOOT3	"/boot/loader"
6222514Sdarrenr#define PATH_KERNEL	"/kernel"
6322514Sdarrenr
6422514Sdarrenr#define ARGS		0x900
6522514Sdarrenr#define NOPT		14
6622514Sdarrenr#define NDEV		5
6722514Sdarrenr#define MEM_BASE	0x12
6822514Sdarrenr#define MEM_EXT 	0x15
6922514Sdarrenr#define V86_CY(x)	((x) & 1)
7022514Sdarrenr#define V86_ZR(x)	((x) & 0x40)
7122514Sdarrenr
7222514Sdarrenr#define DRV_HARD	0x80
7322514Sdarrenr#define DRV_MASK	0x7f
7422514Sdarrenr
7522514Sdarrenr#define TYPE_AD		0
7622514Sdarrenr#define TYPE_DA		2
7722514Sdarrenr#define TYPE_MAXHARD	TYPE_DA
7822514Sdarrenr#define TYPE_FD		4
7922514Sdarrenr
8022514Sdarrenrextern uint32_t _end;
8122514Sdarrenr
8222514Sdarrenrstatic const char optstr[NOPT] = "DhaCcdgmnPprsv";
8322514Sdarrenrstatic const unsigned char flags[NOPT] = {
8422514Sdarrenr    RBX_DUAL,
8522514Sdarrenr    RBX_SERIAL,
8622514Sdarrenr    RBX_ASKNAME,
8722514Sdarrenr    RBX_CDROM,
8822514Sdarrenr    RBX_CONFIG,
8922514Sdarrenr    RBX_KDB,
9022514Sdarrenr    RBX_GDB,
9122514Sdarrenr    RBX_MUTE,
9222514Sdarrenr    RBX_NOINTR,
9322514Sdarrenr    RBX_PROBEKBD,
9422514Sdarrenr    RBX_PAUSE,
9522514Sdarrenr    RBX_DFLTROOT,
9622514Sdarrenr    RBX_SINGLE,
9722514Sdarrenr    RBX_VERBOSE
9822514Sdarrenr};
9922514Sdarrenr
10022514Sdarrenrstatic const char *const dev_nm[NDEV] = {"ad", "wd", "da", "  ", "fd"};
10122514Sdarrenrstatic const unsigned char dev_maj[NDEV] = {30, 0, 4, 1, 2};
10222514Sdarrenr
10322514Sdarrenrstatic struct dsk {
10422514Sdarrenr    unsigned drive;
10522514Sdarrenr    unsigned type;
10622514Sdarrenr    unsigned unit;
10722514Sdarrenr    unsigned slice;
10822514Sdarrenr    unsigned part;
10922514Sdarrenr    unsigned start;
11022514Sdarrenr    int init;
11122514Sdarrenr} dsk;
112static char cmd[512];
113static char kname[1024];
114static uint32_t opts = RB_BOOTINFO;
115static struct bootinfo bootinfo;
116static uint8_t ioctrl = IO_KEYBOARD;
117
118void exit(int);
119static void load(const char *);
120static int parse(char *);
121static int xfsread(ino_t, void *, size_t);
122static int dskread(void *, unsigned, unsigned);
123static void printf(const char *,...);
124static void putchar(int);
125static uint32_t memsize(int);
126static int drvread(void *, unsigned, unsigned);
127static int keyhit(unsigned);
128static int xputc(int);
129static int xgetc(int);
130static int getc(int);
131
132#define memcpy __builtin_memcpy
133
134static inline int
135strcmp(const char *s1, const char *s2)
136{
137    for (; *s1 == *s2 && *s1; s1++, s2++);
138    return *s1 - *s2;
139}
140
141#include "ufsread.c"
142
143static int
144xfsread(ino_t inode, void *buf, size_t nbyte)
145{
146    if ((size_t)fsread(inode, buf, nbyte) != nbyte) {
147	printf("Invalid %s\n", "format");
148	return -1;
149    }
150    return 0;
151}
152
153static inline void
154getstr(char *str, int size)
155{
156    char *s;
157    int c;
158
159    s = str;
160    for (;;) {
161	switch (c = xgetc(0)) {
162	case 0:
163	    break;
164	case '\177':
165	    c = '\b';
166	case '\b':
167	    if (s > str) {
168		s--;
169		putchar('\b');
170		putchar(' ');
171	    } else
172		c = 0;
173	    break;
174	case '\n':
175	case '\r':
176	    *s = 0;
177	    return;
178	default:
179	    if (s - str < size - 1)
180		*s++ = c;
181	}
182	if (c)
183	    putchar(c);
184    }
185}
186
187static inline void
188putc(int c)
189{
190    v86.addr = 0x10;
191    v86.eax = 0xe00 | (c & 0xff);
192    v86.ebx = 0x7;
193    v86int();
194}
195
196int
197main(void)
198{
199    int autoboot;
200    ino_t ino;
201
202    dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base);
203    v86.ctl = V86_FLAGS;
204    dsk.drive = *(uint8_t *)PTOV(ARGS);
205    dsk.type = dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD;
206    dsk.unit = dsk.drive & DRV_MASK;
207    dsk.slice = *(uint8_t *)PTOV(ARGS + 1) + 1;
208    bootinfo.bi_version = BOOTINFO_VERSION;
209    bootinfo.bi_size = sizeof(bootinfo);
210    bootinfo.bi_basemem = 0;	/* XXX will be filled by loader or kernel */
211    bootinfo.bi_extmem = memsize(MEM_EXT);
212    bootinfo.bi_memsizes_valid++;
213
214    /* Process configuration file */
215
216    autoboot = 1;
217
218    if ((ino = lookup(PATH_CONFIG)))
219	fsread(ino, cmd, sizeof(cmd));
220
221    if (*cmd) {
222	printf("%s: %s", PATH_CONFIG, cmd);
223	if (parse(cmd))
224	    autoboot = 0;
225	/* Do not process this command twice */
226	*cmd = 0;
227    }
228
229    /*
230     * Try to exec stage 3 boot loader. If interrupted by a keypress,
231     * or in case of failure, try to load a kernel directly instead.
232     */
233
234    if (autoboot && !*kname) {
235	memcpy(kname, PATH_BOOT3, sizeof(PATH_BOOT3));
236	if (!keyhit(3*SECOND)) {
237	    load(kname);
238	    memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL));
239	}
240    }
241
242    /* Present the user with the boot2 prompt. */
243
244    for (;;) {
245#ifdef UFS1_ONLY
246	printf(" \n>> FreeBSD/i386/UFS1 BOOT\n"
247#else
248	printf(" \n>> FreeBSD/i386/UFS[12] BOOT\n"
249#endif
250	       "Default: %u:%s(%u,%c)%s\n"
251	       "boot: ",
252	       dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit,
253	       'a' + dsk.part, kname);
254	if (ioctrl & IO_SERIAL)
255	    sio_flush();
256	if (!autoboot || keyhit(5*SECOND))
257	    getstr(cmd, sizeof(cmd));
258	else
259	    putchar('\n');
260	autoboot = 0;
261	if (parse(cmd))
262	    putchar('\a');
263	else
264	    load(kname);
265    }
266}
267
268/* XXX - Needed for btxld to link the boot2 binary; do not remove. */
269void
270exit(int x)
271{
272}
273
274static void
275load(const char *fname)
276{
277    union {
278	struct exec ex;
279	Elf32_Ehdr eh;
280    } hdr;
281    Elf32_Phdr ep[2];
282    Elf32_Shdr es[2];
283    caddr_t p;
284    ino_t ino;
285    uint32_t addr, x;
286    int fmt, i, j;
287
288    if (!(ino = lookup(fname))) {
289	if (!ls)
290	    printf("No %s\n", fname);
291	return;
292    }
293    if (xfsread(ino, &hdr, sizeof(hdr)))
294	return;
295    if (N_GETMAGIC(hdr.ex) == ZMAGIC)
296	fmt = 0;
297    else if (IS_ELF(hdr.eh))
298	fmt = 1;
299    else {
300	printf("Invalid %s\n", "format");
301	return;
302    }
303    if (fmt == 0) {
304	addr = hdr.ex.a_entry & 0xffffff;
305	p = PTOV(addr);
306	fs_off = PAGE_SIZE;
307	if (xfsread(ino, p, hdr.ex.a_text))
308	    return;
309	p += roundup2(hdr.ex.a_text, PAGE_SIZE);
310	if (xfsread(ino, p, hdr.ex.a_data))
311	    return;
312	p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE);
313	bootinfo.bi_symtab = VTOP(p);
314	memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms));
315	p += sizeof(hdr.ex.a_syms);
316	if (hdr.ex.a_syms) {
317	    if (xfsread(ino, p, hdr.ex.a_syms))
318		return;
319	    p += hdr.ex.a_syms;
320	    if (xfsread(ino, p, sizeof(int)))
321		return;
322	    x = *(uint32_t *)p;
323	    p += sizeof(int);
324	    x -= sizeof(int);
325	    if (xfsread(ino, p, x))
326		return;
327	    p += x;
328	}
329    } else {
330	fs_off = hdr.eh.e_phoff;
331	for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) {
332	    if (xfsread(ino, ep + j, sizeof(ep[0])))
333		return;
334	    if (ep[j].p_type == PT_LOAD)
335		j++;
336	}
337	for (i = 0; i < 2; i++) {
338	    p = PTOV(ep[i].p_paddr & 0xffffff);
339	    fs_off = ep[i].p_offset;
340	    if (xfsread(ino, p, ep[i].p_filesz))
341		return;
342	}
343	p += roundup2(ep[1].p_memsz, PAGE_SIZE);
344	bootinfo.bi_symtab = VTOP(p);
345	if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) {
346	    fs_off = hdr.eh.e_shoff + sizeof(es[0]) *
347		(hdr.eh.e_shstrndx + 1);
348	    if (xfsread(ino, &es, sizeof(es)))
349		return;
350	    for (i = 0; i < 2; i++) {
351		memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size));
352		p += sizeof(es[i].sh_size);
353		fs_off = es[i].sh_offset;
354		if (xfsread(ino, p, es[i].sh_size))
355		    return;
356		p += es[i].sh_size;
357	    }
358	}
359	addr = hdr.eh.e_entry & 0xffffff;
360    }
361    bootinfo.bi_esymtab = VTOP(p);
362    bootinfo.bi_kernelname = VTOP(fname);
363    bootinfo.bi_bios_dev = dsk.drive;
364    __exec((caddr_t)addr, opts & RBX_MASK,
365	   MAKEBOOTDEV(dev_maj[dsk.type], 0, dsk.slice, dsk.unit, dsk.part),
366	   0, 0, 0, VTOP(&bootinfo));
367}
368
369static int
370parse(char *arg)
371{
372    char *p, *q;
373    int drv, c, i;
374
375    while ((c = *arg++)) {
376	if (c == ' ' || c == '\t' || c == '\n')
377	    continue;
378	for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++);
379	if (*p)
380	    *p++ = 0;
381	if (c == '-') {
382	    while ((c = *arg++)) {
383		for (i = 0; c != optstr[i]; i++)
384		    if (i == NOPT - 1)
385			return -1;
386		opts ^= 1 << flags[i];
387	    }
388	    if (opts & 1 << RBX_PROBEKBD) {
389		i = *(uint8_t *)PTOV(0x496) & 0x10;
390		/* printf("Keyboard: %s\n", i ? "yes" : "no"); */
391		if (!i)
392		    opts |= 1 << RBX_DUAL | 1 << RBX_SERIAL;
393		opts &= ~(1 << RBX_PROBEKBD);
394	    }
395	    ioctrl = opts & 1 << RBX_DUAL ? (IO_SERIAL|IO_KEYBOARD) :
396		     opts & 1 << RBX_SERIAL ? IO_SERIAL : IO_KEYBOARD;
397	    if (ioctrl & IO_SERIAL)
398	        sio_init();
399	} else {
400	    for (q = arg--; *q && *q != '('; q++);
401	    if (*q) {
402		drv = -1;
403		if (arg[1] == ':') {
404		    if (*arg < '0' || *arg > '9')
405			return -1;
406		    drv = *arg - '0';
407		    arg += 2;
408		}
409		if (q - arg != 2)
410		    return -1;
411		for (i = 0; arg[0] != dev_nm[i][0] ||
412			    arg[1] != dev_nm[i][1]; i++)
413		    if (i == NDEV - 1)
414			return -1;
415		dsk.type = i;
416		arg += 3;
417		if (arg[1] != ',' || *arg < '0' || *arg > '9')
418		    return -1;
419		dsk.unit = *arg - '0';
420		arg += 2;
421		dsk.slice = WHOLE_DISK_SLICE;
422		if (arg[1] == ',') {
423		    if (*arg < '0' || *arg > '0' + NDOSPART)
424			return -1;
425		    if ((dsk.slice = *arg - '0'))
426			dsk.slice++;
427		    arg += 2;
428		}
429		if (arg[1] != ')' || *arg < 'a' || *arg > 'p')
430		    return -1;
431		dsk.part = *arg - 'a';
432		arg += 2;
433		if (drv == -1)
434		    drv = dsk.unit;
435		dsk.drive = (dsk.type <= TYPE_MAXHARD
436			     ? DRV_HARD : 0) + drv;
437		dsk_meta = 0;
438	    }
439	    if ((i = p - arg - !*(p - 1))) {
440		if ((size_t)i >= sizeof(kname))
441		    return -1;
442		memcpy(kname, arg, i + 1);
443	    }
444	}
445	arg = p;
446    }
447    return 0;
448}
449
450static int
451dskread(void *buf, unsigned lba, unsigned nblk)
452{
453    struct dos_partition *dp;
454    struct disklabel *d;
455    char *sec;
456    unsigned sl, i;
457
458    if (!dsk_meta) {
459	sec = dmadat->secbuf;
460	dsk.start = 0;
461	if (drvread(sec, DOSBBSECTOR, 1))
462	    return -1;
463	dp = (void *)(sec + DOSPARTOFF);
464	sl = dsk.slice;
465	if (sl < BASE_SLICE) {
466	    for (i = 0; i < NDOSPART; i++)
467		if (dp[i].dp_typ == DOSPTYP_386BSD &&
468		    (dp[i].dp_flag & 0x80 || sl < BASE_SLICE)) {
469		    sl = BASE_SLICE + i;
470		    if (dp[i].dp_flag & 0x80 ||
471			dsk.slice == COMPATIBILITY_SLICE)
472			break;
473		}
474	    if (dsk.slice == WHOLE_DISK_SLICE)
475		dsk.slice = sl;
476	}
477	if (sl != WHOLE_DISK_SLICE) {
478	    if (sl != COMPATIBILITY_SLICE)
479		dp += sl - BASE_SLICE;
480	    if (dp->dp_typ != DOSPTYP_386BSD) {
481		printf("Invalid %s\n", "slice");
482		return -1;
483	    }
484	    dsk.start = dp->dp_start;
485	}
486	if (drvread(sec, dsk.start + LABELSECTOR, 1))
487		return -1;
488	d = (void *)(sec + LABELOFFSET);
489	if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) {
490	    if (dsk.part != RAW_PART) {
491		printf("Invalid %s\n", "label");
492		return -1;
493	    }
494	} else {
495	    if (!dsk.init) {
496		if (d->d_type == DTYPE_SCSI)
497		    dsk.type = TYPE_DA;
498		dsk.init++;
499	    }
500	    if (dsk.part >= d->d_npartitions ||
501		!d->d_partitions[dsk.part].p_size) {
502		printf("Invalid %s\n", "partition");
503		return -1;
504	    }
505	    dsk.start += d->d_partitions[dsk.part].p_offset;
506	    dsk.start -= d->d_partitions[RAW_PART].p_offset;
507	}
508    }
509    return drvread(buf, dsk.start + lba, nblk);
510}
511
512static void
513printf(const char *fmt,...)
514{
515    static const char digits[16] = "0123456789abcdef";
516    va_list ap;
517    char buf[10];
518    char *s;
519    unsigned r, u;
520    int c;
521
522    va_start(ap, fmt);
523    while ((c = *fmt++)) {
524	if (c == '%') {
525	    c = *fmt++;
526	    switch (c) {
527	    case 'c':
528		putchar(va_arg(ap, int));
529		continue;
530	    case 's':
531		for (s = va_arg(ap, char *); *s; s++)
532		    putchar(*s);
533		continue;
534	    case 'u':
535	    case 'x':
536		r = c == 'u' ? 10U : 16U;
537		u = va_arg(ap, unsigned);
538		s = buf;
539		do
540		    *s++ = digits[u % r];
541		while (u /= r);
542		while (--s >= buf)
543		    putchar(*s);
544		continue;
545	    }
546	}
547	putchar(c);
548    }
549    va_end(ap);
550    return;
551}
552
553static void
554putchar(int c)
555{
556    if (c == '\n')
557	xputc('\r');
558    xputc(c);
559}
560
561static uint32_t
562memsize(int type)
563{
564    v86.addr = type;
565    v86.eax = 0x8800;
566    v86int();
567    return v86.eax;
568}
569
570static int
571drvread(void *buf, unsigned lba, unsigned nblk)
572{
573    static unsigned c = 0x2d5c7c2f;
574
575    printf("%c\b", c = c << 8 | c >> 24);
576    v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS;
577    v86.addr = XREADORG;		/* call to xread in boot1 */
578    v86.es = VTOPSEG(buf);
579    v86.eax = lba;
580    v86.ebx = VTOPOFF(buf);
581    v86.ecx = lba >> 16;
582    v86.edx = nblk << 8 | dsk.drive;
583    v86int();
584    v86.ctl = V86_FLAGS;
585    if (V86_CY(v86.efl)) {
586	printf("Disk error 0x%x lba 0x%x\n", v86.eax >> 8 & 0xff, lba);
587	return -1;
588    }
589    return 0;
590}
591
592static int
593keyhit(unsigned ticks)
594{
595    uint32_t t0, t1;
596
597    if (opts & 1 << RBX_NOINTR)
598	return 0;
599    t0 = 0;
600    for (;;) {
601	if (xgetc(1))
602	    return 1;
603	t1 = *(uint32_t *)PTOV(0x46c);
604	if (!t0)
605	    t0 = t1;
606	if (t1 < t0 || t1 >= t0 + ticks)
607	    return 0;
608    }
609}
610
611static int
612xputc(int c)
613{
614    if (ioctrl & IO_KEYBOARD)
615	putc(c);
616    if (ioctrl & IO_SERIAL)
617	sio_putc(c);
618    return c;
619}
620
621static int
622xgetc(int fn)
623{
624    if (opts & 1 << RBX_NOINTR)
625	return 0;
626    for (;;) {
627	if (ioctrl & IO_KEYBOARD && getc(1))
628	    return fn ? 1 : getc(0);
629	if (ioctrl & IO_SERIAL && sio_ischar())
630	    return fn ? 1 : sio_getc();
631	if (fn)
632	    return 0;
633    }
634}
635
636static int
637getc(int fn)
638{
639    v86.addr = 0x16;
640    v86.eax = fn << 8;
641    v86int();
642    return fn == 0 ? v86.eax & 0xff : !V86_ZR(v86.efl);
643}
644