boot1.c revision 293299
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 293299 2016-01-07 02:37:17Z 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 %lu\n",
312		    status & ~EFI_ERROR_MASK);
313
314	status = systab->BootServices->HandleProtocol(loaderhandle,
315	    &LoadedImageGUID, (VOID**)&loaded_image);
316	if (EFI_ERROR(status))
317		printf("HandleProtocol failed with error %lu\n",
318		    status & ~EFI_ERROR_MASK);
319
320	loaded_image->DeviceHandle = bootdevhandle;
321
322	status = systab->BootServices->StartImage(loaderhandle, NULL, NULL);
323	if (EFI_ERROR(status))
324		printf("StartImage failed with error %lu\n",
325		    status & ~EFI_ERROR_MASK);
326}
327
328static void
329panic(const char *fmt, ...)
330{
331	char buf[128];
332	va_list ap;
333
334	va_start(ap, fmt);
335	vsnprintf(buf, sizeof buf, fmt, ap);
336	printf("panic: %s\n", buf);
337	va_end(ap);
338
339	while (1) {}
340}
341
342static int
343printf(const char *fmt, ...)
344{
345	va_list ap;
346	int ret;
347
348	/* Don't annoy the user as we probe for partitions */
349	if (strcmp(fmt,"Not ufs\n") == 0)
350		return 0;
351
352	va_start(ap, fmt);
353	ret = vprintf(fmt, ap);
354	va_end(ap);
355	return (ret);
356}
357
358static int
359putchar(char c, void *arg)
360{
361	CHAR16 buf[2];
362
363	if (c == '\n') {
364		buf[0] = '\r';
365		buf[1] = 0;
366		systab->ConOut->OutputString(systab->ConOut, buf);
367	}
368	buf[0] = c;
369	buf[1] = 0;
370	systab->ConOut->OutputString(systab->ConOut, buf);
371	return (1);
372}
373
374static int
375vprintf(const char *fmt, va_list ap)
376{
377	int ret;
378
379	ret = __printf(fmt, putchar, 0, ap);
380	return (ret);
381}
382
383static int
384vsnprintf(char *str, size_t sz, const char *fmt, va_list ap)
385{
386	struct sp_data sp;
387	int ret;
388
389	sp.sp_buf = str;
390	sp.sp_len = 0;
391	sp.sp_size = sz;
392	ret = __printf(fmt, __sputc, &sp, ap);
393	return (ret);
394}
395
396static int
397__printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap)
398{
399	char buf[(sizeof(long) * 8) + 1];
400	char *nbuf;
401	u_long ul;
402	u_int ui;
403	int lflag;
404	int sflag;
405	char *s;
406	int pad;
407	int ret;
408	int c;
409
410	nbuf = &buf[sizeof buf - 1];
411	ret = 0;
412	while ((c = *fmt++) != 0) {
413		if (c != '%') {
414			ret += putc(c, arg);
415			continue;
416		}
417		lflag = 0;
418		sflag = 0;
419		pad = 0;
420reswitch:	c = *fmt++;
421		switch (c) {
422		case '#':
423			sflag = 1;
424			goto reswitch;
425		case '%':
426			ret += putc('%', arg);
427			break;
428		case 'c':
429			c = va_arg(ap, int);
430			ret += putc(c, arg);
431			break;
432		case 'd':
433			if (lflag == 0) {
434				ui = (u_int)va_arg(ap, int);
435				if (ui < (int)ui) {
436					ui = -ui;
437					ret += putc('-', arg);
438				}
439				s = __uitoa(nbuf, ui, 10);
440			} else {
441				ul = (u_long)va_arg(ap, long);
442				if (ul < (long)ul) {
443					ul = -ul;
444					ret += putc('-', arg);
445				}
446				s = __ultoa(nbuf, ul, 10);
447			}
448			ret += __puts(s, putc, arg);
449			break;
450		case 'l':
451			lflag = 1;
452			goto reswitch;
453		case 'o':
454			if (lflag == 0) {
455				ui = (u_int)va_arg(ap, u_int);
456				s = __uitoa(nbuf, ui, 8);
457			} else {
458				ul = (u_long)va_arg(ap, u_long);
459				s = __ultoa(nbuf, ul, 8);
460			}
461			ret += __puts(s, putc, arg);
462			break;
463		case 'p':
464			ul = (u_long)va_arg(ap, void *);
465			s = __ultoa(nbuf, ul, 16);
466			ret += __puts("0x", putc, arg);
467			ret += __puts(s, putc, arg);
468			break;
469		case 's':
470			s = va_arg(ap, char *);
471			ret += __puts(s, putc, arg);
472			break;
473		case 'u':
474			if (lflag == 0) {
475				ui = va_arg(ap, u_int);
476				s = __uitoa(nbuf, ui, 10);
477			} else {
478				ul = va_arg(ap, u_long);
479				s = __ultoa(nbuf, ul, 10);
480			}
481			ret += __puts(s, putc, arg);
482			break;
483		case 'x':
484			if (lflag == 0) {
485				ui = va_arg(ap, u_int);
486				s = __uitoa(nbuf, ui, 16);
487			} else {
488				ul = va_arg(ap, u_long);
489				s = __ultoa(nbuf, ul, 16);
490			}
491			if (sflag)
492				ret += __puts("0x", putc, arg);
493			ret += __puts(s, putc, arg);
494			break;
495		case '0': case '1': case '2': case '3': case '4':
496		case '5': case '6': case '7': case '8': case '9':
497			pad = pad * 10 + c - '0';
498			goto reswitch;
499		default:
500			break;
501		}
502	}
503	return (ret);
504}
505
506static int
507__sputc(char c, void *arg)
508{
509	struct sp_data *sp;
510
511	sp = arg;
512	if (sp->sp_len < sp->sp_size)
513		sp->sp_buf[sp->sp_len++] = c;
514	sp->sp_buf[sp->sp_len] = '\0';
515	return (1);
516}
517
518static int
519__puts(const char *s, putc_func_t *putc, void *arg)
520{
521	const char *p;
522	int ret;
523
524	ret = 0;
525	for (p = s; *p != '\0'; p++)
526		ret += putc(*p, arg);
527	return (ret);
528}
529
530static char *
531__uitoa(char *buf, u_int ui, int base)
532{
533	char *p;
534
535	p = buf;
536	*p = '\0';
537	do
538		*--p = digits[ui % base];
539	while ((ui /= base) != 0);
540	return (p);
541}
542
543static char *
544__ultoa(char *buf, u_long ul, int base)
545{
546	char *p;
547
548	p = buf;
549	*p = '\0';
550	do
551		*--p = digits[ul % base];
552	while ((ul /= base) != 0);
553	return (p);
554}
555
556