boot1.c revision 294721
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 294721 2016-01-25 10:55:52Z 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			return -1;
253		}
254		dsk_meta++;
255	} else
256		memcpy(&fs, dmadat->sbbuf, sizeof(struct fs));
257	if (!inode)
258		return 0;
259	if (inomap != inode) {
260		n = IPERVBLK(&fs);
261		if (dskread(blkbuf, INO_TO_VBA(&fs, n, inode), DBPERVBLK))
262			return -1;
263		n = INO_TO_VBO(n, inode);
264#if defined(UFS1_ONLY)
265		memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n,
266		    sizeof(struct ufs1_dinode));
267#elif defined(UFS2_ONLY)
268		memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n,
269		    sizeof(struct ufs2_dinode));
270#else
271		if (fs.fs_magic == FS_UFS1_MAGIC)
272			memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n,
273			    sizeof(struct ufs1_dinode));
274		else
275			memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n,
276			    sizeof(struct ufs2_dinode));
277#endif
278		inomap = inode;
279		fs_off = 0;
280		blkmap = indmap = 0;
281	}
282	size = DIP(di_size);
283	n = size - fs_off;
284	return (n);
285}
286
287static struct dmadat __dmadat;
288
289static int
290domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet)
291{
292
293	dmadat = &__dmadat;
294	bootdev = blkio;
295	bootdevpath = device;
296	if (fsread(0, NULL, 0)) {
297		if (!quiet)
298			printf("domount: can't read superblock\n");
299		return (-1);
300	}
301	if (!quiet)
302		printf("Succesfully mounted UFS filesystem\n");
303	return (0);
304}
305
306static void
307load(const char *fname)
308{
309	ufs_ino_t ino;
310	EFI_STATUS status;
311	EFI_HANDLE loaderhandle;
312	EFI_LOADED_IMAGE *loaded_image;
313	void *buffer;
314	size_t bufsize;
315
316	if ((ino = lookup(fname)) == 0) {
317		printf("File %s not found\n", fname);
318		return;
319	}
320
321	bufsize = fsstat(ino);
322	status = systab->BootServices->AllocatePool(EfiLoaderData,
323	    bufsize, &buffer);
324	fsread(ino, buffer, bufsize);
325
326	/* XXX: For secure boot, we need our own loader here */
327	status = systab->BootServices->LoadImage(TRUE, image, bootdevpath,
328	    buffer, bufsize, &loaderhandle);
329	if (EFI_ERROR(status))
330		printf("LoadImage failed with error %lu\n",
331		    EFI_ERROR_CODE(status));
332
333	status = systab->BootServices->HandleProtocol(loaderhandle,
334	    &LoadedImageGUID, (VOID**)&loaded_image);
335	if (EFI_ERROR(status))
336		printf("HandleProtocol failed with error %lu\n",
337		    EFI_ERROR_CODE(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 %lu\n",
344		    EFI_ERROR_CODE(status));
345}
346
347static void
348panic(const char *fmt, ...)
349{
350	char buf[128];
351	va_list ap;
352
353	va_start(ap, fmt);
354	vsnprintf(buf, sizeof buf, fmt, ap);
355	printf("panic: %s\n", buf);
356	va_end(ap);
357
358	while (1) {}
359}
360
361static int
362printf(const char *fmt, ...)
363{
364	va_list ap;
365	int ret;
366
367	/* Don't annoy the user as we probe for partitions */
368	if (strcmp(fmt,"Not ufs\n") == 0)
369		return 0;
370
371	va_start(ap, fmt);
372	ret = vprintf(fmt, ap);
373	va_end(ap);
374	return (ret);
375}
376
377static int
378putchar(char c, void *arg)
379{
380	CHAR16 buf[2];
381
382	if (c == '\n') {
383		buf[0] = '\r';
384		buf[1] = 0;
385		systab->ConOut->OutputString(systab->ConOut, buf);
386	}
387	buf[0] = c;
388	buf[1] = 0;
389	systab->ConOut->OutputString(systab->ConOut, buf);
390	return (1);
391}
392
393static int
394vprintf(const char *fmt, va_list ap)
395{
396	int ret;
397
398	ret = __printf(fmt, putchar, 0, ap);
399	return (ret);
400}
401
402static int
403vsnprintf(char *str, size_t sz, const char *fmt, va_list ap)
404{
405	struct sp_data sp;
406	int ret;
407
408	sp.sp_buf = str;
409	sp.sp_len = 0;
410	sp.sp_size = sz;
411	ret = __printf(fmt, __sputc, &sp, ap);
412	return (ret);
413}
414
415static int
416__printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap)
417{
418	char buf[(sizeof(long) * 8) + 1];
419	char *nbuf;
420	u_long ul;
421	u_int ui;
422	int lflag;
423	int sflag;
424	char *s;
425	int pad;
426	int ret;
427	int c;
428
429	nbuf = &buf[sizeof buf - 1];
430	ret = 0;
431	while ((c = *fmt++) != 0) {
432		if (c != '%') {
433			ret += putc(c, arg);
434			continue;
435		}
436		lflag = 0;
437		sflag = 0;
438		pad = 0;
439reswitch:	c = *fmt++;
440		switch (c) {
441		case '#':
442			sflag = 1;
443			goto reswitch;
444		case '%':
445			ret += putc('%', arg);
446			break;
447		case 'c':
448			c = va_arg(ap, int);
449			ret += putc(c, arg);
450			break;
451		case 'd':
452			if (lflag == 0) {
453				ui = (u_int)va_arg(ap, int);
454				if (ui < (int)ui) {
455					ui = -ui;
456					ret += putc('-', arg);
457				}
458				s = __uitoa(nbuf, ui, 10);
459			} else {
460				ul = (u_long)va_arg(ap, long);
461				if (ul < (long)ul) {
462					ul = -ul;
463					ret += putc('-', arg);
464				}
465				s = __ultoa(nbuf, ul, 10);
466			}
467			ret += __puts(s, putc, arg);
468			break;
469		case 'l':
470			lflag = 1;
471			goto reswitch;
472		case 'o':
473			if (lflag == 0) {
474				ui = (u_int)va_arg(ap, u_int);
475				s = __uitoa(nbuf, ui, 8);
476			} else {
477				ul = (u_long)va_arg(ap, u_long);
478				s = __ultoa(nbuf, ul, 8);
479			}
480			ret += __puts(s, putc, arg);
481			break;
482		case 'p':
483			ul = (u_long)va_arg(ap, void *);
484			s = __ultoa(nbuf, ul, 16);
485			ret += __puts("0x", putc, arg);
486			ret += __puts(s, putc, arg);
487			break;
488		case 's':
489			s = va_arg(ap, char *);
490			ret += __puts(s, putc, arg);
491			break;
492		case 'u':
493			if (lflag == 0) {
494				ui = va_arg(ap, u_int);
495				s = __uitoa(nbuf, ui, 10);
496			} else {
497				ul = va_arg(ap, u_long);
498				s = __ultoa(nbuf, ul, 10);
499			}
500			ret += __puts(s, putc, arg);
501			break;
502		case 'x':
503			if (lflag == 0) {
504				ui = va_arg(ap, u_int);
505				s = __uitoa(nbuf, ui, 16);
506			} else {
507				ul = va_arg(ap, u_long);
508				s = __ultoa(nbuf, ul, 16);
509			}
510			if (sflag)
511				ret += __puts("0x", putc, arg);
512			ret += __puts(s, putc, arg);
513			break;
514		case '0': case '1': case '2': case '3': case '4':
515		case '5': case '6': case '7': case '8': case '9':
516			pad = pad * 10 + c - '0';
517			goto reswitch;
518		default:
519			break;
520		}
521	}
522	return (ret);
523}
524
525static int
526__sputc(char c, void *arg)
527{
528	struct sp_data *sp;
529
530	sp = arg;
531	if (sp->sp_len < sp->sp_size)
532		sp->sp_buf[sp->sp_len++] = c;
533	sp->sp_buf[sp->sp_len] = '\0';
534	return (1);
535}
536
537static int
538__puts(const char *s, putc_func_t *putc, void *arg)
539{
540	const char *p;
541	int ret;
542
543	ret = 0;
544	for (p = s; *p != '\0'; p++)
545		ret += putc(*p, arg);
546	return (ret);
547}
548
549static char *
550__uitoa(char *buf, u_int ui, int base)
551{
552	char *p;
553
554	p = buf;
555	*p = '\0';
556	do
557		*--p = digits[ui % base];
558	while ((ui /= base) != 0);
559	return (p);
560}
561
562static char *
563__ultoa(char *buf, u_long ul, int base)
564{
565	char *p;
566
567	p = buf;
568	*p = '\0';
569	do
570		*--p = digits[ul % base];
571	while ((ul /= base) != 0);
572	return (p);
573}
574