2 * Copyright (c) 1998 Robert Nordier
4 * Copyright (c) 2001 Robert Drehmel
6 * Copyright (c) 2014 Nathan Whitehorn
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
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
20 #include <sys/cdefs.h>
21 __FBSDID("$FreeBSD$");
23 #include <sys/param.h>
24 #include <sys/dirent.h>
25 #include <machine/elf.h>
26 #include <machine/stdarg.h>
29 #include <eficonsctl.h>
31 #define _PATH_LOADER "/boot/loader.efi"
32 #define _PATH_KERNEL "/boot/kernel/kernel"
34 #define BSIZEMAX 16384
36 typedef int putc_func_t(char c, void *arg);
44 static const char digits[] = "0123456789abcdef";
46 static void panic(const char *fmt, ...) __dead2;
47 static int printf(const char *fmt, ...);
48 static int putchar(char c, void *arg);
49 static int vprintf(const char *fmt, va_list ap);
50 static int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap);
52 static int __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap);
53 static int __putc(char c, void *arg);
54 static int __puts(const char *s, putc_func_t *putc, void *arg);
55 static int __sputc(char c, void *arg);
56 static char *__uitoa(char *buf, u_int val, int base);
57 static char *__ultoa(char *buf, u_long val, int base);
59 static int domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet);
60 static void load(const char *fname);
62 EFI_SYSTEM_TABLE *systab;
66 bcopy(const void *src, void *dst, size_t len)
76 memcpy(void *dst, const void *src, size_t len)
82 bzero(void *b, size_t len)
91 strcmp(const char *s1, const char *s2)
93 for (; *s1 == *s2 && *s1; s1++, s2++)
95 return ((u_char)*s1 - (u_char)*s2);
98 static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL;
99 static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL;
100 static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL;
101 static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
103 static EFI_BLOCK_IO *bootdev;
104 static EFI_DEVICE_PATH *bootdevpath;
105 static EFI_HANDLE *bootdevhandle;
107 EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab)
109 EFI_HANDLE handles[128];
111 UINTN i, nparts = sizeof(handles), cols, rows, max_dim, best_mode;
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;
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);
129 * Reset the console and find the best text mode.
131 conout = systab->ConOut;
132 conout->Reset(conout, TRUE);
133 max_dim = best_mode = 0;
135 status = conout->QueryMode(conout, i,
137 if (EFI_ERROR(status))
139 if (cols * rows > max_dim) {
140 max_dim = cols * rows;
145 conout->SetMode(conout, best_mode);
146 conout->EnableCursor(conout, TRUE);
147 conout->ClearScreen(conout);
149 printf(" \n>> FreeBSD EFI boot block\n");
150 printf(" Loader path: %s\n", path);
152 status = systab->BootServices->LocateHandle(ByProtocol,
153 &BlockIoProtocolGUID, NULL, &nparts, handles);
154 nparts /= sizeof(handles[0]);
156 for (i = 0; i < nparts; i++) {
157 status = systab->BootServices->HandleProtocol(handles[i],
158 &DevicePathGUID, (void **)&devpath);
159 if (EFI_ERROR(status))
162 while (!IsDevicePathEnd(NextDevicePathNode(devpath)))
163 devpath = NextDevicePathNode(devpath);
165 status = systab->BootServices->HandleProtocol(handles[i],
166 &BlockIoProtocolGUID, (void **)&blkio);
167 if (EFI_ERROR(status))
170 if (!blkio->Media->LogicalPartition)
173 if (domount(devpath, blkio, 1) >= 0)
178 panic("No bootable partition found");
180 bootdevhandle = handles[i];
183 panic("Load failed");
189 dskread(void *buf, u_int64_t lba, int nblk)
194 lba = lba / (bootdev->Media->BlockSize / DEV_BSIZE);
195 size = nblk * DEV_BSIZE;
196 status = bootdev->ReadBlocks(bootdev, bootdev->Media->MediaId, lba,
199 if (EFI_ERROR(status))
208 fsstat(ufs_ino_t inode)
211 static struct ufs1_dinode dp1;
215 static struct ufs2_dinode dp2;
218 static ufs_ino_t inomap;
221 size_t n, nb, size, off, vboff;
223 ufs2_daddr_t addr2, vbaddr;
224 static ufs2_daddr_t blkmap, indmap;
227 blkbuf = dmadat->blkbuf;
228 indbuf = dmadat->indbuf;
231 for (n = 0; sblock_try[n] != -1; n++) {
232 if (dskread(dmadat->sbbuf, sblock_try[n] / DEV_BSIZE,
233 SBLOCKSIZE / DEV_BSIZE))
235 memcpy(&fs, dmadat->sbbuf, sizeof(struct fs));
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])
243 fs.fs_magic == FS_UFS1_MAGIC ||
244 (fs.fs_magic == FS_UFS2_MAGIC &&
245 fs.fs_sblockloc == sblock_try[n])
248 fs.fs_bsize <= MAXBSIZE &&
249 fs.fs_bsize >= sizeof(struct fs))
252 if (sblock_try[n] == -1) {
258 memcpy(&fs, dmadat->sbbuf, sizeof(struct fs));
261 if (inomap != inode) {
263 if (dskread(blkbuf, INO_TO_VBA(&fs, n, inode), DBPERVBLK))
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));
273 if (fs.fs_magic == FS_UFS1_MAGIC)
274 memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n,
275 sizeof(struct ufs1_dinode));
277 memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n,
278 sizeof(struct ufs2_dinode));
289 static struct dmadat __dmadat;
292 domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet)
297 bootdevpath = device;
298 if (fsread(0, NULL, 0)) {
300 printf("domount: can't read superblock\n");
304 printf("Succesfully mounted UFS filesystem\n");
309 load(const char *fname)
313 EFI_HANDLE loaderhandle;
314 EFI_LOADED_IMAGE *loaded_image;
318 if ((ino = lookup(fname)) == 0) {
319 printf("File %s not found\n", fname);
323 bufsize = fsstat(ino);
324 status = systab->BootServices->AllocatePool(EfiLoaderData,
326 fsread(ino, buffer, bufsize);
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 %lu\n",
333 EFI_ERROR_CODE(status));
335 status = systab->BootServices->HandleProtocol(loaderhandle,
336 &LoadedImageGUID, (VOID**)&loaded_image);
337 if (EFI_ERROR(status))
338 printf("HandleProtocol failed with error %lu\n",
339 EFI_ERROR_CODE(status));
341 loaded_image->DeviceHandle = bootdevhandle;
343 status = systab->BootServices->StartImage(loaderhandle, NULL, NULL);
344 if (EFI_ERROR(status))
345 printf("StartImage failed with error %lu\n",
346 EFI_ERROR_CODE(status));
350 panic(const char *fmt, ...)
356 vsnprintf(buf, sizeof buf, fmt, ap);
357 printf("panic: %s\n", buf);
364 printf(const char *fmt, ...)
369 /* Don't annoy the user as we probe for partitions */
370 if (strcmp(fmt,"Not ufs\n") == 0)
374 ret = vprintf(fmt, ap);
380 putchar(char c, void *arg)
387 systab->ConOut->OutputString(systab->ConOut, buf);
391 systab->ConOut->OutputString(systab->ConOut, buf);
396 vprintf(const char *fmt, va_list ap)
400 ret = __printf(fmt, putchar, 0, ap);
405 vsnprintf(char *str, size_t sz, const char *fmt, va_list ap)
413 ret = __printf(fmt, __sputc, &sp, ap);
418 __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap)
420 char buf[(sizeof(long) * 8) + 1];
431 nbuf = &buf[sizeof buf - 1];
433 while ((c = *fmt++) != 0) {
441 reswitch: c = *fmt++;
447 ret += putc('%', arg);
455 ui = (u_int)va_arg(ap, int);
458 ret += putc('-', arg);
460 s = __uitoa(nbuf, ui, 10);
462 ul = (u_long)va_arg(ap, long);
465 ret += putc('-', arg);
467 s = __ultoa(nbuf, ul, 10);
469 ret += __puts(s, putc, arg);
476 ui = (u_int)va_arg(ap, u_int);
477 s = __uitoa(nbuf, ui, 8);
479 ul = (u_long)va_arg(ap, u_long);
480 s = __ultoa(nbuf, ul, 8);
482 ret += __puts(s, putc, arg);
485 ul = (u_long)va_arg(ap, void *);
486 s = __ultoa(nbuf, ul, 16);
487 ret += __puts("0x", putc, arg);
488 ret += __puts(s, putc, arg);
491 s = va_arg(ap, char *);
492 ret += __puts(s, putc, arg);
496 ui = va_arg(ap, u_int);
497 s = __uitoa(nbuf, ui, 10);
499 ul = va_arg(ap, u_long);
500 s = __ultoa(nbuf, ul, 10);
502 ret += __puts(s, putc, arg);
506 ui = va_arg(ap, u_int);
507 s = __uitoa(nbuf, ui, 16);
509 ul = va_arg(ap, u_long);
510 s = __ultoa(nbuf, ul, 16);
513 ret += __puts("0x", putc, arg);
514 ret += __puts(s, putc, arg);
516 case '0': case '1': case '2': case '3': case '4':
517 case '5': case '6': case '7': case '8': case '9':
518 pad = pad * 10 + c - '0';
528 __sputc(char c, void *arg)
533 if (sp->sp_len < sp->sp_size)
534 sp->sp_buf[sp->sp_len++] = c;
535 sp->sp_buf[sp->sp_len] = '\0';
540 __puts(const char *s, putc_func_t *putc, void *arg)
546 for (p = s; *p != '\0'; p++)
547 ret += putc(*p, arg);
552 __uitoa(char *buf, u_int ui, int base)
559 *--p = digits[ui % base];
560 while ((ui /= base) != 0);
565 __ultoa(char *buf, u_long ul, int base)
572 *--p = digits[ul % base];
573 while ((ul /= base) != 0);