Revert "Unify boot1 with loader" change r324646

Back out the unification commit to boot1. There's some issues on the
arm and arm64 platforms that need to be addressed with code
changes. There's also a discussion on arch@ about the future of
boot1.efi vs just using loader.efi that needs to play out. So take a
pause on these changes until the arm issues can be fixed and it's
clear boot1.efi will survive into FreeBSD 12.

OK'd by: Eric@meatspace
This commit is contained in:
imp 2017-10-17 23:38:27 +00:00
parent 12d07dc151
commit c03b3346b7
8 changed files with 887 additions and 513 deletions

View File

@ -9,10 +9,7 @@ MK_FORTH= no
PROG= boot1.sym
INTERNALPROG=
WARNS?= 3
# Include bcache code.
HAVE_BCACHE= yes
WARNS?= 6
# We implement a slightly non-standard %S in that it always takes a
# CHAR16 that's common in UEFI-land instead of a wchar_t. This only
@ -22,15 +19,13 @@ HAVE_BCACHE= yes
CWARNFLAGS.boot1.c+= -Wno-format
# Disable warnings that are currently incompatible with the zfs boot code
CWARNFLAGS.zfs.c += -Wno-incompatible-pointer-types-discards-qualifiers
CWARNFLAGS.zfs.c += -Wno-missing-variable-declarations
CWARNFLAGS.zfs.c += -Wno-array-bounds
CWARNFLAGS.zfs.c += -Wno-cast-align
CWARNFLAGS.zfs.c += -Wno-cast-qual
CWARNFLAGS.zfs.c += -Wno-missing-prototypes
CWARNFLAGS.zfs.c += -Wno-sign-compare
CWARNFLAGS.zfs.c += -Wno-unused-parameter
CWARNFLAGS.zfs.c += -Wno-unused-function
CWARNFLAGS.zfs_module.c += -Wno-array-bounds
CWARNFLAGS.zfs_module.c += -Wno-cast-align
CWARNFLAGS.zfs_module.c += -Wno-cast-qual
CWARNFLAGS.zfs_module.c += -Wno-missing-prototypes
CWARNFLAGS.zfs_module.c += -Wno-sign-compare
CWARNFLAGS.zfs_module.c += -Wno-unused-parameter
CWARNFLAGS.zfs_module.c += -Wno-unused-function
CWARNFLAGS.skein.c += -Wno-cast-align
.if ${COMPILER_TYPE} == "clang"
CWARNFLAGS.skein.c += -Wno-missing-variable-declarations
@ -39,25 +34,19 @@ CWARNFLAGS.skein.c += -Wno-missing-declarations
.endif
# architecture-specific loader code
SRCS= boot1.c self_reloc.c start.S
SRCS= boot1.c self_reloc.c start.S ufs_module.c
.if ${MK_ZFS} != "no"
.PATH: ${.CURDIR}/../../../crypto/skein
SRCS+= zfs_module.c
SRCS+= skein.c skein_block.c
# Do not unroll skein loops, reduce code size
CFLAGS+= -DSKEIN_LOOP=111
.PATH: ${.CURDIR}/../../zfs
SRCS+= zfs.c
.PATH: ${.CURDIR}/../../../crypto/skein
.endif
.if ${COMPILER_TYPE} == "gcc" && ${COMPILER_VERSION} > 40201
CWARNFLAGS.self_reloc.c+= -Wno-error=maybe-uninitialized
.endif
# Always add MI sources
.include "../../loader.mk"
.PATH: ${.CURDIR}/arch/${MACHINE}
CFLAGS+= -I.
CFLAGS+= -I${.CURDIR}/../include
CFLAGS+= -I${.CURDIR}/../include/${MACHINE}
@ -129,7 +118,7 @@ boot1.efi: ${PROG}
SOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH} \
${OBJCOPY} -j .peheader -j .text -j .sdata -j .data \
-j .dynamic -j .dynsym -j .rel.dyn \
-j .rela.dyn -j .reloc -j .eh_frame -j set_Xcommand_set \
-j .rela.dyn -j .reloc -j .eh_frame \
--output-target=${EFI_TARGET} ${.ALLSRC} ${.TARGET}
boot1.o: ${SASRC}/ufsread.c

View File

@ -23,179 +23,61 @@
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/disk.h>
#include <machine/elf.h>
#include <machine/stdarg.h>
#include <stand.h>
#include <disk.h>
#include <efi.h>
#include <efilib.h>
#include <efiprot.h>
#include <eficonsctl.h>
#ifdef EFI_ZFS_BOOT
#include <libzfs.h>
#endif
typedef CHAR16 efi_char;
#include <efichar.h>
#include <bootstrap.h>
#include "efi_drivers.h"
#include "efizfs.h"
#include "boot_module.h"
#include "paths.h"
static void efi_panic(EFI_STATUS s, const char *fmt, ...) __dead2 __printflike(2, 3);
#ifdef EFI_DEBUG
#define DPRINTF(fmt, args...) printf(fmt, ##args)
#define DSTALL(d) BS->Stall(d)
#else
#define DPRINTF(fmt, ...) {}
#define DSTALL(d) {}
#endif
struct arch_switch archsw; /* MI/MD interface boundary */
static const efi_driver_t *efi_drivers[] = {
NULL
};
extern struct console efi_console;
#if defined(__amd64__) || defined(__i386__)
extern struct console comconsole;
extern struct console nullconsole;
#endif
static const boot_module_t *boot_modules[] =
{
#ifdef EFI_ZFS_BOOT
uint64_t pool_guid;
&zfs_module,
#endif
struct fs_ops *file_system[] = {
#ifdef EFI_ZFS_BOOT
&zfs_fsops,
#endif
&dosfs_fsops,
#ifdef EFI_UFS_BOOT
&ufs_fsops,
&ufs_module
#endif
&cd9660_fsops,
&nfs_fsops,
&gzipfs_fsops,
&bzipfs_fsops,
NULL
};
struct devsw *devsw[] = {
&efipart_hddev,
&efipart_fddev,
&efipart_cddev,
#ifdef EFI_ZFS_BOOT
&zfs_dev,
#endif
NULL
};
struct console *consoles[] = {
&efi_console,
NULL
};
static EFI_LOADED_IMAGE *boot_image;
static EFI_DEVICE_PATH *imgpath;
static EFI_DEVICE_PATH *imgprefix;
/* Definitions we don't actually need for boot, but we need to define
* to make the linker happy.
*/
struct file_format *file_formats[] = { NULL };
struct netif_driver *netif_drivers[] = { NULL };
static int
efi_autoload(void)
{
printf("******** Boot block should not call autoload\n");
return (-1);
}
static ssize_t
efi_copyin(const void *src __unused, vm_offset_t dest __unused,
const size_t len __unused)
{
printf("******** Boot block should not call copyin\n");
return (-1);
}
static ssize_t
efi_copyout(vm_offset_t src __unused, void *dest __unused,
const size_t len __unused)
{
printf("******** Boot block should not call copyout\n");
return (-1);
}
static ssize_t
efi_readin(int fd __unused, vm_offset_t dest __unused,
const size_t len __unused)
{
printf("******** Boot block should not call readin\n");
return (-1);
}
#define NUM_BOOT_MODULES nitems(boot_modules)
/* The initial number of handles used to query EFI for partitions. */
#define NUM_HANDLES_INIT 24
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_GUID FreeBSDBootVarGUID = FREEBSD_BOOT_VAR_GUID;
static EFI_STATUS
do_load(const char *filepath, void **bufp, size_t *bufsize)
/*
* Provide Malloc / Free backed by EFIs AllocatePool / FreePool which ensures
* memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from
* EFI methods.
*/
void *
Malloc(size_t len, const char *file __unused, int line __unused)
{
struct stat st;
void *buf = NULL;
int fd, err;
size_t fsize, remaining;
ssize_t readsize;
void *out;
if ((fd = open(filepath, O_RDONLY)) < 0) {
return (ENOTSUP);
}
if (BS->AllocatePool(EfiLoaderData, len, &out) == EFI_SUCCESS)
return (out);
if ((err = fstat(fd, &st)) != 0) {
goto close_file;
}
return (NULL);
}
fsize = st.st_size;
if ((buf = malloc(fsize)) == NULL) {
err = ENOMEM;
goto close_file;
}
remaining = fsize;
do {
if ((readsize = read(fd, buf, fsize)) < 0) {
err = (-readsize);
goto free_buf;
}
remaining -= readsize;
} while(remaining != 0);
close(fd);
*bufsize = st.st_size;
*bufp = buf;
close_file:
close(fd);
return errno_to_efi_status(err);
free_buf:
free(buf);
goto close_file;
void
Free(void *buf, const char *file __unused, int line __unused)
{
if (buf != NULL)
(void)BS->FreePool(buf);
}
static EFI_STATUS
@ -215,274 +97,97 @@ efi_setenv_freebsd_wcs(const char *varname, CHAR16 *valstr)
return (rv);
}
static int
probe_fs(const char *filepath)
/*
* nodes_match returns TRUE if the imgpath isn't NULL and the nodes match,
* FALSE otherwise.
*/
static BOOLEAN
nodes_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath)
{
int fd;
size_t len;
if ((fd = open(filepath, O_RDONLY)) < 0) {
return (ENOTSUP);
}
if (imgpath == NULL || imgpath->Type != devpath->Type ||
imgpath->SubType != devpath->SubType)
return (FALSE);
close(fd);
len = DevicePathNodeLength(imgpath);
if (len != DevicePathNodeLength(devpath))
return (FALSE);
return (0);
return (memcmp(imgpath, devpath, (size_t)len) == 0);
}
static int
probe_dev(struct devsw *dev, int unit, const char *filepath)
/*
* device_paths_match returns TRUE if the imgpath isn't NULL and all nodes
* in imgpath and devpath match up to their respective occurrences of a
* media node, FALSE otherwise.
*/
static BOOLEAN
device_paths_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath)
{
struct devdesc currdev;
char *devname;
int err;
currdev.d_dev = dev;
currdev.d_type = currdev.d_dev->dv_type;
currdev.d_unit = unit;
currdev.d_opendata = NULL;
devname = efi_fmtdev(&currdev);
if (imgpath == NULL)
return (FALSE);
env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev,
env_nounset);
while (!IsDevicePathEnd(imgpath) && !IsDevicePathEnd(devpath)) {
if (IsDevicePathType(imgpath, MEDIA_DEVICE_PATH) &&
IsDevicePathType(devpath, MEDIA_DEVICE_PATH))
return (TRUE);
err = probe_fs(filepath);
if (!nodes_match(imgpath, devpath))
return (FALSE);
return (err);
imgpath = NextDevicePathNode(imgpath);
devpath = NextDevicePathNode(devpath);
}
return (FALSE);
}
static bool
check_preferred(EFI_HANDLE *h)
/*
* devpath_last returns the last non-path end node in devpath.
*/
static EFI_DEVICE_PATH *
devpath_last(EFI_DEVICE_PATH *devpath)
{
EFI_DEVICE_PATH *path = efi_lookup_devpath(h);
bool out;
if ((path = efi_lookup_devpath(h)) == NULL)
return (false);
while (!IsDevicePathEnd(NextDevicePathNode(devpath)))
devpath = NextDevicePathNode(devpath);
out = efi_devpath_is_prefix(imgpath, path) ||
efi_devpath_is_prefix(imgprefix, path);
return (out);
}
bool
efi_zfs_is_preferred(EFI_HANDLE *h)
{
return (check_preferred(h));
}
static int
load_preferred(EFI_LOADED_IMAGE *img, const char *filepath, void **bufp,
size_t *bufsize, EFI_HANDLE *handlep)
{
pdinfo_list_t *pdi_list;
pdinfo_t *dp, *pp;
char *devname;
#ifdef EFI_ZFS_BOOT
/* Did efi_zfs_probe() detect the boot pool? */
if (pool_guid != 0) {
struct zfs_devdesc currdev;
currdev.d_dev = &zfs_dev;
currdev.d_unit = 0;
currdev.d_type = currdev.d_dev->dv_type;
currdev.d_opendata = NULL;
currdev.pool_guid = pool_guid;
currdev.root_guid = 0;
devname = efi_fmtdev(&currdev);
env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev,
env_nounset);
if (probe_fs(filepath) == 0 &&
do_load(filepath, bufp, bufsize) == EFI_SUCCESS) {
*handlep = efizfs_get_handle_by_guid(pool_guid);
return (0);
}
}
#endif /* EFI_ZFS_BOOT */
/* We have device lists for hd, cd, fd, walk them all. */
pdi_list = efiblk_get_pdinfo_list(&efipart_hddev);
STAILQ_FOREACH(dp, pdi_list, pd_link) {
struct disk_devdesc currdev;
currdev.d_dev = &efipart_hddev;
currdev.d_type = currdev.d_dev->dv_type;
currdev.d_unit = dp->pd_unit;
currdev.d_opendata = NULL;
currdev.d_slice = -1;
currdev.d_partition = -1;
devname = efi_fmtdev(&currdev);
env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev,
env_nounset);
if (check_preferred(dp->pd_handle) &&
probe_fs(filepath) == 0 &&
do_load(filepath, bufp, bufsize) == EFI_SUCCESS) {
*handlep = dp->pd_handle;
return (0);
}
/* Assuming GPT partitioning. */
STAILQ_FOREACH(pp, &dp->pd_part, pd_link) {
if (check_preferred(pp->pd_handle)) {
currdev.d_slice = pp->pd_unit;
currdev.d_partition = 255;
devname = efi_fmtdev(&currdev);
env_setenv("currdev", EV_VOLATILE, devname,
efi_setcurrdev, env_nounset);
if (probe_fs(filepath) == 0 &&
do_load(filepath, bufp, bufsize) ==
EFI_SUCCESS) {
*handlep = pp->pd_handle;
return (0);
}
}
}
}
pdi_list = efiblk_get_pdinfo_list(&efipart_cddev);
STAILQ_FOREACH(dp, pdi_list, pd_link) {
if ((dp->pd_handle == img->DeviceHandle ||
dp->pd_alias == img->DeviceHandle ||
check_preferred(dp->pd_handle)) &&
probe_dev(&efipart_cddev, dp->pd_unit, filepath) == 0 &&
do_load(filepath, bufp, bufsize) == EFI_SUCCESS) {
*handlep = dp->pd_handle;
return (0);
}
}
pdi_list = efiblk_get_pdinfo_list(&efipart_fddev);
STAILQ_FOREACH(dp, pdi_list, pd_link) {
if ((dp->pd_handle == img->DeviceHandle ||
check_preferred(dp->pd_handle)) &&
probe_dev(&efipart_cddev, dp->pd_unit, filepath) == 0 &&
do_load(filepath, bufp, bufsize) == EFI_SUCCESS) {
*handlep = dp->pd_handle;
return (0);
}
}
return (ENOENT);
}
static int
load_all(const char *filepath, void **bufp, size_t *bufsize,
EFI_HANDLE *handlep)
{
pdinfo_list_t *pdi_list;
pdinfo_t *dp, *pp;
zfsinfo_list_t *zfsi_list;
zfsinfo_t *zi;
char *devname;
#ifdef EFI_ZFS_BOOT
zfsi_list = efizfs_get_zfsinfo_list();
STAILQ_FOREACH(zi, zfsi_list, zi_link) {
struct zfs_devdesc currdev;
currdev.d_dev = &zfs_dev;
currdev.d_unit = 0;
currdev.d_type = currdev.d_dev->dv_type;
currdev.d_opendata = NULL;
currdev.pool_guid = zi->zi_pool_guid;
currdev.root_guid = 0;
devname = efi_fmtdev(&currdev);
env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev,
env_nounset);
if (probe_fs(filepath) == 0 &&
do_load(filepath, bufp, bufsize) == EFI_SUCCESS) {
*handlep = zi->zi_handle;
return (0);
}
}
#endif /* EFI_ZFS_BOOT */
/* We have device lists for hd, cd, fd, walk them all. */
pdi_list = efiblk_get_pdinfo_list(&efipart_hddev);
STAILQ_FOREACH(dp, pdi_list, pd_link) {
struct disk_devdesc currdev;
currdev.d_dev = &efipart_hddev;
currdev.d_type = currdev.d_dev->dv_type;
currdev.d_unit = dp->pd_unit;
currdev.d_opendata = NULL;
currdev.d_slice = -1;
currdev.d_partition = -1;
devname = efi_fmtdev(&currdev);
env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev,
env_nounset);
if (probe_fs(filepath) == 0 &&
do_load(filepath, bufp, bufsize) == EFI_SUCCESS) {
*handlep = dp->pd_handle;
return (0);
}
/* Assuming GPT partitioning. */
STAILQ_FOREACH(pp, &dp->pd_part, pd_link) {
currdev.d_slice = pp->pd_unit;
currdev.d_partition = 255;
devname = efi_fmtdev(&currdev);
env_setenv("currdev", EV_VOLATILE, devname,
efi_setcurrdev, env_nounset);
if (probe_fs(filepath) == 0 &&
do_load(filepath, bufp, bufsize) == EFI_SUCCESS) {
*handlep = pp->pd_handle;
return (0);
}
}
}
pdi_list = efiblk_get_pdinfo_list(&efipart_cddev);
STAILQ_FOREACH(dp, pdi_list, pd_link) {
if (probe_dev(&efipart_cddev, dp->pd_unit, filepath) == 0 &&
do_load(filepath, bufp, bufsize) == EFI_SUCCESS) {
*handlep = dp->pd_handle;
return (0);
}
}
pdi_list = efiblk_get_pdinfo_list(&efipart_fddev);
STAILQ_FOREACH(dp, pdi_list, pd_link) {
if (probe_dev(&efipart_fddev, dp->pd_unit, filepath) == 0 &&
do_load(filepath, bufp, bufsize) == EFI_SUCCESS) {
*handlep = dp->pd_handle;
return (0);
}
}
return (ENOENT);
return (devpath);
}
/*
* load_loader attempts to load the loader image data.
*
* It tries each module and its respective devices, identified by mod->probe,
* in order until a successful load occurs at which point it returns EFI_SUCCESS
* and EFI_NOT_FOUND otherwise.
*
* Only devices which have preferred matching the preferred parameter are tried.
*/
static EFI_STATUS
load_loader(EFI_HANDLE *handlep, void **bufp, size_t *bufsize)
load_loader(const boot_module_t **modp, dev_info_t **devinfop, void **bufp,
size_t *bufsize, BOOLEAN preferred)
{
/* Try the preferred handles first, then all the handles */
if (load_preferred(boot_image, PATH_LOADER_EFI, bufp, bufsize,
handlep) == 0) {
return (0);
}
UINTN i;
dev_info_t *dev;
const boot_module_t *mod;
if (load_all(PATH_LOADER_EFI, bufp, bufsize, handlep) == 0) {
return (0);
}
for (i = 0; i < NUM_BOOT_MODULES; i++) {
mod = boot_modules[i];
for (dev = mod->devices(); dev != NULL; dev = dev->next) {
if (dev->preferred != preferred)
continue;
if (mod->load(PATH_LOADER_EFI, dev, bufp, bufsize) ==
EFI_SUCCESS) {
*devinfop = dev;
*modp = mod;
return (EFI_SUCCESS);
}
}
}
return (EFI_NOT_FOUND);
}
@ -497,27 +202,20 @@ try_boot(void)
size_t bufsize, loadersize, cmdsize;
void *buf, *loaderbuf;
char *cmd;
EFI_HANDLE fshandle;
dev_info_t *dev;
const boot_module_t *mod;
EFI_HANDLE loaderhandle;
EFI_LOADED_IMAGE *loaded_image;
EFI_STATUS status;
EFI_DEVICE_PATH *fspath;
status = load_loader(&fshandle, &loaderbuf, &loadersize);
if (status != EFI_SUCCESS) {
return (status);
}
fspath = NULL;
if (status == EFI_SUCCESS) {
status = BS->OpenProtocol(fshandle, &DevicePathGUID,
(void **)&fspath, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE);
if (status != EFI_SUCCESS) {
status = load_loader(&mod, &dev, &loaderbuf, &loadersize,
FALSE);
if (status != EFI_SUCCESS) {
DPRINTF("Failed to get image DevicePath (%lu)\n",
EFI_ERROR_CODE(status));
}
DPRINTF("filesystem device path: %s\n", devpath_str(fspath));
printf("Failed to load '%s'\n", PATH_LOADER_EFI);
return (status);
}
}
/*
@ -532,9 +230,9 @@ try_boot(void)
*/
cmd = NULL;
cmdsize = 0;
status = do_load(PATH_DOTCONFIG, &buf, &bufsize);
status = mod->load(PATH_DOTCONFIG, dev, &buf, &bufsize);
if (status == EFI_NOT_FOUND)
status = do_load(PATH_CONFIG, &buf, &bufsize);
status = mod->load(PATH_CONFIG, dev, &buf, &bufsize);
if (status == EFI_SUCCESS) {
cmdsize = bufsize + 1;
cmd = malloc(cmdsize);
@ -546,25 +244,24 @@ try_boot(void)
buf = NULL;
}
if ((status = BS->LoadImage(TRUE, IH, efi_devpath_last_node(fspath),
if ((status = BS->LoadImage(TRUE, IH, devpath_last(dev->devpath),
loaderbuf, loadersize, &loaderhandle)) != EFI_SUCCESS) {
printf("Failed to load image, size: %zu, (%lu)\n",
loadersize, EFI_ERROR_CODE(status));
printf("Failed to load image provided by %s, size: %zu, (%lu)\n",
mod->name, loadersize, EFI_ERROR_CODE(status));
goto errout;
}
if ((status = BS->OpenProtocol(loaderhandle, &LoadedImageGUID,
(VOID**)&loaded_image, IH, NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL)) != EFI_SUCCESS) {
printf("Failed to query LoadedImage (%lu)\n",
EFI_ERROR_CODE(status));
if ((status = BS->HandleProtocol(loaderhandle, &LoadedImageGUID,
(VOID**)&loaded_image)) != EFI_SUCCESS) {
printf("Failed to query LoadedImage provided by %s (%lu)\n",
mod->name, EFI_ERROR_CODE(status));
goto errout;
}
if (cmd != NULL)
printf(" command args: %s\n", cmd);
loaded_image->DeviceHandle = fshandle;
loaded_image->DeviceHandle = dev->devhandle;
loaded_image->LoadOptionsSize = cmdsize;
loaded_image->LoadOptions = cmd;
@ -582,8 +279,8 @@ try_boot(void)
if ((status = BS->StartImage(loaderhandle, NULL, NULL)) !=
EFI_SUCCESS) {
printf("Failed to start image (%lu)\n",
EFI_ERROR_CODE(status));
printf("Failed to start image provided by %s (%lu)\n",
mod->name, EFI_ERROR_CODE(status));
loaded_image->LoadOptionsSize = 0;
loaded_image->LoadOptions = NULL;
}
@ -599,37 +296,142 @@ try_boot(void)
return (status);
}
EFI_STATUS
main(int argc __unused, CHAR16 *argv[] __unused)
/*
* probe_handle determines if the passed handle represents a logical partition
* if it does it uses each module in order to probe it and if successful it
* returns EFI_SUCCESS.
*/
static EFI_STATUS
probe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath, BOOLEAN *preferred)
{
EFI_STATUS status;
dev_info_t *devinfo;
EFI_BLOCK_IO *blkio;
EFI_DEVICE_PATH *devpath;
EFI_STATUS status;
UINTN i;
SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL;
UINTN i, max_dim, best_mode, cols, rows;
CHAR16 *text;
/* Figure out if we're dealing with an actual partition. */
status = BS->HandleProtocol(h, &DevicePathGUID, (void **)&devpath);
if (status == EFI_UNSUPPORTED)
return (status);
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;
#ifdef EFI_ZFS_BOOT
/* Note this needs to be set before ZFS init. */
archsw.arch_zfs_probe = efi_zfs_probe;
if (status != EFI_SUCCESS) {
DPRINTF("\nFailed to query DevicePath (%lu)\n",
EFI_ERROR_CODE(status));
return (status);
}
#ifdef EFI_DEBUG
{
CHAR16 *text = efi_devpath_name(devpath);
DPRINTF("probing: %S\n", text);
efi_free_devpath_name(text);
}
#endif
status = BS->HandleProtocol(h, &BlockIoProtocolGUID, (void **)&blkio);
if (status == EFI_UNSUPPORTED)
return (status);
/* Init the time source */
efi_time_init();
cons_probe();
if (status != EFI_SUCCESS) {
DPRINTF("\nFailed to query BlockIoProtocol (%lu)\n",
EFI_ERROR_CODE(status));
return (status);
}
if (!blkio->Media->LogicalPartition)
return (EFI_UNSUPPORTED);
*preferred = device_paths_match(imgpath, devpath);
/* Run through each module, see if it can load this partition */
for (i = 0; i < NUM_BOOT_MODULES; i++) {
devinfo = malloc(sizeof(*devinfo));
if (devinfo == NULL) {
DPRINTF("\nFailed to allocate devinfo\n");
continue;
}
devinfo->dev = blkio;
devinfo->devpath = devpath;
devinfo->devhandle = h;
devinfo->devdata = NULL;
devinfo->preferred = *preferred;
devinfo->next = NULL;
status = boot_modules[i]->probe(devinfo);
if (status == EFI_SUCCESS)
return (EFI_SUCCESS);
free(devinfo);
}
return (EFI_UNSUPPORTED);
}
/*
* probe_handle_status calls probe_handle and outputs the returned status
* of the call.
*/
static void
probe_handle_status(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath)
{
EFI_STATUS status;
BOOLEAN preferred;
preferred = FALSE;
status = probe_handle(h, imgpath, &preferred);
DPRINTF("probe: ");
switch (status) {
case EFI_UNSUPPORTED:
printf(".");
DPRINTF(" not supported\n");
break;
case EFI_SUCCESS:
if (preferred) {
printf("%c", '*');
DPRINTF(" supported (preferred)\n");
} else {
printf("%c", '+');
DPRINTF(" supported\n");
}
break;
default:
printf("x");
DPRINTF(" error (%lu)\n", EFI_ERROR_CODE(status));
break;
}
DSTALL(500000);
}
EFI_STATUS
efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab)
{
EFI_HANDLE *handles;
EFI_LOADED_IMAGE *img;
EFI_DEVICE_PATH *imgpath;
EFI_STATUS status;
EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL;
SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL;
UINTN i, max_dim, best_mode, cols, rows, hsize, nhandles;
CHAR16 *text;
/* Basic initialization*/
ST = Xsystab;
IH = Ximage;
BS = ST->BootServices;
RS = ST->RuntimeServices;
/* Set up the console, so printf works. */
status = BS->LocateProtocol(&ConsoleControlGUID, NULL,
(VOID **)&ConsoleControl);
if (status == EFI_SUCCESS)
(void)ConsoleControl->SetMode(ConsoleControl,
EfiConsoleControlScreenText);
/*
* Reset the console and find the best text mode.
*/
conout = ST->ConOut;
conout->Reset(conout, TRUE);
max_dim = best_mode = 0;
for (i = 0; ; i++) {
for (i = 0; ; i++) {
status = conout->QueryMode(conout, i, &cols, &rows);
if (EFI_ERROR(status))
break;
@ -638,37 +440,31 @@ main(int argc __unused, CHAR16 *argv[] __unused)
best_mode = i;
}
}
if (max_dim > 0)
if (max_dim > 0)
conout->SetMode(conout, best_mode);
conout->EnableCursor(conout, TRUE);
conout->ClearScreen(conout);
/* Print this here, so people know it's at least starting. */
printf("\n>> FreeBSD EFI boot block\n");
printf(" Loader path: %s\n\n", PATH_LOADER_EFI);
/* Get the image path and trim it to get the disk on which we
* found this loader.
*/
if ((status = BS->OpenProtocol(IH, &LoadedImageGUID,
(VOID**)&boot_image, IH, NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL)) != EFI_SUCCESS) {
panic("Failed to query LoadedImage (%lu)\n",
EFI_ERROR_CODE(status));
printf(" Initializing modules:");
for (i = 0; i < NUM_BOOT_MODULES; i++) {
printf(" %s", boot_modules[i]->name);
if (boot_modules[i]->init != NULL)
boot_modules[i]->init();
}
putchar('\n');
/* Determine the devpath of our image so we can prefer it. */
status = BS->HandleProtocol(IH, &LoadedImageGUID, (VOID**)&boot_image);
status = BS->HandleProtocol(IH, &LoadedImageGUID, (VOID**)&img);
imgpath = NULL;
if (status == EFI_SUCCESS) {
text = efi_devpath_name(boot_image->FilePath);
text = efi_devpath_name(img->FilePath);
printf(" Load Path: %S\n", text);
efi_setenv_freebsd_wcs("Boot1Path", text);
efi_free_devpath_name(text);
status = BS->HandleProtocol(boot_image->DeviceHandle, &DevicePathGUID,
status = BS->HandleProtocol(img->DeviceHandle, &DevicePathGUID,
(void **)&imgpath);
if (status != EFI_SUCCESS) {
DPRINTF("Failed to get image DevicePath (%lu)\n",
@ -682,35 +478,48 @@ main(int argc __unused, CHAR16 *argv[] __unused)
}
/* The loaded image device path ends with a partition, then a
* file path. Trim them both to get the actual disk.
*/
if ((imgprefix = efi_devpath_trim(imgpath)) == NULL ||
(imgprefix = efi_devpath_trim(imgprefix)) == NULL) {
panic("Couldn't trim device path");
}
/*
* Initialize the block cache. Set the upper limit.
*/
bcache_init(32768, 512);
printf("\n Initializing modules:");
for (i = 0; efi_drivers[i] != NULL; i++) {
printf(" %s", efi_drivers[i]->name);
if (efi_drivers[i]->init != NULL)
efi_drivers[i]->init();
/* Get all the device handles */
hsize = (UINTN)NUM_HANDLES_INIT * sizeof(EFI_HANDLE);
handles = malloc(hsize);
if (handles == NULL) {
printf("Failed to allocate %d handles\n", NUM_HANDLES_INIT);
}
for (i = 0; devsw[i] != NULL; i++) {
if (devsw[i]->dv_init != NULL) {
printf(" %s", devsw[i]->dv_name);
(devsw[i]->dv_init)();
}
}
status = BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL,
&hsize, handles);
switch (status) {
case EFI_SUCCESS:
break;
case EFI_BUFFER_TOO_SMALL:
free(handles);
handles = malloc(hsize);
if (handles == NULL)
efi_panic(EFI_OUT_OF_RESOURCES, "Failed to allocate %d handles\n",
NUM_HANDLES_INIT);
status = BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID,
NULL, &hsize, handles);
if (status != EFI_SUCCESS)
efi_panic(status, "Failed to get device handles\n");
break;
default:
efi_panic(status, "Failed to get device handles\n");
break;
}
putchar('\n');
/* Scan all partitions, probing with all modules. */
nhandles = hsize / sizeof(*handles);
printf(" Probing %zu block devices...", nhandles);
DPRINTF("\n");
for (i = 0; i < nhandles; i++)
probe_handle_status(handles[i], imgpath);
printf(" done\n");
/* Status summary. */
for (i = 0; i < NUM_BOOT_MODULES; i++) {
printf(" ");
boot_modules[i]->status();
}
try_boot();
@ -718,6 +527,25 @@ main(int argc __unused, CHAR16 *argv[] __unused)
efi_panic(EFI_LOAD_ERROR, "No bootable partitions found!");
}
/*
* add_device adds a device to the passed devinfo list.
*/
void
add_device(dev_info_t **devinfop, dev_info_t *devinfo)
{
dev_info_t *dev;
if (*devinfop == NULL) {
*devinfop = devinfo;
return;
}
for (dev = *devinfop; dev->next != NULL; dev = dev->next)
;
dev->next = devinfo;
}
/*
* OK. We totally give up. Exit back to EFI with a sensible status so
* it can try the next option on the list.
@ -725,13 +553,28 @@ main(int argc __unused, CHAR16 *argv[] __unused)
static void
efi_panic(EFI_STATUS s, const char *fmt, ...)
{
va_list ap;
va_list ap;
printf("panic: ");
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
printf("\n");
printf("panic: ");
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
printf("\n");
BS->Exit(IH, s, 0, NULL);
BS->Exit(IH, s, 0, NULL);
}
void
putchar(int c)
{
CHAR16 buf[2];
if (c == '\n') {
buf[0] = '\r';
buf[1] = 0;
ST->ConOut->OutputString(ST->ConOut, buf);
}
buf[0] = c;
buf[1] = 0;
ST->ConOut->OutputString(ST->ConOut, buf);
}

View File

@ -0,0 +1,109 @@
/*-
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*
* $FreeBSD$
*/
#ifndef _BOOT_MODULE_H_
#define _BOOT_MODULE_H_
#include <stdbool.h>
#include <efi.h>
#include <efilib.h>
#include <eficonsctl.h>
#ifdef EFI_DEBUG
#define DPRINTF(fmt, args...) printf(fmt, ##args)
#define DSTALL(d) BS->Stall(d)
#else
#define DPRINTF(fmt, ...) {}
#define DSTALL(d) {}
#endif
/* EFI device info */
typedef struct dev_info
{
EFI_BLOCK_IO *dev;
EFI_DEVICE_PATH *devpath;
EFI_HANDLE *devhandle;
void *devdata;
BOOLEAN preferred;
struct dev_info *next;
} 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 *name;
/* init is the optional initialiser for the module. */
void (*init)(void);
/*
* probe checks to see if the module can handle dev.
*
* Return codes:
* EFI_SUCCESS = The module can handle the device.
* EFI_NOT_FOUND = The module can not handle the device.
* Other = The module encountered an error.
*/
EFI_STATUS (*probe)(dev_info_t* dev);
/*
* load should select the best out of a set of devices that probe
* indicated were loadable and load the specified file.
*
* Return codes:
* EFI_SUCCESS = The module can handle the device.
* EFI_NOT_FOUND = The module can not handle the device.
* Other = The module encountered an error.
*/
EFI_STATUS (*load)(const char *filepath, dev_info_t *devinfo,
void **buf, size_t *bufsize);
/* status outputs information about the probed devices. */
void (*status)(void);
/* valid devices as found by probe. */
dev_info_t *(*devices)(void);
} boot_module_t;
/* Standard boot modules. */
#ifdef EFI_UFS_BOOT
extern const boot_module_t ufs_module;
#endif
#ifdef EFI_ZFS_BOOT
extern const boot_module_t zfs_module;
#endif
/* Functions available to modules. */
extern void add_device(dev_info_t **devinfop, dev_info_t *devinfo);
extern int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap);
#endif

View File

@ -0,0 +1,185 @@
/*-
* 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, 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*
* $FreeBSD$
*/
#include <stdarg.h>
#include <stdbool.h>
#include <sys/cdefs.h>
#include <sys/param.h>
#include <efi.h>
#include "boot_module.h"
static dev_info_t *devinfo;
static dev_info_t *devices;
static int
dskread(void *buf, u_int64_t lba, int nblk)
{
int size;
EFI_STATUS status;
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 (status != EFI_SUCCESS) {
DPRINTF("dskread: failed dev: %p, id: %u, lba: %ju, size: %d, "
"status: %lu\n", devinfo->dev,
devinfo->dev->Media->MediaId, (uintmax_t)lba, size,
EFI_ERROR_CODE(status));
return (-1);
}
return (0);
}
#include "ufsread.c"
static struct dmadat __dmadat;
static int
init_dev(dev_info_t* dev)
{
devinfo = dev;
dmadat = &__dmadat;
return fsread(0, NULL, 0);
}
static EFI_STATUS
probe(dev_info_t* dev)
{
if (init_dev(dev) < 0)
return (EFI_UNSUPPORTED);
add_device(&devices, dev);
return (EFI_SUCCESS);
}
static EFI_STATUS
load(const char *filepath, dev_info_t *dev, void **bufp, size_t *bufsize)
{
ufs_ino_t ino;
EFI_STATUS status;
size_t size;
ssize_t read;
void *buf;
#ifdef EFI_DEBUG
{
CHAR16 *text = efi_devpath_name(dev->devpath);
DPRINTF("Loading '%s' from %S\n", filepath, text);
efi_free_devpath_name(text);
}
#endif
if (init_dev(dev) < 0) {
DPRINTF("Failed to init device\n");
return (EFI_UNSUPPORTED);
}
if ((ino = lookup(filepath)) == 0) {
DPRINTF("Failed to lookup '%s' (file not found?)\n", filepath);
return (EFI_NOT_FOUND);
}
if (fsread_size(ino, NULL, 0, &size) < 0 || size <= 0) {
printf("Failed to read size of '%s' ino: %d\n", filepath, ino);
return (EFI_INVALID_PARAMETER);
}
if ((status = BS->AllocatePool(EfiLoaderData, size, &buf)) !=
EFI_SUCCESS) {
printf("Failed to allocate read buffer %zu for '%s' (%lu)\n",
size, filepath, EFI_ERROR_CODE(status));
return (status);
}
read = fsread(ino, buf, size);
if ((size_t)read != size) {
printf("Failed to read '%s' (%zd != %zu)\n", filepath, read,
size);
(void)BS->FreePool(buf);
return (EFI_INVALID_PARAMETER);
}
DPRINTF("Load complete\n");
*bufp = buf;
*bufsize = size;
return (EFI_SUCCESS);
}
static void
status(void)
{
int i;
dev_info_t *dev;
for (dev = devices, i = 0; dev != NULL; dev = dev->next, i++)
;
printf("%s found ", ufs_module.name);
switch (i) {
case 0:
printf("no partitions\n");
break;
case 1:
printf("%d partition\n", i);
break;
default:
printf("%d partitions\n", i);
}
}
static dev_info_t *
_devices(void)
{
return (devices);
}
const boot_module_t ufs_module =
{
.name = "UFS",
.probe = probe,
.load = load,
.status = status,
.devices = _devices
};

View File

@ -0,0 +1,248 @@
/*-
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*
* $FreeBSD$
*/
#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"
static dev_info_t *devices;
uint64_t
ldi_get_size(void *priv)
{
dev_info_t *devinfo = priv;
return (devinfo->dev->Media->BlockSize *
(devinfo->dev->Media->LastBlock + 1));
}
static int
vdev_read(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes)
{
dev_info_t *devinfo;
uint64_t lba;
size_t size, remainder, rb_size, blksz;
char *bouncebuf = NULL, *rb_buf;
EFI_STATUS status;
devinfo = (dev_info_t *)priv;
lba = off / devinfo->dev->Media->BlockSize;
remainder = off % devinfo->dev->Media->BlockSize;
rb_buf = buf;
rb_size = bytes;
/*
* If we have remainder from off, we need to add remainder part.
* Since buffer must be multiple of the BlockSize, round it all up.
*/
size = roundup2(bytes + remainder, devinfo->dev->Media->BlockSize);
blksz = size;
if (remainder != 0 || size != bytes) {
rb_size = devinfo->dev->Media->BlockSize;
bouncebuf = malloc(rb_size);
if (bouncebuf == NULL) {
printf("vdev_read: out of memory\n");
return (-1);
}
rb_buf = bouncebuf;
blksz = rb_size - remainder;
}
while (bytes > 0) {
status = devinfo->dev->ReadBlocks(devinfo->dev,
devinfo->dev->Media->MediaId, lba, rb_size, rb_buf);
if (EFI_ERROR(status))
goto error;
if (bytes < blksz)
blksz = bytes;
if (bouncebuf != NULL)
memcpy(buf, rb_buf + remainder, blksz);
buf = (void *)((uintptr_t)buf + blksz);
bytes -= blksz;
lba++;
remainder = 0;
blksz = rb_size;
}
free(bouncebuf);
return (0);
error:
free(bouncebuf);
DPRINTF("vdev_read: failed dev: %p, id: %u, lba: %ju, size: %zu,"
" rb_size: %zu, status: %lu\n", devinfo->dev,
devinfo->dev->Media->MediaId, (uintmax_t)lba, bytes, rb_size,
EFI_ERROR_CODE(status));
return (-1);
}
static EFI_STATUS
probe(dev_info_t *dev)
{
spa_t *spa;
dev_info_t *tdev;
EFI_STATUS status;
/* ZFS consumes the dev on success so we need a copy. */
if ((status = BS->AllocatePool(EfiLoaderData, sizeof(*dev),
(void**)&tdev)) != EFI_SUCCESS) {
DPRINTF("Failed to allocate tdev (%lu)\n",
EFI_ERROR_CODE(status));
return (status);
}
memcpy(tdev, dev, sizeof(*dev));
if (vdev_probe(vdev_read, tdev, &spa) != 0) {
(void)BS->FreePool(tdev);
return (EFI_UNSUPPORTED);
}
dev->devdata = spa;
add_device(&devices, dev);
return (EFI_SUCCESS);
}
static EFI_STATUS
load(const char *filepath, dev_info_t *devinfo, void **bufp, size_t *bufsize)
{
spa_t *spa;
struct zfsmount zfsmount;
dnode_phys_t dn;
struct stat st;
int err;
void *buf;
EFI_STATUS status;
spa = devinfo->devdata;
#ifdef EFI_DEBUG
{
CHAR16 *text = efi_devpath_name(devinfo->devpath);
DPRINTF("load: '%s' spa: '%s', devpath: %S\n", filepath,
spa->spa_name, text);
efi_free_devpath_name(text);
}
#endif
if ((err = zfs_spa_init(spa)) != 0) {
DPRINTF("Failed to load pool '%s' (%d)\n", spa->spa_name, err);
return (EFI_NOT_FOUND);
}
if ((err = zfs_mount(spa, 0, &zfsmount)) != 0) {
DPRINTF("Failed to mount pool '%s' (%d)\n", spa->spa_name, err);
return (EFI_NOT_FOUND);
}
if ((err = zfs_lookup(&zfsmount, filepath, &dn)) != 0) {
if (err == ENOENT) {
DPRINTF("Failed to find '%s' on pool '%s' (%d)\n",
filepath, spa->spa_name, err);
return (EFI_NOT_FOUND);
}
printf("Failed to lookup '%s' on pool '%s' (%d)\n", filepath,
spa->spa_name, err);
return (EFI_INVALID_PARAMETER);
}
if ((err = zfs_dnode_stat(spa, &dn, &st)) != 0) {
printf("Failed to stat '%s' on pool '%s' (%d)\n", filepath,
spa->spa_name, err);
return (EFI_INVALID_PARAMETER);
}
if ((status = BS->AllocatePool(EfiLoaderData, (UINTN)st.st_size, &buf))
!= EFI_SUCCESS) {
printf("Failed to allocate load buffer %jd for pool '%s' for '%s' "
"(%lu)\n", (intmax_t)st.st_size, spa->spa_name, filepath, EFI_ERROR_CODE(status));
return (EFI_INVALID_PARAMETER);
}
if ((err = dnode_read(spa, &dn, 0, buf, st.st_size)) != 0) {
printf("Failed to read node from %s (%d)\n", spa->spa_name,
err);
(void)BS->FreePool(buf);
return (EFI_INVALID_PARAMETER);
}
*bufsize = st.st_size;
*bufp = buf;
return (EFI_SUCCESS);
}
static void
status(void)
{
spa_t *spa;
spa = STAILQ_FIRST(&zfs_pools);
if (spa == NULL) {
printf("%s found no pools\n", zfs_module.name);
return;
}
printf("%s found the following pools:", zfs_module.name);
STAILQ_FOREACH(spa, &zfs_pools, spa_link)
printf(" %s", spa->spa_name);
printf("\n");
}
static void
init(void)
{
zfs_init();
}
static dev_info_t *
_devices(void)
{
return (devices);
}
const boot_module_t zfs_module =
{
.name = "ZFS",
.init = init,
.probe = probe,
.load = load,
.status = status,
.devices = _devices
};

View File

@ -10,9 +10,8 @@ LIB= efi
INTERNALLIB=
WARNS?= 2
SRCS= delay.c devpath.c efi_console.c efichar.c efinet.c efipart.c env.c \
errno.c handles.c wchar.c libefi.c efi_driver_utils.c efizfs.c \
devicename.c efi_main.c
SRCS= delay.c devpath.c efi_console.c efichar.c efinet.c efipart.c env.c errno.c \
handles.c wchar.c libefi.c efi_driver_utils.c efizfs.c devicename.c
.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386"
SRCS+= time.c

View File

@ -21,6 +21,7 @@ SRCS= autoload.c \
bootinfo.c \
conf.c \
copy.c \
efi_main.c \
main.c \
self_reloc.c \
smbios.c \