gptboot.c revision 329175
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: stable/11/stand/i386/gptboot/gptboot.c 329175 2018-02-12 17:44:35Z kevans $");
18
19#include <sys/param.h>
20#include <sys/gpt.h>
21#include <sys/dirent.h>
22#include <sys/reboot.h>
23
24#include <machine/bootinfo.h>
25#include <machine/elf.h>
26#include <machine/pc/bios.h>
27#include <machine/psl.h>
28
29#include <stdarg.h>
30
31#include <a.out.h>
32
33#include <btxv86.h>
34
35#include "stand.h"
36
37#include "bootargs.h"
38#include "lib.h"
39#include "rbx.h"
40#include "drv.h"
41#include "cons.h"
42#include "gpt.h"
43#include "paths.h"
44
45#define ARGS		0x900
46#define NOPT		14
47#define NDEV		3
48#define MEM_BASE	0x12
49#define MEM_EXT 	0x15
50
51#define DRV_HARD	0x80
52#define DRV_MASK	0x7f
53
54#define TYPE_AD		0
55#define TYPE_DA		1
56#define TYPE_MAXHARD	TYPE_DA
57#define TYPE_FD		2
58
59extern uint32_t _end;
60
61static const uuid_t freebsd_ufs_uuid = GPT_ENT_TYPE_FREEBSD_UFS;
62static const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */
63static const unsigned char flags[NOPT] = {
64	RBX_DUAL,
65	RBX_SERIAL,
66	RBX_ASKNAME,
67	RBX_CDROM,
68	RBX_CONFIG,
69	RBX_KDB,
70	RBX_GDB,
71	RBX_MUTE,
72	RBX_NOINTR,
73	RBX_PAUSE,
74	RBX_QUIET,
75	RBX_DFLTROOT,
76	RBX_SINGLE,
77	RBX_VERBOSE
78};
79uint32_t opts;
80
81static const char *const dev_nm[NDEV] = {"ad", "da", "fd"};
82static const unsigned char dev_maj[NDEV] = {30, 4, 2};
83
84static struct dsk dsk;
85static char kname[1024];
86static int comspeed = SIOSPD;
87static struct bootinfo bootinfo;
88#ifdef LOADER_GELI_SUPPORT
89static struct geli_boot_args geliargs;
90#endif
91
92static vm_offset_t	high_heap_base;
93static uint32_t		bios_basemem, bios_extmem, high_heap_size;
94
95static struct bios_smap smap;
96
97/*
98 * The minimum amount of memory to reserve in bios_extmem for the heap.
99 */
100#define	HEAP_MIN	(3 * 1024 * 1024)
101
102static char *heap_next;
103static char *heap_end;
104
105static void load(void);
106static int parse_cmds(char *, int *);
107static int dskread(void *, daddr_t, unsigned);
108#ifdef LOADER_GELI_SUPPORT
109static int vdev_read(void *vdev __unused, void *priv, off_t off, void *buf,
110	size_t bytes);
111#endif
112
113#include "ufsread.c"
114#include "gpt.c"
115#ifdef LOADER_GELI_SUPPORT
116#include "geliboot.c"
117static char gelipw[GELI_PW_MAXLEN];
118static struct keybuf *gelibuf;
119#endif
120
121static inline int
122xfsread(ufs_ino_t inode, void *buf, size_t nbyte)
123{
124
125	if ((size_t)fsread(inode, buf, nbyte) != nbyte) {
126		printf("Invalid %s\n", "format");
127		return (-1);
128	}
129	return (0);
130}
131
132static void
133bios_getmem(void)
134{
135    uint64_t size;
136
137    /* Parse system memory map */
138    v86.ebx = 0;
139    do {
140	v86.ctl = V86_FLAGS;
141	v86.addr = MEM_EXT;		/* int 0x15 function 0xe820*/
142	v86.eax = 0xe820;
143	v86.ecx = sizeof(struct bios_smap);
144	v86.edx = SMAP_SIG;
145	v86.es = VTOPSEG(&smap);
146	v86.edi = VTOPOFF(&smap);
147	v86int();
148	if ((v86.efl & 1) || (v86.eax != SMAP_SIG))
149	    break;
150	/* look for a low-memory segment that's large enough */
151	if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0) &&
152	    (smap.length >= (512 * 1024)))
153	    bios_basemem = smap.length;
154	/* look for the first segment in 'extended' memory */
155	if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0x100000)) {
156	    bios_extmem = smap.length;
157	}
158
159	/*
160	 * Look for the largest segment in 'extended' memory beyond
161	 * 1MB but below 4GB.
162	 */
163	if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base > 0x100000) &&
164	    (smap.base < 0x100000000ull)) {
165	    size = smap.length;
166
167	    /*
168	     * If this segment crosses the 4GB boundary, truncate it.
169	     */
170	    if (smap.base + size > 0x100000000ull)
171		size = 0x100000000ull - smap.base;
172
173	    if (size > high_heap_size) {
174		high_heap_size = size;
175		high_heap_base = smap.base;
176	    }
177	}
178    } while (v86.ebx != 0);
179
180    /* Fall back to the old compatibility function for base memory */
181    if (bios_basemem == 0) {
182	v86.ctl = 0;
183	v86.addr = 0x12;		/* int 0x12 */
184	v86int();
185
186	bios_basemem = (v86.eax & 0xffff) * 1024;
187    }
188
189    /* Fall back through several compatibility functions for extended memory */
190    if (bios_extmem == 0) {
191	v86.ctl = V86_FLAGS;
192	v86.addr = 0x15;		/* int 0x15 function 0xe801*/
193	v86.eax = 0xe801;
194	v86int();
195	if (!(v86.efl & 1)) {
196	    bios_extmem = ((v86.ecx & 0xffff) + ((v86.edx & 0xffff) * 64)) * 1024;
197	}
198    }
199    if (bios_extmem == 0) {
200	v86.ctl = 0;
201	v86.addr = 0x15;		/* int 0x15 function 0x88*/
202	v86.eax = 0x8800;
203	v86int();
204	bios_extmem = (v86.eax & 0xffff) * 1024;
205    }
206
207    /*
208     * If we have extended memory and did not find a suitable heap
209     * region in the SMAP, use the last 3MB of 'extended' memory as a
210     * high heap candidate.
211     */
212    if (bios_extmem >= HEAP_MIN && high_heap_size < HEAP_MIN) {
213	high_heap_size = HEAP_MIN;
214	high_heap_base = bios_extmem + 0x100000 - HEAP_MIN;
215    }
216}
217
218static int
219gptinit(void)
220{
221
222	if (gptread(&freebsd_ufs_uuid, &dsk, dmadat->secbuf) == -1) {
223		printf("%s: unable to load GPT\n", BOOTPROG);
224		return (-1);
225	}
226	if (gptfind(&freebsd_ufs_uuid, &dsk, dsk.part) == -1) {
227		printf("%s: no UFS partition was found\n", BOOTPROG);
228		return (-1);
229	}
230#ifdef LOADER_GELI_SUPPORT
231	if (geli_taste(vdev_read, &dsk, (gpttable[curent].ent_lba_end -
232	    gpttable[curent].ent_lba_start)) == 0) {
233		if (geli_havekey(&dsk) != 0 && geli_passphrase(gelipw,
234		    dsk.unit, 'p', curent + 1, &dsk) != 0) {
235			printf("%s: unable to decrypt GELI key\n", BOOTPROG);
236			return (-1);
237		}
238	}
239#endif
240
241	dsk_meta = 0;
242	return (0);
243}
244
245int main(void);
246
247int
248main(void)
249{
250	char cmd[512], cmdtmp[512];
251	ssize_t sz;
252	int autoboot, dskupdated;
253	ufs_ino_t ino;
254
255	dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base);
256
257	bios_getmem();
258
259	if (high_heap_size > 0) {
260		heap_end = PTOV(high_heap_base + high_heap_size);
261		heap_next = PTOV(high_heap_base);
262	} else {
263		heap_next = (char *)dmadat + sizeof(*dmadat);
264		heap_end = (char *)PTOV(bios_basemem);
265	}
266	setheap(heap_next, heap_end);
267
268	v86.ctl = V86_FLAGS;
269	v86.efl = PSL_RESERVED_DEFAULT | PSL_I;
270	dsk.drive = *(uint8_t *)PTOV(ARGS);
271	dsk.type = dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD;
272	dsk.unit = dsk.drive & DRV_MASK;
273	dsk.part = -1;
274	dsk.start = 0;
275	bootinfo.bi_version = BOOTINFO_VERSION;
276	bootinfo.bi_size = sizeof(bootinfo);
277	bootinfo.bi_basemem = bios_basemem / 1024;
278	bootinfo.bi_extmem = bios_extmem / 1024;
279	bootinfo.bi_memsizes_valid++;
280	bootinfo.bi_bios_dev = dsk.drive;
281
282#ifdef LOADER_GELI_SUPPORT
283	geli_init();
284#endif
285	/* Process configuration file */
286
287	if (gptinit() != 0)
288		return (-1);
289
290	autoboot = 1;
291	*cmd = '\0';
292
293	for (;;) {
294		*kname = '\0';
295		if ((ino = lookup(PATH_CONFIG)) ||
296		    (ino = lookup(PATH_DOTCONFIG))) {
297			sz = fsread(ino, cmd, sizeof(cmd) - 1);
298			cmd[(sz < 0) ? 0 : sz] = '\0';
299		}
300		if (*cmd != '\0') {
301			memcpy(cmdtmp, cmd, sizeof(cmdtmp));
302			if (parse_cmds(cmdtmp, &dskupdated))
303				break;
304			if (dskupdated && gptinit() != 0)
305				break;
306			if (!OPT_CHECK(RBX_QUIET))
307				printf("%s: %s", PATH_CONFIG, cmd);
308			*cmd = '\0';
309		}
310
311		if (autoboot && keyhit(3)) {
312			if (*kname == '\0')
313				memcpy(kname, PATH_LOADER, sizeof(PATH_LOADER));
314			break;
315		}
316		autoboot = 0;
317
318		/*
319		 * Try to exec stage 3 boot loader. If interrupted by a
320		 * keypress, or in case of failure, try to load a kernel
321		 * directly instead.
322		 */
323		if (*kname != '\0')
324			load();
325		memcpy(kname, PATH_LOADER, sizeof(PATH_LOADER));
326		load();
327		memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL));
328		load();
329		gptbootfailed(&dsk);
330		if (gptfind(&freebsd_ufs_uuid, &dsk, -1) == -1)
331			break;
332		dsk_meta = 0;
333	}
334
335	/* Present the user with the boot2 prompt. */
336
337	for (;;) {
338		if (!OPT_CHECK(RBX_QUIET)) {
339			printf("\nFreeBSD/x86 boot\n"
340			    "Default: %u:%s(%up%u)%s\n"
341			    "boot: ",
342			    dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit,
343			    dsk.part, kname);
344		}
345		if (ioctrl & IO_SERIAL)
346			sio_flush();
347		*cmd = '\0';
348		if (keyhit(0))
349			getstr(cmd, sizeof(cmd));
350		else if (!OPT_CHECK(RBX_QUIET))
351			putchar('\n');
352		if (parse_cmds(cmd, &dskupdated)) {
353			putchar('\a');
354			continue;
355		}
356		if (dskupdated && gptinit() != 0)
357			continue;
358		load();
359	}
360	/* NOTREACHED */
361}
362
363/* XXX - Needed for btxld to link the boot2 binary; do not remove. */
364void
365exit(int x)
366{
367	while (1);
368	__unreachable();
369}
370
371static void
372load(void)
373{
374    union {
375	struct exec ex;
376	Elf32_Ehdr eh;
377    } hdr;
378    static Elf32_Phdr ep[2];
379    static Elf32_Shdr es[2];
380    caddr_t p;
381    ufs_ino_t ino;
382    uint32_t addr, x;
383    int fmt, i, j;
384
385    if (!(ino = lookup(kname))) {
386	if (!ls) {
387	    printf("%s: No %s on %u:%s(%up%u)\n", BOOTPROG,
388		kname, dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit,
389		dsk.part);
390	}
391	return;
392    }
393    if (xfsread(ino, &hdr, sizeof(hdr)))
394	return;
395    if (N_GETMAGIC(hdr.ex) == ZMAGIC)
396	fmt = 0;
397    else if (IS_ELF(hdr.eh))
398	fmt = 1;
399    else {
400	printf("Invalid %s\n", "format");
401	return;
402    }
403    if (fmt == 0) {
404	addr = hdr.ex.a_entry & 0xffffff;
405	p = PTOV(addr);
406	fs_off = PAGE_SIZE;
407	if (xfsread(ino, p, hdr.ex.a_text))
408	    return;
409	p += roundup2(hdr.ex.a_text, PAGE_SIZE);
410	if (xfsread(ino, p, hdr.ex.a_data))
411	    return;
412	p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE);
413	bootinfo.bi_symtab = VTOP(p);
414	memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms));
415	p += sizeof(hdr.ex.a_syms);
416	if (hdr.ex.a_syms) {
417	    if (xfsread(ino, p, hdr.ex.a_syms))
418		return;
419	    p += hdr.ex.a_syms;
420	    if (xfsread(ino, p, sizeof(int)))
421		return;
422	    x = *(uint32_t *)p;
423	    p += sizeof(int);
424	    x -= sizeof(int);
425	    if (xfsread(ino, p, x))
426		return;
427	    p += x;
428	}
429    } else {
430	fs_off = hdr.eh.e_phoff;
431	for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) {
432	    if (xfsread(ino, ep + j, sizeof(ep[0])))
433		return;
434	    if (ep[j].p_type == PT_LOAD)
435		j++;
436	}
437	for (i = 0; i < 2; i++) {
438	    p = PTOV(ep[i].p_paddr & 0xffffff);
439	    fs_off = ep[i].p_offset;
440	    if (xfsread(ino, p, ep[i].p_filesz))
441		return;
442	}
443	p += roundup2(ep[1].p_memsz, PAGE_SIZE);
444	bootinfo.bi_symtab = VTOP(p);
445	if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) {
446	    fs_off = hdr.eh.e_shoff + sizeof(es[0]) *
447		(hdr.eh.e_shstrndx + 1);
448	    if (xfsread(ino, &es, sizeof(es)))
449		return;
450	    for (i = 0; i < 2; i++) {
451		memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size));
452		p += sizeof(es[i].sh_size);
453		fs_off = es[i].sh_offset;
454		if (xfsread(ino, p, es[i].sh_size))
455		    return;
456		p += es[i].sh_size;
457	    }
458	}
459	addr = hdr.eh.e_entry & 0xffffff;
460    }
461    bootinfo.bi_esymtab = VTOP(p);
462    bootinfo.bi_kernelname = VTOP(kname);
463    bootinfo.bi_bios_dev = dsk.drive;
464#ifdef LOADER_GELI_SUPPORT
465    geliargs.size = sizeof(geliargs);
466    explicit_bzero(gelipw, sizeof(gelipw));
467    gelibuf = malloc(sizeof(struct keybuf) + (GELI_MAX_KEYS * sizeof(struct keybuf_ent)));
468    geli_fill_keybuf(gelibuf);
469    geliargs.notapw = '\0';
470    geliargs.keybuf_sentinel = KEYBUF_SENTINEL;
471    geliargs.keybuf = gelibuf;
472#endif
473    __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK),
474	   MAKEBOOTDEV(dev_maj[dsk.type], dsk.part + 1, dsk.unit, 0xff),
475	   KARGS_FLAGS_EXTARG, 0, 0, VTOP(&bootinfo)
476#ifdef LOADER_GELI_SUPPORT
477	   , geliargs
478#endif
479	   );
480}
481
482static int
483parse_cmds(char *cmdstr, int *dskupdated)
484{
485    char *arg = cmdstr;
486    char *ep, *p, *q;
487    const char *cp;
488    unsigned int drv;
489    int c, i, j;
490
491    *dskupdated = 0;
492    while ((c = *arg++)) {
493	if (c == ' ' || c == '\t' || c == '\n')
494	    continue;
495	for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++);
496	ep = p;
497	if (*p)
498	    *p++ = 0;
499	if (c == '-') {
500	    while ((c = *arg++)) {
501		if (c == 'P') {
502		    if (*(uint8_t *)PTOV(0x496) & 0x10) {
503			cp = "yes";
504		    } else {
505			opts |= OPT_SET(RBX_DUAL) | OPT_SET(RBX_SERIAL);
506			cp = "no";
507		    }
508		    printf("Keyboard: %s\n", cp);
509		    continue;
510		} else if (c == 'S') {
511		    j = 0;
512		    while ((unsigned int)(i = *arg++ - '0') <= 9)
513			j = j * 10 + i;
514		    if (j > 0 && i == -'0') {
515			comspeed = j;
516			break;
517		    }
518		    /* Fall through to error below ('S' not in optstr[]). */
519		}
520		for (i = 0; c != optstr[i]; i++)
521		    if (i == NOPT - 1)
522			return -1;
523		opts ^= OPT_SET(flags[i]);
524	    }
525	    ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) :
526		     OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD;
527	    if (ioctrl & IO_SERIAL) {
528	        if (sio_init(115200 / comspeed) != 0)
529		    ioctrl &= ~IO_SERIAL;
530	    }
531	} else {
532	    for (q = arg--; *q && *q != '('; q++);
533	    if (*q) {
534		drv = -1;
535		if (arg[1] == ':') {
536		    drv = *arg - '0';
537		    if (drv > 9)
538			return (-1);
539		    arg += 2;
540		}
541		if (q - arg != 2)
542		    return -1;
543		for (i = 0; arg[0] != dev_nm[i][0] ||
544			    arg[1] != dev_nm[i][1]; i++)
545		    if (i == NDEV - 1)
546			return -1;
547		dsk.type = i;
548		arg += 3;
549		dsk.unit = *arg - '0';
550		if (arg[1] != 'p' || dsk.unit > 9)
551		    return -1;
552		arg += 2;
553		dsk.part = *arg - '0';
554		if (dsk.part < 1 || dsk.part > 9)
555		    return -1;
556		arg++;
557		if (arg[0] != ')')
558		    return -1;
559		arg++;
560		if (drv == -1)
561		    drv = dsk.unit;
562		dsk.drive = (dsk.type <= TYPE_MAXHARD
563			     ? DRV_HARD : 0) + drv;
564		*dskupdated = 1;
565	    }
566	    if ((i = ep - arg)) {
567		if ((size_t)i >= sizeof(kname))
568		    return -1;
569		memcpy(kname, arg, i + 1);
570	    }
571	}
572	arg = p;
573    }
574    return 0;
575}
576
577static int
578dskread(void *buf, daddr_t lba, unsigned nblk)
579{
580	int err;
581
582	err = drvread(&dsk, buf, lba + dsk.start, nblk);
583
584#ifdef LOADER_GELI_SUPPORT
585	if (err == 0 && is_geli(&dsk) == 0) {
586		/* Decrypt */
587		if (geli_read(&dsk, lba * DEV_BSIZE, buf, nblk * DEV_BSIZE))
588			return (err);
589	}
590#endif
591
592	return (err);
593}
594
595#ifdef LOADER_GELI_SUPPORT
596/*
597 * Read function compartible with the ZFS callback, required to keep the GELI
598 * Implementation the same for both UFS and ZFS
599 */
600static int
601vdev_read(void *vdev __unused, void *priv, off_t off, void *buf, size_t bytes)
602{
603	char *p;
604	daddr_t lba;
605	unsigned int nb;
606	struct dsk *dskp = (struct dsk *) priv;
607
608	if ((off & (DEV_BSIZE - 1)) || (bytes & (DEV_BSIZE - 1)))
609		return (-1);
610
611	p = buf;
612	lba = off / DEV_BSIZE;
613	lba += dskp->start;
614
615	while (bytes > 0) {
616		nb = bytes / DEV_BSIZE;
617		if (nb > VBLKSIZE / DEV_BSIZE)
618			nb = VBLKSIZE / DEV_BSIZE;
619		if (drvread(dskp, dmadat->blkbuf, lba, nb))
620			return (-1);
621		memcpy(p, dmadat->blkbuf, nb * DEV_BSIZE);
622		p += nb * DEV_BSIZE;
623		lba += nb;
624		bytes -= nb * DEV_BSIZE;
625	}
626
627	return (0);
628}
629#endif /* LOADER_GELI_SUPPORT */
630