boot1.c revision 293297
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: stable/10/sys/boot/efi/boot1/boot1.c 293297 2016-01-07 02:22:45Z emaste $");
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
62EFI_SYSTEM_TABLE *systab;
63EFI_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);
112	EFI_STATUS status;
113	EFI_DEVICE_PATH *devpath;
114	EFI_BOOT_SERVICES *BS;
115	EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL;
116	char *path = _PATH_LOADER;
117
118	systab = Xsystab;
119	image = Ximage;
120
121	BS = systab->BootServices;
122	status = BS->LocateProtocol(&ConsoleControlGUID, NULL,
123	    (VOID **)&ConsoleControl);
124	if (status == EFI_SUCCESS)
125		(void)ConsoleControl->SetMode(ConsoleControl,
126		    EfiConsoleControlScreenText);
127
128	printf(" \n>> FreeBSD EFI boot block\n");
129	printf("   Loader path: %s\n", path);
130
131	status = systab->BootServices->LocateHandle(ByProtocol,
132	    &BlockIoProtocolGUID, NULL, &nparts, handles);
133	nparts /= sizeof(handles[0]);
134
135	for (i = 0; i < nparts; i++) {
136		status = systab->BootServices->HandleProtocol(handles[i],
137		    &DevicePathGUID, (void **)&devpath);
138		if (EFI_ERROR(status))
139			continue;
140
141		while (!IsDevicePathEnd(NextDevicePathNode(devpath)))
142			devpath = NextDevicePathNode(devpath);
143
144		status = systab->BootServices->HandleProtocol(handles[i],
145		    &BlockIoProtocolGUID, (void **)&blkio);
146		if (EFI_ERROR(status))
147			continue;
148
149		if (!blkio->Media->LogicalPartition)
150			continue;
151
152		if (domount(devpath, blkio, 1) >= 0)
153			break;
154	}
155
156	if (i == nparts)
157		panic("No bootable partition found");
158
159	bootdevhandle = handles[i];
160	load(path);
161
162	panic("Load failed");
163
164	return EFI_SUCCESS;
165}
166
167static int
168dskread(void *buf, u_int64_t lba, int nblk)
169{
170	EFI_STATUS status;
171	int size;
172
173	lba = lba / (bootdev->Media->BlockSize / DEV_BSIZE);
174	size = nblk * DEV_BSIZE;
175	status = bootdev->ReadBlocks(bootdev, bootdev->Media->MediaId, lba,
176	    size, buf);
177
178	if (EFI_ERROR(status))
179		return (-1);
180
181	return (0);
182}
183
184#include "ufsread.c"
185
186static ssize_t
187fsstat(ufs_ino_t inode)
188{
189#ifndef UFS2_ONLY
190	static struct ufs1_dinode dp1;
191	ufs1_daddr_t addr1;
192#endif
193#ifndef UFS1_ONLY
194	static struct ufs2_dinode dp2;
195#endif
196	static struct fs fs;
197	static ufs_ino_t inomap;
198	char *blkbuf;
199	void *indbuf;
200	size_t n, nb, size, off, vboff;
201	ufs_lbn_t lbn;
202	ufs2_daddr_t addr2, vbaddr;
203	static ufs2_daddr_t blkmap, indmap;
204	u_int u;
205
206	blkbuf = dmadat->blkbuf;
207	indbuf = dmadat->indbuf;
208	if (!dsk_meta) {
209		inomap = 0;
210		for (n = 0; sblock_try[n] != -1; n++) {
211			if (dskread(dmadat->sbbuf, sblock_try[n] / DEV_BSIZE,
212			    SBLOCKSIZE / DEV_BSIZE))
213				return -1;
214			memcpy(&fs, dmadat->sbbuf, sizeof(struct fs));
215			if ((
216#if defined(UFS1_ONLY)
217			    fs.fs_magic == FS_UFS1_MAGIC
218#elif defined(UFS2_ONLY)
219			    (fs.fs_magic == FS_UFS2_MAGIC &&
220			    fs.fs_sblockloc == sblock_try[n])
221#else
222			    fs.fs_magic == FS_UFS1_MAGIC ||
223			    (fs.fs_magic == FS_UFS2_MAGIC &&
224			    fs.fs_sblockloc == sblock_try[n])
225#endif
226			    ) &&
227			    fs.fs_bsize <= MAXBSIZE &&
228			    fs.fs_bsize >= sizeof(struct fs))
229				break;
230		}
231		if (sblock_try[n] == -1) {
232			printf("Not ufs\n");
233			return -1;
234		}
235		dsk_meta++;
236	} else
237		memcpy(&fs, dmadat->sbbuf, sizeof(struct fs));
238	if (!inode)
239		return 0;
240	if (inomap != inode) {
241		n = IPERVBLK(&fs);
242		if (dskread(blkbuf, INO_TO_VBA(&fs, n, inode), DBPERVBLK))
243			return -1;
244		n = INO_TO_VBO(n, inode);
245#if defined(UFS1_ONLY)
246		memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n,
247		    sizeof(struct ufs1_dinode));
248#elif defined(UFS2_ONLY)
249		memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n,
250		    sizeof(struct ufs2_dinode));
251#else
252		if (fs.fs_magic == FS_UFS1_MAGIC)
253			memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n,
254			    sizeof(struct ufs1_dinode));
255		else
256			memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n,
257			    sizeof(struct ufs2_dinode));
258#endif
259		inomap = inode;
260		fs_off = 0;
261		blkmap = indmap = 0;
262	}
263	size = DIP(di_size);
264	n = size - fs_off;
265	return (n);
266}
267
268static struct dmadat __dmadat;
269
270static int
271domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet)
272{
273
274	dmadat = &__dmadat;
275	bootdev = blkio;
276	bootdevpath = device;
277	if (fsread(0, NULL, 0)) {
278		if (!quiet)
279			printf("domount: can't read superblock\n");
280		return (-1);
281	}
282	if (!quiet)
283		printf("Succesfully mounted UFS filesystem\n");
284	return (0);
285}
286
287static void
288load(const char *fname)
289{
290	ufs_ino_t ino;
291	EFI_STATUS status;
292	EFI_HANDLE loaderhandle;
293	EFI_LOADED_IMAGE *loaded_image;
294	void *buffer;
295	size_t bufsize;
296
297	if ((ino = lookup(fname)) == 0) {
298		printf("File %s not found\n", fname);
299		return;
300	}
301
302	bufsize = fsstat(ino);
303	status = systab->BootServices->AllocatePool(EfiLoaderData,
304	    bufsize, &buffer);
305	fsread(ino, buffer, bufsize);
306
307	/* XXX: For secure boot, we need our own loader here */
308	status = systab->BootServices->LoadImage(TRUE, image, bootdevpath,
309	    buffer, bufsize, &loaderhandle);
310	if (EFI_ERROR(status))
311		printf("LoadImage failed with error %d\n", status);
312
313	status = systab->BootServices->HandleProtocol(loaderhandle,
314	    &LoadedImageGUID, (VOID**)&loaded_image);
315	if (EFI_ERROR(status))
316		printf("HandleProtocol failed with error %d\n", status);
317
318	loaded_image->DeviceHandle = bootdevhandle;
319
320	status = systab->BootServices->StartImage(loaderhandle, NULL, NULL);
321	if (EFI_ERROR(status))
322		printf("StartImage failed with error %d\n", status);
323}
324
325static void
326panic(const char *fmt, ...)
327{
328	char buf[128];
329	va_list ap;
330
331	va_start(ap, fmt);
332	vsnprintf(buf, sizeof buf, fmt, ap);
333	printf("panic: %s\n", buf);
334	va_end(ap);
335
336	while (1) {}
337}
338
339static int
340printf(const char *fmt, ...)
341{
342	va_list ap;
343	int ret;
344
345	/* Don't annoy the user as we probe for partitions */
346	if (strcmp(fmt,"Not ufs\n") == 0)
347		return 0;
348
349	va_start(ap, fmt);
350	ret = vprintf(fmt, ap);
351	va_end(ap);
352	return (ret);
353}
354
355static int
356putchar(char c, void *arg)
357{
358	CHAR16 buf[2];
359
360	if (c == '\n') {
361		buf[0] = '\r';
362		buf[1] = 0;
363		systab->ConOut->OutputString(systab->ConOut, buf);
364	}
365	buf[0] = c;
366	buf[1] = 0;
367	systab->ConOut->OutputString(systab->ConOut, buf);
368	return (1);
369}
370
371static int
372vprintf(const char *fmt, va_list ap)
373{
374	int ret;
375
376	ret = __printf(fmt, putchar, 0, ap);
377	return (ret);
378}
379
380static int
381vsnprintf(char *str, size_t sz, const char *fmt, va_list ap)
382{
383	struct sp_data sp;
384	int ret;
385
386	sp.sp_buf = str;
387	sp.sp_len = 0;
388	sp.sp_size = sz;
389	ret = __printf(fmt, __sputc, &sp, ap);
390	return (ret);
391}
392
393static int
394__printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap)
395{
396	char buf[(sizeof(long) * 8) + 1];
397	char *nbuf;
398	u_long ul;
399	u_int ui;
400	int lflag;
401	int sflag;
402	char *s;
403	int pad;
404	int ret;
405	int c;
406
407	nbuf = &buf[sizeof buf - 1];
408	ret = 0;
409	while ((c = *fmt++) != 0) {
410		if (c != '%') {
411			ret += putc(c, arg);
412			continue;
413		}
414		lflag = 0;
415		sflag = 0;
416		pad = 0;
417reswitch:	c = *fmt++;
418		switch (c) {
419		case '#':
420			sflag = 1;
421			goto reswitch;
422		case '%':
423			ret += putc('%', arg);
424			break;
425		case 'c':
426			c = va_arg(ap, int);
427			ret += putc(c, arg);
428			break;
429		case 'd':
430			if (lflag == 0) {
431				ui = (u_int)va_arg(ap, int);
432				if (ui < (int)ui) {
433					ui = -ui;
434					ret += putc('-', arg);
435				}
436				s = __uitoa(nbuf, ui, 10);
437			} else {
438				ul = (u_long)va_arg(ap, long);
439				if (ul < (long)ul) {
440					ul = -ul;
441					ret += putc('-', arg);
442				}
443				s = __ultoa(nbuf, ul, 10);
444			}
445			ret += __puts(s, putc, arg);
446			break;
447		case 'l':
448			lflag = 1;
449			goto reswitch;
450		case 'o':
451			if (lflag == 0) {
452				ui = (u_int)va_arg(ap, u_int);
453				s = __uitoa(nbuf, ui, 8);
454			} else {
455				ul = (u_long)va_arg(ap, u_long);
456				s = __ultoa(nbuf, ul, 8);
457			}
458			ret += __puts(s, putc, arg);
459			break;
460		case 'p':
461			ul = (u_long)va_arg(ap, void *);
462			s = __ultoa(nbuf, ul, 16);
463			ret += __puts("0x", putc, arg);
464			ret += __puts(s, putc, arg);
465			break;
466		case 's':
467			s = va_arg(ap, char *);
468			ret += __puts(s, putc, arg);
469			break;
470		case 'u':
471			if (lflag == 0) {
472				ui = va_arg(ap, u_int);
473				s = __uitoa(nbuf, ui, 10);
474			} else {
475				ul = va_arg(ap, u_long);
476				s = __ultoa(nbuf, ul, 10);
477			}
478			ret += __puts(s, putc, arg);
479			break;
480		case 'x':
481			if (lflag == 0) {
482				ui = va_arg(ap, u_int);
483				s = __uitoa(nbuf, ui, 16);
484			} else {
485				ul = va_arg(ap, u_long);
486				s = __ultoa(nbuf, ul, 16);
487			}
488			if (sflag)
489				ret += __puts("0x", putc, arg);
490			ret += __puts(s, putc, arg);
491			break;
492		case '0': case '1': case '2': case '3': case '4':
493		case '5': case '6': case '7': case '8': case '9':
494			pad = pad * 10 + c - '0';
495			goto reswitch;
496		default:
497			break;
498		}
499	}
500	return (ret);
501}
502
503static int
504__sputc(char c, void *arg)
505{
506	struct sp_data *sp;
507
508	sp = arg;
509	if (sp->sp_len < sp->sp_size)
510		sp->sp_buf[sp->sp_len++] = c;
511	sp->sp_buf[sp->sp_len] = '\0';
512	return (1);
513}
514
515static int
516__puts(const char *s, putc_func_t *putc, void *arg)
517{
518	const char *p;
519	int ret;
520
521	ret = 0;
522	for (p = s; *p != '\0'; p++)
523		ret += putc(*p, arg);
524	return (ret);
525}
526
527static char *
528__uitoa(char *buf, u_int ui, int base)
529{
530	char *p;
531
532	p = buf;
533	*p = '\0';
534	do
535		*--p = digits[ui % base];
536	while ((ui /= base) != 0);
537	return (p);
538}
539
540static char *
541__ultoa(char *buf, u_long ul, int base)
542{
543	char *p;
544
545	p = buf;
546	*p = '\0';
547	do
548		*--p = digits[ul % base];
549	while ((ul /= base) != 0);
550	return (p);
551}
552
553