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