xref: /freebsd/stand/i386/gptboot/gptboot.c (revision 4f52dfbb8d6c4d446500c5b097e3806ec219fbd4)
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 #ifdef LOADER_GELI_SUPPORT
289 	geli_init();
290 #endif
291 	/* Process configuration file */
292 
293 	if (gptinit() != 0)
294 		return (-1);
295 
296 	autoboot = 1;
297 	*cmd = '\0';
298 
299 	for (;;) {
300 		*kname = '\0';
301 		if ((ino = lookup(PATH_CONFIG)) ||
302 		    (ino = lookup(PATH_DOTCONFIG))) {
303 			sz = fsread(ino, cmd, sizeof(cmd) - 1);
304 			cmd[(sz < 0) ? 0 : sz] = '\0';
305 		}
306 		if (*cmd != '\0') {
307 			memcpy(cmdtmp, cmd, sizeof(cmdtmp));
308 			if (parse_cmds(cmdtmp, &dskupdated))
309 				break;
310 			if (dskupdated && gptinit() != 0)
311 				break;
312 			if (!OPT_CHECK(RBX_QUIET))
313 				printf("%s: %s", PATH_CONFIG, cmd);
314 			*cmd = '\0';
315 		}
316 
317 		if (autoboot && keyhit(3)) {
318 			if (*kname == '\0')
319 				memcpy(kname, PATH_LOADER, sizeof(PATH_LOADER));
320 			break;
321 		}
322 		autoboot = 0;
323 
324 		/*
325 		 * Try to exec stage 3 boot loader. If interrupted by a
326 		 * keypress, or in case of failure, try to load a kernel
327 		 * directly instead.
328 		 */
329 		if (*kname != '\0')
330 			load();
331 		memcpy(kname, PATH_LOADER, sizeof(PATH_LOADER));
332 		load();
333 		memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL));
334 		load();
335 		gptbootfailed(&dsk);
336 		if (gptfind(&freebsd_ufs_uuid, &dsk, -1) == -1)
337 			break;
338 		dsk_meta = 0;
339 	}
340 
341 	/* Present the user with the boot2 prompt. */
342 
343 	for (;;) {
344 		if (!OPT_CHECK(RBX_QUIET)) {
345 			printf("\nFreeBSD/x86 boot\n"
346 			    "Default: %u:%s(%up%u)%s\n"
347 			    "boot: ",
348 			    dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit,
349 			    dsk.part, kname);
350 		}
351 		if (ioctrl & IO_SERIAL)
352 			sio_flush();
353 		*cmd = '\0';
354 		if (keyhit(0))
355 			getstr(cmd, sizeof(cmd));
356 		else if (!OPT_CHECK(RBX_QUIET))
357 			putchar('\n');
358 		if (parse_cmds(cmd, &dskupdated)) {
359 			putchar('\a');
360 			continue;
361 		}
362 		if (dskupdated && gptinit() != 0)
363 			continue;
364 		load();
365 	}
366 	/* NOTREACHED */
367 }
368 
369 /* XXX - Needed for btxld to link the boot2 binary; do not remove. */
370 void
371 exit(int x)
372 {
373 
374 	while (1);
375 	__unreachable();
376 }
377 
378 static void
379 load(void)
380 {
381 	union {
382 		struct exec ex;
383 		Elf32_Ehdr eh;
384 	} hdr;
385 	static Elf32_Phdr ep[2];
386 	static Elf32_Shdr es[2];
387 	caddr_t p;
388 	ufs_ino_t ino;
389 	uint32_t addr, x;
390 	int fmt, i, j;
391 
392 	if (!(ino = lookup(kname))) {
393 		if (!ls) {
394 			printf("%s: No %s on %u:%s(%up%u)\n", BOOTPROG,
395 			    kname, dsk.drive & DRV_MASK, dev_nm[dsk.type],
396 			    dsk.unit,
397 			    dsk.part);
398 		}
399 		return;
400 	}
401 	if (xfsread(ino, &hdr, sizeof(hdr)))
402 		return;
403 	if (N_GETMAGIC(hdr.ex) == ZMAGIC)
404 		fmt = 0;
405 	else if (IS_ELF(hdr.eh))
406 		fmt = 1;
407 	else {
408 		printf("Invalid %s\n", "format");
409 		return;
410 	}
411 	if (fmt == 0) {
412 		addr = hdr.ex.a_entry & 0xffffff;
413 		p = PTOV(addr);
414 		fs_off = PAGE_SIZE;
415 		if (xfsread(ino, p, hdr.ex.a_text))
416 			return;
417 		p += roundup2(hdr.ex.a_text, PAGE_SIZE);
418 		if (xfsread(ino, p, hdr.ex.a_data))
419 			return;
420 		p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE);
421 		bootinfo.bi_symtab = VTOP(p);
422 		memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms));
423 		p += sizeof(hdr.ex.a_syms);
424 		if (hdr.ex.a_syms) {
425 			if (xfsread(ino, p, hdr.ex.a_syms))
426 				return;
427 			p += hdr.ex.a_syms;
428 			if (xfsread(ino, p, sizeof(int)))
429 				return;
430 			x = *(uint32_t *)p;
431 			p += sizeof(int);
432 			x -= sizeof(int);
433 			if (xfsread(ino, p, x))
434 				return;
435 			p += x;
436 		}
437 	} else {
438 		fs_off = hdr.eh.e_phoff;
439 		for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) {
440 			if (xfsread(ino, ep + j, sizeof(ep[0])))
441 				return;
442 			if (ep[j].p_type == PT_LOAD)
443 				j++;
444 		}
445 		for (i = 0; i < 2; i++) {
446 			p = PTOV(ep[i].p_paddr & 0xffffff);
447 			fs_off = ep[i].p_offset;
448 			if (xfsread(ino, p, ep[i].p_filesz))
449 				return;
450 		}
451 		p += roundup2(ep[1].p_memsz, PAGE_SIZE);
452 		bootinfo.bi_symtab = VTOP(p);
453 		if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) {
454 			fs_off = hdr.eh.e_shoff + sizeof(es[0]) *
455 			    (hdr.eh.e_shstrndx + 1);
456 			if (xfsread(ino, &es, sizeof(es)))
457 				return;
458 			for (i = 0; i < 2; i++) {
459 				memcpy(p, &es[i].sh_size,
460 				    sizeof(es[i].sh_size));
461 				p += sizeof(es[i].sh_size);
462 				fs_off = es[i].sh_offset;
463 				if (xfsread(ino, p, es[i].sh_size))
464 					return;
465 				p += es[i].sh_size;
466 			}
467 		}
468 		addr = hdr.eh.e_entry & 0xffffff;
469 	}
470 	bootinfo.bi_esymtab = VTOP(p);
471 	bootinfo.bi_kernelname = VTOP(kname);
472 	bootinfo.bi_bios_dev = dsk.drive;
473 #ifdef LOADER_GELI_SUPPORT
474 	geliargs.size = sizeof(geliargs);
475 	explicit_bzero(gelipw, sizeof(gelipw));
476 	gelibuf = malloc(sizeof(struct keybuf) +
477 	    (GELI_MAX_KEYS * sizeof(struct keybuf_ent)));
478 	geli_fill_keybuf(gelibuf);
479 	geliargs.notapw = '\0';
480 	geliargs.keybuf_sentinel = KEYBUF_SENTINEL;
481 	geliargs.keybuf = gelibuf;
482 #endif
483 	__exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK),
484 	    MAKEBOOTDEV(dev_maj[dsk.type], dsk.part + 1, dsk.unit, 0xff),
485 	    KARGS_FLAGS_EXTARG, 0, 0, VTOP(&bootinfo)
486 #ifdef LOADER_GELI_SUPPORT
487 	    , geliargs
488 #endif
489 	    );
490 }
491 
492 static int
493 parse_cmds(char *cmdstr, int *dskupdated)
494 {
495 	char *arg;
496 	char *ep, *p, *q;
497 	const char *cp;
498 	unsigned int drv;
499 	int c, i, j;
500 
501 	arg = cmdstr;
502 	*dskupdated = 0;
503 	while ((c = *arg++)) {
504 		if (c == ' ' || c == '\t' || c == '\n')
505 			continue;
506 		for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++);
507 		ep = p;
508 		if (*p)
509 			*p++ = 0;
510 		if (c == '-') {
511 			while ((c = *arg++)) {
512 				if (c == 'P') {
513 					if (*(uint8_t *)PTOV(0x496) & 0x10) {
514 						cp = "yes";
515 					} else {
516 						opts |= OPT_SET(RBX_DUAL) |
517 						    OPT_SET(RBX_SERIAL);
518 						cp = "no";
519 					}
520 					printf("Keyboard: %s\n", cp);
521 					continue;
522 				} else if (c == 'S') {
523 					j = 0;
524 					while ((unsigned int)(i = *arg++ - '0')
525 					    <= 9)
526 						j = j * 10 + i;
527 					if (j > 0 && i == -'0') {
528 						comspeed = j;
529 						break;
530 					}
531 					/*
532 					 * Fall through to error below
533 					 * ('S' not in optstr[]).
534 					 */
535 				}
536 				for (i = 0; c != optstr[i]; i++)
537 					if (i == NOPT - 1)
538 						return (-1);
539 				opts ^= OPT_SET(flags[i]);
540 			}
541 			ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) :
542 			    OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD;
543 			if (ioctrl & IO_SERIAL) {
544 				if (sio_init(115200 / comspeed) != 0)
545 					ioctrl &= ~IO_SERIAL;
546 			}
547 		} else {
548 			for (q = arg--; *q && *q != '('; q++);
549 			if (*q) {
550 				drv = -1;
551 				if (arg[1] == ':') {
552 					drv = *arg - '0';
553 					if (drv > 9)
554 						return (-1);
555 					arg += 2;
556 				}
557 				if (q - arg != 2)
558 					return (-1);
559 				for (i = 0; arg[0] != dev_nm[i][0] ||
560 				    arg[1] != dev_nm[i][1]; i++)
561 					if (i == NDEV - 1)
562 						return (-1);
563 				dsk.type = i;
564 				arg += 3;
565 				dsk.unit = *arg - '0';
566 				if (arg[1] != 'p' || dsk.unit > 9)
567 					return (-1);
568 				arg += 2;
569 				dsk.part = *arg - '0';
570 				if (dsk.part < 1 || dsk.part > 9)
571 					return (-1);
572 				arg++;
573 				if (arg[0] != ')')
574 					return (-1);
575 				arg++;
576 				if (drv == -1)
577 					drv = dsk.unit;
578 				dsk.drive = (dsk.type <= TYPE_MAXHARD
579 				    ? DRV_HARD : 0) + drv;
580 				*dskupdated = 1;
581 			}
582 			if ((i = ep - arg)) {
583 				if ((size_t)i >= sizeof(kname))
584 					return (-1);
585 				memcpy(kname, arg, i + 1);
586 			}
587 		}
588 		arg = p;
589 	}
590 	return (0);
591 }
592 
593 static int
594 dskread(void *buf, daddr_t lba, unsigned nblk)
595 {
596 	int err;
597 
598 	err = drvread(&dsk, buf, lba + dsk.start, nblk);
599 
600 #ifdef LOADER_GELI_SUPPORT
601 	if (err == 0 && is_geli(&dsk) == 0) {
602 		/* Decrypt */
603 		if (geli_read(&dsk, lba * DEV_BSIZE, buf, nblk * DEV_BSIZE))
604 			return (err);
605 	}
606 #endif
607 
608 	return (err);
609 }
610 
611 #ifdef LOADER_GELI_SUPPORT
612 /*
613  * Read function compartible with the ZFS callback, required to keep the GELI
614  * Implementation the same for both UFS and ZFS
615  */
616 static int
617 vdev_read(void *vdev __unused, void *priv, off_t off, void *buf, size_t bytes)
618 {
619 	char *p;
620 	daddr_t lba;
621 	unsigned int nb;
622 	struct dsk *dskp;
623 
624 	dskp = (struct dsk *)priv;
625 
626 	if ((off & (DEV_BSIZE - 1)) || (bytes & (DEV_BSIZE - 1)))
627 		return (-1);
628 
629 	p = buf;
630 	lba = off / DEV_BSIZE;
631 	lba += dskp->start;
632 
633 	while (bytes > 0) {
634 		nb = bytes / DEV_BSIZE;
635 		if (nb > VBLKSIZE / DEV_BSIZE)
636 			nb = VBLKSIZE / DEV_BSIZE;
637 		if (drvread(dskp, dmadat->blkbuf, lba, nb))
638 			return (-1);
639 		memcpy(p, dmadat->blkbuf, nb * DEV_BSIZE);
640 		p += nb * DEV_BSIZE;
641 		lba += nb;
642 		bytes -= nb * DEV_BSIZE;
643 	}
644 
645 	return (0);
646 }
647 #endif /* LOADER_GELI_SUPPORT */
648