Unify boot1 with loader
Refactor boot1 to use the same I/O code as /boot/loader uses. Refactor to use the common efi_main.c. Submitted by: Eric McCorkle Differential Revision: https://reviews.freebsd.org/D10447
This commit is contained in:
parent
7e23517415
commit
891f691139
@ -8,7 +8,10 @@ MK_SSP= no
|
||||
|
||||
PROG= boot1.sym
|
||||
INTERNALPROG=
|
||||
WARNS?= 6
|
||||
WARNS?= 3
|
||||
|
||||
# Include bcache code.
|
||||
HAVE_BCACHE= yes
|
||||
|
||||
# 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
|
||||
@ -18,13 +21,15 @@ WARNS?= 6
|
||||
CWARNFLAGS.boot1.c+= -Wno-format
|
||||
|
||||
# Disable warnings that are currently incompatible with the zfs boot code
|
||||
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.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.skein.c += -Wno-cast-align
|
||||
.if ${COMPILER_TYPE} == "clang"
|
||||
CWARNFLAGS.skein.c += -Wno-missing-variable-declarations
|
||||
@ -33,19 +38,27 @@ CWARNFLAGS.skein.c += -Wno-missing-declarations
|
||||
.endif
|
||||
|
||||
# architecture-specific loader code
|
||||
SRCS= boot1.c self_reloc.c start.S ufs_module.c
|
||||
SRCS= boot1.c self_reloc.c start.S
|
||||
.if ${MK_ZFS} != "no"
|
||||
SRCS+= zfs_module.c
|
||||
.PATH: ${.CURDIR}/../../../crypto/skein
|
||||
SRCS+= skein.c skein_block.c
|
||||
# Do not unroll skein loops, reduce code size
|
||||
CFLAGS+= -DSKEIN_LOOP=111
|
||||
.PATH: ${.CURDIR}/../../../crypto/skein
|
||||
.PATH: ${.CURDIR}/../../zfs
|
||||
SRCS+= zfs.c
|
||||
.endif
|
||||
|
||||
.if ${COMPILER_TYPE} == "gcc" && ${COMPILER_VERSION} > 40201
|
||||
CWARNFLAGS.self_reloc.c+= -Wno-error=maybe-uninitialized
|
||||
.endif
|
||||
|
||||
# Always add MI sources
|
||||
.PATH: ${.CURDIR}/../../common
|
||||
.include "${.CURDIR}/../../common/Makefile.inc"
|
||||
CFLAGS+= -I${.CURDIR}/../../common
|
||||
|
||||
.PATH: ${.CURDIR}/arch/${MACHINE}
|
||||
|
||||
CFLAGS+= -I.
|
||||
CFLAGS+= -I${.CURDIR}/../include
|
||||
CFLAGS+= -I${.CURDIR}/../include/${MACHINE}
|
||||
@ -117,7 +130,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 .rela.dyn -j .reloc -j .eh_frame -j set_Xcommand_set \
|
||||
--output-target=${EFI_TARGET} ${.ALLSRC} ${.TARGET}
|
||||
|
||||
boot1.o: ${SASRC}/ufsread.c
|
||||
|
@ -23,61 +23,179 @@
|
||||
__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 "boot_module.h"
|
||||
#include <bootstrap.h>
|
||||
|
||||
#include "efi_drivers.h"
|
||||
#include "efizfs.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
|
||||
|
||||
static const boot_module_t *boot_modules[] =
|
||||
{
|
||||
#ifdef EFI_ZFS_BOOT
|
||||
&zfs_module,
|
||||
#endif
|
||||
#ifdef EFI_UFS_BOOT
|
||||
&ufs_module
|
||||
#endif
|
||||
struct arch_switch archsw; /* MI/MD interface boundary */
|
||||
|
||||
static const efi_driver_t *efi_drivers[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
#define NUM_BOOT_MODULES nitems(boot_modules)
|
||||
extern struct console efi_console;
|
||||
#if defined(__amd64__) || defined(__i386__)
|
||||
extern struct console comconsole;
|
||||
extern struct console nullconsole;
|
||||
#endif
|
||||
|
||||
#ifdef EFI_ZFS_BOOT
|
||||
uint64_t pool_guid;
|
||||
#endif
|
||||
|
||||
struct fs_ops *file_system[] = {
|
||||
#ifdef EFI_ZFS_BOOT
|
||||
&zfs_fsops,
|
||||
#endif
|
||||
&dosfs_fsops,
|
||||
#ifdef EFI_UFS_BOOT
|
||||
&ufs_fsops,
|
||||
#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);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
/*
|
||||
* 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)
|
||||
static EFI_STATUS
|
||||
do_load(const char *filepath, void **bufp, size_t *bufsize)
|
||||
{
|
||||
void *out;
|
||||
struct stat st;
|
||||
void *buf = NULL;
|
||||
int fd, err;
|
||||
size_t fsize, remaining;
|
||||
ssize_t readsize;
|
||||
|
||||
if (BS->AllocatePool(EfiLoaderData, len, &out) == EFI_SUCCESS)
|
||||
return (out);
|
||||
if ((fd = open(filepath, O_RDONLY)) < 0) {
|
||||
return (ENOTSUP);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
if ((err = fstat(fd, &st)) != 0) {
|
||||
goto close_file;
|
||||
}
|
||||
|
||||
void
|
||||
Free(void *buf, const char *file __unused, int line __unused)
|
||||
{
|
||||
if (buf != NULL)
|
||||
(void)BS->FreePool(buf);
|
||||
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;
|
||||
}
|
||||
|
||||
static EFI_STATUS
|
||||
@ -97,98 +215,275 @@ efi_setenv_freebsd_wcs(const char *varname, CHAR16 *valstr)
|
||||
return (rv);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
static int
|
||||
probe_fs(const char *filepath)
|
||||
{
|
||||
size_t len;
|
||||
int fd;
|
||||
|
||||
if (imgpath == NULL || imgpath->Type != devpath->Type ||
|
||||
imgpath->SubType != devpath->SubType)
|
||||
return (FALSE);
|
||||
if ((fd = open(filepath, O_RDONLY)) < 0) {
|
||||
return (ENOTSUP);
|
||||
}
|
||||
|
||||
len = DevicePathNodeLength(imgpath);
|
||||
if (len != DevicePathNodeLength(devpath))
|
||||
return (FALSE);
|
||||
close(fd);
|
||||
|
||||
return (memcmp(imgpath, devpath, (size_t)len) == 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
static int
|
||||
probe_dev(struct devsw *dev, int unit, const char *filepath)
|
||||
{
|
||||
struct devdesc currdev;
|
||||
char *devname;
|
||||
int err;
|
||||
|
||||
if (imgpath == NULL)
|
||||
return (FALSE);
|
||||
currdev.d_dev = dev;
|
||||
currdev.d_type = currdev.d_dev->dv_type;
|
||||
currdev.d_unit = unit;
|
||||
currdev.d_opendata = NULL;
|
||||
devname = efi_fmtdev(&currdev);
|
||||
|
||||
while (!IsDevicePathEnd(imgpath) && !IsDevicePathEnd(devpath)) {
|
||||
if (IsDevicePathType(imgpath, MEDIA_DEVICE_PATH) &&
|
||||
IsDevicePathType(devpath, MEDIA_DEVICE_PATH))
|
||||
return (TRUE);
|
||||
env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev,
|
||||
env_nounset);
|
||||
|
||||
if (!nodes_match(imgpath, devpath))
|
||||
return (FALSE);
|
||||
err = probe_fs(filepath);
|
||||
|
||||
imgpath = NextDevicePathNode(imgpath);
|
||||
devpath = NextDevicePathNode(devpath);
|
||||
return (err);
|
||||
}
|
||||
|
||||
static bool
|
||||
check_preferred(EFI_HANDLE *h)
|
||||
{
|
||||
EFI_DEVICE_PATH *path = efi_lookup_devpath(h);
|
||||
bool out;
|
||||
|
||||
if ((path = efi_lookup_devpath(h)) == NULL)
|
||||
return (false);
|
||||
|
||||
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 */
|
||||
|
||||
return (FALSE);
|
||||
}
|
||||
/* 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;
|
||||
|
||||
/*
|
||||
* devpath_last returns the last non-path end node in devpath.
|
||||
*/
|
||||
static EFI_DEVICE_PATH *
|
||||
devpath_last(EFI_DEVICE_PATH *devpath)
|
||||
{
|
||||
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);
|
||||
|
||||
while (!IsDevicePathEnd(NextDevicePathNode(devpath)))
|
||||
devpath = NextDevicePathNode(devpath);
|
||||
env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev,
|
||||
env_nounset);
|
||||
|
||||
return (devpath);
|
||||
}
|
||||
if (check_preferred(dp->pd_handle) &&
|
||||
probe_fs(filepath) == 0 &&
|
||||
do_load(filepath, bufp, bufsize) == EFI_SUCCESS) {
|
||||
*handlep = dp->pd_handle;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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(const boot_module_t **modp, dev_info_t **devinfop, void **bufp,
|
||||
size_t *bufsize, BOOLEAN preferred)
|
||||
{
|
||||
UINTN i;
|
||||
dev_info_t *dev;
|
||||
const boot_module_t *mod;
|
||||
/* 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);
|
||||
|
||||
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;
|
||||
env_setenv("currdev", EV_VOLATILE, devname,
|
||||
efi_setcurrdev, env_nounset);
|
||||
|
||||
if (mod->load(PATH_LOADER_EFI, dev, bufp, bufsize) ==
|
||||
EFI_SUCCESS) {
|
||||
*devinfop = dev;
|
||||
*modp = mod;
|
||||
return (EFI_SUCCESS);
|
||||
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);
|
||||
}
|
||||
|
||||
static EFI_STATUS
|
||||
load_loader(EFI_HANDLE *handlep, void **bufp, size_t *bufsize)
|
||||
{
|
||||
/* Try the preferred handles first, then all the handles */
|
||||
if (load_preferred(boot_image, PATH_LOADER_EFI, bufp, bufsize,
|
||||
handlep) == 0) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (load_all(PATH_LOADER_EFI, bufp, bufsize, handlep) == 0) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
return (EFI_NOT_FOUND);
|
||||
}
|
||||
|
||||
@ -202,20 +497,27 @@ try_boot(void)
|
||||
size_t bufsize, loadersize, cmdsize;
|
||||
void *buf, *loaderbuf;
|
||||
char *cmd;
|
||||
dev_info_t *dev;
|
||||
const boot_module_t *mod;
|
||||
EFI_HANDLE fshandle;
|
||||
EFI_HANDLE loaderhandle;
|
||||
EFI_LOADED_IMAGE *loaded_image;
|
||||
EFI_STATUS status;
|
||||
EFI_DEVICE_PATH *fspath;
|
||||
|
||||
status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE);
|
||||
if (status != EFI_SUCCESS) {
|
||||
status = load_loader(&mod, &dev, &loaderbuf, &loadersize,
|
||||
FALSE);
|
||||
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);
|
||||
if (status != EFI_SUCCESS) {
|
||||
printf("Failed to load '%s'\n", PATH_LOADER_EFI);
|
||||
return (status);
|
||||
}
|
||||
DPRINTF("Failed to get image DevicePath (%lu)\n",
|
||||
EFI_ERROR_CODE(status));
|
||||
}
|
||||
DPRINTF("filesystem device path: %s\n", devpath_str(fspath));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -230,9 +532,9 @@ try_boot(void)
|
||||
*/
|
||||
cmd = NULL;
|
||||
cmdsize = 0;
|
||||
status = mod->load(PATH_DOTCONFIG, dev, &buf, &bufsize);
|
||||
status = do_load(PATH_DOTCONFIG, &buf, &bufsize);
|
||||
if (status == EFI_NOT_FOUND)
|
||||
status = mod->load(PATH_CONFIG, dev, &buf, &bufsize);
|
||||
status = do_load(PATH_CONFIG, &buf, &bufsize);
|
||||
if (status == EFI_SUCCESS) {
|
||||
cmdsize = bufsize + 1;
|
||||
cmd = malloc(cmdsize);
|
||||
@ -244,24 +546,25 @@ try_boot(void)
|
||||
buf = NULL;
|
||||
}
|
||||
|
||||
if ((status = BS->LoadImage(TRUE, IH, devpath_last(dev->devpath),
|
||||
if ((status = BS->LoadImage(TRUE, IH, efi_devpath_last_node(fspath),
|
||||
loaderbuf, loadersize, &loaderhandle)) != EFI_SUCCESS) {
|
||||
printf("Failed to load image provided by %s, size: %zu, (%lu)\n",
|
||||
mod->name, loadersize, EFI_ERROR_CODE(status));
|
||||
printf("Failed to load image, size: %zu, (%lu)\n",
|
||||
loadersize, EFI_ERROR_CODE(status));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
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));
|
||||
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));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (cmd != NULL)
|
||||
printf(" command args: %s\n", cmd);
|
||||
|
||||
loaded_image->DeviceHandle = dev->devhandle;
|
||||
loaded_image->DeviceHandle = fshandle;
|
||||
loaded_image->LoadOptionsSize = cmdsize;
|
||||
loaded_image->LoadOptions = cmd;
|
||||
|
||||
@ -279,8 +582,8 @@ try_boot(void)
|
||||
|
||||
if ((status = BS->StartImage(loaderhandle, NULL, NULL)) !=
|
||||
EFI_SUCCESS) {
|
||||
printf("Failed to start image provided by %s (%lu)\n",
|
||||
mod->name, EFI_ERROR_CODE(status));
|
||||
printf("Failed to start image (%lu)\n",
|
||||
EFI_ERROR_CODE(status));
|
||||
loaded_image->LoadOptionsSize = 0;
|
||||
loaded_image->LoadOptions = NULL;
|
||||
}
|
||||
@ -296,142 +599,37 @@ errout:
|
||||
return (status);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
dev_info_t *devinfo;
|
||||
EFI_BLOCK_IO *blkio;
|
||||
EFI_DEVICE_PATH *devpath;
|
||||
EFI_STATUS status;
|
||||
UINTN i;
|
||||
|
||||
/* Figure out if we're dealing with an actual partition. */
|
||||
status = BS->HandleProtocol(h, &DevicePathGUID, (void **)&devpath);
|
||||
if (status == EFI_UNSUPPORTED)
|
||||
return (status);
|
||||
|
||||
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);
|
||||
|
||||
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)
|
||||
main(int argc __unused, CHAR16 *argv[] __unused)
|
||||
{
|
||||
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;
|
||||
EFI_STATUS status;
|
||||
|
||||
/* Basic initialization*/
|
||||
ST = Xsystab;
|
||||
IH = Ximage;
|
||||
BS = ST->BootServices;
|
||||
RS = ST->RuntimeServices;
|
||||
SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL;
|
||||
UINTN i, max_dim, best_mode, cols, rows;
|
||||
CHAR16 *text;
|
||||
|
||||
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;
|
||||
#endif
|
||||
|
||||
/* Init the time source */
|
||||
efi_time_init();
|
||||
cons_probe();
|
||||
|
||||
/* 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;
|
||||
@ -440,31 +638,37 @@ efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab)
|
||||
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);
|
||||
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();
|
||||
|
||||
/* 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));
|
||||
}
|
||||
putchar('\n');
|
||||
|
||||
/* Determine the devpath of our image so we can prefer it. */
|
||||
status = BS->HandleProtocol(IH, &LoadedImageGUID, (VOID**)&img);
|
||||
status = BS->HandleProtocol(IH, &LoadedImageGUID, (VOID**)&boot_image);
|
||||
imgpath = NULL;
|
||||
if (status == EFI_SUCCESS) {
|
||||
text = efi_devpath_name(img->FilePath);
|
||||
text = efi_devpath_name(boot_image->FilePath);
|
||||
printf(" Load Path: %S\n", text);
|
||||
efi_setenv_freebsd_wcs("Boot1Path", text);
|
||||
efi_free_devpath_name(text);
|
||||
|
||||
status = BS->HandleProtocol(img->DeviceHandle, &DevicePathGUID,
|
||||
status = BS->HandleProtocol(boot_image->DeviceHandle, &DevicePathGUID,
|
||||
(void **)&imgpath);
|
||||
if (status != EFI_SUCCESS) {
|
||||
DPRINTF("Failed to get image DevicePath (%lu)\n",
|
||||
@ -478,48 +682,35 @@ efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab)
|
||||
|
||||
}
|
||||
|
||||
/* 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);
|
||||
/* 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();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
for (i = 0; devsw[i] != NULL; i++) {
|
||||
if (devsw[i]->dv_init != NULL) {
|
||||
printf(" %s", devsw[i]->dv_name);
|
||||
(devsw[i]->dv_init)();
|
||||
}
|
||||
}
|
||||
|
||||
/* 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();
|
||||
}
|
||||
putchar('\n');
|
||||
|
||||
try_boot();
|
||||
|
||||
@ -527,25 +718,6 @@ efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab)
|
||||
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.
|
||||
@ -553,28 +725,13 @@ add_device(dev_info_t **devinfop, dev_info_t *devinfo)
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
BS->Exit(IH, s, 0, NULL);
|
||||
}
|
||||
|
@ -1,109 +0,0 @@
|
||||
/*-
|
||||
* 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
|
@ -1,185 +0,0 @@
|
||||
/*-
|
||||
* 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
|
||||
};
|
@ -1,248 +0,0 @@
|
||||
/*-
|
||||
* 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
|
||||
};
|
@ -11,8 +11,9 @@ 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
|
||||
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
|
||||
|
||||
.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386"
|
||||
SRCS+= time.c
|
||||
|
@ -16,7 +16,6 @@ SRCS= autoload.c \
|
||||
bootinfo.c \
|
||||
conf.c \
|
||||
copy.c \
|
||||
efi_main.c \
|
||||
main.c \
|
||||
self_reloc.c \
|
||||
smbios.c \
|
||||
|
Loading…
x
Reference in New Issue
Block a user