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