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