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