Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F153154299
D4104.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
39 KB
Referenced Files
None
Subscribers
None
D4104.diff
View Options
Index: sys/boot/efi/boot1/Makefile
===================================================================
--- sys/boot/efi/boot1/Makefile
+++ sys/boot/efi/boot1/Makefile
@@ -13,7 +13,7 @@
INTERNALPROG=
# architecture-specific loader code
-SRCS= boot1.c self_reloc.c start.S
+SRCS= boot1.c self_reloc.c start.S ufs_module.c zfs_module.c
CFLAGS+= -I.
CFLAGS+= -I${.CURDIR}/../include
@@ -20,6 +20,8 @@
CFLAGS+= -I${.CURDIR}/../include/${MACHINE}
CFLAGS+= -I${.CURDIR}/../../../contrib/dev/acpica/include
CFLAGS+= -I${.CURDIR}/../../..
+CFLAGS+= -I${.CURDIR}/../../zfs/
+CFLAGS+= -I${.CURDIR}/../../../cddl/boot/zfs/
# Always add MI sources and REGULAR efi loader bits
.PATH: ${.CURDIR}/../loader/arch/${MACHINE}
Index: sys/boot/efi/boot1/boot1.c
===================================================================
--- sys/boot/efi/boot1/boot1.c
+++ sys/boot/efi/boot1/boot1.c
@@ -5,6 +5,8 @@
* All rights reserved.
* Copyright (c) 2014 Nathan Whitehorn
* All rights reserved.
+ * Copyright (c) 2015 Eric McCorkle
+ * All rights reverved.
*
* Redistribution and use in source and binary forms are freely
* permitted provided that the above copyright notice and this
@@ -21,7 +23,6 @@
__FBSDID("$FreeBSD$");
#include <sys/param.h>
-#include <sys/dirent.h>
#include <machine/elf.h>
#include <machine/stdarg.h>
@@ -28,6 +29,8 @@
#include <efi.h>
#include <eficonsctl.h>
+#include "boot_module.h"
+
#define _PATH_LOADER "/boot/loader.efi"
#define _PATH_KERNEL "/boot/kernel/kernel"
@@ -41,14 +44,20 @@
u_int sp_size;
};
+static const boot_module_t* const boot_modules[] =
+{
+#ifdef ZFS_EFI_BOOT
+ &zfs_module,
+#endif
+#ifdef UFS_EFI_BOOT
+ &ufs_module
+#endif
+};
+
+#define NUM_BOOT_MODULES (sizeof(boot_modules) / sizeof(boot_module_t*))
+
static const char digits[] = "0123456789abcdef";
-static void panic(const char *fmt, ...) __dead2;
-static int printf(const char *fmt, ...);
-static int putchar(char c, void *arg);
-static int vprintf(const char *fmt, va_list ap);
-static int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap);
-
static int __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap);
static int __putc(char c, void *arg);
static int __puts(const char *s, putc_func_t *putc, void *arg);
@@ -58,11 +67,101 @@
static int domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet);
static void load(const char *fname);
+static void try_load(const boot_module_t* mod, const dev_info_t devs[],
+ size_t ndevs);
static EFI_SYSTEM_TABLE *systab;
static EFI_HANDLE *image;
-static void
+void*
+Malloc(size_t len, const char *file, int line)
+{
+ void* out;
+ if (systab->BootServices->AllocatePool(EfiLoaderData,
+ len, &out) !=
+ EFI_SUCCESS) {
+ printf("Can't allocate memory pool\n");
+ return NULL;
+ }
+ return out;
+}
+
+char*
+strcpy(char *dst, const char *src) {
+ int i;
+ for(i = 0; src[i]; i++)
+ dst[i] = src[i];
+
+ return dst;
+}
+
+char*
+strchr(const char *s, int c) {
+ int i;
+ for(i = 0; s[i]; i++)
+ if (s[i] == c)
+ return (char*)(s + i);
+
+ return NULL;
+}
+
+int
+strncmp(const char *a, const char *b, size_t len)
+{
+ int i;
+ for (i = 0; i < len; i++)
+ if(a[i] == '\0' && b[i] == '\0') {
+ return 0;
+ } else if(a[i] < b[i]) {
+ return -1;
+ } else if(a[i] > b[i]) {
+ return 1;
+ }
+
+ return 0;
+}
+
+size_t
+strlen(const char *s) {
+ size_t len = 0;
+ for(; *s != '\0'; s++, len++);
+
+ return len;
+}
+
+char*
+strdup(const char *s) {
+ const int len = strlen(s);
+ char* const out = malloc(len);
+ int i;
+
+ for(i = 0; i < len; i++)
+ out[i] = s[i];
+
+ return out;
+}
+
+int
+bcmp(const void *a, const void *b, size_t len)
+{
+ const char *sa = a;
+ const char *sb = b;
+ int i;
+
+ for (i = 0; i < len; i++)
+ if(sa[i] != sb[i])
+ return 1;
+
+ return 0;
+}
+
+int
+memcmp(const void *a, const void *b, size_t len)
+{
+ return bcmp(a, b, len);
+}
+
+void
bcopy(const void *src, void *dst, size_t len)
{
const char *s = src;
@@ -72,22 +171,25 @@
*d++ = *s++;
}
-static void
+void*
memcpy(void *dst, const void *src, size_t len)
{
bcopy(src, dst, len);
+ return dst;
}
-static void
-bzero(void *b, size_t len)
+void*
+memset(void *b, int val, size_t len)
{
char *p = b;
while (len-- != 0)
- *p++ = 0;
+ *p++ = val;
+
+ return b;
}
-static int
+int
strcmp(const char *s1, const char *s2)
{
for (; *s1 == *s2 && *s1; s1++, s2++)
@@ -95,30 +197,92 @@
return ((u_char)*s1 - (u_char)*s2);
}
+int
+putchr(char c, void *arg)
+{
+ CHAR16 buf[2];
+
+ if (c == '\n') {
+ buf[0] = '\r';
+ buf[1] = 0;
+ systab->ConOut->OutputString(systab->ConOut, buf);
+ }
+ buf[0] = c;
+ buf[1] = 0;
+ systab->ConOut->OutputString(systab->ConOut, buf);
+ return (1);
+}
+
static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL;
static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL;
static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL;
static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
-static EFI_BLOCK_IO *bootdev;
-static EFI_DEVICE_PATH *bootdevpath;
-static EFI_HANDLE *bootdevhandle;
+#define MAX_DEVS 128
-EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab)
+/*
+ * This function only returns if it fails to load the kernel. If it
+ * succeeds, it simply boots the kernel.
+ */
+void
+try_load(const boot_module_t* mod, const dev_info_t devs[], size_t ndevs)
{
- EFI_HANDLE handles[128];
+ int idx;
+ size_t bufsize;
+ void* const buffer = mod->load(devs, ndevs, _PATH_LOADER,
+ &idx, &bufsize);
+ EFI_HANDLE loaderhandle;
+ EFI_LOADED_IMAGE *loaded_image;
+
+ if (buffer == NULL) {
+ printf("Could not load file\n");
+ return;
+ }
+ if (systab->BootServices->LoadImage(TRUE, image, devs[idx].devpath,
+ buffer, bufsize, &loaderhandle) !=
+ EFI_SUCCESS)
+ return;
+
+ if (systab->BootServices->HandleProtocol(loaderhandle,
+ &LoadedImageGUID,
+ (VOID**)&loaded_image) !=
+ EFI_SUCCESS)
+ return;
+
+ loaded_image->DeviceHandle = devs[idx].devhandle;
+
+ if (systab->BootServices->StartImage(loaderhandle, NULL, NULL) !=
+ EFI_SUCCESS)
+ return;
+}
+
+void
+efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab)
+{
+ EFI_HANDLE handles[MAX_DEVS];
+ dev_info_t module_devs[NUM_BOOT_MODULES][MAX_DEVS];
+ size_t dev_offsets[NUM_BOOT_MODULES];
EFI_BLOCK_IO *blkio;
- UINTN i, nparts = sizeof(handles), cols, rows, max_dim, best_mode;
+ UINTN nparts = sizeof(handles);
EFI_STATUS status;
EFI_DEVICE_PATH *devpath;
EFI_BOOT_SERVICES *BS;
EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL;
SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL;
- char *path = _PATH_LOADER;
+ UINTN i;
+ UINTN j;
+ UINTN max_dim;
+ UINTN best_mode;
+ UINTN cols;
+ UINTN rows;
+ /* Basic initialization*/
systab = Xsystab;
image = Ximage;
+ memset(dev_offsets, 0, NUM_BOOT_MODULES * sizeof(size_t));
+
+ /* Set up the console, so printf works. */
BS = systab->BootServices;
status = BS->LocateProtocol(&ConsoleControlGUID, NULL,
(VOID **)&ConsoleControl);
@@ -148,13 +312,27 @@
printf("\n"
">> FreeBSD EFI boot block\n");
- printf(" Loader path: %s\n", path);
+ printf(" Loader path: %s\n\n", _PATH_LOADER);
+ printf(" Initializing modules:");
+ for(i = 0; i < NUM_BOOT_MODULES; i++) {
+ if (NULL != boot_modules[i]) {
+ printf(" %s", boot_modules[i]->name);
+ boot_modules[i]->init(image, systab, BS);
+ }
+ }
+ putchr('\n', NULL);
+
+ /* Get all the device handles */
status = systab->BootServices->LocateHandle(ByProtocol,
&BlockIoProtocolGUID, NULL, &nparts, handles);
nparts /= sizeof(handles[0]);
+ /* Scan all partitions, probing with all modules. */
for (i = 0; i < nparts; i++) {
+ dev_info_t devinfo;
+
+ /* Figure out if we're dealing with an actual partition. */
status = systab->BootServices->HandleProtocol(handles[i],
&DevicePathGUID, (void **)&devpath);
if (EFI_ERROR(status))
@@ -170,181 +348,38 @@
if (!blkio->Media->LogicalPartition)
continue;
+ /* Setup devinfo */
+ devinfo.dev = blkio;
+ devinfo.devpath = devpath;
+ devinfo.devhandle = handles[i];
+ devinfo.devdata = NULL;
- if (domount(devpath, blkio, 1) >= 0)
- break;
+ /* Run through each module, see if it can load this partition */
+ for (j = 0; j < NUM_BOOT_MODULES; j++ ) {
+ if (NULL != boot_modules[j] &&
+ boot_modules[j]->probe(&devinfo)) {
+ /* If it can, save it to the device list for
+ * that module.
+ */
+ module_devs[j][dev_offsets[j]++] = devinfo;
+ }
+ }
}
- if (i == nparts)
- panic("No bootable partition found");
+ /*
+ * Select a partition to boot. We do this by trying each
+ * module in order.
+ */
+ for (i = 0; i < NUM_BOOT_MODULES; i++)
+ if (NULL != boot_modules[i])
+ try_load(boot_modules[i], module_devs[i],
+ dev_offsets[i]);
- bootdevhandle = handles[i];
- load(path);
-
- panic("Load failed");
-
- return EFI_SUCCESS;
+ /* If we get here, we're out of luck... */
+ panic("No bootable partitions found!");
}
-static int
-dskread(void *buf, u_int64_t lba, int nblk)
-{
- EFI_STATUS status;
- int size;
-
- lba = lba / (bootdev->Media->BlockSize / DEV_BSIZE);
- size = nblk * DEV_BSIZE;
- status = bootdev->ReadBlocks(bootdev, bootdev->Media->MediaId, lba,
- size, buf);
-
- if (EFI_ERROR(status))
- return (-1);
-
- return (0);
-}
-
-#include "ufsread.c"
-
-static ssize_t
-fsstat(ufs_ino_t inode)
-{
-#ifndef UFS2_ONLY
- static struct ufs1_dinode dp1;
- ufs1_daddr_t addr1;
-#endif
-#ifndef UFS1_ONLY
- static struct ufs2_dinode dp2;
-#endif
- static struct fs fs;
- static ufs_ino_t inomap;
- char *blkbuf;
- void *indbuf;
- size_t n, nb, size, off, vboff;
- ufs_lbn_t lbn;
- ufs2_daddr_t addr2, vbaddr;
- static ufs2_daddr_t blkmap, indmap;
- u_int u;
-
- blkbuf = dmadat->blkbuf;
- indbuf = dmadat->indbuf;
- if (!dsk_meta) {
- inomap = 0;
- for (n = 0; sblock_try[n] != -1; n++) {
- if (dskread(dmadat->sbbuf, sblock_try[n] / DEV_BSIZE,
- SBLOCKSIZE / DEV_BSIZE))
- return -1;
- memcpy(&fs, dmadat->sbbuf, sizeof(struct fs));
- if ((
-#if defined(UFS1_ONLY)
- fs.fs_magic == FS_UFS1_MAGIC
-#elif defined(UFS2_ONLY)
- (fs.fs_magic == FS_UFS2_MAGIC &&
- fs.fs_sblockloc == sblock_try[n])
-#else
- fs.fs_magic == FS_UFS1_MAGIC ||
- (fs.fs_magic == FS_UFS2_MAGIC &&
- fs.fs_sblockloc == sblock_try[n])
-#endif
- ) &&
- fs.fs_bsize <= MAXBSIZE &&
- fs.fs_bsize >= sizeof(struct fs))
- break;
- }
- if (sblock_try[n] == -1) {
- printf("Not ufs\n");
- return -1;
- }
- dsk_meta++;
- } else
- memcpy(&fs, dmadat->sbbuf, sizeof(struct fs));
- if (!inode)
- return 0;
- if (inomap != inode) {
- n = IPERVBLK(&fs);
- if (dskread(blkbuf, INO_TO_VBA(&fs, n, inode), DBPERVBLK))
- return -1;
- n = INO_TO_VBO(n, inode);
-#if defined(UFS1_ONLY)
- memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n,
- sizeof(struct ufs1_dinode));
-#elif defined(UFS2_ONLY)
- memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n,
- sizeof(struct ufs2_dinode));
-#else
- if (fs.fs_magic == FS_UFS1_MAGIC)
- memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n,
- sizeof(struct ufs1_dinode));
- else
- memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n,
- sizeof(struct ufs2_dinode));
-#endif
- inomap = inode;
- fs_off = 0;
- blkmap = indmap = 0;
- }
- size = DIP(di_size);
- n = size - fs_off;
- return (n);
-}
-
-static struct dmadat __dmadat;
-
-static int
-domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet)
-{
-
- dmadat = &__dmadat;
- bootdev = blkio;
- bootdevpath = device;
- if (fsread(0, NULL, 0)) {
- if (!quiet)
- printf("domount: can't read superblock\n");
- return (-1);
- }
- if (!quiet)
- printf("Succesfully mounted UFS filesystem\n");
- return (0);
-}
-
-static void
-load(const char *fname)
-{
- ufs_ino_t ino;
- EFI_STATUS status;
- EFI_HANDLE loaderhandle;
- EFI_LOADED_IMAGE *loaded_image;
- void *buffer;
- size_t bufsize;
-
- if ((ino = lookup(fname)) == 0) {
- printf("File %s not found\n", fname);
- return;
- }
-
- bufsize = fsstat(ino);
- status = systab->BootServices->AllocatePool(EfiLoaderData,
- bufsize, &buffer);
- fsread(ino, buffer, bufsize);
-
- /* XXX: For secure boot, we need our own loader here */
- status = systab->BootServices->LoadImage(TRUE, image, bootdevpath,
- buffer, bufsize, &loaderhandle);
- if (EFI_ERROR(status))
- printf("LoadImage failed with error %lx\n", status);
-
- status = systab->BootServices->HandleProtocol(loaderhandle,
- &LoadedImageGUID, (VOID**)&loaded_image);
- if (EFI_ERROR(status))
- printf("HandleProtocol failed with error %lx\n", status);
-
- loaded_image->DeviceHandle = bootdevhandle;
-
- status = systab->BootServices->StartImage(loaderhandle, NULL, NULL);
- if (EFI_ERROR(status))
- printf("StartImage failed with error %lx\n", status);
-}
-
-static void
+void
panic(const char *fmt, ...)
{
char buf[128];
@@ -358,7 +393,7 @@
while (1) {}
}
-static int
+int
printf(const char *fmt, ...)
{
va_list ap;
@@ -369,39 +404,18 @@
return 0;
va_start(ap, fmt);
- ret = vprintf(fmt, ap);
+ ret = __printf(fmt, putchr, 0, ap);
va_end(ap);
return (ret);
}
-static int
-putchar(char c, void *arg)
+void vprintf(const char *fmt, va_list ap)
{
- CHAR16 buf[2];
-
- if (c == '\n') {
- buf[0] = '\r';
- buf[1] = 0;
- systab->ConOut->OutputString(systab->ConOut, buf);
- }
- buf[0] = c;
- buf[1] = 0;
- systab->ConOut->OutputString(systab->ConOut, buf);
- return (1);
+ __printf(fmt, putchr, 0, ap);
}
-static int
-vprintf(const char *fmt, va_list ap)
+int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap)
{
- int ret;
-
- ret = __printf(fmt, putchar, 0, ap);
- return (ret);
-}
-
-static int
-vsnprintf(char *str, size_t sz, const char *fmt, va_list ap)
-{
struct sp_data sp;
int ret;
Index: sys/boot/efi/boot1/boot_module.h
===================================================================
--- sys/boot/efi/boot1/boot_module.h
+++ sys/boot/efi/boot1/boot_module.h
@@ -0,0 +1,60 @@
+#ifndef _BOOT_MODULE_H_
+#define _BOOT_MODULE_H_
+
+#include <stdbool.h>
+
+#include <efi.h>
+#include <efilib.h>
+#include <eficonsctl.h>
+
+#define UFS_EFI_BOOT 1
+#define ZFS_EFI_BOOT 1
+
+// EFI device info
+typedef struct dev_info_t
+{
+ EFI_BLOCK_IO *dev;
+ EFI_DEVICE_PATH *devpath;
+ EFI_HANDLE *devhandle;
+ void *devdata;
+} dev_info_t;
+
+// A boot loader module. This is a standard interface for filesystem
+// modules in the EFI system.
+typedef struct boot_module_t
+{
+ const char* const name;
+
+ // Initialize the module.
+ void (* const init)(EFI_HANDLE image,
+ EFI_SYSTEM_TABLE* systab,
+ EFI_BOOT_SERVICES *bootsrv);
+
+ // Check to see if curr_dev is a device that this module can handle.
+ bool (* const probe)(dev_info_t* dev);
+
+ // Select the best out of a set of devices that probe indicated were
+ // loadable, and load it.
+ void* (* const load)(const dev_info_t devs[],
+ size_t ndevs,
+ const char* loader_path,
+ int* idxref,
+ size_t* bufsizeref);
+} boot_module_t;
+
+// Standard boot modules
+#ifdef UFS_EFI_BOOT
+extern const boot_module_t ufs_module;
+#endif
+#ifdef ZFS_EFI_BOOT
+extern const boot_module_t zfs_module;
+#endif
+
+// Functions available to modules
+extern int strcmp(const char *s1, const char *s2);
+extern void bcopy(const void *src, void *dst, size_t len);
+extern void panic(const char *fmt, ...) __dead2;
+extern int printf(const char *fmt, ...);
+extern int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap);
+
+#endif
Index: sys/boot/efi/boot1/ufs_module.c
===================================================================
--- sys/boot/efi/boot1/ufs_module.c
+++ sys/boot/efi/boot1/ufs_module.c
@@ -0,0 +1,203 @@
+/*-
+ * Copyright (c) 1998 Robert Nordier
+ * All rights reserved.
+ * Copyright (c) 2001 Robert Drehmel
+ * All rights reserved.
+ * Copyright (c) 2014 Nathan Whitehorn
+ * All rights reserved.
+ * Copyright (c) 2015 Eric McCorkle
+ * All rights reverved.
+ *
+ * Redistribution and use in source and binary forms are freely
+ * permitted provided that the above copyright notice and this
+ * paragraph and the following disclaimer are duplicated in all
+ * such forms.
+ *
+ * This software is provided "AS IS" and without any express or
+ * implied warranties, including, without limitation, the implied
+ * warranties of merchantability and fitness for a particular
+ * purpose.
+ */
+#include <stdarg.h>
+#include <stdbool.h>
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+
+#include <efi.h>
+
+#include "boot_module.h"
+
+static EFI_HANDLE image;
+static EFI_SYSTEM_TABLE* systab;
+static EFI_BOOT_SERVICES *bootsrv;
+static dev_info_t devinfo;
+static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL;
+
+static int
+dskread(void *buf, u_int64_t lba, int nblk)
+{
+ EFI_STATUS status;
+ int size;
+
+ lba = lba / (devinfo.dev->Media->BlockSize / DEV_BSIZE);
+ size = nblk * DEV_BSIZE;
+ status = devinfo.dev->ReadBlocks(devinfo.dev,
+ devinfo.dev->Media->MediaId, lba,
+ size, buf);
+
+ if (EFI_ERROR(status))
+ return (-1);
+
+ return (0);
+}
+
+#include "ufsread.c"
+
+static ssize_t
+fsstat(ufs_ino_t inode)
+{
+#ifndef UFS2_ONLY
+ static struct ufs1_dinode dp1;
+ ufs1_daddr_t addr1;
+#endif
+#ifndef UFS1_ONLY
+ static struct ufs2_dinode dp2;
+#endif
+ static struct fs fs;
+ static ufs_ino_t inomap;
+ char *blkbuf;
+ void *indbuf;
+ size_t n, nb, size, off, vboff;
+ ufs_lbn_t lbn;
+ ufs2_daddr_t addr2, vbaddr;
+ static ufs2_daddr_t blkmap, indmap;
+ u_int u;
+
+ blkbuf = dmadat->blkbuf;
+ indbuf = dmadat->indbuf;
+ if (!dsk_meta) {
+ inomap = 0;
+ for (n = 0; sblock_try[n] != -1; n++) {
+ if (dskread(dmadat->sbbuf, sblock_try[n] / DEV_BSIZE,
+ SBLOCKSIZE / DEV_BSIZE))
+ return -1;
+ memcpy(&fs, dmadat->sbbuf, sizeof(struct fs));
+ if ((
+#if defined(UFS1_ONLY)
+ fs.fs_magic == FS_UFS1_MAGIC
+#elif defined(UFS2_ONLY)
+ (fs.fs_magic == FS_UFS2_MAGIC &&
+ fs.fs_sblockloc == sblock_try[n])
+#else
+ fs.fs_magic == FS_UFS1_MAGIC ||
+ (fs.fs_magic == FS_UFS2_MAGIC &&
+ fs.fs_sblockloc == sblock_try[n])
+#endif
+ ) &&
+ fs.fs_bsize <= MAXBSIZE &&
+ fs.fs_bsize >= sizeof(struct fs))
+ break;
+ }
+ if (sblock_try[n] == -1) {
+ return -1;
+ }
+ dsk_meta++;
+ } else
+ memcpy(&fs, dmadat->sbbuf, sizeof(struct fs));
+ if (!inode)
+ return 0;
+ if (inomap != inode) {
+ n = IPERVBLK(&fs);
+ if (dskread(blkbuf, INO_TO_VBA(&fs, n, inode), DBPERVBLK))
+ return -1;
+ n = INO_TO_VBO(n, inode);
+#if defined(UFS1_ONLY)
+ memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n,
+ sizeof(struct ufs1_dinode));
+#elif defined(UFS2_ONLY)
+ memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n,
+ sizeof(struct ufs2_dinode));
+#else
+ if (fs.fs_magic == FS_UFS1_MAGIC)
+ memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n,
+ sizeof(struct ufs1_dinode));
+ else
+ memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n,
+ sizeof(struct ufs2_dinode));
+#endif
+ inomap = inode;
+ fs_off = 0;
+ blkmap = indmap = 0;
+ }
+ size = DIP(di_size);
+ n = size - fs_off;
+ return (n);
+}
+
+static struct dmadat __dmadat;
+
+static bool
+probe(dev_info_t* const dev)
+{
+ devinfo = *dev;
+ dmadat = &__dmadat;
+ if (fsread(0, NULL, 0)) {
+ return 0;
+ }
+ return 1;
+}
+
+static void*
+try_load(dev_info_t dev, const char* loader_path, size_t* bufsizeref)
+{
+ ufs_ino_t ino;
+ EFI_STATUS status;
+ void *buffer;
+ size_t bufsize;
+
+ devinfo = dev;
+ if ((ino = lookup(loader_path)) == 0) {
+ printf("File %s not found\n", loader_path);
+ return NULL;
+ }
+
+ bufsize = fsstat(ino);
+ *bufsizeref = bufsize;
+ status = systab->BootServices->AllocatePool(EfiLoaderData,
+ bufsize, &buffer);
+ fsread(ino, buffer, bufsize);
+ return buffer;
+}
+
+static void*
+load(const dev_info_t devs[], size_t ndevs, const char *loader_path,
+ int *idxref, size_t *bufsizeref)
+{
+ int i;
+ for(i = 0; i < ndevs; i++) {
+ void* const out = try_load(devs[i], loader_path, bufsizeref);
+ if (out != NULL) {
+ *idxref = i;
+ return out;
+ }
+ }
+ return NULL;
+}
+
+
+static void
+init(EFI_HANDLE xImage, EFI_SYSTEM_TABLE* xSystab, EFI_BOOT_SERVICES * xBootsrv)
+{
+ image = xImage;
+ systab = xSystab;
+ bootsrv = xBootsrv;
+}
+
+const boot_module_t ufs_module =
+{
+ .name = "UFS",
+ .init = init,
+ .probe = probe,
+ .load = load
+};
Index: sys/boot/efi/boot1/zfs_module.c
===================================================================
--- sys/boot/efi/boot1/zfs_module.c
+++ sys/boot/efi/boot1/zfs_module.c
@@ -0,0 +1,184 @@
+/* Copyright (c) 2015 Eric McCorkle. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * 3. Neither the name of the author nor the names of any contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdbool.h>
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+
+#include <efi.h>
+
+#include "boot_module.h"
+
+#include "libzfs.h"
+#include "zfsimpl.c"
+
+#define PATH_CONFIG "/boot/config"
+#define PATH_DOTCONFIG "/boot/.config"
+
+static EFI_HANDLE image;
+static EFI_SYSTEM_TABLE* systab;
+static EFI_BOOT_SERVICES *bootsrv;
+
+static int
+vdev_read(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes)
+{
+ const dev_info_t * const devinfo = (const dev_info_t *) priv;
+ const off_t lba = off / devinfo->dev->Media->BlockSize;
+ const EFI_STATUS status =
+ devinfo->dev->ReadBlocks(devinfo->dev,
+ devinfo->dev->Media->MediaId,
+ lba, bytes, buf);
+ if (EFI_ERROR(status))
+ return (-1);
+
+ return (0);
+}
+
+static bool
+probe(dev_info_t *dev)
+{
+ spa_t *spa;
+ int result = vdev_probe(vdev_read, dev, &spa);
+ dev->devdata = spa;
+
+ return result == 0;
+}
+
+static void*
+try_load(dev_info_t devinfo, const char *loader_path, size_t *bufsizeref)
+{
+ spa_t *spa = devinfo.devdata;
+ struct zfsmount zfsmount;
+ dnode_phys_t dn;
+ bool autoboot = true;
+
+ if (zfs_spa_init(spa) != 0)
+ // Mount failed. Don't report this loudly
+ return NULL;
+
+ // First, try mounting the ZFS volume
+ if (zfs_mount(spa, 0, &zfsmount) != 0)
+ // Mount failed. Don't report this loudly
+ return NULL;
+
+ if (zfs_lookup(&zfsmount, loader_path, &dn) != 0)
+ return NULL;
+
+ struct stat st;
+ if (zfs_dnode_stat(spa, &dn, &st))
+ return NULL;
+
+ const size_t bufsize = st.st_size;
+ void *buffer;
+ EFI_STATUS status;
+
+ *bufsizeref = bufsize;
+
+ if (systab->BootServices->AllocatePool(EfiLoaderData,
+ bufsize, &buffer) !=
+ EFI_SUCCESS)
+ return NULL;
+
+ if (dnode_read(spa, &dn, 0, buffer, bufsize) < 0)
+ return NULL;
+
+ return buffer;
+}
+
+static int
+zfs_mount_ds(const char *dsname, struct zfsmount *zfsmount, spa_t **spa)
+{
+ uint64_t newroot;
+ spa_t *newspa;
+ char *q;
+
+ q = strchr(dsname, '/');
+ if (q)
+ *q++ = '\0';
+ newspa = spa_find_by_name(dsname);
+ if (newspa == NULL) {
+ printf("\nCan't find ZFS pool %s\n", dsname);
+ return -1;
+ }
+
+ if (zfs_spa_init(newspa))
+ return -1;
+
+ newroot = 0;
+ if (q) {
+ if (zfs_lookup_dataset(newspa, q, &newroot)) {
+ printf("\nCan't find dataset %s in ZFS pool %s\n",
+ q, newspa->spa_name);
+ return -1;
+ }
+ }
+ if (zfs_mount(newspa, newroot, zfsmount)) {
+ printf("\nCan't mount ZFS dataset\n");
+ return -1;
+ }
+ *spa = newspa;
+ return (0);
+}
+
+static void*
+load(const dev_info_t devs[], size_t ndevs, const char *loader_path,
+ int *idxref, size_t *bufsizeref)
+{
+ for(int i = 0; i < ndevs; i++) {
+ void * const out = try_load(devs[i], loader_path, bufsizeref);
+ if (out != NULL) {
+ *idxref = i;
+ return out;
+ }
+ }
+ return NULL;
+}
+
+static void
+init(EFI_HANDLE xImage, EFI_SYSTEM_TABLE *xSystab, EFI_BOOT_SERVICES *xBootsrv)
+{
+ image = xImage;
+ systab = xSystab;
+ bootsrv = xBootsrv;
+ zfs_init();
+}
+
+const boot_module_t zfs_module =
+{
+ .name = "ZFS",
+ .init = init,
+ .probe = probe,
+ .load = load
+};
Index: sys/boot/efi/include/efilib.h
===================================================================
--- sys/boot/efi/include/efilib.h
+++ sys/boot/efi/include/efilib.h
@@ -43,7 +43,8 @@
int efi_register_handles(struct devsw *, EFI_HANDLE *, EFI_HANDLE *, int);
EFI_HANDLE efi_find_handle(struct devsw *, int);
-int efi_handle_lookup(EFI_HANDLE, struct devsw **, int *);
+void efi_handle_update_dev(EFI_HANDLE, struct devsw *, int, uint64_t);
+int efi_handle_lookup(EFI_HANDLE, struct devsw **, int *, uint64_t *);
int efi_status_to_errno(EFI_STATUS);
time_t efi_time(EFI_TIME *);
Index: sys/boot/efi/libefi/handles.c
===================================================================
--- sys/boot/efi/libefi/handles.c
+++ sys/boot/efi/libefi/handles.c
@@ -35,6 +35,7 @@
EFI_HANDLE alias;
struct devsw *dev;
int unit;
+ uint64_t extra;
};
struct entry *entry;
@@ -78,8 +79,24 @@
return (NULL);
}
+void
+efi_handle_update_dev(EFI_HANDLE handle, struct devsw *dev, int unit,
+ uint64_t guid)
+{
+ int idx;
+
+ for (idx = 0; idx < nentries; idx++) {
+ if (entry[idx].handle != handle)
+ continue;
+ entry[idx].dev = dev;
+ entry[idx].unit = unit;
+ entry[idx].alias = NULL;
+ entry[idx].extra = guid;
+ }
+}
+
int
-efi_handle_lookup(EFI_HANDLE h, struct devsw **dev, int *unit)
+efi_handle_lookup(EFI_HANDLE h, struct devsw **dev, int *unit, uint64_t *extra)
{
int idx;
@@ -90,6 +107,8 @@
*dev = entry[idx].dev;
if (unit != NULL)
*unit = entry[idx].unit;
+ if (extra != NULL)
+ *extra = entry[idx].extra;
return (0);
}
return (ENOENT);
Index: sys/boot/efi/loader/Makefile
===================================================================
--- sys/boot/efi/loader/Makefile
+++ sys/boot/efi/loader/Makefile
@@ -21,7 +21,8 @@
main.c \
self_reloc.c \
smbios.c \
- vers.c
+ vers.c \
+ ${.CURDIR}/../../zfs/zfs.c
.PATH: ${.CURDIR}/arch/${MACHINE}
# For smbios.c
@@ -35,6 +36,8 @@
CFLAGS+= -I${.CURDIR}/../../../contrib/dev/acpica/include
CFLAGS+= -I${.CURDIR}/../../..
CFLAGS+= -I${.CURDIR}/../../i386/libi386
+CFLAGS+= -I${.CURDIR}/../../zfs
+CFLAGS+= -I${.CURDIR}/../../../cddl/boot/zfs
CFLAGS+= -DNO_PCI -DEFI
# make buildenv doesn't set DESTDIR, this means LIBSTAND
@@ -67,7 +70,7 @@
CFLAGS+= -DEFI_STAGING_SIZE=${EFI_STAGING_SIZE}
.endif
-# Always add MI sources
+# Always add MI sources
.PATH: ${.CURDIR}/../../common
.include "${.CURDIR}/../../common/Makefile.inc"
CFLAGS+= -I${.CURDIR}/../../common
@@ -85,6 +88,9 @@
vers.c: ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/../../efi/loader/version
sh ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version ${NEWVERSWHAT}
+#zfs.c: ${.CURDIR}/../../zfs/zfs.c
+# cp ${.CURDIR}/../../zfs/zfs.c ${.CURDIR}
+
OBJCOPY?= objcopy
OBJDUMP?= objdump
Index: sys/boot/efi/loader/conf.c
===================================================================
--- sys/boot/efi/loader/conf.c
+++ sys/boot/efi/loader/conf.c
@@ -31,14 +31,17 @@
#include <bootstrap.h>
#include <efi.h>
#include <efilib.h>
+#include "../zfs/libzfs.h"
struct devsw *devsw[] = {
&efipart_dev,
&efinet_dev,
+ &zfs_dev,
NULL
};
struct fs_ops *file_system[] = {
+ &zfs_fsops,
&dosfs_fsops,
&ufs_fsops,
&cd9660_fsops,
Index: sys/boot/efi/loader/devicename.c
===================================================================
--- sys/boot/efi/loader/devicename.c
+++ sys/boot/efi/loader/devicename.c
@@ -32,6 +32,7 @@
#include <string.h>
#include <sys/disklabel.h>
#include "bootstrap.h"
+#include "libzfs.h"
#include <efi.h>
#include <efilib.h>
@@ -38,7 +39,7 @@
static int efi_parsedev(struct devdesc **, const char *, const char **);
-/*
+/*
* Point (dev) at an allocated device specifier for the device matching the
* path in (devspec). If it contains an explicit device specification,
* use that. If not, use the default device.
@@ -61,7 +62,8 @@
}
/* Parse the device name off the beginning of the devspec. */
- return (efi_parsedev(dev, devspec, path));
+ const int out = efi_parsedev(dev, devspec, path);
+ return out;
}
/*
@@ -99,24 +101,37 @@
if (devsw[i] == NULL)
return (ENOENT);
- idev = malloc(sizeof(struct devdesc));
- if (idev == NULL)
- return (ENOMEM);
+ np = devspec + strlen(dv->dv_name);
- idev->d_dev = dv;
- idev->d_type = dv->dv_type;
- idev->d_unit = -1;
+ if (DEVT_ZFS == dv->dv_type) {
+ idev = malloc(sizeof(struct zfs_devdesc));
+ int out = zfs_parsedev((struct zfs_devdesc*)idev, np, path);
+ if (0 == out) {
+ *dev = idev;
+ cp = strchr(np + 1, ':');
+ } else {
+ free(idev);
+ return out;
+ }
+ } else {
+ idev = malloc(sizeof(struct devdesc));
+ if (idev == NULL)
+ return (ENOMEM);
- err = 0;
- np = devspec + strlen(dv->dv_name);
- if (*np != '\0' && *np != ':') {
- idev->d_unit = strtol(np, &cp, 0);
- if (cp == np) {
- idev->d_unit = -1;
- free(idev);
- return (EUNIT);
- }
- }
+ idev->d_dev = dv;
+ idev->d_type = dv->dv_type;
+ idev->d_unit = -1;
+ if (*np != '\0' && *np != ':') {
+ idev->d_unit = strtol(np, &cp, 0);
+ if (cp == np) {
+ idev->d_unit = -1;
+ free(idev);
+ return (EUNIT);
+ }
+ }
+ }
+
+ err = 0;
if (*cp != '\0' && *cp != ':') {
free(idev);
return (EINVAL);
@@ -138,6 +153,8 @@
static char buf[32]; /* XXX device length constant? */
switch(dev->d_type) {
+ case DEVT_ZFS:
+ return zfs_fmtdev(dev);
case DEVT_NONE:
strcpy(buf, "(no device)");
break;
Index: sys/boot/efi/loader/main.c
===================================================================
--- sys/boot/efi/loader/main.c
+++ sys/boot/efi/loader/main.c
@@ -39,6 +39,7 @@
#include <smbios.h>
#include "loader_efi.h"
+#include "libzfs.h"
extern char bootprog_name[];
extern char bootprog_rev[];
@@ -45,8 +46,9 @@
extern char bootprog_date[];
extern char bootprog_maker[];
-struct devdesc currdev; /* our current device */
-struct arch_switch archsw; /* MI/MD interface boundary */
+/* our current device */
+/* MI/MD interface boundary */
+struct arch_switch archsw;
EFI_GUID acpi = ACPI_TABLE_GUID;
EFI_GUID acpi20 = ACPI_20_TABLE_GUID;
@@ -61,6 +63,22 @@
EFI_GUID debugimg = DEBUG_IMAGE_INFO_TABLE_GUID;
EFI_GUID fdtdtb = FDT_TABLE_GUID;
+static void efi_zfs_probe(void);
+
+/*
+ * Need this because EFI uses UTF-16 unicode string constants, but we
+ * use UTF-8.
+ */
+static void
+print_str16(const CHAR16 *str)
+{
+ int i;
+ for(i = 0; str[i]; i++)
+ {
+ printf("%c", str[i]);
+ }
+}
+
EFI_STATUS
main(int argc, CHAR16 *argv[])
{
@@ -69,6 +87,14 @@
EFI_GUID *guid;
int i;
+ archsw.arch_autoload = efi_autoload;
+ archsw.arch_getdev = efi_getdev;
+ archsw.arch_copyin = efi_copyin;
+ archsw.arch_copyout = efi_copyout;
+ archsw.arch_readin = efi_readin;
+ // Note this needs to be set before ZFS init
+ archsw.arch_zfs_probe = efi_zfs_probe;
+
/*
* XXX Chicken-and-egg problem; we want to have console output
* early, but some console attributes may depend on reading from
@@ -86,12 +112,19 @@
* March through the device switch probing for things.
*/
for (i = 0; devsw[i] != NULL; i++)
- if (devsw[i]->dv_init != NULL)
+ if (devsw[i]->dv_init != NULL)
(devsw[i]->dv_init)();
/* Get our loaded image protocol interface structure. */
BS->HandleProtocol(IH, &imgid, (VOID**)&img);
+ printf("Command line arguments:");
+ for(i = 0; i < argc; i++) {
+ printf(" ");
+ print_str16(argv[i]);
+ }
+ printf("\n");
+
printf("Image base: 0x%lx\n", (u_long)img->ImageBase);
printf("EFI version: %d.%02d\n", ST->Hdr.Revision >> 16,
ST->Hdr.Revision & 0xffff);
@@ -105,9 +138,6 @@
printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
printf("(%s, %s)\n", bootprog_maker, bootprog_date);
- efi_handle_lookup(img->DeviceHandle, &currdev.d_dev, &currdev.d_unit);
- currdev.d_type = currdev.d_dev->dv_type;
-
/*
* Disable the watchdog timer. By default the boot manager sets
* the timer to 5 minutes before invoking a boot option. If we
@@ -119,19 +149,39 @@
*/
BS->SetWatchdogTimer(0, 0, 0, NULL);
- env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev),
- efi_setcurrdev, env_nounset);
- env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset,
- env_nounset);
+ struct devsw *dev;
+ int unit;
+ uint64_t pool_guid;
+ efi_handle_lookup(img->DeviceHandle, &dev, &unit, &pool_guid);
+ switch (dev->dv_type) {
+ case DEVT_ZFS: {
+ struct zfs_devdesc currdev;
+ currdev.d_dev = dev;
+ currdev.d_unit = unit;
+ currdev.d_type = currdev.d_dev->dv_type;
+ currdev.d_opendata = NULL;
+ currdev.pool_guid = pool_guid;
+ currdev.root_guid = 0;
+ env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev),
+ efi_setcurrdev, env_nounset);
+ env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset,
+ env_nounset);
+ } break;
+ default: {
+ struct devdesc currdev;
+ currdev.d_dev = dev;
+ currdev.d_unit = unit;
+ currdev.d_opendata = NULL;
+ currdev.d_type = currdev.d_dev->dv_type;
+ env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev),
+ efi_setcurrdev, env_nounset);
+ env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset,
+ env_nounset);
+ } break;
+ }
setenv("LINES", "24", 1); /* optional */
- archsw.arch_autoload = efi_autoload;
- archsw.arch_getdev = efi_getdev;
- archsw.arch_copyin = efi_copyin;
- archsw.arch_copyout = efi_copyout;
- archsw.arch_readin = efi_readin;
-
for (i = 0; i < ST->NumberOfTableEntries; i++) {
guid = &ST->ConfigurationTable[i].VendorGuid;
if (!memcmp(guid, &smbios, sizeof(EFI_GUID))) {
@@ -402,6 +452,27 @@
return (CMD_OK);
}
+COMMAND_SET(lszfs, "lszfs", "list child datasets of a zfs dataset",
+ command_lszfs);
+
+static int
+command_lszfs(int argc, char *argv[])
+{
+ int err;
+
+ if (argc != 2) {
+ command_errmsg = "wrong number of arguments";
+ return (CMD_ERROR);
+ }
+
+ err = zfs_list(argv[1]);
+ if (err != 0) {
+ command_errmsg = strerror(err);
+ return (CMD_ERROR);
+ }
+ return (CMD_OK);
+}
+
#ifdef LOADER_FDT_SUPPORT
extern int command_fdt_internal(int argc, char *argv[]);
@@ -420,3 +491,23 @@
COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt);
#endif
+
+static void
+efi_zfs_probe(void)
+{
+ EFI_BLOCK_IO *blkio;
+ EFI_HANDLE h;
+ EFI_STATUS status;
+ u_int unit = 0;
+ char devname[32];
+ uint64_t pool_guid;
+
+ for (int i = 0, h = efi_find_handle(&efipart_dev, 0);
+ h != NULL; h = efi_find_handle(&efipart_dev, ++i)) {
+ snprintf(devname, sizeof devname, "%s%d:",
+ efipart_dev.dv_name, i);
+ if(0 == zfs_probe_dev(devname, &pool_guid)) {
+ efi_handle_update_dev(h, &zfs_dev, unit++, pool_guid);
+ }
+ }
+}
Index: sys/boot/zfs/zfs.c
===================================================================
--- sys/boot/zfs/zfs.c
+++ sys/boot/zfs/zfs.c
@@ -140,7 +140,7 @@
n = size;
if (fp->f_seekp + n > sb.st_size)
n = sb.st_size - fp->f_seekp;
-
+
rc = dnode_read(spa, &fp->f_dnode, fp->f_seekp, start, n);
if (rc)
return (rc);
@@ -493,7 +493,7 @@
}
}
close(pa.fd);
- return (0);
+ return (ret);
}
/*
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Apr 20, 12:25 PM (13 h, 43 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31839108
Default Alt Text
D4104.diff (39 KB)
Attached To
Mode
D4104: ZFS EFI Boot Support
Attached
Detach File
Event Timeline
Log In to Comment