boot1.c revision 293274
1/*-
2 * Copyright (c) 1998 Robert Nordier
3 * All rights reserved.
4 * Copyright (c) 2001 Robert Drehmel
5 * All rights reserved.
6 * Copyright (c) 2014 Nathan Whitehorn
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms are freely
10 * permitted provided that the above copyright notice and this
11 * paragraph and the following disclaimer are duplicated in all
12 * such forms.
13 *
14 * This software is provided "AS IS" and without any express or
15 * implied warranties, including, without limitation, the implied
16 * warranties of merchantability and fitness for a particular
17 * purpose.
18 */
19
20#include <sys/cdefs.h>
21__FBSDID("$FreeBSD: head/sys/boot/efi/boot1/boot1.c 293274 2016-01-06 20:48:29Z smh $");
22
23#include <sys/param.h>
24#include <sys/dirent.h>
25#include <machine/elf.h>
26#include <machine/stdarg.h>
27
28#include <efi.h>
29#include <eficonsctl.h>
30
31#define _PATH_LOADER	"/boot/loader.efi"
32#define _PATH_KERNEL	"/boot/kernel/kernel"
33
34#define BSIZEMAX	16384
35
36typedef int putc_func_t(char c, void *arg);
37
38struct sp_data {
39	char	*sp_buf;
40	u_int	sp_len;
41	u_int	sp_size;
42};
43
44static const char digits[] = "0123456789abcdef";
45
46static void panic(const char *fmt, ...) __dead2;
47static int printf(const char *fmt, ...);
48static int putchar(char c, void *arg);
49static int vprintf(const char *fmt, va_list ap);
50static int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap);
51
52static int __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap);
53static int __putc(char c, void *arg);
54static int __puts(const char *s, putc_func_t *putc, void *arg);
55static int __sputc(char c, void *arg);
56static char *__uitoa(char *buf, u_int val, int base);
57static char *__ultoa(char *buf, u_long val, int base);
58
59static int domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet);
60static void load(const char *fname);
61
62static EFI_SYSTEM_TABLE *systab;
63static EFI_HANDLE *image;
64
65static void
66bcopy(const void *src, void *dst, size_t len)
67{
68	const char *s = src;
69	char *d = dst;
70
71	while (len-- != 0)
72		*d++ = *s++;
73}
74
75static void
76memcpy(void *dst, const void *src, size_t len)
77{
78	bcopy(src, dst, len);
79}
80
81static void
82bzero(void *b, size_t len)
83{
84	char *p = b;
85
86	while (len-- != 0)
87		*p++ = 0;
88}
89
90static int
91strcmp(const char *s1, const char *s2)
92{
93	for (; *s1 == *s2 && *s1; s1++, s2++)
94		;
95	return ((u_char)*s1 - (u_char)*s2);
96}
97
98static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL;
99static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL;
100static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL;
101static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
102
103static EFI_BLOCK_IO *bootdev;
104static EFI_DEVICE_PATH *bootdevpath;
105static EFI_HANDLE *bootdevhandle;
106
107EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab)
108{
109	EFI_HANDLE handles[128];
110	EFI_BLOCK_IO *blkio;
111	UINTN i, nparts = sizeof(handles), cols, rows, max_dim, best_mode;
112	EFI_STATUS status;
113	EFI_DEVICE_PATH *devpath;
114	EFI_BOOT_SERVICES *BS;
115	EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL;
116	SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL;
117	char *path = _PATH_LOADER;
118
119	systab = Xsystab;
120	image = Ximage;
121
122	BS = systab->BootServices;
123	status = BS->LocateProtocol(&ConsoleControlGUID, NULL,
124	    (VOID **)&ConsoleControl);
125	if (status == EFI_SUCCESS)
126		(void)ConsoleControl->SetMode(ConsoleControl,
127		    EfiConsoleControlScreenText);
128	/*
129	 * Reset the console and find the best text mode.
130	 */
131	conout = systab->ConOut;
132	conout->Reset(conout, TRUE);
133	max_dim = best_mode = 0;
134	for (i = 0; ; i++) {
135		status = conout->QueryMode(conout, i, &cols, &rows);
136		if (EFI_ERROR(status))
137			break;
138		if (cols * rows > max_dim) {
139			max_dim = cols * rows;
140			best_mode = i;
141		}
142	}
143	if (max_dim > 0)
144		conout->SetMode(conout, best_mode);
145	conout->EnableCursor(conout, TRUE);
146	conout->ClearScreen(conout);
147
148	printf("\n"
149	       ">> FreeBSD EFI boot block\n");
150	printf("   Loader path: %s\n", path);
151
152	status = systab->BootServices->LocateHandle(ByProtocol,
153	    &BlockIoProtocolGUID, NULL, &nparts, handles);
154	nparts /= sizeof(handles[0]);
155
156	for (i = 0; i < nparts; i++) {
157		status = systab->BootServices->HandleProtocol(handles[i],
158		    &DevicePathGUID, (void **)&devpath);
159		if (EFI_ERROR(status))
160			continue;
161
162		while (!IsDevicePathEnd(NextDevicePathNode(devpath)))
163			devpath = NextDevicePathNode(devpath);
164
165		status = systab->BootServices->HandleProtocol(handles[i],
166		    &BlockIoProtocolGUID, (void **)&blkio);
167		if (EFI_ERROR(status))
168			continue;
169
170		if (!blkio->Media->LogicalPartition)
171			continue;
172
173		if (domount(devpath, blkio, 1) >= 0)
174			break;
175	}
176
177	if (i == nparts)
178		panic("No bootable partition found");
179
180	bootdevhandle = handles[i];
181	load(path);
182
183	panic("Load failed");
184
185	return EFI_SUCCESS;
186}
187
188static int
189dskread(void *buf, u_int64_t lba, int nblk)
190{
191	EFI_STATUS status;
192	int size;
193
194	lba = lba / (bootdev->Media->BlockSize / DEV_BSIZE);
195	size = nblk * DEV_BSIZE;
196	status = bootdev->ReadBlocks(bootdev, bootdev->Media->MediaId, lba,
197	    size, buf);
198
199	if (EFI_ERROR(status))
200		return (-1);
201
202	return (0);
203}
204
205#include "ufsread.c"
206
207static ssize_t
208fsstat(ufs_ino_t inode)
209{
210#ifndef UFS2_ONLY
211	static struct ufs1_dinode dp1;
212	ufs1_daddr_t addr1;
213#endif
214#ifndef UFS1_ONLY
215	static struct ufs2_dinode dp2;
216#endif
217	static struct fs fs;
218	static ufs_ino_t inomap;
219	char *blkbuf;
220	void *indbuf;
221	size_t n, nb, size, off, vboff;
222	ufs_lbn_t lbn;
223	ufs2_daddr_t addr2, vbaddr;
224	static ufs2_daddr_t blkmap, indmap;
225	u_int u;
226
227	blkbuf = dmadat->blkbuf;
228	indbuf = dmadat->indbuf;
229	if (!dsk_meta) {
230		inomap = 0;
231		for (n = 0; sblock_try[n] != -1; n++) {
232			if (dskread(dmadat->sbbuf, sblock_try[n] / DEV_BSIZE,
233			    SBLOCKSIZE / DEV_BSIZE))
234				return -1;
235			memcpy(&fs, dmadat->sbbuf, sizeof(struct fs));
236			if ((
237#if defined(UFS1_ONLY)
238			    fs.fs_magic == FS_UFS1_MAGIC
239#elif defined(UFS2_ONLY)
240			    (fs.fs_magic == FS_UFS2_MAGIC &&
241			    fs.fs_sblockloc == sblock_try[n])
242#else
243			    fs.fs_magic == FS_UFS1_MAGIC ||
244			    (fs.fs_magic == FS_UFS2_MAGIC &&
245			    fs.fs_sblockloc == sblock_try[n])
246#endif
247			    ) &&
248			    fs.fs_bsize <= MAXBSIZE &&
249			    fs.fs_bsize >= sizeof(struct fs))
250				break;
251		}
252		if (sblock_try[n] == -1) {
253			printf("Not ufs\n");
254			return -1;
255		}
256		dsk_meta++;
257	} else
258		memcpy(&fs, dmadat->sbbuf, sizeof(struct fs));
259	if (!inode)
260		return 0;
261	if (inomap != inode) {
262		n = IPERVBLK(&fs);
263		if (dskread(blkbuf, INO_TO_VBA(&fs, n, inode), DBPERVBLK))
264			return -1;
265		n = INO_TO_VBO(n, inode);
266#if defined(UFS1_ONLY)
267		memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n,
268		    sizeof(struct ufs1_dinode));
269#elif defined(UFS2_ONLY)
270		memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n,
271		    sizeof(struct ufs2_dinode));
272#else
273		if (fs.fs_magic == FS_UFS1_MAGIC)
274			memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n,
275			    sizeof(struct ufs1_dinode));
276		else
277			memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n,
278			    sizeof(struct ufs2_dinode));
279#endif
280		inomap = inode;
281		fs_off = 0;
282		blkmap = indmap = 0;
283	}
284	size = DIP(di_size);
285	n = size - fs_off;
286	return (n);
287}
288
289static struct dmadat __dmadat;
290
291static int
292domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet)
293{
294
295	dmadat = &__dmadat;
296	bootdev = blkio;
297	bootdevpath = device;
298	if (fsread(0, NULL, 0)) {
299		if (!quiet)
300			printf("domount: can't read superblock\n");
301		return (-1);
302	}
303	if (!quiet)
304		printf("Succesfully mounted UFS filesystem\n");
305	return (0);
306}
307
308static void
309load(const char *fname)
310{
311	ufs_ino_t ino;
312	EFI_STATUS status;
313	EFI_HANDLE loaderhandle;
314	EFI_LOADED_IMAGE *loaded_image;
315	void *buffer;
316	size_t bufsize;
317
318	if ((ino = lookup(fname)) == 0) {
319		printf("File %s not found\n", fname);
320		return;
321	}
322
323	bufsize = fsstat(ino);
324	status = systab->BootServices->AllocatePool(EfiLoaderData,
325	    bufsize, &buffer);
326	fsread(ino, buffer, bufsize);
327
328	/* XXX: For secure boot, we need our own loader here */
329	status = systab->BootServices->LoadImage(TRUE, image, bootdevpath,
330	    buffer, bufsize, &loaderhandle);
331	if (EFI_ERROR(status))
332		printf("LoadImage failed with error %lu\n",
333		    EFI_ERROR_CODE(status));
334
335	status = systab->BootServices->HandleProtocol(loaderhandle,
336	    &LoadedImageGUID, (VOID**)&loaded_image);
337	if (EFI_ERROR(status))
338		printf("HandleProtocol failed with error %lu\n",
339		    EFI_ERROR_CODE(status));
340
341	loaded_image->DeviceHandle = bootdevhandle;
342
343	status = systab->BootServices->StartImage(loaderhandle, NULL, NULL);
344	if (EFI_ERROR(status))
345		printf("StartImage failed with error %lu\n",
346		    EFI_ERROR_CODE(status));
347}
348
349static void
350panic(const char *fmt, ...)
351{
352	char buf[128];
353	va_list ap;
354
355	va_start(ap, fmt);
356	vsnprintf(buf, sizeof buf, fmt, ap);
357	printf("panic: %s\n", buf);
358	va_end(ap);
359
360	while (1) {}
361}
362
363static int
364printf(const char *fmt, ...)
365{
366	va_list ap;
367	int ret;
368
369	/* Don't annoy the user as we probe for partitions */
370	if (strcmp(fmt,"Not ufs\n") == 0)
371		return 0;
372
373	va_start(ap, fmt);
374	ret = vprintf(fmt, ap);
375	va_end(ap);
376	return (ret);
377}
378
379static int
380putchar(char c, void *arg)
381{
382	CHAR16 buf[2];
383
384	if (c == '\n') {
385		buf[0] = '\r';
386		buf[1] = 0;
387		systab->ConOut->OutputString(systab->ConOut, buf);
388	}
389	buf[0] = c;
390	buf[1] = 0;
391	systab->ConOut->OutputString(systab->ConOut, buf);
392	return (1);
393}
394
395static int
396vprintf(const char *fmt, va_list ap)
397{
398	int ret;
399
400	ret = __printf(fmt, putchar, 0, ap);
401	return (ret);
402}
403
404static int
405vsnprintf(char *str, size_t sz, const char *fmt, va_list ap)
406{
407	struct sp_data sp;
408	int ret;
409
410	sp.sp_buf = str;
411	sp.sp_len = 0;
412	sp.sp_size = sz;
413	ret = __printf(fmt, __sputc, &sp, ap);
414	return (ret);
415}
416
417static int
418__printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap)
419{
420	char buf[(sizeof(long) * 8) + 1];
421	char *nbuf;
422	u_long ul;
423	u_int ui;
424	int lflag;
425	int sflag;
426	char *s;
427	int pad;
428	int ret;
429	int c;
430
431	nbuf = &buf[sizeof buf - 1];
432	ret = 0;
433	while ((c = *fmt++) != 0) {
434		if (c != '%') {
435			ret += putc(c, arg);
436			continue;
437		}
438		lflag = 0;
439		sflag = 0;
440		pad = 0;
441reswitch:	c = *fmt++;
442		switch (c) {
443		case '#':
444			sflag = 1;
445			goto reswitch;
446		case '%':
447			ret += putc('%', arg);
448			break;
449		case 'c':
450			c = va_arg(ap, int);
451			ret += putc(c, arg);
452			break;
453		case 'd':
454			if (lflag == 0) {
455				ui = (u_int)va_arg(ap, int);
456				if (ui < (int)ui) {
457					ui = -ui;
458					ret += putc('-', arg);
459				}
460				s = __uitoa(nbuf, ui, 10);
461			} else {
462				ul = (u_long)va_arg(ap, long);
463				if (ul < (long)ul) {
464					ul = -ul;
465					ret += putc('-', arg);
466				}
467				s = __ultoa(nbuf, ul, 10);
468			}
469			ret += __puts(s, putc, arg);
470			break;
471		case 'l':
472			lflag = 1;
473			goto reswitch;
474		case 'o':
475			if (lflag == 0) {
476				ui = (u_int)va_arg(ap, u_int);
477				s = __uitoa(nbuf, ui, 8);
478			} else {
479				ul = (u_long)va_arg(ap, u_long);
480				s = __ultoa(nbuf, ul, 8);
481			}
482			ret += __puts(s, putc, arg);
483			break;
484		case 'p':
485			ul = (u_long)va_arg(ap, void *);
486			s = __ultoa(nbuf, ul, 16);
487			ret += __puts("0x", putc, arg);
488			ret += __puts(s, putc, arg);
489			break;
490		case 's':
491			s = va_arg(ap, char *);
492			ret += __puts(s, putc, arg);
493			break;
494		case 'u':
495			if (lflag == 0) {
496				ui = va_arg(ap, u_int);
497				s = __uitoa(nbuf, ui, 10);
498			} else {
499				ul = va_arg(ap, u_long);
500				s = __ultoa(nbuf, ul, 10);
501			}
502			ret += __puts(s, putc, arg);
503			break;
504		case 'x':
505			if (lflag == 0) {
506				ui = va_arg(ap, u_int);
507				s = __uitoa(nbuf, ui, 16);
508			} else {
509				ul = va_arg(ap, u_long);
510				s = __ultoa(nbuf, ul, 16);
511			}
512			if (sflag)
513				ret += __puts("0x", putc, arg);
514			ret += __puts(s, putc, arg);
515			break;
516		case '0': case '1': case '2': case '3': case '4':
517		case '5': case '6': case '7': case '8': case '9':
518			pad = pad * 10 + c - '0';
519			goto reswitch;
520		default:
521			break;
522		}
523	}
524	return (ret);
525}
526
527static int
528__sputc(char c, void *arg)
529{
530	struct sp_data *sp;
531
532	sp = arg;
533	if (sp->sp_len < sp->sp_size)
534		sp->sp_buf[sp->sp_len++] = c;
535	sp->sp_buf[sp->sp_len] = '\0';
536	return (1);
537}
538
539static int
540__puts(const char *s, putc_func_t *putc, void *arg)
541{
542	const char *p;
543	int ret;
544
545	ret = 0;
546	for (p = s; *p != '\0'; p++)
547		ret += putc(*p, arg);
548	return (ret);
549}
550
551static char *
552__uitoa(char *buf, u_int ui, int base)
553{
554	char *p;
555
556	p = buf;
557	*p = '\0';
558	do
559		*--p = digits[ui % base];
560	while ((ui /= base) != 0);
561	return (p);
562}
563
564static char *
565__ultoa(char *buf, u_long ul, int base)
566{
567	char *p;
568
569	p = buf;
570	*p = '\0';
571	do
572		*--p = digits[ul % base];
573	while ((ul /= base) != 0);
574	return (p);
575}
576