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