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